/* -*- 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 .
*/
//Class declaration; here because they are only used in this file enumclass SubColFlags {
Page = 0x01, //Helplines of the page
Tab = 0x08, //Helplines inside tables
Fly = 0x10, //Helplines inside fly frames
Sect = 0x20, //Helplines inside sections
};
class SwLineRects
{ public:
std::vector<SwLineRect> m_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 m_nLastCount; //avoid unnecessary cycles in PaintLines
SwLineRects()
: m_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 );
/** * 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 PaintSwFrameBackground 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.
std::unique_ptr<BorderLines> pBLines;
std::unique_ptr<SwLineRects> pSLines;
std::unique_ptr<SwSubsRects> pSSubsLines;
// global variable for sub-lines of body, header, footer, section and footnote frames.
std::unique_ptr<SwSubsRects> pSSpecSubsLines;
SfxProgress *pSProgress;
// Sizes of a pixel and the corresponding halves. Will be reset when // entering SwRootFrame::PaintSwFrame
tools::Long nSPixelSzW;
tools::Long nSPixelSzH;
tools::Long nSHalfPixelSzW;
tools::Long nSHalfPixelSzH;
tools::Long nSMinDistPixelW;
tools::Long nSMinDistPixelH;
Color aSGlobalRetoucheColor;
// Current zoom factor double aSScaleX; double aSScaleY;
/** * To be able to save the statics so the paint is more or less reentrant
*/ class SwSavePaintStatics : public SwPaintProperties
{ public:
SwSavePaintStatics();
~SwSavePaintStatics();
};
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 < m_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(m_aLineRects[i]);
// add condition <aSubsLineRect.IsLocked()> in order to consider only // border lines, which are *not* locked. if ( aSubsLineRect.IsPainted() ||
aSubsLineRect.IsLocked() ) continue;
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 (m_aLineRects.size() == m_nLastCount) return;
// #i16816# tagged pdf support
SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
// #i16816# tagged pdf support
SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
// Remove all help line that are almost covered (tables) for (sal_Int32 i = 0; i != static_cast<sal_Int32>(m_aLineRects.size()); ++i)
{
SwLineRect& rLi = m_aLineRects[i]; constbool bVerticalSubs = rLi.Height() > rLi.Width();
for (size_type k = i + 1; k != m_aLineRects.size(); ++k)
{
SwLineRect& rLk = m_aLineRects[k]; if ( rLi.SSize() == rLk.SSize() )
{ if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) )
{ if ( bVerticalSubs )
{
tools::Long nLi = rLi.Right();
tools::Long nLk = rLk.Right(); if ( rLi.Top() == rLk.Top() &&
((nLi < rLk.Left() && nLi+21 > rLk.Left()) ||
(nLk < rLi.Left() && nLk+21 > rLi.Left())))
{
m_aLineRects.erase(m_aLineRects.begin() + i); // don't continue with inner loop any more: // the array may shrink!
--i; break;
}
} else
{
tools::Long nLi = rLi.Bottom();
tools::Long nLk = rLk.Bottom(); if ( rLi.Left() == rLk.Left() &&
((nLi < rLk.Top() && nLi+21 > rLk.Top()) ||
(nLk < rLi.Top() && nLk+21 > rLi.Top())))
{
m_aLineRects.erase(m_aLineRects.begin() + i); // don't continue with inner loop any more: // the array may shrink!
--i; break;
}
}
}
}
}
}
if (pRects && (!pRects->m_aLineRects.empty()))
RemoveSuperfluousSubsidiaryLines( *pRects, properties );
// 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 (SwLineRect& rLRect : m_aLineRects)
{ // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines. if ( !rLRect.IsPainted() &&
!rLRect.IsLocked() )
{ const Color *pCol = nullptr;
SwViewShell *pShell = properties.pSGlobalShell; const SwViewOption *pOpt = pShell->GetViewOptions(); switch ( rLRect.GetSubColor() )
{ case SubColFlags::Page: pCol = &pOpt->GetDocBoundariesColor(); break; case SubColFlags::Tab: pCol = &pOpt->GetTableBoundariesColor(); break; case SubColFlags::Fly: case SubColFlags::Sect: pCol = &pOpt->GetSectionBoundColor(); break;
}
/** * 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;
}
// 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.AddTop( 1 );
}
if ( rRect.Bottom() < aPxCenterRect.Bottom() )
{ // 'leave pixel overlapping on bottom'
aAlignedPxRect.AddBottom( - 1 );
}
if ( rRect.Left() > aPxCenterRect.Left() )
{ // 'leave pixel overlapping on left'
aAlignedPxRect.AddLeft( 1 );
}
if ( rRect.Right() < aPxCenterRect.Right() )
{ // 'leave pixel overlapping on right'
aAlignedPxRect.AddRight( - 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;
}
// 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);
}
}
/** * 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() ) );
}
/** * Calculate PrtArea plus surrounding plus shadow
*/ staticvoid lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame, const SwBorderAttrs &rAttrs, constbool 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->getFramePrintArea();
rRect.Pos() += pFrame->getFrameArea().Pos();
} elseif ( pFrame->IsCellFrame() )
rRect = pFrame->getFrameArea(); else
{
rRect = pFrame->getFramePrintArea();
rRect.Pos() += pFrame->getFrameArea().Pos();
//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) continue;
/// Change internal order of condition /// first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()" /// have not to be performed, if frame is in "Hell" const SwFrame* pLower = pFly->Lower(); if (!bHell && pLower && pLower->IsNoTextFrame() &&
(static_cast<SwNoTextFrame const*>(pLower)->IsTransparent() || static_cast<SwNoTextFrame const*>(pLower)->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->getFramePrintArea() );
aRect += pFly->getFrameArea().Pos();
rRegion -= aRect;
rClipState.subtractRange(lcl_ShrinkFly(aRect));
}
} if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
gProp.pSRetoucheFly = nullptr;
}
staticvoid lcl_implDrawGraphicBackground(const SvxBrushItem& _rBackgrdBrush,
vcl::RenderContext& _rOut, 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.IsTransparent() ) /// background color is transparent --> draw transparent.
{
bDrawTransparent = true;
nTransparencyPercent = ((255 - aColor.GetAlpha())*100 + 0x7F)/0xFF;
} elseif ( (_rGraphicObj.GetAttr().IsTransparent()) &&
(_rBackgrdBrush.GetColor() == COL_TRANSPARENT) ) /// graphic is drawn transparent and background color is /// "no fill"/"auto fill" --> draw transparent
{
bDrawTransparent = true;
nTransparencyPercent = 100 - (_rGraphicObj.GetAttr().GetAlpha() * 100 + 127) / 255;
}
/** * 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 an inline, checking the conditions and calling method * method <lcl_implDrawGraphicBackground(..)> for the intrinsic drawing. * * @param _rBackgrdBrush * background brush contain the color the background has to be drawn. * * @param _rOut * 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.
*/ staticvoid lcl_DrawGraphicBackground( const SvxBrushItem& _rBackgrdBrush,
OutputDevice& _rOut, 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_implDrawGraphicBackground( _rBackgrdBrush, _rOut, _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_DrawGraphicBackground> * * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
*/ staticvoid lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext &rOutDev, const SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut, 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, &rOutDev );
// Change type from <bool> to <bool>. constbool bNotInside = !rOut.Contains( aAlignedGrfRect ); if ( bNotInside )
{
rOutDev.Push( vcl::PushFlags::CLIPREGION );
rOutDev.IntersectClipRegion( rOut.SVRect() );
}
// Outsource drawing of background with a background color
::lcl_DrawGraphicBackground( rBrush, rOutDev, 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, rOutDev );
if (!aPaintRange.isEmpty() &&
!rPaintRegion.empty() &&
!basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
!basegfx::fTools::equalZero(aPaintRange.getHeight()))
{ // 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 (comphelper::IsFuzzing() || SvtOptionsDrawinglayer::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. staticconstdouble fExpandX = 0.55; staticconstdouble 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));
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.Contains( 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, &rOutDev ); // draw background color for aligned paint rectangle
lcl_DrawGraphicBackground( *pBrush, rOutDev, 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
rOutDev.Push( vcl::PushFlags::CLIPREGION );
rOutDev.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.
// 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.
pGraphicObj->DrawTiled( rOutDev,
aAlignedPaintRect.SVRect(),
aGrf.SSize(),
Size( aPaintOffset.X(), aPaintOffset.Y() ),
std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
} // reset clipping at output device
rOutDev.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( false, "new Graphic position?" );
}
/// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of /// graphic is already drawn or not. bool bGrfBackgrdAlreadyDrawn = false; if ( bRetouche )
{
rOutDev.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
rOutDev.SetLineColor();
// check, if an 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.IsTransparent()) &&
(pBrush->GetColor() == COL_TRANSPARENT)
)
{
bTransparentGrfWithNoFillBackgrd = true;
nGrfTransparency = 255 - aGrfAttr.GetAlpha();
}
} 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" // )
// #i75614# reset draw mode in high contrast mode in order to get fill color set const DrawModeFlags nOldDrawMode = rOutDev.GetDrawMode(); if ( gProp.pSGlobalShell->GetWin() &&
Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
{
rOutDev.SetDrawMode( DrawModeFlags::Default );
}
// 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( rOutDev.GetFillColor() != aColor.GetRGBColor() )
rOutDev.SetFillColor( aColor.GetRGBColor() ); break;
} default:
{ if( rOutDev.GetFillColor() != aColor )
{ if (aColor.IsTransparent() && !rOutDev.HasAlpha())
rOutDev.SetFillColor(); else
rOutDev.SetFillColor( aColor );
} break;
}
}
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 // 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 : (255 - aColor.GetAlpha())
)*100 + 0x7F)/0xFF); // draw poly-polygon transparent
rOutDev.DrawTransparent( aDrawPoly, nTransparencyPercent );
break;
} caseDefault: 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 )
{
rOutDev.DrawRect( aRegion[i].SVRect() );
}
}
}
rOutDev.Pop();
}
/** * Local helper for SwRootFrame::PaintSwFrame(..) - 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
*/ staticvoid 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.AdjustLeft( -(aTwipToPxSize.Width()/2 + 1) );
aSizedRect.AdjustRight( aTwipToPxSize.Width()/2 + 1 );
aSizedRect.AdjustTop( -(aTwipToPxSize.Height()/2 + 1) );
aSizedRect.AdjustBottom(aTwipToPxSize.Height()/2 + 1);
/** * Assuming that this entry is for a Word-style covering cell and the border matching eType is * set, limit the end position of this border in case covered cells have no borders set.
*/ void LimitVerticalEndPos(const SwFrame& rFrame, VerticalType eType);
};
constauto& rCellFrame = static_cast<const SwCellFrame&>(rFrame);
std::vector<const SwCellFrame*> aCoveredCells = rCellFrame.GetCoveredCells(); // Iterate in reverse order, so we can stop at the first cell that has a border. This can // determine what is the minimal end position that is safe to use as a limit. for (auto it = aCoveredCells.rbegin(); it != aCoveredCells.rend(); ++it)
{ const SwCellFrame* pCoveredCell = *it;
SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCoveredCell ); const SwBorderAttrs& rAttrs = *aAccess.Get(); const SvxBoxItem& rBox = rAttrs.GetBox(); if (eType == VerticalType::LEFT && rBox.GetLeft())
{ break;
}
if (eType == VerticalType::RIGHT && rBox.GetRight())
{ break;
}
if (!bHori && rEntry.mnLimitedEndPos)
{
aEnd.setY(rEntry.mnLimitedEndPos);
}
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().AdjustY( -nRepaintRectSize );
// To decide on visibility it is also necessary to expand the RepaintRect // to left/right according existing BorderLine overlap matchings, else there // will be repaint errors when scrolling in e.t TripleLine BorderLines. // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB if(aStyles[1].IsUsed() || aStyles[3].IsUsed() || aStyles[4].IsUsed() || aStyles[6].IsUsed())
{ constdouble fLineWidthMaxLeft(std::max(aStyles[1].GetWidth(), aStyles[3].GetWidth())); constdouble fLineWidthMaxRight(std::max(aStyles[4].GetWidth(), aStyles[6].GetWidth()));
aRepaintRect.Width(aRepaintRect.Width() + (fLineWidthMaxLeft + fLineWidthMaxRight));
aRepaintRect.Pos().AdjustX( -fLineWidthMaxLeft );
}
} else
{
aRepaintRect.Width( 2 * nRepaintRectSize );
aRepaintRect.Pos().AdjustX( -nRepaintRectSize );
// 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.setX( aUpperAligned.Left() ); elseif (aStart.X() == aUpper.Right_())
aPaintStart.setX( aUpperAligned.Right_() ); if (aStart.Y() == aUpper.Top())
aPaintStart.setY( aUpperAligned.Top() ); elseif (aStart.Y() == aUpper.Bottom_())
aPaintStart.setY( aUpperAligned.Bottom_() );
// create instance of SdrFrameBorderPrimitive2D if // SdrFrameBorderDataVector is used if(!aData.empty())
{
drawinglayer::primitive2d::Primitive2DContainer aSequence;
aSequence.append( new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
std::move(aData), true)); // force visualization to minimal one discrete unit (pixel) // paint
mrTabFrame.ProcessPrimitives(aSequence);
}
/** * Special case: #i9860# * first line in follow table without repeated headlines * Special case: tdf#150308 * first visible line of a table with preceding hidden deleted rows
*/ staticbool lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
SwTabFrame const& rTabFrame, SwFrame const& rFrame, SvxBoxItem const& rBoxItem)
{
SwRowFrame const*const pThisRowFrame = dynamic_cast<const SwRowFrame*>(rFrame.GetUpper()); return (pThisRowFrame
&& (pThisRowFrame->GetUpper() == &rTabFrame)
&& ( rTabFrame.IsFollow() // tdf#150308 first table row isn't equal to the table row of the first // row frame of the first table frame: there are invisible deleted rows // in Hide Changes mode before the first visible table row
|| rTabFrame.GetTable()->GetTabLines().front() != pThisRowFrame->GetTabLine() )
&& !rTabFrame.GetTable()->GetRowsToRepeat()
&& ( !pThisRowFrame->GetPrev()
|| static_cast<const SwRowFrame*>(pThisRowFrame->GetPrev())
->IsRowSpanLine())
&& !rBoxItem.GetTop()
&& rBoxItem.GetBottom());
}
/** * Special case: * last visible cell of a table row followed with a hidden deleted cell, * and the right border of the visible cell was painted by its left border
*/ staticbool lcl_IsLastVisibleCellBeforeHiddenCellAtTheEndOfRow(
SwFrame const& rFrame, SvxBoxItem const& rBoxItem)
{
SwRowFrame const*const pThisRowFrame = dynamic_cast<const SwRowFrame*>(rFrame.GetUpper()); const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rFrame);
return pThisRowFrame // last visible cell
&& !rFrame.GetNext() // it has only left border
&& !rBoxItem.GetRight()
&& rBoxItem.GetLeft() // last visible table cell isn't equal to the last cell: // there are invisible deleted cells in Hide Changes mode
&& pThisRowFrame->GetTabLine()->GetTabBoxes().back() != pThisCell->GetTabBox();
}
void SwTabFramePainter::InsertFollowTopBorder(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, bool bWordTableCell, SwTwips nTop, SwTwips nLeft,
SwTwips nRight, bool bTopIsOuter)
{ // Figure out which cell to copy. int nCol = 0; const SwFrame* pCell = &rFrame; while (pCell)
{ if (!pCell->GetPrev())
{ break;
}
++nCol;
pCell = pCell->GetPrev();
}
auto pThisRow = dynamic_cast<const SwRowFrame*>(rFrame.GetUpper()); if (!pThisRow || pThisRow->GetUpper() != &mrTabFrame)
{ return;
}
if (!mrTabFrame.IsFollow() || mrTabFrame.GetTable()->GetRowsToRepeat())
{ return;
}
if (pThisRow->GetPrev() || rBoxItem.GetTop() || rBoxItem.GetBottom())
{ return;
}
// This is then a first row in a follow table, without repeated headlines. auto pLastRow = dynamic_cast<const SwRowFrame*>(mrTabFrame.GetLastLower()); if (!pLastRow || pLastRow == pThisRow)
{ return;
}
const SwFrame* pLastCell = pLastRow->GetLower(); if (!pLastCell)
{ return;
}
for (int i = 0; i < nCol; ++i)
{ if (!pLastCell->GetNext())
{ // Reference row has merged cells, work with the last possible one. break;
}
// The matching (same column) row in the last row has a bottom border for us.
svx::frame::Style aFollowB(rLastBoxItem.GetBottom(), 1.0);
aFollowB.SetWordTableCell(bWordTableCell);
SwLineEntry aFollowTop(nTop, nLeft, nRight, bTopIsOuter, aFollowB);
aFollowB.SetRefMode(svx::frame::RefMode::Begin);
Insert(aFollowTop, true);
}
void SwTabFramePainter::InsertMasterBottomBorder(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, bool bWordTableCell, SwTwips nBottom, SwTwips nLeft,
SwTwips nRight, bool bBottomIsOuter)
{ // Figure out which cell to copy. int nCol = 0; const SwFrame* pCell = &rFrame; while (pCell)
{ if (!pCell->GetPrev())
{ break;
}
++nCol;
pCell = pCell->GetPrev();
}
auto pThisRow = dynamic_cast<const SwRowFrame*>(rFrame.GetUpper()); if (!pThisRow || pThisRow->GetUpper() != &mrTabFrame)
{ return;
}
if (mrTabFrame.IsFollow() || !mrTabFrame.GetFollow())
{ return;
}
// This is a master table that is split. if (pThisRow->GetNext() || rBoxItem.GetTop() || rBoxItem.GetBottom())
{ return;
}
// This is then a last row in a master table. auto pFirstRow = dynamic_cast<const SwRowFrame*>(mrTabFrame.GetLower()); if (!pFirstRow || pFirstRow == pThisRow)
{ return;
}
const SwFrame* pFirstCell = pFirstRow->GetLower(); if (!pFirstCell)
{ return;
}
for (int i = 0; i < nCol; ++i)
{ if (!pFirstCell->GetNext())
{ // Reference row has merged cells, work with the last possible one. break;
}
// The matching (same column) row in the first row has a top border for us.
svx::frame::Style aMasterT(rFirstBoxItem.GetTop(), 1.0);
aMasterT.SetWordTableCell(bWordTableCell);
SwLineEntry aMasterBottom(nBottom, nLeft, nRight, bBottomIsOuter, aMasterT);
aMasterT.SetRefMode(svx::frame::RefMode::Begin);
Insert(aMasterBottom, true);
}
void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect& rPaintArea)
{ // build 4 line entries for the 4 borders:
SwRect aBorderRect = rFrame.getFrameArea();
// no scaling needed, it's all in the primitives and the target device
svx::frame::Style aL(rBoxItem.GetLeft(), 1.0);
aL.SetWordTableCell(bWordTableCell);
svx::frame::Style aR(rBoxItem.GetRight(), 1.0);
aR.SetWordTableCell(bWordTableCell);
svx::frame::Style aT(rBoxItem.GetTop(), 1.0);
aT.SetWordTableCell(bWordTableCell);
svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
aB.SetWordTableCell(bWordTableCell);
// First cell in a row. bool bLeftIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() == &rFrame; // Last cell in a row. bool bRightIsOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr; // First row in a table. bool bTopIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetUpper()->GetLower() == rFrame.GetUpper(); // Last row in a table. bool bBottomIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() == nullptr;
aR.MirrorSelf(); if (!bWordTableCell || !bBottomIsOuter)
{ // Outer horizontal lines are never mirrored in Word.
aB.MirrorSelf();
}
// The bWordTableCell code only works for LTR at the moment, avoid it for RTL. if (rOld.mnLimitedEndPos || (bWordTableCell && (rOld.mbOuter != rNew.mbOuter) && !bR2L))
{ // Don't merge with this line entry as it ends sooner than mnEndPos.
++aIter; continue;
}
/** * Paint once for every visible page which is touched by Rect * * 1. Paint borders and backgrounds * 2. Paint the draw layer (frames and drawing objects) that is * below the document (hell) * 3. Paint the document content (text) * 4. Paint the draw layer that is above the document
|*/ void SwRootFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, PaintFrameMode) const
{
OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." );
// Copy rRect; for one, rRect could become dangling during the below action, and for another it // needs to be copied to aRect anyway as that is modified further down below:
SwRect aRect( rRect );
//Trigger an action to clear things up if needed. //Using this trick we can ensure that all values are valid in all paints - //no problems, no special case(s). // #i92745# // Extend check on certain states of the 'current' <SwViewShell> instance to // all existing <SwViewShell> instances. bool bPerformLayoutAction( true );
{ for(SwViewShell& rTmpViewShell : pSh->GetRingContainer())
{ if ( rTmpViewShell.IsInEndAction() ||
rTmpViewShell.IsPaintInProgress() ||
( rTmpViewShell.Imp()->IsAction() &&
rTmpViewShell.Imp()->GetLayAction().IsActionInProgress() ) )
{
bPerformLayoutAction = false;
}
gProp.pSLines.reset(new SwLineRects); // Container for borders.
// #104289#. During painting, something (OLE) can // load the linguistic, which in turn can cause a reformat // of the document. Dangerous! We better set this flag to // avoid the reformat. constbool bOldAction = IsCallbackActionEnabled(); const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( false );
// #126222. The positions of headers and footers of the previous // pages have to be updated, else these headers and footers could // get visible at a wrong position. const SwPageFrame *pPageDeco = static_cast<const SwPageFrame*>(pPage->GetPrev()); while (pPageDeco)
{
pPageDeco->PaintDecorators();
OSL_ENSURE(!pPageDeco->GetPrev() || pPageDeco->GetPrev()->IsPageFrame(), "Neighbour of page is not a page.");
pPageDeco = static_cast<const SwPageFrame*>(pPageDeco->GetPrev());
}
if ( aRect.Overlaps( aPaintRect ) )
{ if ( pSh->GetWin() )
{
gProp.pSSubsLines.reset(new SwSubsRects);
gProp.pSSpecSubsLines.reset(new SwSubsRects);
}
gProp.pBLines.reset(new BorderLines);
aPaintRect.Intersection_( aRect );
if ( bExtraData &&
pSh->GetWin() && pSh->IsInEndAction() )
{ // enlarge paint rectangle to complete page width, subtract // current paint area and invalidate the resulting region.
SwRectFnSet aRectFnSet(pPage);
SwRect aPageRectTemp( aPaintRect );
aRectFnSet.SetLeftAndWidth( aPageRectTemp,
aRectFnSet.GetLeft(pPage->getFrameArea()),
aRectFnSet.GetWidth(pPage->getFrameArea()) );
aPageRectTemp.Intersection_( pSh->VisArea() );
vcl::Region aPageRectRegion( aPageRectTemp.SVRect() );
aPageRectRegion.Exclude( aPaintRect.SVRect() );
pSh->GetWin()->Invalidate( aPageRectRegion, InvalidateFlags::Children );
}
// #i80793# // enlarge paint rectangle for objects overlapping the same pixel // in all cases and before the DrawingLayer overlay is initialized.
lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
// #i68597# // moved paint pre-process for DrawingLayer overlay here since the above // code dependent from bExtraData may expand the PaintRect
{ // #i75172# if called from SwViewShell::ImplEndAction it should no longer // really be used but handled by SwViewShell::ImplEndAction already const vcl::Region aDLRegion(aPaintRect.SVRect());
pSh->DLPrePaint2(aDLRegion);
}
if(OUTDEV_WINDOW == gProp.pSGlobalShell->GetOut()->GetOutDevType())
{ // changed method SwLayVout::Enter(..) // 2nd parameter is no longer <const> and will be set to the // rectangle the virtual output device is calculated from <aPaintRect>, // if the virtual output is used.
s_pVout->Enter(pSh, aPaintRect, !s_isNoVirDev);
// Adjust paint rectangle to pixel size // Thus, all objects overlapping on pixel level with the unadjusted // paint rectangle will be considered in the paint.
lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
}
// maybe this can be put in the above scope. Since we are not sure, just leave it ATM
s_pVout->SetOrgRect( aPaintRect );
// determine background color of page for <PaintLayer> method // calls, paint <hell> or <heaven> const Color aPageBackgrdColor(pPage->GetDrawBackgroundColor());
// no paint of page border and shadow, if writer is in place mode.
SwDocShell* pShell = pSh->GetDoc()->GetDocShell(); if( pSh->GetWin() && pShell && !pShell->IsInPlaceActive() )
{
SwPageFrame::PaintBorderAndShadow( pPage->getFrameArea(), pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
SwPageFrame::PaintNotesSidebar( pPage->getFrameArea(), pSh, pPage->GetPhyPageNum(), bRightSidebar);
}
gProp.pSLines->PaintLines( pSh->GetOut(), gProp ); if ( pSh->GetWin() )
{
gProp.pSSubsLines->PaintSubsidiary( pSh->GetOut(), gProp.pSLines.get(), gProp );
gProp.pSSubsLines.reset();
gProp.pSSpecSubsLines.reset();
} // fdo#42750: delay painting these until after subsidiary lines // fdo#45562: delay painting these until after hell layer // fdo#47717: but do it before heaven layer
{
SwTaggedPDFHelper tag(nullptr, nullptr, nullptr, rRenderContext);
ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
}
if ( aRect.Overlaps( aEmptyPageRect ) )
{ // #i75172# if called from SwViewShell::ImplEndAction it should no longer // really be used but handled by SwViewShell::ImplEndAction already
{ const vcl::Region aDLRegion(aPaintRect.SVRect());
pSh->DLPrePaint2(aDLRegion);
}
if( pSh->GetOut()->GetFillColor() != aGlobalRetoucheColor )
pSh->GetOut()->SetFillColor( aGlobalRetoucheColor ); // No line color
pSh->GetOut()->SetLineColor(); // Use aligned page rectangle
{
SwRect aTmpPageRect( aEmptyPageRect );
::SwAlignRect( aTmpPageRect, pSh, &rRenderContext );
aEmptyPageRect = aTmpPageRect;
}
OSL_ENSURE( !pPage->GetNext() || pPage->GetNext()->IsPageFrame(), "Neighbour of page is not a page." );
pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
}
//It's possible that the Cont will get destroyed.
SwContentFrame *pCnt = pCont->ContainsContent(); while ( pCnt && pCnt->IsInFootnote() )
{
pCnt->Calc(pRenderContext);
pCnt = pCnt->GetNextContentFrame();
}
}
namespace {
class SwShortCut
{
SwRectDist m_fnCheck;
tools::Long m_nLimit;
void SwLayoutFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, PaintFrameMode ePaintFrameMode) const
{ if (!getFramePrintArea().HasArea() && !IsRowFrame())
{ // tdf#163032 row frame may contain rowspan>1 cell that must be painted return; // do not paint hidden frame
}
// #i16816# tagged pdf support
Frame_Info aFrameInfo(*this, false);
SwTaggedPDFHelper aTaggedPDFHelper( nullptr,
PAINT_HEADER_FOOTER == ePaintFrameMode ? nullptr : &aFrameInfo,
nullptr, rRenderContext );
::std::optional<SwTaggedPDFHelper> oTaggedLink; if (IsFlyFrame())
{ // tdf#154939 Link nested inside Figure autoconst pItem(GetFormat()->GetAttrSet().GetItemIfSet(RES_URL)); if (pItem && !pItem->GetURL().isEmpty())
{
Frame_Info linkInfo(*this, true);
oTaggedLink.emplace(nullptr, &linkInfo, nullptr, rRenderContext);
}
}
const SwFrame *pFrame = Lower(); if ( !pFrame ) return;
pFrame = SkipFrame(pFrame, ePaintFrameMode); if (!pFrame) return;
SwFrameDeleteGuard g(const_cast<SwLayoutFrame*>(this)); // lock because Calc() and recursion
SwShortCut aShortCut( *pFrame, rRect ); bool bCnt = pFrame->IsContentFrame(); if ( bCnt )
pFrame->Calc(&rRenderContext);
const SwPageFrame *pPage = nullptr; bool bWin = gProp.pSGlobalShell->GetWin() != nullptr; if (comphelper::LibreOfficeKit::isTiledPainting()) // Tiled rendering is similar to printing in this case: painting transparently multiple // times will result in darker colors: avoid that.
bWin = false;
//We need to retouch if a frame explicitly requests it. //First do the retouch, because this could flatten the borders. if ( pFrame->IsRetouche() )
{ if ( pFrame->IsRetoucheFrame() && bWin && !pFrame->GetNext() )
{ if ( !pPage )
pPage = FindPageFrame();
pFrame->Retouch( pPage, rRect );
}
pFrame->ResetRetouche();
}
if ( rRect.Overlaps( aPaintRect ) )
{ if ( bCnt && pFrame->IsCompletePaint() &&
!(comphelper::LibreOfficeKit::isActive() && comphelper::LibreOfficeKit::isTiledPainting()) &&
!rRect.Contains( aPaintRect ) && Application::AnyInput( VclInputFlags::KEYBOARD ) )
{ //fix(8104): It may happen, that the processing wasn't complete //but some parts of the paragraph were still repainted. //This could lead to the situation, that other parts of the //paragraph won't be repainted at all. The only solution seems //to be an invalidation of the window. //To not make it too severe the rectangle is limited by //painting the desired part and only invalidating the //remaining paragraph parts. if ( aPaintRect.Left() == rRect.Left() &&
aPaintRect.Right() == rRect.Right() )
{
aPaintRect.Bottom( rRect.Top() - 1 ); if ( aPaintRect.Height() > 0 )
gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
aPaintRect.Top( rRect.Bottom() + 1 );
aPaintRect.Bottom( pFrame->getFrameArea().Bottom() ); if ( aPaintRect.Height() > 0 )
gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
aPaintRect.Top( pFrame->getFrameArea().Top() );
aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
} else
{
gProp.pSGlobalShell->InvalidateWindows( aPaintRect );
pFrame = pFrame->GetNext(); if ( pFrame )
{
bCnt = pFrame->IsContentFrame(); if ( bCnt )
pFrame->Calc(&rRenderContext);
} continue;
}
}
pFrame->ResetCompletePaint();
aPaintRect.Intersection_( rRect );
if ( Lower() && Lower()->IsColumnFrame() )
{ //Paint the column separator line if needed. The page is //responsible for the page frame - not the upper. const SwFrameFormat *pFormat = GetUpper() && GetUpper()->IsPageFrame()
? GetUpper()->GetFormat()
: GetFormat(); const SwFormatCol &rCol = pFormat->GetCol(); if ( rCol.GetLineAdj() != COLADJ_NONE )
{ if ( !pPage )
pPage = pFrame->FindPageFrame();
// Test if the first node is a table const SwFrame* pFirstFrame = pLayBody->Lower(); if ( pFirstFrame && pFirstFrame->IsTabFrame() )
pFlowFrame = static_cast< const SwTabFrame* >( pFirstFrame );
// Paint the break only if: // * Not in header footer edition, to avoid conflicts with the // header/footer marker // * Non-printing characters are shown, as this is more consistent // with other formatting marks if ( !(!gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
!gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) &&
gProp.pSGlobalShell->GetViewOptions()->IsLineBreak()) ) return;
/** * For feature #99657# * * OD 12.08.2002 * determines, if background of fly frame has to be drawn transparent * declaration found in /core/inc/flyfrm.cxx * * OD 08.10.2002 #103898# - If the background of the fly frame itself is not * transparent and the background is inherited from its parent/grandparent, * the background brush, used for drawing, has to be investigated for transparency. * * @return true, if background is transparent drawn
*/ bool SwFlyFrame::IsBackgroundTransparent() const
{ bool bBackgroundTransparent = GetFormat()->IsBackgroundTransparent(); if ( !bBackgroundTransparent &&
GetFormat()->IsBackgroundBrushInherited() )
{ const SvxBrushItem* pBackgroundBrush = nullptr;
std::optional<Color> xSectionTOXColor;
SwRect aDummyRect;
drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
//Attribute dependent, don't paint for printer or Preview bool bPaint = gProp.pSFlyOnlyDraw || static_cast<SwContact*>(pUserCall)->GetFormat()->GetPrint().GetValue(); if ( !bPaint )
bPaint = rSh.GetWin() && !rSh.IsPreview();
if ( bPaint )
{ //The paint may be prevented by the superior Flys.
SwFrame *pAnch = nullptr; if ( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr ) // i#117962#
{
bPaint = false;
} if ( auto pFlyDraw = dynamic_cast<SwVirtFlyDrawObj *>( pObj ) )
{
SwFlyFrame *pFly = pFlyDraw->GetFlyFrame(); if ( gProp.pSFlyOnlyDraw && gProp.pSFlyOnlyDraw == pFly ) returntrue;
//Try to avoid displaying the intermediate stage, Flys which don't //overlap with the page on which they are anchored won't be //painted. //HACK: exception: printing of frames in tables, those can overlap //a page once in a while when dealing with oversized tables (HTML).
SwPageFrame *pPage = pFly->FindPageFrame(); if ( pPage && pPage->getFrameArea().Overlaps( pFly->getFrameArea() ) )
{
pAnch = pFly->AnchorFrame();
}
} else
{ // Consider 'virtual' drawing objects
SwDrawContact* pDrawContact = dynamic_cast<SwDrawContact*>(pUserCall);
pAnch = pDrawContact ? pDrawContact->GetAnchorFrame(pObj) : nullptr; if ( pAnch )
{ if ( !pAnch->isFrameAreaPositionValid() )
pAnch = nullptr; elseif ( rSh.GetOut() == rSh.getIDocumentDeviceAccess().getPrinter( false ))
{ //HACK: we have to omit some of the objects for printing, //otherwise they would be printed twice. //The objects should get printed if the TableHack is active //right now. Afterwards they must not be printed if the //page over which they float position wise gets printed. const SwPageFrame *pPage = pAnch->FindPageFrame(); if ( !pPage->getFrameArea().Overlaps( SwRect(pObj->GetCurrentBoundRect()) ) )
pAnch = nullptr;
}
} else
{ if ( dynamic_cast< const SdrObjGroup *>( pObj ) == nullptr )
{
OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" );
}
}
} if ( pAnch )
{ if ( pAnch->IsInFly() )
bPaint = SwFlyFrame::IsPaint(pAnch->FindFlyFrame()->GetVirtDrawObj(), rSh); elseif ( gProp.pSFlyOnlyDraw )
bPaint = false;
} else
bPaint = false;
} return bPaint;
}
// set strikethrough for deleted objects anchored to character void SwFrame::SetDrawObjsAsDeleted( bool bDeleted )
{ if ( SwSortedObjs *pObjs = GetDrawObjs() )
{ for (SwAnchoredObject* pAnchoredObj : *pObjs)
{ if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
{
pFly->SetDeleted(bDeleted);
}
}
}
}
void SwFlyFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, PaintFrameMode) const
{ //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
SwViewShell *pShell = getRootFrame()->GetCurrShell(); if (pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocShell())
{ bool bInGenerateThumbnail = pShell->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail(); if (bInGenerateThumbnail)
{ const SwRect& aVisRect = pShell->VisArea(); if (!aVisRect.Overlaps(getFrameArea())) return;
}
}
//because of the overlapping of frames and drawing objects the flys have to //paint their borders (and those of the internal ones) directly. //e.g. #33066#
gProp.pSLines->LockLines(true);
BorderLinesGuard blg; // this should not paint borders added from PaintBaBo
{ bool bContour = GetFormat()->GetSurround().IsContour();
tools::PolyPolygon aPoly; if ( bContour )
{ // add 2nd parameter with value <true> // to indicate that method is called for paint in order to avoid // load of the intrinsic graphic.
bContour = GetContour( aPoly, true );
}
// #i47804# - distinguish complete background paint // and margin paint. // paint complete background for Writer text fly frames bool bPaintCompleteBack( !pNoText ); // paint complete background for transparent graphic and contour, // if own background color exists. constbool bIsGraphicTransparent = pNoText && pNoText->IsTransparent(); if ( !bPaintCompleteBack &&
( bIsGraphicTransparent|| bContour ) )
{ const SwFlyFrameFormat* pSwFrameFormat = GetFormat();
if (pSwFrameFormat && pSwFrameFormat->supportsFullDrawingLayerFillAttributeSet())
{ // check for transparency const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(pSwFrameFormat->getSdrAllFillAttributesHelper());
// check if the new fill attributes are used if(aFillAttributes && aFillAttributes->isUsed())
{
bPaintCompleteBack = true;
}
} else
{
std::unique_ptr<SvxBrushItem> aBack = GetFormat()->makeBackgroundBrushItem(); // to determine, if background has to be painted, by checking, if // background color is not COL_TRANSPARENT ("no fill"/"auto fill") // or a background graphic exists.
bPaintCompleteBack =
aBack->GetColor() != COL_TRANSPARENT ||
aBack->GetGraphicPos() != GPOS_NONE;
}
} // paint of margin needed. constbool bPaintMarginOnly( !bPaintCompleteBack &&
getFramePrintArea().SSize() != getFrameArea().SSize() );
// #i47804# - paint background of parent fly frame // for transparent graphics in layer Hell, if parent fly frame isn't // in layer Hell. It's only painted the intersection between the // parent fly frame area and the paint area <aRect> const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
if ( bPaintCompleteBack || bPaintMarginOnly )
{ //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder //receives the original Rect but PaintSwFrameBackground only the limited //one.
// paint background
{
SwRegionRects aRegion( aRect ); // #i80822# // suppress painting of background in printing area for // non-transparent graphics. if ( bPaintMarginOnly ||
( pNoText && !bIsGraphicTransparent ) )
{ //What we actually want to paint is the small stripe between //PrtArea and outer border.
SwRect aTmp( getFramePrintArea() ); aTmp += getFrameArea().Pos();
aRegion -= aTmp;
} if ( bContour )
{
rRenderContext.Push(); // #i80822# // apply clip region under the same conditions, which are // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region // for painting the graphic/OLE. Thus, the clip region is // also applied for the PDF export.
SwViewShell *pSh = getRootFrame()->GetCurrShell();
for ( size_t i = 0; i < aRegion.size(); ++i )
{
PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
}
rRenderContext.Pop();
} else
{ for ( size_t i = 0; i < aRegion.size(); ++i )
{
PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
}
}
}
// paint border before painting background
PaintSwFrameShadowAndBorder(rRect, pPage, rAttrs);
rRenderContext.Pop();
}
}
// fly frame will paint it's subsidiary lines and // the subsidiary lines of its lowers on its own, due to overlapping with // other fly frames or other objects. if( gProp.pSGlobalShell->GetWin()
&& !bIsChart ) //#i102950# don't paint additional borders for charts
{ bool bSubsLineRectsCreated; if ( gProp.pSSubsLines )
{ // Lock already existing subsidiary lines
gProp.pSSubsLines->LockLines( true );
bSubsLineRectsCreated = false;
} else
{ // create new subsidiary lines
gProp.pSSubsLines.reset(new SwSubsRects);
bSubsLineRectsCreated = true;
}
bool bSpecSubsLineRectsCreated; if ( gProp.pSSpecSubsLines )
{ // Lock already existing special subsidiary lines
gProp.pSSpecSubsLines->LockLines( true );
bSpecSubsLineRectsCreated = false;
} else
{ // create new special subsidiary lines
gProp.pSSpecSubsLines.reset(new SwSubsRects);
bSpecSubsLineRectsCreated = true;
} // Add subsidiary lines of fly frame and its lowers
RefreshLaySubsidiary( pPage, aRect ); // paint subsidiary lines of fly frame and its lowers
gProp.pSSpecSubsLines->PaintSubsidiary( &rRenderContext, nullptr, gProp );
gProp.pSSubsLines->PaintSubsidiary(&rRenderContext, gProp.pSLines.get(), gProp); if ( !bSubsLineRectsCreated ) // unlock subsidiary lines
gProp.pSSubsLines->LockLines( false ); else
{ // delete created subsidiary lines container
gProp.pSSubsLines.reset();
}
if ( !bSpecSubsLineRectsCreated ) // unlock special subsidiary lines
gProp.pSSpecSubsLines->LockLines( false ); else
{ // delete created special subsidiary lines container
gProp.pSSpecSubsLines.reset();
}
}
void SwTextFrame::PaintParagraphStylesHighlighting() const
{ // Maybe avoid the dynamic_cast and just use GetActiveWrtShell() // NO! Multiple windows will not display the highlighting correctly if GetActiveWrtShell is used.
SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(gProp.pSGlobalShell);
if (!pWrtSh) return;
if (!pWrtSh->GetView().IsSpotlightParaStyles()) return;
vcl::RenderContext* pRenderContext = pWrtSh->GetOut(); if (!pRenderContext) return;
bool bSpotlightStyle; if (comphelper::LibreOfficeKit::isActive())
{ // For simplicity in kit mode, we render in the document "all styles"
bSpotlightStyle = true; // Do this so these are stable across views regardless of an individual // user's selection mode in the style panel.
nStyleNumber = pWrtSh->GetDoc()->GetTextFormatColls()->GetPos(pColl);
nStyleColor = ColorHash(sStyleName.toString());
} else
{
StylesSpotlightColorMap& rParaStylesColorMap
= pWrtSh->GetView().GetStylesSpotlightParaColorMap();
bSpotlightStyle = rParaStylesColorMap.contains(sStyleName.toString()); if (bSpotlightStyle)
{
nStyleNumber = rParaStylesColorMap[sStyleName.toString()].second;
nStyleColor = rParaStylesColorMap[sStyleName.toString()].first;
}
}
// draw styles highlighter if (bSpotlightStyle)
{
SwRect aFrameAreaRect(getFrameArea());
// draw hatch pattern if paragraph has direct formatting if (SwDoc::HasParagraphDirectFormatting(SwPosition(*GetTextNodeForParaProps())))
{
Color aHatchColor(nStyleColor); // make hatch line color 41% darker than the fill color
aHatchColor.ApplyTintOrShade(-4100);
Hatch aHatch(HatchStyle::Single, aHatchColor, 50, 450_deg10);
pRenderContext->DrawHatch(tools::PolyPolygon(aRect), aHatch);
}
void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, PaintFrameMode) const
{ if (!getFramePrintArea().HasArea())
{ return; // do not paint hidden frame
} const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions(); if (pViewOption->IsTable())
{ // tdf#77388 first paint the cell content to avoid of removing own border
SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
/** * Paint border shadow * * @param[in] rRect aligned rect to clip the result * @param[in,out] rOutRect full painting area as input * painting area reduced by shadow space for border and background as output * @param[in] rShadow includes shadow attributes * @param[in] bDrawFullShadowRectangle paint full rect of shadow * @param[in] bTop paint top part of the shadow * @param[in] bBottom paint bottom part of the shadow * @param[in] bLeft paint left part of the shadow * @param[in] bRight paint right part of the shadow
**/ staticvoid lcl_PaintShadow( const SwRect& rRect, SwRect& rOutRect, const SvxShadowItem& rShadow, constbool bDrawFullShadowRectangle, constbool bTop, constbool bBottom, constbool bLeft, constbool bRight,
SwPaintProperties const & properties)
{ const tools::Long nWidth = ::lcl_AlignWidth ( rShadow.GetWidth(), properties ); const tools::Long nHeight = ::lcl_AlignHeight( rShadow.GetWidth(), properties );
DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
Color aShadowColor( rShadow.GetColor().GetRGBColor() ); if( !aRegion.empty() && properties.pSGlobalShell->GetWin() &&
Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
{ // In high contrast mode, the output device has already set the // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function // to ignore the setting of a new color. Therefore we have to reset // the drawing mode
pOut->SetDrawMode( DrawModeFlags::Default );
aShadowColor = properties.pSGlobalShell->GetViewOptions()->GetFontColor();
}
if ( pOut->GetFillColor() != aShadowColor )
pOut->SetFillColor( aShadowColor );
/** * Paints a shadow if the format requests so. * * The shadow is always painted on the outer edge of the OutRect. * If needed, the OutRect is shrunk so the painting of the border can be * done on it. * * @note: draw full shadow rectangle for frames with transparent drawn backgrounds (OD 23.08.2002 #99657#)
*/ void SwFrame::PaintShadow( const SwRect& rRect, SwRect& rOutRect, const SwBorderAttrs &rAttrs ) const
{
SvxShadowItem rShadow = rAttrs.GetShadow();
if( IsVertical() )
{ switch( rShadow.GetLocation() )
{ case SvxShadowLocation::BottomRight: rShadow.SetLocation(SvxShadowLocation::BottomLeft); break; case SvxShadowLocation::TopLeft: rShadow.SetLocation(SvxShadowLocation::TopRight); break; case SvxShadowLocation::TopRight: rShadow.SetLocation(SvxShadowLocation::BottomRight); break; case SvxShadowLocation::BottomLeft: rShadow.SetLocation(SvxShadowLocation::TopLeft); break; default: break;
}
}
// determine, if full shadow rectangle have to be drawn or only two shadow rectangles beside the frame. // draw full shadow rectangle, if frame background is drawn transparent. // Status Quo: // SwLayoutFrame can have transparent drawn backgrounds. Thus, // "asked" their frame format. constbool bDrawFullShadowRectangle =
( IsLayoutFrame() && static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent()
);
class SwBorderRectanglePrimitive2D : public BufferedDecompositionPrimitive2D
{ private: /// the transformation defining the geometry of this BorderRectangle
basegfx::B2DHomMatrix maB2DHomMatrix;
/// the four styles to be used
svx::frame::Style maStyleTop;
svx::frame::Style maStyleRight;
svx::frame::Style maStyleBottom;
svx::frame::Style maStyleLeft;
// go round-robin, from TopLeft to TopRight, down, left and back up. That // way, the borders will not need to be mirrored in any way if(getStyleTop().IsUsed())
{ // create BorderPrimitive(s) for top border const basegfx::B2DVector aVector(aTopRight - aTopLeft);
aData.emplace_back(
aTopLeft,
aVector,
getStyleTop(),
nullptr);
drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData.back());
aBorderLineTarget.append( new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
aBorderTransform,
aStyleTop,
aStyleRight,
aStyleBottom,
aStyleLeft));
gProp.pBLines->AddBorderLines(std::move(aBorderLineTarget));
}
/// #i15844# staticconst SwFrame* lcl_HasNextCell( const SwFrame& rFrame )
{
OSL_ENSURE( rFrame.IsCellFrame(), "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame" );
const SwFrame* pTmpFrame = &rFrame; do
{ if ( pTmpFrame->GetNext() ) return pTmpFrame->GetNext();
pTmpFrame = pTmpFrame->GetUpper()->GetUpper();
} while ( pTmpFrame->IsCellFrame() );
return nullptr;
}
/** * Determine cell frame, from which the border attributes * for paint of top/bottom border has to be used. * * OD 21.02.2003 #b4779636#, #107692# * * @param _pCellFrame * input parameter - constant pointer to cell frame for which the cell frame * for the border attributes has to be determined. * * @param _rCellBorderAttrs * input parameter - constant reference to the border attributes of cell frame * <_pCellFrame>. * * @param _bTop * input parameter - boolean, that controls, if cell frame for top border or * for bottom border has to be determined. * * @return constant pointer to cell frame, for which the border attributes has * to be used
*/ staticconst SwFrame* lcl_GetCellFrameForBorderAttrs( const SwFrame* _pCellFrame, const SwBorderAttrs& _rCellBorderAttrs, constbool _bTop )
{
OSL_ENSURE( _pCellFrame, "No cell frame available, dying soon" );
// determine, if cell frame is at bottom/top border of a table frame and // the table frame has/is a follow. const SwFrame* pTmpFrame = _pCellFrame; bool bCellAtBorder = true; bool bCellAtLeftBorder = !_pCellFrame->GetPrev(); bool bCellAtRightBorder = !_pCellFrame->GetNext(); while( !pTmpFrame->IsRowFrame() || !pTmpFrame->GetUpper()->IsTabFrame() )
{
pTmpFrame = pTmpFrame->GetUpper(); if ( pTmpFrame->IsRowFrame() &&
(_bTop ? pTmpFrame->GetPrev() : pTmpFrame->GetNext())
)
{
bCellAtBorder = false;
} if ( pTmpFrame->IsCellFrame() )
{ if ( pTmpFrame->GetPrev() )
{
bCellAtLeftBorder = false;
} if ( pTmpFrame->GetNext() )
{
bCellAtRightBorder = false;
}
}
}
OSL_ENSURE( pTmpFrame && pTmpFrame->IsRowFrame(), "No RowFrame available" );
const SwFrame* pRet = _pCellFrame; if ( bCellNeedsAttribute )
{ // determine, if cell frame has no borders inside the table. const SwFrame* pNextCell = nullptr; bool bNoBordersInside = false;
if ( bNoBordersInside )
{ if ( _bTop && !_rCellBorderAttrs.GetBox().GetTop() )
{ //-hack // Cell frame has no top border and no border inside the table, but // it is at the top border of a table frame, which is a follow. // Thus, use border attributes of cell frame in first row of complete table. // First, determine first table frame of complete table.
SwTabFrame* pMasterTabFrame = pParentTabFrame->FindMaster( true ); // determine first row of complete table. const SwFrame* pFirstRow = pMasterTabFrame->GetLower(); // return first cell in first row
SwFrame* pLowerCell = const_cast<SwFrame*>(pFirstRow->GetLower()); while ( !pLowerCell->IsCellFrame() ||
( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
)
{
pLowerCell = pLowerCell->GetLower();
}
OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
pRet = pLowerCell;
} elseif ( !_bTop && !_rCellBorderAttrs.GetBox().GetBottom() )
{ //-hack // Cell frame has no bottom border and no border inside the table, // but it is at the bottom border of a table frame, which has a follow. // Thus, use border attributes of cell frame in last row of complete table. // First, determine last table frame of complete table.
SwTabFrame* pLastTabFrame = const_cast<SwTabFrame*>(pParentTabFrame->GetFollow()); while ( pLastTabFrame->GetFollow() )
{
pLastTabFrame = pLastTabFrame->GetFollow();
} // determine last row of complete table.
SwFrame* pLastRow = pLastTabFrame->GetLastLower(); // return first bottom border cell in last row
SwFrame* pLowerCell = pLastRow->GetLower(); while ( !pLowerCell->IsCellFrame() ||
( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
)
{ if ( pLowerCell->IsRowFrame() )
{ while ( pLowerCell->GetNext() )
{
pLowerCell = pLowerCell->GetNext();
}
}
pLowerCell = pLowerCell->GetLower();
}
OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
pRet = pLowerCell;
}
}
}
//If the rectangle is completely inside the PrtArea, no border needs to //be painted. //For the PrtArea the aligned value needs to be used, otherwise it could //happen, that some parts won't be processed.
SwRect aRect( getFramePrintArea() );
aRect += getFrameArea().Pos();
::SwAlignRect( aRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() ); // new local boolean variable in order to // suspend border paint under special cases - see below. // NOTE: This is a fix for the implementation of feature #99657#. bool bDrawOnlyShadowForTransparentFrame = false; if ( aRect.Contains( rRect ) )
{ // paint shadow, if background is transparent. // Because of introduced transparent background for fly frame #99657#, // the shadow have to be drawn if the background is transparent, // in spite the fact that the paint rectangle <rRect> lies fully // in the printing area. // NOTE to chosen solution: // On transparent background, continue processing, but suspend // drawing of border by setting <bDrawOnlyShadowForTransparentFrame> // to true. if ( IsLayoutFrame() && static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent() )
{
bDrawOnlyShadowForTransparentFrame = true;
} else
{ return;
}
}
// if ContentFrame and joined Prev/Next, reset top/bottom as needed if(IsContentFrame())
{ const SwFrame* pDirRefFrame(IsCellFrame() ? FindTabFrame() : this); const SwRectFnSet aRectFnSet(pDirRefFrame); const SwRectFn _aRectFn(aRectFnSet.FnRect());
if(rAttrs.JoinedWithPrev(*this))
{ // tdf#115296 re-add adaptation of vert distance to close the evtl. // existing gap to previous frame const SwFrame* pPrevFrame(GetPrev());
(aRect.*_aRectFn->fnSetTop)( (pPrevFrame->*_aRectFn->fnGetPrtBottom)() );
// ...and disable top border paint/creation
pTopBorder = nullptr;
}
if(rAttrs.JoinedWithNext(*this))
{ // tdf#115296 re-add adaptation of vert distance to close the evtl. // existing gap to next frame const SwFrame* pNextFrame(GetNext());
(aRect.*_aRectFn->fnSetBottom)( (pNextFrame->*_aRectFn->fnGetPrtTop)() );
/** * Special implementation because of the footnote line * * Currently only the top frame needs to be taken into account * Other lines and shadows are set aside
*/ void SwFootnoteContFrame::PaintSwFrameShadowAndBorder( const SwRect& rRect, const SwPageFrame* pPage, const SwBorderAttrs&) const
{ //If the rectangle is completely inside the PrtArea, no border needs to //be painted.
SwRect aRect( getFramePrintArea() );
aRect.Pos() += getFrameArea().Pos(); if ( !aRect.Contains( rRect ) )
PaintLine( rRect, pPage );
}
/// Paint footnote lines. void SwFootnoteContFrame::PaintLine( const SwRect& rRect, const SwPageFrame *pPage ) const
{ //The length of the line is derived from the percentual indication on the //PageDesc. The position is also stated on the PageDesc. //The pen can directly be taken from the PageDesc.
/** * Paint margin area of a page * * OD 20.11.2002 for #104598#: * implement paint of margin area; margin area will be painted for a * view shell with a window and if the document is not in online layout. * * @param _rOutputRect * input parameter - constant instance reference of the rectangle, for * which an output has to be generated. * * @param _pViewShell * input parameter - instance of the view shell, on which the output * has to be generated.
*/ void SwPageFrame::PaintMarginArea( const SwRect& _rOutputRect,
SwViewShell const * _pViewShell ) const
{ if ( !_pViewShell->GetWin() || _pViewShell->GetViewOptions()->getBrowseMode() ) return;
// We paint the right shadow if we're not in book mode // or if we've no sibling or are the last page of the "row" return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetNext()
|| (this == Lower()) || (bIsLTR && OnRightPage())
|| (!bIsLTR && !OnRightPage());
// We paint the left shadow if we're not in book mode // or if we've no sibling or are the last page of the "row" return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetPrev()
|| (bIsLTR && !OnRightPage())
|| (!bIsLTR && OnRightPage());
}
/// Wrapper around pOut->DrawBitmapEx. staticvoid lcl_paintBitmapExToRect(vcl::RenderContext *pOut, const Point& aPoint, const Size& aSize, const BitmapEx& rBitmapEx, PaintArea eArea)
{ if(!comphelper::LibreOfficeKit::isActive())
{ // The problem is that if we get called multiple times and the color is // partly transparent, then the result will get darker and darker. To avoid // this, always paint the background color before doing the real paint.
tools::Rectangle aRect(aPoint, aSize);
if (!aRect.IsEmpty())
{ switch (eArea)
{ case LEFT: aRect.SetLeft( aRect.Right() - 1 ); break; case RIGHT: aRect.SetRight( aRect.Left() + 1 ); break; case TOP: aRect.SetTop( aRect.Bottom() - 1 ); break; case BOTTOM: aRect.SetBottom( aRect.Top() + 1 ); break;
}
}
/** * mod #i6193# paint sidebar for notes * IMPORTANT: if you change the rects here, also change SwPostItMgr::ScrollbarHit
*/ /*static*/void SwPageFrame::PaintNotesSidebar(const SwRect& _rPageRect, SwViewShell* _pViewShell, sal_uInt16 nPageNum, bool bRight)
{ //TODO: cut out scrollbar area and arrows out of sidepane rect, otherwise it could flicker when pressing arrow buttons if (!_pViewShell ) return;
const SwPostItMgr *pMgr = _pViewShell->GetPostItMgr(); if (!(pMgr && pMgr->ShowNotes() && pMgr->HasNotes())) // do not show anything in print preview return;
sal_Int32 nScrollerHeight = pMgr->GetSidebarScrollerHeight(); const tools::Rectangle aVisRect = _pViewShell->VisArea().SVRect(); //draw border and sidepane
_pViewShell->GetOut()->SetLineColor(); if (!bRight)
{
_pViewShell->GetOut()->SetFillColor(_pViewShell->GetViewOptions()->GetDocBoundariesColor());
_pViewShell->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height()))) ; if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
_pViewShell->GetOut()->SetFillColor(COL_BLACK); else
_pViewShell->GetOut()->SetFillColor(_pViewShell->GetViewOptions()->GetSectionBoundColor());
_pViewShell->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarWidth()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height()))) ;
} else
{
_pViewShell->GetOut()->SetFillColor(_pViewShell->GetViewOptions()->GetDocBoundariesColor());
SwRect aSidebarBorder(aPageRect.TopRight(),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height()));
_pViewShell->GetOut()->DrawRect(aSidebarBorder.SVRect()); if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
_pViewShell->GetOut()->SetFillColor(COL_BLACK); else
_pViewShell->GetOut()->SetFillColor(_pViewShell->GetViewOptions()->GetSectionBoundColor());
SwRect aSidebar(Point(aPageRect.Right()+pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height()));
_pViewShell->GetOut()->DrawRect(aSidebar.SVRect());
} if (!pMgr->ShowScrollbar(nPageNum)) return;
_pViewShell->GetOut()->SetLineColor();
Point aMiddleFirst(aPointBottom + Point(pMgr->GetSidebarWidth()/6,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
Point aMiddleSecond(aPointBottom + Point(pMgr->GetSidebarWidth()/3*2,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
PaintNotesSidebarArrows(aMiddleFirst,aMiddleSecond,_pViewShell,pMgr->GetArrowColor(KEY_PAGEUP,nPageNum), pMgr->GetArrowColor(KEY_PAGEDOWN,nPageNum));
} if (!aRectTop.Overlaps(aVisRect)) return;
// Always ask for full shadow since we want a bounding rect // including at least the page frame
SwPageFrame::GetHorizontalShadowRect( _rPageRect, _pViewShell, pRenderContext, aTmpRect, false, false, bRightSidebar );
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this ); const SwBorderAttrs &rAttrs = *aAccess.Get();
// take care of page margin area // Note: code move from <SwFrame::PaintSwFrameBackground(..)> to new method // <SwPageFrame::Paintmargin(..)>. if ( IsPageFrame() && !bOnlyTextBackground)
{ static_cast<const SwPageFrame*>(this)->PaintMarginArea( rRect, gProp.pSGlobalShell );
}
/// Do not paint background for fly frames without a background brush by /// calling <PaintBaBo> at the page or at the fly frame its anchored void SwFrame::PaintSwFrameBackground( const SwRect &rRect, const SwPageFrame *pPage, const SwBorderAttrs & rAttrs, constbool bLowerMode, constbool bLowerBorder, constbool bOnlyTextBackground,
PaintFrameMode ePaintFrameMode) const
{ // #i1837# - no paint of table background, if corresponding option is *not* set.
SwViewShell *pSh = gProp.pSGlobalShell; if( IsTabFrame() &&
!pSh->GetViewOptions()->IsTable() )
{ return;
}
// nothing to do for covered table cells: if( IsCellFrame() && IsCoveredCell() ) return;
// #i16816# tagged pdf support
SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh->GetOut() );
const SvxBrushItem* pItem; // temporary background brush for a fly frame without a background brush
std::unique_ptr<SvxBrushItem> pTmpBackBrush;
std::optional<Color> pCol;
SwRect aOrigBackRect; constbool bPageFrame = IsPageFrame(); bool bLowMode = true;
drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
if ( bBack && IsCellFrame() && !getRootFrame()->IsHideRedlines() && // skip cell background to show the row colored according to its tracked change
RedlineType::None != static_cast<const SwRowFrame*>(GetUpper())->GetTabLine()->GetRedlineType() )
{ return;
}
//- Output if a separate background is used. bool bNoFlyBackground = !gProp.bSFlyMetafile && !bBack && IsFlyFrame(); if ( bNoFlyBackground )
{ // Fly frame has no background. // Try to find background brush at parents, if previous call of // <GetBackgroundBrush> disabled this option with the parameter <bLowerMode> if ( bLowerMode )
{
bBack = GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/false );
} // If still no background found for the fly frame, initialize the // background brush <pItem> with global retouche color and set <bBack> // to true, that fly frame will paint its background using this color. if ( !bBack )
{ // #i6467# - on print output, pdf output and in embedded mode not editing color COL_WHITE is used // instead of the global retouche color. if ( pSh->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
pSh->GetViewOptions()->IsPDFExport() ||
( pSh->GetDoc()->GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED &&
!pSh->GetDoc()->GetDocShell()->IsInPlaceActive()
)
)
{
pTmpBackBrush.reset(new SvxBrushItem( COL_WHITE, RES_BACKGROUND ));
// Determine, if background transparency // have to be considered for drawing. // Status Quo: background transparency have to be // considered for fly frames constbool bConsiderBackgroundTransparency = IsFlyFrame(); bool bDone(false);
// #i125189# We are also done when the new DrawingLayer FillAttributes are used // or the FillStyle is set (different from drawing::FillStyle_NONE) if (aFillAttributes)
{ if(aFillAttributes->isUsed())
{ // check if really something is painted
bDone = DrawFillAttributes(aFillAttributes, aOrigBackRect, aRegion, aClipState, *pOut);
}
if(!bDone)
{ // if not, still a FillStyle could be set but the transparency is at 100%, // thus need to check the model data itself for FillStyle (do not rely on // SdrAllFillAttributesHelper since it already contains optimized information, // e.g. transparency leads to no fill) const drawing::FillStyle eFillStyle(GetAttrSet()->Get(XATTR_FILLSTYLE).GetValue());
if(!bDone)
{ for (size_t i = 0; i < aRegion.size(); ++i)
{ if (1 < aRegion.size())
{
::SwAlignRect( aRegion[i], gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() ); if( !aRegion[i].HasArea() ) continue;
} // add 6th parameter to indicate, if background transparency have to be considered // Set missing 5th parameter to the default value GRFNUM_NO // - see declaration in /core/inc/frmtool.hxx.
::DrawGraphic(
pItem,
*pOut,
aOrigBackRect,
aRegion[i],
GRFNUM_NO,
bConsiderBackgroundTransparency );
}
}
}
} else
bLowMode = bLowerMode;
}
//Now process lower and his neighbour. //We end this as soon as a Frame leaves the chain and therefore is not a lower //of me anymore const SwFrame *pFrame = GetLower(); if ( !pFrame ) return;
/// Refreshes all subsidiary lines of a page. void SwPageFrame::RefreshSubsidiary( const SwRect &rRect ) const
{ if ( !(isSubsidiaryLinesEnabled() ||
gProp.pSGlobalShell->GetViewOptions()->IsTextBoundaries() ||
gProp.pSGlobalShell->GetViewOptions()->IsSectionBoundaries() ||
gProp.pSGlobalShell->GetViewOptions()->IsTableBoundaries()) ) return;
if ( !rRect.HasArea() ) return;
//During paint using the root, the array is controlled from there. //Otherwise we'll handle it for our self. bool bDelSubs = false; if ( !gProp.pSSubsLines )
{
gProp.pSSubsLines.reset(new SwSubsRects); // create container for special subsidiary lines
gProp.pSSpecSubsLines.reset(new SwSubsRects);
bDelSubs = true;
}
RefreshLaySubsidiary( this, rRect );
if ( bDelSubs )
{ // paint special subsidiary lines and delete its container
gProp.pSSpecSubsLines->PaintSubsidiary( gProp.pSGlobalShell->GetOut(), nullptr, gProp );
gProp.pSSpecSubsLines.reset();
/** * Subsidiary lines to paint the PrtAreas * Only the LayoutFrames which directly contain Content * Paints the desired line and pays attention to not overpaint any flys
*/ staticvoid lcl_RefreshLine( const SwLayoutFrame *pLay, const SwPageFrame *pPage, const Point &rP1, const Point &rP2, const SubColFlags nSubColor,
SwLineRects* pSubsLines )
{ //In which direction do we loop? Can only be horizontal or vertical.
OSL_ENSURE( ((rP1.X() == rP2.X()) || (rP1.Y() == rP2.Y())), "Sloped subsidiary lines are not allowed." );
constbool bHori = rP1.Y() == rP2.Y();
// use pointers to member function in order to unify flow typedef tools::Long (Point::*pmfPtGet)() const; typedefvoid (Point::*pmfPtSet)(tools::Long); const pmfPtGet pDirPtX = &Point::X; const pmfPtGet pDirPtY = &Point::Y; const pmfPtGet pDirPt = bHori ? pDirPtX : pDirPtY; const pmfPtSet pDirPtSetX = &Point::setX; const pmfPtSet pDirPtSetY = &Point::setY; const pmfPtSet pDirPtSet = bHori ? pDirPtSetX : pDirPtSetY;
Point aP1( rP1 );
Point aP2( rP2 );
while ( (aP1.*pDirPt)() < (aP2.*pDirPt)() )
{ //If the starting point lies in a fly, it is directly set behind the //fly. //The end point moves to the start if the end point lies in a fly or we //have a fly between starting point and end point. // In this way, every position is output one by one.
//If I'm a fly I'll only avoid those flys which are places 'above' me; //this means those who are behind me in the array. //Even if I'm inside a fly or inside a fly inside a fly a.s.o I won't //avoid any of those flys.
SwOrderIter aIter( pPage ); const SwFlyFrame *pMyFly = pLay->FindFlyFrame(); if ( pMyFly )
{
aIter.Current( pMyFly->GetVirtDrawObj() ); while ( nullptr != (pMyFly = pMyFly->GetAnchorFrame()->FindFlyFrame()) )
{ if ( aIter()->GetOrdNum() > pMyFly->GetVirtDrawObj()->GetOrdNum() )
aIter.Current( pMyFly->GetVirtDrawObj() );
}
} else
aIter.Bottom();
//I certainly won't avoid myself, even if I'm placed _inside_ the //fly I won't avoid it. if ( !pFly || (pFly == pLay || pFly->IsAnLower( pLay )) )
{
aIter.Next(); continue;
}
// do *not* consider fly frames with a transparent background. // do *not* consider fly frame, which belongs to an invisible layer if ( pFly->IsBackgroundTransparent() ||
!pFly->GetFormat()->GetDoc().getIDocumentDrawModelAccess().IsVisibleLayerId( pObj->GetLayer() ) )
{
aIter.Next(); continue;
}
//Is the Obj placed on the line const tools::Long nP1OthPt = !bHori ? rP1.X() : rP1.Y(); const tools::Rectangle &rBound = pObj->GetCurrentBoundRect(); const Point aDrPt( rBound.TopLeft() ); const tools::Long nDrOthPt = !bHori ? aDrPt.X() : aDrPt.Y(); const Size aDrSz( rBound.GetSize() ); const tools::Long nDrOthSz = !bHori ? aDrSz.Width() : aDrSz.Height();
// Actually loop over the corners to create the two lines for ( int i = 0; i < 4; i++ )
{
basegfx::B2DVector aHorizVector( aXOffDirs[i], 0.0 );
basegfx::B2DVector aVertVector( 0.0, aYOffDirs[i] );
basegfx::BColor aLineColor = SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor(); for (size_t i = 0; i < rPolygons.size(); ++i)
aSeq[i] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(rPolygons[i], aLineColor);
// Actually loop over the corners to create the two lines for ( int i = 0; i < 4; i++ )
{
basegfx::B2DVector aHorizVector( aXOffDirs[i], 0.0 );
basegfx::B2DVector aVertVector( 0.0, aYOffDirs[i] );
const SwFrame *pLow = Lower(); while (pLow)
{ if (pLow->getFrameArea().HasArea())
{ if (pLow->IsHeaderFrame() || pLow->IsFooterFrame())
{ static_cast<const SwHeadFootFrame*>(pLow)->AddSubsidiaryLinesBounds(rViewShell, rRects);
}
}
pLow = pLow->GetNext();
}
}
void SwColumnFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect & ) const
{ const SwFrame* pLay = Lower(); const SwFrame* pFootnoteCont = nullptr; const SwFrame* pColBody = nullptr; while ( pLay && !( pFootnoteCont && pColBody ) )
{ if ( pLay->IsFootnoteContFrame( ) )
pFootnoteCont = pLay; if ( pLay->IsBodyFrame() )
pColBody = pLay;
pLay = pLay->GetNext();
}
assert(pColBody && "presumably this is impossible");
SwRect aArea( pColBody->getFrameArea() );
// #i3662# - enlarge top of column body frame's printing area // in sections to top of section frame. constbool bColInSection = GetUpper()->IsSctFrame(); if ( bColInSection )
{ if ( IsVertical() )
aArea.Right( GetUpper()->getFrameArea().Right() ); else
aArea.Top( GetUpper()->getFrameArea().Top() );
}
if ( pFootnoteCont )
aArea.AddBottom( pFootnoteCont->getFrameArea().Bottom() - aArea.Bottom() );
/** * The SwBodyFrame doesn't print any subsidiary line: it's bounds are painted * either by the parent page or the parent column frame.
*/ void SwBodyFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect & ) const
{
}
/** * This method is overridden in order to have no subsidiary lines * around the footnotes.
*/ void SwFootnoteFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect & ) const
{
}
/** * This method is overridden in order to have no subsidiary lines * around the footnotes containers.
*/ void SwFootnoteContFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect & ) const
{
}
bNewTableModel = pTabFrame->GetTable()->IsNewModel(); // in the new table model, we have an early return for all cell-related // frames, except from non-covered table cells if ( bNewTableModel ) if ( IsTabFrame() ||
IsRowFrame() ||
( IsCellFrame() && IsCoveredCell() ) ) return;
}
if ( (IsSctFrame() || IsFlyFrame()) &&
!gProp.pSGlobalShell->GetViewOptions()->IsSectionBoundaries() ) return; if ( IsTextFrame() &&
!gProp.pSGlobalShell->GetViewOptions()->IsTextBoundaries() ) return;
// #i3662# - use frame area for cells for section use also frame area constbool bUseFrameArea = bCell || IsSctFrame();
SwRect aOriginal( bUseFrameArea ? getFrameArea() : getFramePrintArea() ); if ( !bUseFrameArea )
aOriginal.Pos() += getFrameArea().Pos();
// NOTE: for cell frames only left and right (horizontal layout) respectively // top and bottom (vertical layout) lines painted. // NOTE2: this does not hold for the new table model!!! We paint the top border // of each non-covered table cell. constbool bVert = IsVertical(); if ( bFlys )
{ // add control for drawing left and right lines if ( !bCell || bNewTableModel || !bVert )
{ if ( aOriginal.Left() == aOut.Left() )
::lcl_RefreshLine( this, pPage, aOut.Pos(), aLB, nSubColor, pUsedSubsLines ); // in vertical layout set page/column break at right if ( aOriginal.Right() == nRight )
::lcl_RefreshLine( this, pPage, aRT, aRB, nSubColor, pUsedSubsLines );
} // adjust control for drawing top and bottom lines if ( !bCell || bNewTableModel || bVert )
{ if ( aOriginal.Top() == aOut.Top() ) // in horizontal layout set page/column break at top
::lcl_RefreshLine( this, pPage, aOut.Pos(), aRT, nSubColor, pUsedSubsLines ); if ( aOriginal.Bottom() == nBottom )
::lcl_RefreshLine( this, pPage, aLB, aRB, nSubColor,
pUsedSubsLines );
}
} else
{ // add control for drawing left and right lines if ( !bCell || bNewTableModel || !bVert )
{ if ( aOriginal.Left() == aOut.Left() )
{ const SwRect aRect( aOut.Pos(), aLB );
pUsedSubsLines->AddLineRect( aRect, nullptr,
SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
} // in vertical layout set page/column break at right if ( aOriginal.Right() == nRight )
{ const SwRect aRect( aRT, aRB );
pUsedSubsLines->AddLineRect( aRect, nullptr,
SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
}
} // adjust control for drawing top and bottom lines if ( !bCell || bNewTableModel || bVert )
{ if ( aOriginal.Top() == aOut.Top() )
{ // in horizontal layout set page/column break at top const SwRect aRect( aOut.Pos(), aRT );
pUsedSubsLines->AddLineRect( aRect, nullptr,
SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
} if ( aOriginal.Bottom() == nBottom )
{ const SwRect aRect( aLB, aRB );
pUsedSubsLines->AddLineRect( aRect, nullptr,
SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
}
}
}
}
/** * Refreshes all extra data (line breaks a.s.o) of the page. Basically only those objects * are considered which horizontally overlap the Rect.
*/ void SwPageFrame::RefreshExtraData( const SwRect &rRect ) const
{ const SwLineNumberInfo &rInfo = GetFormat()->GetDoc().GetLineNumberInfo(); bool bLineInFly = (rInfo.IsPaintLineNumbers() && rInfo.IsCountInFlys())
|| static_cast<sal_Int16>(SwModule::get()->GetRedlineMarkPos()) != text::HoriOrientation::NONE;
/** * For #102450# * Determine the color, that is respectively will be drawn as background * for the page frame. * Using existing method SwFrame::GetBackgroundBrush to determine the color * that is set at the page frame respectively is parent. If none is found * return the global retouche color * * @return Color
*/
Color SwPageFrame::GetDrawBackgroundColor() const
{ const SvxBrushItem* pBrushItem;
std::optional<Color> xDummyColor;
SwRect aDummyRect;
drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
if ( GetBackgroundBrush( aFillAttributes, pBrushItem, xDummyColor, aDummyRect, true, /*bConsiderTextBox=*/false) )
{ if(aFillAttributes && aFillAttributes->isUsed())
{ // let SdrAllFillAttributesHelper do the average color calculation return Color(aFillAttributes->getAverageColor(aGlobalRetoucheColor.getBColor()));
} elseif(pBrushItem)
{
OUString referer;
SwViewShell * sh1 = getRootFrame()->GetCurrShell(); if (sh1 != nullptr) {
SfxObjectShell * sh2 = sh1->GetDoc()->GetPersist(); if (sh2 != nullptr && sh2->HasName()) {
referer = sh2->GetMedium()->GetName();
}
} const Graphic* pGraphic = pBrushItem->GetGraphic(referer);
if(pGraphic)
{ // #29105# when a graphic is set, it may be possible to calculate a single // color which looks good in all places of the graphic. Since it is // planned to have text edit on the overlay one day and the fallback // to aGlobalRetoucheColor returns something useful, just use that // for now.
} else
{ // not a graphic, use (hopefully) initialized color return pBrushItem->GetColor();
}
}
}
/** * Retouch for a section * * Retouch will only be done, if the Frame is the last one in his chain. * The whole area of the upper which is located below the Frame will be * cleared using PaintSwFrameBackground.
*/ void SwFrame::Retouch( const SwPageFrame * pPage, const SwRect &rRect ) const
{ if ( gProp.bSFlyMetafile ) return;
OSL_ENSURE( GetUpper(), "Retouche try without Upper." );
OSL_ENSURE( getRootFrame()->GetCurrShell() && gProp.pSGlobalShell->GetWin(), "Retouche on a printer?" );
if ( aRetouche.HasArea() )
{ //Omit the passed Rect. To do this, we unfortunately need a region to //cut out.
SwRegionRects aRegion( aRetouche );
aRegion -= rRect;
SwViewShell *pSh = getRootFrame()->GetCurrShell();
// #i16816# tagged pdf support
SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh->GetOut() );
for ( size_t i = 0; i < aRegion.size(); ++i )
{ const SwRect &rRetouche = aRegion[i];
GetUpper()->PaintBaBo( rRetouche, pPage );
//Hell and Heaven need to be refreshed too. //To avoid recursion my retouch flag needs to be reset first!
ResetRetouche(); if ( rRetouche.HasArea() )
{ const Color aPageBackgrdColor(pPage->GetDrawBackgroundColor()); const IDocumentDrawModelAccess& rIDDMA = pSh->getIDocumentDrawModelAccess(); // --> OD #i76669#
SwViewObjectContactRedirector aSwRedirector( *pSh ); // <--
//Because we leave all paint areas, we need to refresh the //subsidiary lines.
pPage->RefreshSubsidiary( rRetouche );
}
} if ( SwViewShell::IsLstEndAction() )
ResetRetouche();
}
/** * Determine the background brush for the frame: * the background brush is taken from it-self or from its parent (anchor/upper). * Normally, the background brush is taken, which has no transparent color or * which has a background graphic. But there are some special cases: * (1) No background brush is taken from a page frame, if view option "IsPageBack" * isn't set. * (2) Background brush from an index section is taken under special conditions. * In this case parameter <rpCol> is set to the index shading color. * (3) New (OD 20.08.2002) - Background brush is taken, if on background drawing * of the frame transparency is considered and its color is not "no fill"/"auto fill" * * Old description in German: * Returns the Backgroundbrush for the area of the Frame. * The Brush is defined by the Frame or by an upper, the first Brush is * used. If no Brush is defined for a Frame, false is returned. * * @param rpBrush * output parameter - constant reference pointer the found background brush * * @param rpFillStyle * output parameter - constant reference pointer the found background fill style * * @param rpFillGradient * output parameter - constant reference pointer the found background fill gradient * * @param rpCol * output parameter - constant reference pointer to the color of the index shading * set under special conditions, if background brush is taken from an index section. * * @param rOrigRect * in-/output parameter - reference to the rectangle the background brush is * considered for - adjusted to the frame, from which the background brush is * taken. * * @param bLowerMode * input parameter - boolean indicating, if background brush should *not* be * taken from parent. * * @param bConsiderTextBox * consider the TextBox of this fly frame (if there is any) when determining * the background color, useful for automatic font color. * * @return true, if a background brush for the frame is found
*/ bool SwFrame::GetBackgroundBrush(
drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes, const SvxBrushItem* & rpBrush,
std::optional<Color>& rxCol,
SwRect &rOrigRect, bool bLowerMode, bool bConsiderTextBox ) const
{ const SwFrame *pFrame = this;
SwViewShell *pSh = getRootFrame()->GetCurrShell(); const SwViewOption *pOpt = pSh->GetViewOptions();
rpBrush = nullptr;
rxCol.reset(); do
{ if ( pFrame->IsPageFrame() && !pOpt->IsPageBack() ) returnfalse;
if (pFrame->supportsFullDrawingLayerFillAttributeSet())
{ bool bHandledTextBox = false; if (pFrame->IsFlyFrame() && bConsiderTextBox)
{ const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(pFrame);
SwFrameFormat* pShape
= SwTextBoxHelper::getOtherTextBoxFormat(pFlyFrame->GetFormat(), RES_FLYFRMFMT); if (pShape)
{
SdrObject* pObject = pShape->FindRealSdrObject(); if (pObject)
{ // Work with the fill attributes of the shape of the fly frame.
rFillAttributes =
std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(
pObject->GetMergedItemSet());
bHandledTextBox = true;
}
}
}
if( pFrame->IsSctFrame() )
{ const SwSection* pSection = static_cast<const SwSectionFrame*>(pFrame)->GetSection(); // Note: If frame <pFrame> is a section of the index and // it its background color is "no fill"/"auto fill" and // it has no background graphic and // we are not in the page preview and // we are not in read-only mode and // option "index shadings" is set and // the output is not the printer // then set <rpCol> to the color of the index shading if( pSection && ( SectionType::ToxHeader == pSection->GetType() ||
SectionType::ToxContent == pSection->GetType() ) &&
(rBack.GetColor() == COL_TRANSPARENT) &&
rBack.GetGraphicPos() == GPOS_NONE &&
!pOpt->IsPagePreview() &&
!pOpt->IsReadonly() && // #114856# Form view
!pOpt->IsFormView() &&
pOpt->IsIndexShadings() &&
!pOpt->IsPDFExport() &&
pSh->GetOut()->GetOutDevType() != OUTDEV_PRINTER )
{
rxCol = pOpt->GetIndexShadingsColor();
}
}
// determine, if background draw of frame <pFrame> considers transparency // Status Quo: background transparency have to be // considered for fly frames constbool bConsiderBackgroundTransparency = pFrame->IsFlyFrame();
// #i125189# Do not base the decision for using the parent's fill style for this // frame when the new DrawingLayer FillAttributes are used on the SdrAllFillAttributesHelper // information. There the data is already optimized to no fill in the case that the // transparence is at 100% while no fill is the criteria for derivation bool bNewDrawingLayerFillStyleIsUsedAndNotNoFill(false);
if(rFillAttributes)
{ // the new DrawingLayer FillStyle is used if(rFillAttributes->isUsed())
{ // it's not drawing::FillStyle_NONE
bNewDrawingLayerFillStyleIsUsedAndNotNoFill = true;
} else
{ // maybe optimized already when 100% transparency is used somewhere, need to test // XFillStyleItem directly from the model data const drawing::FillStyle eFillStyle(pFrame->GetAttrSet()->Get(XATTR_FILLSTYLE).GetValue());
// add condition: // If <bConsiderBackgroundTransparency> is set - see above -, // return brush of frame <pFrame>, if its color is *not* "no fill"/"auto fill" if ( // #i125189# Done when the new DrawingLayer FillAttributes are used and // not drawing::FillStyle_NONE (see above)
bNewDrawingLayerFillStyleIsUsedAndNotNoFill ||
// done when SvxBrushItem is used
rBack.GetColor().GetAlpha() == 255 || rBack.GetGraphicPos() != GPOS_NONE ||
//Enlarge the rectangle if needed, so the border is painted too.
SwRect aOut( pFly->getFrameArea() );
SwBorderAttrAccess aAccess( SwFrame::GetCache(), pFly ); const SwBorderAttrs &rAttrs = *aAccess.Get(); if ( rAttrs.CalcRightLine() )
aOut.AddWidth(2*gProp.nSPixelSzW ); if ( rAttrs.CalcBottomLine() )
aOut.AddHeight(2*gProp.nSPixelSzH );
// #i92711# start Pre/PostPaint encapsulation before pOut is changed to the buffering VDev const vcl::Region aRepaintRegion(aOut.SVRect());
pSh->DLPrePaint2(aRepaintRegion);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.