//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 );
/** *Containerforstaticproperties
*/ 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;
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;
}
// 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;
}
/** *CalculatePrtAreaplussurroundingplusshadow
*/ 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;
}
// 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();
}
/** *LocalhelperforSwRootFrame::PaintSwFrame(..)-Adjustgivenrectangletopixelsize * *ByODat27.09.2002for#103636# *Inordertoavoidpainterrorscausedbymultiplealignments(e.g.::SwAlignRect(..)) *andotherchangestothetobepaintedrectangle,thismethodiscalledforthe *rectangletobepaintedinordertoadjustittothepixelitisoverlapping
*/ 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);
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
*/
static bool 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 tableframe: 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
*/
static bool 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;
}
// new right segment
const SwLineEntry aRight(nKey, rNew.mnEndPos, rOld.mnEndPos, rOld.mbOuter, rOldAttr);
// update current lines set
pLineSet->erase( aIter );
if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
break; // we are finished
}
else if ( SwLineEntry::OVERLAP3 == nOverlapType )
{
// new left segment
const SwLineEntry aLeft(nKey, rNew.mnStartPos, rOld.mnStartPos, rOld.mbOuter, rNewAttr);
/**
* 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.
const bool 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#154939Link nested inside Figure
auto const 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 headerfooter 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 )
return true;
//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;
else if ( 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);
else if ( 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.
const bool 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.
const bool 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 framearea 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
**/
static void lcl_PaintShadow( const SwRect& rRect, SwRect& rOutRect,
const SvxShadowItem& rShadow, const bool bDrawFullShadowRectangle,
const bool bTop, const bool bBottom,
const bool bLeft, const bool 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.
const bool 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());
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)() );
/** *Specialimplementationbecauseofthefootnoteline * *Currentlyonlythetopframeneedstobetakenintoaccount *Otherlinesandshadowsaresetaside
*/ 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.
// 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#paintsidebarfornotes *IMPORTANT:ifyouchangetherectshere,alsochangeSwPostItMgr::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, const bool bLowerMode, const bool bLowerBorder, const bool 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; const bool 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 const bool 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();
/** *SubsidiarylinestopaintthePrtAreas *OnlytheLayoutFrameswhichdirectlycontainContent *Paintsthedesiredlineandpaysattentiontonotoverpaintanyflys
*/ 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." );
const bool bHori = rP1.Y() == rP2.Y();
// use pointers to member function in order to unify flow
typedef tools::Long (Point::*pmfPtGet)() const;
typedef void (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. const bool 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() );
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 const bool 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. const bool 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 );
}
}
}
}
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();
}
}
}
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();
}
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 const bool 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.0.376Bemerkung:
¤
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.