/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */#include <config_features.h>#include <vcl/gdimtf.hxx>#include <vcl/window.hxx>#include <vcl/dialog.hxx>#include <vcl/virdev.hxx>#include <vcl/cursor.hxx>#include <vcl/settings.hxx>#include <sal/types.h>#include <sal/log.hxx>#include <window.h>#include <salgdi.hxx>#include <salframe.hxx>#include <svdata.hxx>#include <comphelper/lok.hxx>#if HAVE_FEATURE_OPENGL#include <vcl/opengl/OpenGLHelper.hxx>#endif// PaintBufferGuardPaintBufferGuard::PaintBufferGuard(ImplFrameData*pFrameData,vcl::Window*pWindow):mpFrameData(pFrameData),m_pWindow(pWindow),mbBackground(false),mnOutOffX(0),mnOutOffY(0){if(!pFrameData->mpBuffer)return;// 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 thismbBackground=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");PushFlagsnFlags=PushFlags::NONE;nFlags|=PushFlags::CLIPREGION;nFlags|=PushFlags::FILLCOLOR;nFlags|=PushFlags::FONT;nFlags|=PushFlags::LINECOLOR;nFlags|=PushFlags::MAPMODE;maSettings=pFrameData->mpBuffer->GetSettings();nFlags|=PushFlags::REFPOINT;nFlags|=PushFlags::TEXTCOLOR;nFlags|=PushFlags::TEXTLINECOLOR;nFlags|=PushFlags::OVERLINECOLOR;nFlags|=PushFlags::TEXTFILLCOLOR;nFlags|=PushFlags::TEXTALIGN;nFlags|=PushFlags::RASTEROP;nFlags|=PushFlags::TEXTLAYOUTMODE;nFlags|=PushFlags::TEXTLANGUAGE;pFrameData->mpBuffer->Push(nFlags);pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());pFrameData->mpBuffer->SetFont(pWindow->GetFont());pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());mnOutOffX=pFrameData->mpBuffer->GetOutOffXPixel();mnOutOffY=pFrameData->mpBuffer->GetOutOffYPixel();pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());}PaintBufferGuard::~PaintBufferGuard(){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.SizeaPaintRectSize;if(m_pWindow->GetMapMode().GetMapUnit()==MapUnit::MapPixel){aPaintRectSize=m_aPaintRect.GetSize();}else{tools::RectangleaRectanglePixel=m_pWindow->LogicToPixel(m_aPaintRect);aPaintRectSize=m_pWindow->PixelToLogic(aRectanglePixel.GetSize());}m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(),aPaintRectSize,m_aPaintRect.TopLeft(),aPaintRectSize,*mpFrameData->mpBuffer.get());}}// Restore buffer state.mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);mpFrameData->mpBuffer->Pop();mpFrameData->mpBuffer->SetSettings(maSettings);if(mbBackground)mpFrameData->mpBuffer->SetBackground(maBackground);elsempFrameData->mpBuffer->SetBackground();}voidPaintBufferGuard::SetPaintRect(consttools::Rectangle&rRectangle){m_aPaintRect=rRectangle;}vcl::RenderContext*PaintBufferGuard::GetRenderContext(){if(mpFrameData->mpBuffer)returnmpFrameData->mpBuffer;elsereturnm_pWindow;}classPaintHelper{private:VclPtr<vcl::Window>m_pWindow;std::unique_ptr<vcl::Region>m_pChildRegion;tools::Rectanglem_aSelectionRect;tools::Rectanglem_aPaintRect;vcl::Regionm_aPaintRegion;ImplPaintFlagsconstm_nPaintFlags;boolm_bPop:1;boolm_bRestoreCursor:1;boolm_bStartedBufferedPaint:1;///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.public:PaintHelper(vcl::Window*pWindow,ImplPaintFlagsnPaintFlags);voidSetPop(){m_bPop=true;}voidSetPaintRect(consttools::Rectangle&rRect){m_aPaintRect=rRect;}voidSetSelectionRect(consttools::Rectangle&rRect){m_aSelectionRect=rRect;}voidSetRestoreCursor(boolbRestoreCursor){m_bRestoreCursor=bRestoreCursor;}boolGetRestoreCursor()const{returnm_bRestoreCursor;}ImplPaintFlagsGetPaintFlags()const{returnm_nPaintFlags;}vcl::Region&GetPaintRegion(){returnm_aPaintRegion;}voidDoPaint(constvcl::Region*pRegion);/// Start buffered paint: set it up to have the same settings as m_pWindow.voidStartBufferedPaint();/// Paint the content of the buffer to the current m_pWindow.voidPaintBuffer();~PaintHelper();};PaintHelper::PaintHelper(vcl::Window*pWindow,ImplPaintFlagsnPaintFlags):m_pWindow(pWindow),m_nPaintFlags(nPaintFlags),m_bPop(false),m_bRestoreCursor(false),m_bStartedBufferedPaint(false){}voidPaintHelper::StartBufferedPaint(){ImplFrameData*pFrameData=m_pWindow->mpWindowImpl->mpFrameData;assert(!pFrameData->mbInBufferedPaint);pFrameData->mbInBufferedPaint=true;pFrameData->maBufferedRect=tools::Rectangle();m_bStartedBufferedPaint=true;}voidPaintHelper::PaintBuffer(){ImplFrameData*pFrameData=m_pWindow->mpWindowImpl->mpFrameData;assert(pFrameData->mbInBufferedPaint);assert(m_bStartedBufferedPaint);PaintBufferGuardaGuard(pFrameData,m_pWindow);aGuard.SetPaintRect(pFrameData->maBufferedRect);}voidPaintHelper::DoPaint(constvcl::Region*pRegion){WindowImpl*pWindowImpl=m_pWindow->ImplGetWindowImpl();vcl::Region*pWinChildClipRegion=m_pWindow->ImplGetWinChildClipRegion();ImplFrameData*pFrameData=m_pWindow->mpWindowImpl->mpFrameData;if(pWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAll||pFrameData->mbInBufferedPaint){pWindowImpl->maInvalidateRegion=*pWinChildClipRegion;}else{if(pRegion)pWindowImpl->maInvalidateRegion.Union(*pRegion);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(newvcl::Region(pWindowImpl->maInvalidateRegion));pWindowImpl->maInvalidateRegion.Intersect(*pWinChildClipRegion);}pWindowImpl->mnPaintFlags=ImplPaintFlags::NONE;if(!pWindowImpl->maInvalidateRegion.IsEmpty()){#if HAVE_FEATURE_OPENGLVCL_GL_INFO("PaintHelper::DoPaint on "<<typeid(*m_pWindow).name()<<" '"<<m_pWindow->GetText()<<"' begin");#endif// double-buffering: setup the buffer if it does not existif(!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 informationif(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());if(pFrameData->mbInBufferedPaint&&m_pWindow->SupportsDoubleBuffering()){// double-bufferingPaintBufferGuardg(pFrameData,m_pWindow);m_pWindow->ApplySettings(*pFrameData->mpBuffer.get());m_pWindow->PushPaintHelper(this,*pFrameData->mpBuffer.get());m_pWindow->Paint(*pFrameData->mpBuffer.get(),m_aPaintRect);pFrameData->maBufferedRect.Union(m_aPaintRect);}else{// direct paintingm_pWindow->ApplySettings(*m_pWindow);m_pWindow->PushPaintHelper(this,*m_pWindow);m_pWindow->Paint(*m_pWindow,m_aPaintRect);}#if HAVE_FEATURE_OPENGLVCL_GL_INFO("PaintHelper::DoPaint end on "<<typeid(*m_pWindow).name()<<" '"<<m_pWindow->GetText()<<"'");#endif}}namespacevcl{voidRenderTools::DrawSelectionBackground(vcl::RenderContext&rRenderContext,vcl::Windowconst&rWindow,consttools::Rectangle&rRect,sal_uInt16nHighlight,boolbChecked,boolbDrawBorder,boolbDrawExtBorderOnly,Color*pSelectionTextColor,longnCornerRadius,Colorconst*pPaintColor){if(rRect.IsEmpty())return;boolbRoundEdges=nCornerRadius>0;constStyleSettings&rStyles=rRenderContext.GetSettings().GetStyleSettings();// colors used for item highlightingColoraSelectionBorderColor(pPaintColor?*pPaintColor:rStyles.GetHighlightColor());ColoraSelectionFillColor(aSelectionBorderColor);boolbDark=rStyles.GetFaceColor().IsDark();boolbBright=(rStyles.GetFaceColor()==COL_WHITE);intc1=aSelectionBorderColor.GetLuminance();intc2=rWindow.GetDisplayBackground().GetColor().GetLuminance();if(!bDark&&!bBright&&std::abs(c2-c1)<(pPaintColor?40:75)){// contrast too lowsal_uInt16h,s,b;aSelectionFillColor.RGBtoHSB(h,s,b);if(b>50)b-=40;elseb+=40;aSelectionFillColor=Color::HSBtoRGB(h,s,b);aSelectionBorderColor=aSelectionFillColor;}if(bRoundEdges){if(aSelectionBorderColor.IsDark())aSelectionBorderColor.IncreaseLuminance(128);elseaSelectionBorderColor.DecreaseLuminance(128);}tools::RectangleaRect(rRect);if(bDrawExtBorderOnly){aRect.AdjustLeft(-1);aRect.AdjustTop(-1);aRect.AdjustRight(1);aRect.AdjustBottom(1);}rRenderContext.Push(PushFlags::FILLCOLOR|PushFlags::LINECOLOR);if(bDrawBorder)rRenderContext.SetLineColor(bDark?COL_WHITE:(bBright?COL_BLACK:aSelectionBorderColor));elserRenderContext.SetLineColor();sal_uInt16nPercent=0;if(!nHighlight){if(bDark)aSelectionFillColor=COL_BLACK;elsenPercent=80;// just checked (light)}else{if(bChecked&&nHighlight==2){if(bDark)aSelectionFillColor=COL_LIGHTGRAY;elseif(bBright){aSelectionFillColor=COL_BLACK;rRenderContext.SetLineColor(COL_BLACK);nPercent=0;}elsenPercent=bRoundEdges?40:20;// selected, pressed or checked ( very dark )}elseif(bChecked||nHighlight==1){if(bDark)aSelectionFillColor=COL_GRAY;elseif(bBright){aSelectionFillColor=COL_BLACK;rRenderContext.SetLineColor(COL_BLACK);nPercent=0;}elsenPercent=bRoundEdges?60:35;// selected, pressed or checked ( very dark )}else{if(bDark)aSelectionFillColor=COL_LIGHTGRAY;elseif(bBright){aSelectionFillColor=COL_BLACK;rRenderContext.SetLineColor(COL_BLACK);if(nHighlight==3)nPercent=80;elsenPercent=0;}elsenPercent=70;// selected ( dark )}}if(bDark&&bDrawExtBorderOnly){rRenderContext.SetFillColor();if(pSelectionTextColor)*pSelectionTextColor=rStyles.GetHighlightTextColor();}else{rRenderContext.SetFillColor(aSelectionFillColor);if(pSelectionTextColor){ColoraTextColor=rWindow.IsControlBackground()?rWindow.GetControlForeground():rStyles.GetButtonTextColor();ColoraHLTextColor=rStyles.GetHighlightTextColor();intnTextDiff=std::abs(aSelectionFillColor.GetLuminance()-aTextColor.GetLuminance());intnHLDiff=std::abs(aSelectionFillColor.GetLuminance()-aHLTextColor.GetLuminance());*pSelectionTextColor=(nHLDiff>=nTextDiff)?aHLTextColor:aTextColor;}}if(bDark){rRenderContext.DrawRect(aRect);}else{if(bRoundEdges){tools::PolygonaPoly(aRect,nCornerRadius,nCornerRadius);tools::PolyPolygonaPolyPoly(aPoly);rRenderContext.DrawTransparent(aPolyPoly,nPercent);}else{tools::PolygonaPoly(aRect);tools::PolyPolygonaPolyPoly(aPoly);rRenderContext.DrawTransparent(aPolyPoly,nPercent);}}rRenderContext.Pop();// LINECOLOR | FILLCOLOR}voidWindow::PushPaintHelper(PaintHelper*pHelper,vcl::RenderContext&rRenderContext){pHelper->SetPop();if(mpWindowImpl->mpCursor)pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());mbInitClipRegion=true;mpWindowImpl->mbInPaint=true;// restore Paint-Regionvcl::Region&rPaintRegion=pHelper->GetPaintRegion();rPaintRegion=mpWindowImpl->maInvalidateRegion;tools::RectangleaPaintRect=rPaintRegion.GetBoundRect();// RTL: re-mirror paint rect and region at this windowif(ImplIsAntiparallel()){rRenderContext.ReMirror(aPaintRect);rRenderContext.ReMirror(rPaintRegion);}aPaintRect=ImplDevicePixelToLogic(aPaintRect);mpWindowImpl->mpPaintRegion=&rPaintRegion;mpWindowImpl->maInvalidateRegion.SetEmpty();if((pHelper->GetPaintFlags()&ImplPaintFlags::Erase)&&rRenderContext.IsBackground()){if(rRenderContext.IsClipRegion()){vcl::RegionaOldRegion=rRenderContext.GetClipRegion();rRenderContext.SetClipRegion();Erase(rRenderContext);rRenderContext.SetClipRegion(aOldRegion);}elseErase(rRenderContext);}// #98943# trigger drawing of toolbox selection after all children are paintedif(mpWindowImpl->mbDrawSelectionBackground)pHelper->SetSelectionRect(aPaintRect);pHelper->SetPaintRect(aPaintRect);}voidWindow::PopPaintHelper(PaintHelperconst*pHelper){if(mpWindowImpl->mpWinData){if(mpWindowImpl->mbFocusVisible)ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);}mpWindowImpl->mbInPaint=false;mbInitClipRegion=true;mpWindowImpl->mpPaintRegion=nullptr;if(mpWindowImpl->mpCursor)mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());}}/* namespace vcl */PaintHelper::~PaintHelper(){WindowImpl*pWindowImpl=m_pWindow->ImplGetWindowImpl();if(m_bPop){m_pWindow->PopPaintHelper(this);}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 insideif(m_bStartedBufferedPaint&&pFrameData->mbInBufferedPaint){PaintBuffer();pFrameData->mbInBufferedPaint=false;pFrameData->maBufferedRect=tools::Rectangle();}// #98943# draw toolbox selectionif(!m_aSelectionRect.IsEmpty())m_pWindow->DrawSelectionBackground(m_aSelectionRect,3,false,true);}namespacevcl{voidWindow::ImplCallPaint(constvcl::Region*pRegion,ImplPaintFlagsnPaintFlags){// call PrePaint. PrePaint may add to the invalidate region as well as// other parameters used below.PrePaint(*this);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(mpWindowImpl->mbPaintDisabled){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 returningPostPaint(*this);return;}nPaintFlags=mpWindowImpl->mnPaintFlags&~ImplPaintFlags::Paint;PaintHelperaHelper(this,nPaintFlags);if(mpWindowImpl->mnPaintFlags&ImplPaintFlags::Paint)aHelper.DoPaint(pRegion);elsempWindowImpl->mnPaintFlags=ImplPaintFlags::NONE;// call PostPaintPostPaint(*this);}voidWindow::ImplCallOverlapPaint(){// emit overlapping windows firstvcl::Window*pTempWindow=mpWindowImpl->mpFirstOverlap;while(pTempWindow){if(pTempWindow->mpWindowImpl->mbReallyVisible)pTempWindow->ImplCallOverlapPaint();pTempWindow=pTempWindow->mpWindowImpl->mpNext;}// only then ourselfif(mpWindowImpl->mnPaintFlags&(ImplPaintFlags::Paint|ImplPaintFlags::PaintChildren)){// RTL: notify ImplCallPaint to check for re-mirroring// because we were called from the Sal layerImplCallPaint(nullptr,mpWindowImpl->mnPaintFlags/*| ImplPaintFlags::CheckRtl */);}}IMPL_LINK_NOARG(Window,ImplHandlePaintHdl,Timer*,void)<--- syntax error{// save paint events until layout is doneif(IsSystemWindow()&&static_cast<constSystemWindow*>(this)->hasPendingLayout()){mpWindowImpl->mpFrameData->maPaintIdle.Start();return;}// save paint events until resizing or initial sizing doneif(mpWindowImpl->mbFrame&&mpWindowImpl->mpFrameData->maResizeIdle.IsActive()){mpWindowImpl->mpFrameData->maPaintIdle.Start();}elseif(mpWindowImpl->mbReallyVisible){ImplCallOverlapPaint();}}IMPL_LINK_NOARG(Window,ImplHandleResizeTimerHdl,Timer*,void){if(mpWindowImpl->mbReallyVisible){ImplCallResize();if(mpWindowImpl->mpFrameData->maPaintIdle.IsActive()){mpWindowImpl->mpFrameData->maPaintIdle.Stop();mpWindowImpl->mpFrameData->maPaintIdle.Invoke(nullptr);}}}voidWindow::ImplInvalidateFrameRegion(constvcl::Region*pRegion,InvalidateFlagsnFlags){// set PAINTCHILDREN for all parent windows till the first OverlapWindowif(!ImplIsOverlapWindow()){vcl::Window*pTempWindow=this;ImplPaintFlagsnTranspPaint=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-FlagsmpWindowImpl->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 itmpWindowImpl->maInvalidateRegion.Union(*pRegion);}// Handle transparent windows correctly: invalidate must be done on the first opaque parentif(((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 parentpChildRegion=ImplGetWinChildClipRegion();else// invalidate the same region in the parent that has to be repainted in the childpChildRegion=&mpWindowImpl->maInvalidateRegion;nFlags|=InvalidateFlags::Children;// paint should also be done on all childrennFlags&=~InvalidateFlags::NoErase;// parent should paint and erase to create proper backgroundpParent->ImplInvalidateFrameRegion(pChildRegion,nFlags);}}if(!mpWindowImpl->mpFrameData->maPaintIdle.IsActive())mpWindowImpl->mpFrameData->maPaintIdle.Start();}voidWindow::ImplInvalidateOverlapFrameRegion(constvcl::Region&rRegion){vcl::RegionaRegion=rRegion;ImplClipBoundaries(aRegion,true,true);if(!aRegion.IsEmpty())ImplInvalidateFrameRegion(&aRegion,InvalidateFlags::Children);// now we invalidate the overlapping windowsvcl::Window*pTempWindow=mpWindowImpl->mpFirstOverlap;while(pTempWindow){if(pTempWindow->IsVisible())pTempWindow->ImplInvalidateOverlapFrameRegion(rRegion);pTempWindow=pTempWindow->mpWindowImpl->mpNext;}}voidWindow::ImplInvalidateParentFrameRegion(vcl::Region&rRegion){if(mpWindowImpl->mbOverlapWin)mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion(rRegion);else{if(ImplGetParent())ImplGetParent()->ImplInvalidateFrameRegion(&rRegion,InvalidateFlags::Children);}}voidWindow::ImplInvalidate(constvcl::Region*pRegion,InvalidateFlagsnFlags){// check what has to be redrawnboolbInvalidateAll=!pRegion;// take Transparent-Invalidate into accountvcl::Window*pOpaqueWindow=this;if((mpWindowImpl->mbPaintTransparent&&!(nFlags&InvalidateFlags::NoTransparent))||(nFlags&InvalidateFlags::Transparent)){vcl::Window*pTempWindow=pOpaqueWindow->ImplGetParent();while(pTempWindow){if(!pTempWindow->IsPaintTransparent()){pOpaqueWindow=pTempWindow;nFlags|=InvalidateFlags::Children;bInvalidateAll=false;break;}if(pTempWindow->ImplIsOverlapWindow())break;pTempWindow=pTempWindow->ImplGetParent();}}// assemble regionInvalidateFlagsnOrgFlags=nFlags;if(!(nFlags&(InvalidateFlags::Children|InvalidateFlags::NoChildren))){if(GetStyle()&WB_CLIPCHILDREN)nFlags|=InvalidateFlags::NoChildren;elsenFlags|=InvalidateFlags::Children;}if((nFlags&InvalidateFlags::NoChildren)&&mpWindowImpl->mpFirstChild)bInvalidateAll=false;if(bInvalidateAll)ImplInvalidateFrameRegion(nullptr,nFlags);else{tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));vcl::RegionaRegion(aRect);if(pRegion){// RTL: remirror region before intersecting itif(ImplIsAntiparallel()){constOutputDevice*pOutDev=GetOutDev();vcl::RegionaRgn(*pRegion);pOutDev->ReMirror(aRgn);aRegion.Intersect(aRgn);}elseaRegion.Intersect(*pRegion);}ImplClipBoundaries(aRegion,true,true);if(nFlags&InvalidateFlags::NoChildren){nFlags&=~InvalidateFlags::Children;if(!(nFlags&InvalidateFlags::NoClipChildren)){if(nOrgFlags&InvalidateFlags::NoChildren)ImplClipAllChildren(aRegion);else{if(ImplClipChildren(aRegion))nFlags|=InvalidateFlags::Children;}}}if(!aRegion.IsEmpty())ImplInvalidateFrameRegion(&aRegion,nFlags);// transparency is handled here, pOpaqueWindow not required}if(nFlags&InvalidateFlags::Update)pOpaqueWindow->Update();// start painting at the opaque parent}voidWindow::ImplMoveInvalidateRegion(consttools::Rectangle&rRect,longnHorzScroll,longnVertScroll,boolbChildren){if((mpWindowImpl->mnPaintFlags&(ImplPaintFlags::Paint|ImplPaintFlags::PaintAll))==ImplPaintFlags::Paint){vcl::RegionaTempRegion=mpWindowImpl->maInvalidateRegion;aTempRegion.Intersect(rRect);aTempRegion.Move(nHorzScroll,nVertScroll);mpWindowImpl->maInvalidateRegion.Union(aTempRegion);}if(bChildren&&(mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintChildren)){vcl::Window*pWindow=mpWindowImpl->mpFirstChild;while(pWindow){pWindow->ImplMoveInvalidateRegion(rRect,nHorzScroll,nVertScroll,true);pWindow=pWindow->mpWindowImpl->mpNext;}}}voidWindow::ImplMoveAllInvalidateRegions(consttools::Rectangle&rRect,longnHorzScroll,longnVertScroll,boolbChildren){// also shift Paint-Region when paints need processingImplMoveInvalidateRegion(rRect,nHorzScroll,nVertScroll,bChildren);// Paint-Region should be shifted, as drawn by the parentsif(!ImplIsOverlapWindow()){vcl::RegionaPaintAllRegion;vcl::Window*pPaintAllWindow=this;do{pPaintAllWindow=pPaintAllWindow->ImplGetParent();if(pPaintAllWindow->mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAllChildren){if(pPaintAllWindow->mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAll){aPaintAllRegion.SetEmpty();break;}elseaPaintAllRegion.Union(pPaintAllWindow->mpWindowImpl->maInvalidateRegion);}}while(!pPaintAllWindow->ImplIsOverlapWindow());if(!aPaintAllRegion.IsEmpty()){aPaintAllRegion.Move(nHorzScroll,nVertScroll);InvalidateFlagsnPaintFlags=InvalidateFlags::NONE;if(bChildren)nPaintFlags|=InvalidateFlags::Children;ImplInvalidateFrameRegion(&aPaintAllRegion,nPaintFlags);}}}voidWindow::ImplValidateFrameRegion(constvcl::Region*pRegion,ValidateFlagsnFlags){if(!pRegion)mpWindowImpl->maInvalidateRegion.SetEmpty();else{// when all child windows have to be drawn we need to invalidate them before doing soif((mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAllChildren)&&mpWindowImpl->mpFirstChild){vcl::RegionaChildRegion=mpWindowImpl->maInvalidateRegion;if(mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAll){tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));aChildRegion=aRect;}vcl::Window*pChild=mpWindowImpl->mpFirstChild;while(pChild){pChild->Invalidate(aChildRegion,InvalidateFlags::Children|InvalidateFlags::NoTransparent);pChild=pChild->mpWindowImpl->mpNext;}}if(mpWindowImpl->mnPaintFlags&ImplPaintFlags::PaintAll){tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));mpWindowImpl->maInvalidateRegion=aRect;}mpWindowImpl->maInvalidateRegion.Exclude(*pRegion);}mpWindowImpl->mnPaintFlags&=~ImplPaintFlags::PaintAll;if(nFlags&ValidateFlags::Children){vcl::Window*pChild=mpWindowImpl->mpFirstChild;while(pChild){pChild->ImplValidateFrameRegion(pRegion,nFlags);pChild=pChild->mpWindowImpl->mpNext;}}}voidWindow::ImplValidate(){// assemble regionboolbValidateAll=true;ValidateFlagsnFlags=ValidateFlags::NONE;if(GetStyle()&WB_CLIPCHILDREN)nFlags|=ValidateFlags::NoChildren;elsenFlags|=ValidateFlags::Children;if((nFlags&ValidateFlags::NoChildren)&&mpWindowImpl->mpFirstChild)bValidateAll=false;if(bValidateAll)ImplValidateFrameRegion(nullptr,nFlags);else{tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));vcl::RegionaRegion(aRect);ImplClipBoundaries(aRegion,true,true);if(nFlags&ValidateFlags::NoChildren){nFlags&=~ValidateFlags::Children;if(ImplClipChildren(aRegion))nFlags|=ValidateFlags::Children;}if(!aRegion.IsEmpty())ImplValidateFrameRegion(&aRegion,nFlags);}}voidWindow::ImplUpdateAll(){if(!mpWindowImpl->mbReallyVisible)return;boolbFlush=false;if(mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame){PointaPoint(0,0);vcl::RegionaRegion(tools::Rectangle(aPoint,Size(mnOutWidth,mnOutHeight)));ImplInvalidateOverlapFrameRegion(aRegion);if(mpWindowImpl->mbFrame||(mpWindowImpl->mpBorderWindow&&mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame))bFlush=true;}// an update changes the OverlapWindow, such that for later paints// not too much has to be drawn, if ALLCHILDREN etc. is setvcl::Window*pWindow=ImplGetFirstOverlapWindow();pWindow->ImplCallOverlapPaint();if(bFlush)Flush();}voidWindow::PrePaint(vcl::RenderContext&/*rRenderContext*/){}voidWindow::PostPaint(vcl::RenderContext&/*rRenderContext*/){}voidWindow::Paint(vcl::RenderContext&/*rRenderContext*/,consttools::Rectangle&rRect){CallEventListeners(VclEventId::WindowPaint,const_cast<tools::Rectangle*>(&rRect));}voidWindow::SetPaintTransparent(boolbTransparent){// transparency is not useful for frames as the background would have to be provided by a different frameif(bTransparent&&mpWindowImpl->mbFrame)return;if(mpWindowImpl->mpBorderWindow)mpWindowImpl->mpBorderWindow->SetPaintTransparent(bTransparent);mpWindowImpl->mbPaintTransparent=bTransparent;}voidWindow::SetWindowRegionPixel(){if(mpWindowImpl->mpBorderWindow)mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();elseif(mpWindowImpl->mbFrame){mpWindowImpl->maWinRegion=vcl::Region(true);mpWindowImpl->mbWinRegion=false;mpWindowImpl->mpFrame->ResetClipRegion();}else{if(mpWindowImpl->mbWinRegion){mpWindowImpl->maWinRegion=vcl::Region(true);mpWindowImpl->mbWinRegion=false;ImplSetClipFlag();if(IsReallyVisible()){tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));vcl::RegionaRegion(aRect);ImplInvalidateParentFrameRegion(aRegion);}}}}voidWindow::SetWindowRegionPixel(constvcl::Region&rRegion){if(mpWindowImpl->mpBorderWindow)mpWindowImpl->mpBorderWindow->SetWindowRegionPixel(rRegion);elseif(mpWindowImpl->mbFrame){if(!rRegion.IsNull()){mpWindowImpl->maWinRegion=rRegion;mpWindowImpl->mbWinRegion=!rRegion.IsEmpty();if(mpWindowImpl->mbWinRegion){// set/update ClipRegionRectangleVectoraRectangles;mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());for(autoconst&rectangle:aRectangles){mpWindowImpl->mpFrame->UnionClipRegion(rectangle.Left(),rectangle.Top(),rectangle.GetWidth(),// orig nWidth was ((R - L) + 1), same as GetWidth doesrectangle.GetHeight());// same for height}mpWindowImpl->mpFrame->EndSetClipRegion();//long nX;//long nY;//long nWidth;//long nHeight;//sal_uLong nRectCount;//ImplRegionInfo aInfo;//sal_Bool bRegionRect;//nRectCount = mpWindowImpl->maWinRegion.GetRectCount();//mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );//bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );//while ( bRegionRect )//{// mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );// bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );//}//mpWindowImpl->mpFrame->EndSetClipRegion();}elseSetWindowRegionPixel();}elseSetWindowRegionPixel();}else{if(rRegion.IsNull()){if(mpWindowImpl->mbWinRegion){mpWindowImpl->maWinRegion=vcl::Region(true);mpWindowImpl->mbWinRegion=false;ImplSetClipFlag();}}else{mpWindowImpl->maWinRegion=rRegion;mpWindowImpl->mbWinRegion=true;ImplSetClipFlag();}if(IsReallyVisible()){tools::RectangleaRect(Point(mnOutOffX,mnOutOffY),Size(mnOutWidth,mnOutHeight));vcl::RegionaRegion(aRect);ImplInvalidateParentFrameRegion(aRegion);}}}vcl::RegionWindow::GetPaintRegion()const{if(mpWindowImpl->mpPaintRegion){vcl::RegionaRegion=*mpWindowImpl->mpPaintRegion;aRegion.Move(-mnOutOffX,-mnOutOffY);returnPixelToLogic(aRegion);}else{vcl::RegionaPaintRegion(true);returnaPaintRegion;}}voidWindow::Invalidate(InvalidateFlagsnFlags){if(!comphelper::LibreOfficeKit::isActive()&&(!IsDeviceOutputNecessary()||!mnOutWidth||!mnOutHeight))return;ImplInvalidate(nullptr,nFlags);LogicInvalidate(nullptr);}voidWindow::Invalidate(consttools::Rectangle&rRect,InvalidateFlagsnFlags){if(!comphelper::LibreOfficeKit::isActive()&&(!IsDeviceOutputNecessary()||!mnOutWidth||!mnOutHeight))return;OutputDevice*pOutDev=GetOutDev();tools::RectangleaRect=pOutDev->ImplLogicToDevicePixel(rRect);if(!aRect.IsEmpty()){vcl::RegionaRegion(aRect);ImplInvalidate(&aRegion,nFlags);tools::RectangleaLogicRectangle(rRect);LogicInvalidate(&aLogicRectangle);}}voidWindow::Invalidate(constvcl::Region&rRegion,InvalidateFlagsnFlags){if(!comphelper::LibreOfficeKit::isActive()&&(!IsDeviceOutputNecessary()||!mnOutWidth||!mnOutHeight))return;if(rRegion.IsNull()){ImplInvalidate(nullptr,nFlags);LogicInvalidate(nullptr);}else{vcl::RegionaRegion=ImplPixelToDevicePixel(LogicToPixel(rRegion));if(!aRegion.IsEmpty()){ImplInvalidate(&aRegion,nFlags);tools::RectangleaLogicRectangle=rRegion.GetBoundRect();LogicInvalidate(&aLogicRectangle);}}}voidWindow::LogicInvalidate(consttools::Rectangle*pRectangle){if(pRectangle){tools::RectangleaRect=GetOutDev()->ImplLogicToDevicePixel(*pRectangle);PixelInvalidate(&aRect);}elsePixelInvalidate(nullptr);}voidWindow::PixelInvalidate(consttools::Rectangle*pRectangle){if(comphelper::LibreOfficeKit::isDialogPainting()||!comphelper::LibreOfficeKit::isActive())return;if(constvcl::ILibreOfficeKitNotifier*pNotifier=GetLOKNotifier()){// In case we are routing the window, notify the clientstd::vector<vcl::LOKPayloadItem>aPayload;if(pRectangle)aPayload.push_back(std::make_pair(OString("rectangle"),pRectangle->toString()));else{consttools::RectangleaRect(Point(0,0),GetSizePixel());aPayload.push_back(std::make_pair(OString("rectangle"),aRect.toString()));}pNotifier->notifyWindow(GetLOKWindowId(),"invalidate",aPayload);}// Added for dialog items. Pass invalidation to the parent window.elseif(VclPtr<vcl::Window>pParent=GetParentWithLOKNotifier()){consttools::RectangleaRect(Point(GetOutOffXPixel(),GetOutOffYPixel()),GetSizePixel());pParent->PixelInvalidate(&aRect);}}voidWindow::Validate(){if(!comphelper::LibreOfficeKit::isActive()&&(!IsDeviceOutputNecessary()||!mnOutWidth||!mnOutHeight))return;ImplValidate();}boolWindow::HasPaintEvent()const{if(!mpWindowImpl->mbReallyVisible)returnfalse;if(mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame)returntrue;if(mpWindowImpl->mnPaintFlags&ImplPaintFlags::Paint)returntrue;if(!ImplIsOverlapWindow()){constvcl::Window*pTempWindow=this;do{pTempWindow=pTempWindow->ImplGetParent();if(pTempWindow->mpWindowImpl->mnPaintFlags&(ImplPaintFlags::PaintChildren|ImplPaintFlags::PaintAllChildren))returntrue;}while(!pTempWindow->ImplIsOverlapWindow());}returnfalse;}voidWindow::Update(){if(mpWindowImpl->mpBorderWindow){mpWindowImpl->mpBorderWindow->Update();return;}if(!mpWindowImpl->mbReallyVisible)return;boolbFlush=false;if(mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame){PointaPoint(0,0);vcl::RegionaRegion(tools::Rectangle(aPoint,Size(mnOutWidth,mnOutHeight)));ImplInvalidateOverlapFrameRegion(aRegion);if(mpWindowImpl->mbFrame||(mpWindowImpl->mpBorderWindow&&mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame))bFlush=true;}// First we should skip all windows which are Paint-Transparentvcl::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 setpWindow=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 Paintif(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 remainvcl::Window*pUpdateOverlapWindow=ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap;while(pUpdateOverlapWindow){pUpdateOverlapWindow->Update();pUpdateOverlapWindow=pUpdateOverlapWindow->mpWindowImpl->mpNext;}pUpdateWindow->ImplCallPaint(nullptr,pUpdateWindow->mpWindowImpl->mnPaintFlags);pUpdateWindow->LogicInvalidate(nullptr);if(xWindow->IsDisposed())return;bFlush=true;}if(bFlush)Flush();}voidWindow::ImplPaintToDevice(OutputDevice*i_pTargetOutDev,constPoint&i_rPos){// Special drawing when called through LOKit// TODO: Move to its own methodif(comphelper::LibreOfficeKit::isActive()){VclPtrInstance<VirtualDevice>pDevice(*i_pTargetOutDev);SizeaSize(GetOutputSizePixel());pDevice->SetOutputSizePixel(aSize);vcl::FontaCopyFont=GetFont();pDevice->SetFont(aCopyFont);pDevice->SetTextColor(GetTextColor());if(IsLineColor())pDevice->SetLineColor(GetLineColor());elsepDevice->SetLineColor();if(IsFillColor())pDevice->SetFillColor(GetFillColor());elsepDevice->SetFillColor();if(IsTextLineColor())pDevice->SetTextLineColor(GetTextLineColor());elsepDevice->SetTextLineColor();if(IsOverlineColor())pDevice->SetOverlineColor(GetOverlineColor());elsepDevice->SetOverlineColor();if(IsTextFillColor())pDevice->SetTextFillColor(GetTextFillColor());elsepDevice->SetTextFillColor();pDevice->SetTextAlign(GetTextAlign());pDevice->SetRasterOp(GetRasterOp());tools::RectangleaPaintRect;aPaintRect=tools::Rectangle(Point(),GetOutputSizePixel());vcl::RegionaClipRegion(GetClipRegion());pDevice->SetClipRegion();aClipRegion.Intersect(aPaintRect);pDevice->SetClipRegion(aClipRegion);if(!IsPaintTransparent()&&IsBackground()&&!(GetParentClipMode()&ParentClipMode::NoClip))Erase(*pDevice);Paint(*pDevice,tools::Rectangle(Point(),GetOutputSizePixel()));i_pTargetOutDev->DrawOutDev(i_rPos,aSize,Point(),aSize,*pDevice);// get rid of virtual device now so they don't pile up during recursive callspDevice.disposeAndClear();for(vcl::Window*pChild=mpWindowImpl->mpFirstChild;pChild;pChild=pChild->mpWindowImpl->mpNext){if(pChild->mpWindowImpl->mpFrame==mpWindowImpl->mpFrame&&pChild->IsVisible()){longnDeltaX=pChild->mnOutOffX-mnOutOffX;longnDeltaY=pChild->mnOutOffY-mnOutOffY;PointaPos(i_rPos);aPos+=Point(nDeltaX,nDeltaY);pChild->ImplPaintToDevice(i_pTargetOutDev,aPos);}}return;}boolbRVisible=mpWindowImpl->mbReallyVisible;mpWindowImpl->mbReallyVisible=mpWindowImpl->mbVisible;boolbDevOutput=mbDevOutput;mbDevOutput=true;constOutputDevice*pOutDev=GetOutDev();longnOldDPIX=pOutDev->GetDPIX();longnOldDPIY=pOutDev->GetDPIY();mnDPIX=i_pTargetOutDev->GetDPIX();mnDPIY=i_pTargetOutDev->GetDPIY();boolbOutput=IsOutputEnabled();EnableOutput();doublefScaleX=1;doublefScaleY=1;boolbNeedsScaling=false;if(comphelper::LibreOfficeKit::isActive()){if(GetMapMode().GetMapUnit()!=MapUnit::MapPixel&&// Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)// For these preview we don't need to scale even though the unit is not pixel.GetMapMode().GetMapUnit()!=MapUnit::Map100thMM){bNeedsScaling=true;// 1000.0 is used to reduce rounding imprecision (Size uses integers)SizeaLogicSize=PixelToLogic(Size(1000.0,1000.0));fScaleX=aLogicSize.Width()/1000.0;fScaleY=aLogicSize.Height()/1000.0;}}else{// TODO: Above scaling was added for LOK only, would be good to check how it works in other use casesSAL_WARN_IF(GetMapMode().GetMapUnit()!=MapUnit::MapPixel,"vcl.window","MapMode must be PIXEL based");if(GetMapMode().GetMapUnit()!=MapUnit::MapPixel)return;}// preserve graphicsstatePush();vcl::RegionaClipRegion(GetClipRegion());SetClipRegion();GDIMetaFile*pOldMtf=GetConnectMetaFile();GDIMetaFileaMtf;SetConnectMetaFile(&aMtf);// put a push action to metafilePush();// copy graphics state to metafilevcl::FontaCopyFont=GetFont();if(nOldDPIX!=mnDPIX||nOldDPIY!=mnDPIY){aCopyFont.SetFontHeight(aCopyFont.GetFontHeight()*mnDPIY/nOldDPIY);aCopyFont.SetAverageFontWidth(aCopyFont.GetAverageFontWidth()*mnDPIX/nOldDPIX);}SetFont(aCopyFont);SetTextColor(GetTextColor());if(IsLineColor())SetLineColor(GetLineColor());elseSetLineColor();if(IsFillColor())SetFillColor(GetFillColor());elseSetFillColor();if(IsTextLineColor())SetTextLineColor(GetTextLineColor());elseSetTextLineColor();if(IsOverlineColor())SetOverlineColor(GetOverlineColor());elseSetOverlineColor();if(IsTextFillColor())SetTextFillColor(GetTextFillColor());elseSetTextFillColor();SetTextAlign(GetTextAlign());SetRasterOp(GetRasterOp());if(IsRefPoint())SetRefPoint(GetRefPoint());elseSetRefPoint();SetLayoutMode(GetLayoutMode());SetDigitLanguage(GetDigitLanguage());tools::RectangleaPaintRect;if(bNeedsScaling){aPaintRect=tools::Rectangle(Point(0,0),Size(GetOutputSizePixel().Width()*fScaleX,GetOutputSizePixel().Height()*fScaleY));}else{aPaintRect=tools::Rectangle(Point(0,0),GetOutputSizePixel());}aClipRegion.Intersect(aPaintRect);SetClipRegion(aClipRegion);// do the actual paint// backgroundif(!IsPaintTransparent()&&IsBackground()&&!(GetParentClipMode()&ParentClipMode::NoClip)){Erase(*this);if(bNeedsScaling)aMtf.Scale(fScaleX,fScaleY);}// foregroundPaint(*this,aPaintRect);// put a pop action to metafilePop();SetConnectMetaFile(pOldMtf);EnableOutput(bOutput);mpWindowImpl->mbReallyVisible=bRVisible;// paint metafile to VDevVclPtrInstance<VirtualDevice>pMaskedDevice(*i_pTargetOutDev,DeviceFormat::DEFAULT,DeviceFormat::DEFAULT);if(bNeedsScaling)pMaskedDevice->SetMapMode(GetMapMode());pMaskedDevice->SetOutputSizePixel(GetOutputSizePixel());pMaskedDevice->EnableRTL(IsRTLEnabled());aMtf.WindStart();aMtf.Play(pMaskedDevice);BitmapExaBmpEx(pMaskedDevice->GetBitmapEx(Point(0,0),aPaintRect.GetSize()));i_pTargetOutDev->DrawBitmapEx(i_rPos,aBmpEx);// get rid of virtual device now so they don't pile up during recursive callspMaskedDevice.disposeAndClear();for(vcl::Window*pChild=mpWindowImpl->mpFirstChild;pChild;pChild=pChild->mpWindowImpl->mpNext){if(pChild->mpWindowImpl->mpFrame==mpWindowImpl->mpFrame&&pChild->IsVisible()){longnDeltaX=pChild->mnOutOffX-mnOutOffX;if(pOutDev->HasMirroredGraphics())nDeltaX=mnOutWidth-nDeltaX-pChild->mnOutWidth;longnDeltaY=pChild->GetOutOffYPixel()-GetOutOffYPixel();PointaPos(i_rPos);PointaDelta(nDeltaX,nDeltaY);aPos+=aDelta;pChild->ImplPaintToDevice(i_pTargetOutDev,aPos);}}// restore graphics statePop();EnableOutput(bOutput);mpWindowImpl->mbReallyVisible=bRVisible;mbDevOutput=bDevOutput;mnDPIX=nOldDPIX;mnDPIY=nOldDPIY;}voidWindow::PaintToDevice(OutputDevice*pDev,constPoint&rPos,constSize&/*rSize*/){SAL_WARN_IF(pDev->HasMirroredGraphics(),"vcl.window","PaintToDevice to mirroring graphics");SAL_WARN_IF(pDev->IsRTLEnabled(),"vcl.window","PaintToDevice to mirroring device");vcl::Window*pRealParent=nullptr;if(!mpWindowImpl->mbVisible){vcl::Window*pTempParent=ImplGetDefaultWindow();pTempParent->EnableChildTransparentMode();pRealParent=GetParent();SetParent(pTempParent);// trigger correct visibility flags for childrenShow();Hide();}boolbVisible=mpWindowImpl->mbVisible;mpWindowImpl->mbVisible=true;if(mpWindowImpl->mpBorderWindow)mpWindowImpl->mpBorderWindow->ImplPaintToDevice(pDev,rPos);elseImplPaintToDevice(pDev,rPos);mpWindowImpl->mbVisible=bVisible;if(pRealParent)SetParent(pRealParent);}voidWindow::Erase(vcl::RenderContext&rRenderContext){if(!IsDeviceOutputNecessary()||ImplIsRecordLayout())return;boolbNativeOK=false;ControlPartaCtrlPart=ImplGetWindowImpl()->mnNativeBackground;if(aCtrlPart!=ControlPart::NONE&&!IsControlBackground()){tools::RectangleaCtrlRegion(Point(),GetOutputSizePixel());ControlStatenState=ControlState::NONE;if(IsEnabled())nState|=ControlState::ENABLED;bNativeOK=rRenderContext.DrawNativeControl(ControlType::WindowBackground,aCtrlPart,aCtrlRegion,nState,ImplControlValue(),OUString());}if(mbBackground&&!bNativeOK){RasterOpeRasterOp=GetRasterOp();if(eRasterOp!=RasterOp::OverPaint)SetRasterOp(RasterOp::OverPaint);rRenderContext.DrawWallpaper(0,0,mnOutWidth,mnOutHeight,maBackground);if(eRasterOp!=RasterOp::OverPaint)rRenderContext.SetRasterOp(eRasterOp);}if(mpAlphaVDev)mpAlphaVDev->Erase();}voidWindow::ImplScroll(consttools::Rectangle&rRect,longnHorzScroll,longnVertScroll,ScrollFlagsnFlags){if(!IsDeviceOutputNecessary())return;nHorzScroll=ImplLogicWidthToDevicePixel(nHorzScroll);nVertScroll=ImplLogicHeightToDevicePixel(nVertScroll);if(!nHorzScroll&&!nVertScroll)return;if(mpWindowImpl->mpCursor)mpWindowImpl->mpCursor->ImplSuspend();ScrollFlagsnOrgFlags=nFlags;if(!(nFlags&(ScrollFlags::Children|ScrollFlags::NoChildren))){if(GetStyle()&WB_CLIPCHILDREN)nFlags|=ScrollFlags::NoChildren;elsenFlags|=ScrollFlags::Children;}vcl::RegionaInvalidateRegion;boolbScrollChildren(nFlags&ScrollFlags::Children);if(!mpWindowImpl->mpFirstChild)bScrollChildren=false;OutputDevice*pOutDev=GetOutDev();// RTL: check if this window requires special actionboolbReMirror=ImplIsAntiparallel();tools::RectangleaRectMirror(rRect);if(bReMirror){// make sure the invalidate region of this window is// computed in the same coordinate space as the one from the overlap windowspOutDev->ReMirror(aRectMirror);}// adapt paint areasImplMoveAllInvalidateRegions(aRectMirror,nHorzScroll,nVertScroll,bScrollChildren);ImplCalcOverlapRegion(aRectMirror,aInvalidateRegion,!bScrollChildren,false);// 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 nHorzScrollif(!aInvalidateRegion.IsEmpty()){aInvalidateRegion.Move(bReMirror?-nHorzScroll:nHorzScroll,nVertScroll);}tools::RectangleaDestRect(aRectMirror);aDestRect.Move(bReMirror?-nHorzScroll:nHorzScroll,nVertScroll);vcl::RegionaWinInvalidateRegion(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);}aInvalidateRegion.Union(aWinInvalidateRegion);PointaPoint(mnOutOffX,mnOutOffY);vcl::RegionaRegion(tools::Rectangle(aPoint,Size(mnOutWidth,mnOutHeight)));if(nFlags&ScrollFlags::Clip)aRegion.Intersect(rRect);if(mpWindowImpl->mbWinRegion)aRegion.Intersect(ImplPixelToDevicePixel(mpWindowImpl->maWinRegion));aRegion.Exclude(aInvalidateRegion);ImplClipBoundaries(aRegion,false,true);if(!bScrollChildren){if(nOrgFlags&ScrollFlags::NoChildren)ImplClipAllChildren(aRegion);elseImplClipChildren(aRegion);}if(mbClipRegion&&(nFlags&ScrollFlags::UseClipRegion))aRegion.Intersect(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);}pOutDev->SelectClipRegion(aRegion,pGraphics);pGraphics->CopyArea(rRect.Left()+nHorzScroll,rRect.Top()+nVertScroll,rRect.Left(),rRect.Top(),rRect.GetWidth(),rRect.GetHeight(),this);}#endifif(mpWindowImpl->mpWinData){if(mpWindowImpl->mbFocusVisible)ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);if(mpWindowImpl->mbTrackVisible&&(mpWindowImpl->mpWinData->mnTrackFlags&ShowTrackFlags::TrackWindow))InvertTracking(*mpWindowImpl->mpWinData->mpTrackRect,mpWindowImpl->mpWinData->mnTrackFlags);}}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-handlermpWindowImpl->mnPaintFlags|=ImplPaintFlags::CheckRtl;if(!bScrollChildren){if(nOrgFlags&ScrollFlags::NoChildren)ImplClipAllChildren(aInvalidateRegion);elseImplClipChildren(aInvalidateRegion);}ImplInvalidateFrameRegion(&aInvalidateRegion,InvalidateFlags::Children);}if(bScrollChildren){vcl::Window*pWindow=mpWindowImpl->mpFirstChild;while(pWindow){PointaPos=pWindow->GetPosPixel();aPos+=Point(nHorzScroll,nVertScroll);pWindow->SetPosPixel(aPos);pWindow=pWindow->mpWindowImpl->mpNext;}}if(nFlags&ScrollFlags::Update)Update();if(mpWindowImpl->mpCursor)mpWindowImpl->mpCursor->ImplResume();}}/* namespace vcl *//* vim:set shiftwidth=4 softtabstop=4 expandtab: */