/* -*- 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 .
*/
// transfer various settings // FIXME: this must disappear as we move to RenderContext only, // the painting must become state-less, so that no actual // vcl::Window setting affects this
mbBackground = pFrameData->mpBuffer->IsBackground(); if (pWindow->IsBackground())
{
maBackground = pFrameData->mpBuffer->GetBackground();
pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
} //else //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
PaintBufferGuard::~PaintBufferGuard() COVERITY_NOEXCEPT_FALSE
{ if (!mpFrameData->mpBuffer) return;
if (!m_aPaintRect.IsEmpty())
{ // copy the buffer content to the actual window // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are // painting directly instead of using Invalidate() // [ie. everything you can see was painted directly to the // window either above or in eg. an event handler] if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
{ // Make sure that the +1 value GetSize() adds to the size is in pixels.
Size aPaintRectSize; if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
{
aPaintRectSize = m_aPaintRect.GetSize();
} else
{
tools::Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
}
if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible) /* #98602# need to repaint all children within the * tracking rectangle, so the following invert * operation takes places without traces of the previous * one.
*/
pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren)
m_pChildRegion.reset( new vcl::Region(pWindowImpl->maInvalidateRegion) );
pWindowImpl->maInvalidateRegion.Intersect(rWinChildClipRegion);
}
pWindowImpl->mnPaintFlags = ImplPaintFlags::NONE; if (pWindowImpl->maInvalidateRegion.IsEmpty()) return;
#if HAVE_FEATURE_OPENGL
VCL_GL_INFO("PaintHelper::DoPaint on " << typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin"); #endif // double-buffering: setup the buffer if it does not exist if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
StartBufferedPaint();
// double-buffering: if this window does not support double-buffering, // but we are in the middle of double-buffered paint, we might be // losing information if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
// colors used for item highlighting
Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
Color aSelectionFillColor(aSelectionBorderColor);
int c1 = aSelectionBorderColor.GetLuminance(); int c2 = rWindow.GetBackgroundColor().GetLuminance();
if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
{ // contrast too low
sal_uInt16 h, s, b;
aSelectionFillColor.RGBtoHSB( h, s, b ); if( b > 50 ) b -= 40; else b += 40;
aSelectionFillColor = Color::HSBtoRGB( h, s, b );
aSelectionBorderColor = aSelectionFillColor;
}
if (bRoundEdges)
{ if (aSelectionBorderColor.IsDark())
aSelectionBorderColor.IncreaseLuminance(128); else
aSelectionBorderColor.DecreaseLuminance(128);
}
// RTL: re-mirror paint rect and region at this window if (GetOutDev()->ImplIsAntiparallel())
{
rRenderContext.ReMirror(aPaintRect);
rRenderContext.ReMirror(rPaintRegion);
}
aPaintRect = GetOutDev()->ImplDevicePixelToLogic(aPaintRect);
mpWindowImpl->mpPaintRegion = &rPaintRegion;
mpWindowImpl->maInvalidateRegion.SetEmpty();
// #98943# trigger drawing of toolbox selection after all children are painted if (mpWindowImpl->mbDrawSelectionBackground)
pHelper->SetSelectionRect(aPaintRect);
pHelper->SetPaintRect(aPaintRect);
}
void Window::PopPaintHelper(PaintHelper const *pHelper)
{ if (mpWindowImpl->mpWinData)
{ if (mpWindowImpl->mbFocusVisible)
ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
}
mpWindowImpl->mbInPaint = false;
GetOutDev()->mbInitClipRegion = true;
mpWindowImpl->mpPaintRegion = nullptr; if (mpWindowImpl->mpCursor)
mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
}
ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData; if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
{ // Paint from the bottom child window and frontward.
vcl::Window* pTempWindow = pWindowImpl->mpLastChild; while (pTempWindow)
{ if (pTempWindow->mpWindowImpl->mbVisible)
pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
}
}
if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) ) /* #98602# need to invert the tracking rect AFTER * the children have painted
*/
m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
// double-buffering: paint in case we created the buffer, the children are // already painted inside if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
{
PaintBuffer();
pFrameData->mbInBufferedPaint = false;
pFrameData->maBufferedRect = tools::Rectangle();
}
void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
{ // call PrePaint. PrePaint may add to the invalidate region as well as // other parameters used below.
PrePaint(*GetOutDev());
mpWindowImpl->mbPaintFrame = false;
if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll); if (nPaintFlags & ImplPaintFlags::PaintChildren)
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren; if (nPaintFlags & ImplPaintFlags::Erase)
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase; if (nPaintFlags & ImplPaintFlags::CheckRtl)
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl; if (!mpWindowImpl->mpFirstChild)
mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
// If tiled rendering is used, windows are only invalidated, never painted to. if (mpWindowImpl->mbPaintDisabled || comphelper::LibreOfficeKit::isActive())
{ if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren); elseif ( pRegion )
Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
// call PostPaint before returning
PostPaint(*GetOutDev());
if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
aHelper.DoPaint(pRegion); else
mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
// call PostPaint
PostPaint(*GetOutDev());
}
void Window::ImplCallOverlapPaint()
{ if (!mpWindowImpl) return;
// emit overlapping windows first
vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap; while ( pTempWindow )
{ if ( pTempWindow->mpWindowImpl->mbReallyVisible )
pTempWindow->ImplCallOverlapPaint();
pTempWindow = pTempWindow->mpWindowImpl->mpNext;
}
// only then ourself if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
{ // RTL: notify ImplCallPaint to check for re-mirroring // because we were called from the Sal layer
ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
}
}
// save paint events until layout is done if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
{
mpWindowImpl->mpFrameData->maPaintIdle.Start(); return;
}
// save paint events until resizing or initial sizing done if (mpWindowImpl->mbFrame &&
mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
{
mpWindowImpl->mpFrameData->maPaintIdle.Start();
} elseif ( mpWindowImpl->mbReallyVisible )
{
ImplCallOverlapPaint(); if (comphelper::LibreOfficeKit::isActive() &&
mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
mpWindowImpl->mpFrameData->maPaintIdle.Stop();
}
}
void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
{ // set PAINTCHILDREN for all parent windows till the first OverlapWindow if ( !ImplIsOverlapWindow() )
{
vcl::Window* pTempWindow = this;
ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE; do
{
pTempWindow = pTempWindow->ImplGetParent(); if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren ) break;
pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint; if( ! pTempWindow->IsPaintTransparent() )
nTranspPaint = ImplPaintFlags::NONE;
} while ( !pTempWindow->ImplIsOverlapWindow() );
}
// set Paint-Flags
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint; if ( nFlags & InvalidateFlags::Children )
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren; if ( !(nFlags & InvalidateFlags::NoErase) )
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
if ( !pRegion )
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll; elseif ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
{ // if not everything has to be redrawn, add the region to it
mpWindowImpl->maInvalidateRegion.Union( *pRegion );
}
// Handle transparent windows correctly: invalidate must be done on the first opaque parent if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
&& ImplGetParent() )
{
vcl::Window *pParent = ImplGetParent(); while( pParent && pParent->IsPaintTransparent() )
pParent = pParent->ImplGetParent(); if( pParent )
{
vcl::Region *pChildRegion; if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll ) // invalidate the whole child window region in the parent
pChildRegion = &ImplGetWinChildClipRegion(); else // invalidate the same region in the parent that has to be repainted in the child
pChildRegion = &mpWindowImpl->maInvalidateRegion;
nFlags |= InvalidateFlags::Children; // paint should also be done on all children
nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
}
}
if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
mpWindowImpl->mpFrameData->maPaintIdle.Start();
}
// now we invalidate the overlapping windows
vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap; while ( pTempWindow )
{ if ( pTempWindow->IsVisible() )
pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
tools::Long nHorzScroll, tools::Long nVertScroll, bool bChildren )
{ // also shift Paint-Region when paints need processing
ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren ); // Paint-Region should be shifted, as drawn by the parents if ( ImplIsOverlapWindow() ) return;
// an update changes the OverlapWindow, such that for later paints // not too much has to be drawn, if ALLCHILDREN etc. is set
vcl::Window* pWindow = ImplGetFirstOverlapWindow();
pWindow->ImplCallOverlapPaint();
void Window::SetPaintTransparent( bool bTransparent )
{ // transparency is not useful for frames as the background would have to be provided by a different frame if( bTransparent && mpWindowImpl->mbFrame ) return;
if ( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
for (autoconst& rectangle : aRectangles)
{
mpWindowImpl->mpFrame->UnionClipRegion(
rectangle.Left(),
rectangle.Top(),
rectangle.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
rectangle.GetHeight()); // same for height
}
void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
{ if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive()) return;
Size aSize = GetSizePixel(); if (aSize.IsEmpty()) return;
if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
{ // In case we are routing the window, notify the client
std::vector<vcl::LOKPayloadItem> aPayload;
tools::Rectangle aRect(Point(0, 0), aSize); if (pRectangle)
aRect = *pRectangle;
if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
GetOutDev()->ReMirror(aRect);
// First we should skip all windows which are Paint-Transparent
vcl::Window* pUpdateWindow = this;
vcl::Window* pWindow = pUpdateWindow; while ( !pWindow->ImplIsOverlapWindow() )
{ if ( !pWindow->mpWindowImpl->mbPaintTransparent )
{
pUpdateWindow = pWindow; break;
}
pWindow = pWindow->ImplGetParent();
} // In order to limit drawing, an update only draws the window which // has PAINTALLCHILDREN set
pWindow = pUpdateWindow; do
{ if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
pUpdateWindow = pWindow; if ( pWindow->ImplIsOverlapWindow() ) break;
pWindow = pWindow->ImplGetParent();
} while ( pWindow );
// if there is something to paint, trigger a Paint if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
{
VclPtr<vcl::Window> xWindow(this);
// trigger an update also for system windows on top of us, // otherwise holes would remain
vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow(); if (pUpdateOverlapWindow->mpWindowImpl)
pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpFirstOverlap; else
pUpdateOverlapWindow = nullptr; while ( pUpdateOverlapWindow )
{
pUpdateOverlapWindow->PaintImmediately();
pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
}
if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
pUpdateWindow->LogicInvalidate(nullptr);
if (xWindow->isDisposed()) return;
bFlush = true;
}
if ( bFlush )
GetOutDev()->Flush();
}
void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
{ // Special drawing when called through LOKit // TODO: Move to its own method if (comphelper::LibreOfficeKit::isActive())
{
VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
pDevice->EnableRTL(IsRTLEnabled());
if( pOutDev->HasMirroredGraphics() )
nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
Point aPos( i_rPos ); // tdf#165706 those delta values are in pixels, but aPos copied from // i_rPos *may* be in logical coordinates if a MapMode is set at // i_pTargetOutDev. To not mix values of different coordinate systems // it *needs* to be converted (which does nothing if no MapMode)
Point aDelta( i_pTargetOutDev->PixelToLogic( Point( nDeltaX, nDeltaY )) );
aPos += aDelta;
pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
}
}
if ( !mpWindowImpl->mpFirstChild )
bScrollChildren = false;
OutputDevice *pOutDev = GetOutDev();
// RTL: check if this window requires special action bool bReMirror = GetOutDev()->ImplIsAntiparallel();
tools::Rectangle aRectMirror( rRect ); if( bReMirror )
{ // make sure the invalidate region of this window is // computed in the same coordinate space as the one from the overlap windows
pOutDev->ReMirror( aRectMirror );
}
// adapt paint areas
ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
// if the scrolling on the device is performed in the opposite direction // then move the overlaps in that direction to compute the invalidate region // on the correct side, i.e., revert nHorzScroll if (!aInvalidateRegion.IsEmpty())
{
aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
}
tools::Rectangle aDestRect(aRectMirror);
aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
vcl::Region aWinInvalidateRegion(aRectMirror); if (!SupportsDoubleBuffering())
{ // There will be no CopyArea() call below, so invalidate the // whole visible area, not only the smaller one that was just // scrolled in.
aWinInvalidateRegion.Exclude(aDestRect);
}
ImplClipBoundaries( aRegion, false, true ); if ( !bScrollChildren )
{ if ( nOrgFlags & ScrollFlags::NoChildren )
ImplClipAllChildren( aRegion ); else
ImplClipChildren( aRegion );
} if ( GetOutDev()->mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
aRegion.Intersect( GetOutDev()->maRegion ); if ( !aRegion.IsEmpty() )
{ if ( mpWindowImpl->mpWinData )
{ if ( mpWindowImpl->mbFocusVisible )
ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect ); if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
} #ifndef IOS // This seems completely unnecessary with tiled rendering, and // causes the "AquaSalGraphics::copyArea() for non-layered // graphics" message. Presumably we should bypass this on all // platforms when dealing with a "window" that uses tiled // rendering at the moment. Unclear how to figure that out, // though. Also unclear whether we actually could just not // create a "frame window", whatever that exactly is, in the // tiled rendering case, or at least for platforms where tiles // rendering is all there is.
SalGraphics* pGraphics = ImplGetFrameGraphics(); // The invalidation area contains the area what would be copied here, // so avoid copying in case of double buffering. if (pGraphics && !SupportsDoubleBuffering())
{ if( bReMirror )
{
pOutDev->ReMirror( aRegion );
}
if ( !aInvalidateRegion.IsEmpty() )
{ // RTL: the invalidate region for this windows is already computed in frame coordinates // so it has to be re-mirrored before calling the Paint-handler
mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
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.