sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "ScreenRedraw.h" sl@0: sl@0: #include sl@0: sl@0: #include "debugbar.h" sl@0: #include "inifile.h" sl@0: #include "screen.h" sl@0: #include "pointer.h" sl@0: #include "rootwin.h" sl@0: #include "walkwindowtree.h" sl@0: #include "wstop.h" sl@0: #include "WsMemMgr.h" sl@0: #include "renderstagemanager.h" sl@0: #include "graphics/WsRenderStageFactory.h" sl@0: #include "graphics/WsRenderStage.h" sl@0: #include "graphics/wsgraphicscontext.h" sl@0: #include "EVENT.H" sl@0: sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: #include sl@0: #include "../debuglog/debuglog.h" sl@0: #endif sl@0: sl@0: GLREF_D CDebugLogBase *wsDebugLog; sl@0: sl@0: #ifdef USE_DEBUG_REGIONS sl@0: # define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg) sl@0: # define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect) sl@0: #else sl@0: # define DEBUG_REGION(col,fill,reg) sl@0: # define DEBUG_RECT(col,fill,rect) sl@0: #endif sl@0: sl@0: #ifdef _DEBUG sl@0: # define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}} sl@0: # define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}} sl@0: #else sl@0: # define LOG_SCREEN_REDRAW_START sl@0: # define LOG_SCREEN_REDRAW_END sl@0: #endif sl@0: sl@0: sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: # ifdef __WINS__ sl@0: _LIT(KDefaultFrameCaptureLocation, "c:\\"); sl@0: # else sl@0: _LIT(KDefaultFrameCaptureLocation, "e:\\"); sl@0: # endif sl@0: #endif //USE_DEBUG_FRAME_CAPTURE sl@0: sl@0: CScreenRedraw::TTimedRect::TTimedRect(TAnimType aType, const TRect& aRect, const TTime& aTime, CWsWindow* aWindow) sl@0: : iType(aType), iRect(aRect), iTime(aTime), iWindow(aWindow) sl@0: { sl@0: } sl@0: sl@0: TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther) sl@0: { sl@0: if(aOne.iTime < aOther.iTime) sl@0: return -1; sl@0: else if(aOne.iTime > aOther.iTime) sl@0: return 1; sl@0: else sl@0: return 0; sl@0: } sl@0: sl@0: CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen) sl@0: { sl@0: CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen) sl@0: { sl@0: } sl@0: sl@0: CScreenRedraw::~CScreenRedraw() sl@0: { sl@0: CRenderStageManager::Release(iRenderStages); sl@0: iRenderStages = NULL; sl@0: iTimedDrawRect.Close(); sl@0: iInvalid.Reset(); sl@0: iTopElement.Reset(); sl@0: iQuickFadeList.Reset(); sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: delete iDebugBitmap; sl@0: delete iDebugBitmapDevice; sl@0: delete iDebugBitmapGc; sl@0: #endif //USE_DEBUG_FRAME_CAPTURE sl@0: } sl@0: sl@0: void CScreenRedraw::ConstructL() sl@0: { sl@0: sl@0: LEAVE_LOG_INSTALL_C; sl@0: sl@0: iRenderStages = CRenderStageManager::ConnectL( sl@0: iScreen.ScreenNumber(), sl@0: static_cast(&iScreen), sl@0: this sl@0: ); sl@0: sl@0: LEAVE_LOG_UNINSTALL_C; sl@0: sl@0: WS_ASSERT_ALWAYS(iRenderStages, EWsPanicNoRenderStagePipeline); sl@0: iRenderStageTextCursor = static_cast(iRenderStages->ResolveObjectInterface(KMWsTextCursor)); sl@0: WS_ASSERT_ALWAYS(iRenderStageTextCursor, EWsPanicTextCursorInterfaceMissing); sl@0: sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: _LIT(KWSERVIniFileVarFrameCapture,"FRAMECAPTURE"); sl@0: iFrameCapture = WsIniFile->FindVar(KWSERVIniFileVarFrameCapture); sl@0: sl@0: // Location to save captured images sl@0: if (!WsIniFile->FindVar(KWSERVIniFileVarFrameCapture, iFrameCaptureLocation) || iFrameCaptureLocation.Length() == 0) sl@0: { sl@0: iFrameCaptureLocation.Set(KDefaultFrameCaptureLocation); sl@0: } sl@0: #endif //USE_DEBUG_FRAME_CAPTURE sl@0: } sl@0: sl@0: MWsTextCursor* CScreenRedraw::RenderStageTextCursor() const sl@0: { sl@0: return iRenderStageTextCursor; sl@0: } sl@0: sl@0: const TTime& CScreenRedraw::Now() const sl@0: { sl@0: if(!iAnimating) sl@0: { sl@0: iNow.UniversalTime(); sl@0: } sl@0: return iNow; sl@0: } sl@0: sl@0: void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow) sl@0: { sl@0: iRenderScheduled = ETrue; sl@0: TTime then(Now() + aFromNow); sl@0: if ((!iScheduled) || then < iNext) sl@0: iNext = then; sl@0: iScheduled = ETrue; sl@0: CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext); sl@0: } sl@0: sl@0: void CScreenRedraw::ScheduleRedraw() sl@0: { sl@0: iNext = Now(); sl@0: iScheduled = ETrue; sl@0: sl@0: // The other scheduler also removes future animations which this one encompasses. sl@0: // We choose not to do the region calculations needed to achieve that here. sl@0: CWindowServer* server = CWsTop::WindowServer(); sl@0: ASSERT(server); sl@0: MWsAnimationScheduler* sched = server->AnimationScheduler(); sl@0: if(sched) sl@0: sched->ScheduleRedraw(iScreen,iNext); sl@0: else sl@0: RDebug::Printf("CWsTop::WindowServer()->RedrawScheduler() is NULL!!!"); sl@0: } sl@0: sl@0: /** sl@0: @param aRect in screen coordinates sl@0: */ sl@0: void CScreenRedraw::ScheduleAnimation(TAnimType aType, const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/, CWsWindow* aWindow) sl@0: { sl@0: TRect scheduledRect(aRect); sl@0: TRect test(aRect); sl@0: // In changetracking mode, animation is either scheduled via a window dirty region (aWindow non-NULL) sl@0: // or via a sprite manager dirty region (aWindow NULL) if scheduling a floating sprite sl@0: if (iScreen.ChangeTracking()) sl@0: { sl@0: if (aWindow) sl@0: { sl@0: // scheduling a window dirty rect for a window/anim/sprite sl@0: test.Intersection(aWindow->Abs()); sl@0: scheduledRect.Move(-aWindow->Origin()); // convert to window coordinates sl@0: } sl@0: // else, // scheduling a sprite manager dirty rect for a floating sprite sl@0: } sl@0: else sl@0: { sl@0: // scheduling a screen dirty rect sl@0: test.Intersection(iScreen.DrawableArea()); sl@0: aWindow = NULL; // ensure all future timed draw screen rects are checked below sl@0: } sl@0: if(!test.IsEmpty()) sl@0: { sl@0: const TTime then(Now() + aFromNow); sl@0: TTimedRect tRect(aType, scheduledRect, then, aWindow); sl@0: sl@0: const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare); sl@0: if (KErrNone == error) sl@0: { sl@0: if (iScheduled) sl@0: { sl@0: if (then < iNext) sl@0: { sl@0: iNext = then; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iNext = then; sl@0: iScheduled = ETrue; sl@0: } sl@0: // remove further futures that are completely contained sl@0: TInt count = iTimedDrawRect.Count(); sl@0: for(TInt i=0; i then.Int64()) sl@0: { sl@0: TRect rect(scheduledRect); sl@0: rect.BoundingRect(future.iRect); sl@0: if(rect == scheduledRect) // future is completely contained within scheduledRect sl@0: { sl@0: iTimedDrawRect.Remove(i); sl@0: count--; sl@0: i--; sl@0: } sl@0: } sl@0: } sl@0: CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext); sl@0: sl@0: // Blue rectangles for scheduled animations sl@0: DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect); sl@0: } sl@0: } sl@0: } sl@0: sl@0: TBool CScreenRedraw::IsScheduled(TAnimType aType, const TRect& aRect, CWsWindow* aWindow) const sl@0: { sl@0: TRect rect(aRect); sl@0: if(aWindow) sl@0: { sl@0: rect.Move(-aWindow->Origin()); //convert to window coordinates sl@0: } sl@0: sl@0: const TInt count(iTimedDrawRect.Count()); sl@0: for(TInt i=0; iAnimationScheduler()->DoRedrawNow(iScreen); sl@0: } sl@0: sl@0: #ifdef USE_DEBUG_REGIONS sl@0: void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect) sl@0: { sl@0: if (aRect) sl@0: { sl@0: CFbsBitGc * gc = iScreen.GetBitGc(); sl@0: gc->SetPenColor(aColor); sl@0: gc->SetPenStyle(CGraphicsContext::ESolidPen); sl@0: gc->SetPenSize(TSize(2,2)); sl@0: gc->SetBrushColor(aFill); sl@0: gc->SetBrushStyle(CGraphicsContext::ESolidBrush); sl@0: TRect smaller = *aRect; sl@0: smaller.iBr.iX -= 1; sl@0: smaller.iBr.iY -= 1; sl@0: gc->DrawRect(smaller); sl@0: iScreen.Update(); sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion) sl@0: { sl@0: if (aRegion) sl@0: { sl@0: CFbsBitGc * gc = iScreen.GetBitGc(); sl@0: gc->SetPenColor(aColor); sl@0: gc->SetPenStyle(CGraphicsContext::ESolidPen); sl@0: gc->SetPenSize(TSize(2,2)); sl@0: gc->SetBrushColor(aFill); sl@0: gc->SetBrushStyle(CGraphicsContext::ESolidBrush); sl@0: for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect) sl@0: { sl@0: TRect smaller = *rect; sl@0: smaller.iBr.iX -= 1; sl@0: smaller.iBr.iY -= 1; sl@0: gc->DrawRect(smaller); sl@0: } sl@0: iScreen.Update(); sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: void CScreenRedraw::OnAnimation(TRequestStatus* aFinished) sl@0: { sl@0: LOG_SCREEN_REDRAW_START sl@0: WS_ASSERT_ALWAYS(!iAnimating,EWsPanicAnimationAlreadyAnimating); sl@0: WS_ASSERT_ALWAYS(iScheduled,EWsPanicAnimationNotScheduled); sl@0: iAnimating = ETrue; sl@0: iScheduled = EFalse; sl@0: sl@0: const TBool changeTracking = iScreen.ChangeTracking(); sl@0: sl@0: const TRegionFix<1> fallbackRegion(iScreen.RootWindow()->Abs()); sl@0: sl@0: CWsActiveScheduler::Static()->PrepareDraw(); sl@0: sl@0: // Calculate any updates required by region changes: sl@0: RegionUpdate(); sl@0: sl@0: // Use the timed rectangles to mark screen, window or floating sprite as dirty sl@0: RWsRegionBuf<10> floatingSpriteDirtyRegion; sl@0: const TBool futureAnimationRequired = ScheduleTimedRects(floatingSpriteDirtyRegion); sl@0: if (floatingSpriteDirtyRegion.CheckError()) sl@0: { sl@0: floatingSpriteDirtyRegion.Reset(); sl@0: floatingSpriteDirtyRegion.Copy(fallbackRegion); sl@0: } sl@0: sl@0: TWalkWindowTreeSchedule* scheduler = NULL; sl@0: TWalkWindowListSchedule windowScheduler(iScheduledWindowList, iInvalid); //ChangeTracking sl@0: if (!changeTracking) sl@0: { sl@0: // Animating rectangles could cause iInvalid to overlap iTopElement, in which case iTopElement won't work. sl@0: iTopElement.SubRegion(iInvalid); sl@0: iTopElement.Intersect(iScreen.RootWindow()->WindowArea()); sl@0: iTopElement.Tidy(); sl@0: // Anything in the top element is implicitly invalid sl@0: iInvalid.Union(iTopElement); sl@0: iInvalid.Intersect(iScreen.RootWindow()->WindowArea()); sl@0: iInvalid.Tidy(); sl@0: sl@0: if(iInvalid.CheckError()) sl@0: { sl@0: iTopElement.Reset(); sl@0: iInvalid.Reset(); sl@0: iInvalid.Copy(fallbackRegion); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // In ChangeTracking mode, iInvalid is only used to tell the render stage sl@0: // which part of the screen needs updating. sl@0: iInvalid.Reset(); sl@0: iInvalid.Copy(floatingSpriteDirtyRegion); sl@0: scheduler = &windowScheduler; sl@0: windowScheduler.WalkWindowList(); sl@0: CWsTop::TriggerRedraws(iScreen.RootWindow()); //In case WalkWindowList did queue a request for the client to provide draw commands sl@0: iInvalid.Tidy(); sl@0: if(iInvalid.CheckError()) sl@0: { sl@0: iInvalid.Reset(); sl@0: iInvalid.Copy(fallbackRegion); sl@0: } sl@0: } sl@0: sl@0: // At this point, if the DEBUG_REGION is being used: sl@0: // Red represents invalid regions that need to be redrawn completely. sl@0: // Yellow represents regions that only need the top window to be drawn. sl@0: // Blue represents regions which are being animated server side. sl@0: if (iRenderScheduled || !iInvalid.IsEmpty() || iQuickFadeList.Count() > 0) sl@0: { sl@0: iRenderScheduled = EFalse; sl@0: sl@0: TWalkWindowTreeScheduleRegions regionScheduler(iInvalid, iTopElement); //!ChangeTeacking sl@0: TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap());//!ChangeTeacking sl@0: sl@0: RWsRegionBuf<20> animationRegion; sl@0: sl@0: if (!changeTracking) sl@0: { sl@0: animationRegion.Copy(iInvalid); sl@0: AddQuickFadeableRegions(animationRegion); sl@0: if (animationRegion.CheckError()) sl@0: { sl@0: animationRegion.Reset(); sl@0: animationRegion.Copy(fallbackRegion); sl@0: } sl@0: iAnimationRegion = &animationRegion; //iAnimationRegion must be reset to NULL before the call stack unwinds. sl@0: sl@0: scheduler = ®ionScheduler; sl@0: iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren); sl@0: if (!regionScheduler.ScheduledRegionsOk()) sl@0: { sl@0: // our region calculations for what to draw failed at some point. sl@0: // From this point on we MUST NOT rely on allocating memory sl@0: scheduler = &fallbackScheduler; sl@0: iScreen.FallbackMap()->Prepare(); sl@0: iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren); sl@0: iAnimationRegion = iScreen.FallbackMap()->Region(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iAnimationRegion = &iInvalid; sl@0: } sl@0: sl@0: CWsActiveScheduler::Static()->StartDraw(); sl@0: CWsMemoryManager::Static()->EnableReserve(); sl@0: sl@0: // Redraw debug regions more brightly than before: sl@0: DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),iAnimationRegion); sl@0: DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopElement); sl@0: sl@0: // Pipe the drawing into the first render stage: sl@0: iRenderStages->Begin(iAnimationRegion); sl@0: sl@0: RWsRegionBuf<10> accumulatedDrawing; sl@0: sl@0: MWsGraphicsContext * stageGc = static_cast(iRenderStages->ResolveObjectInterface(KMWsGraphicsContext)); sl@0: for (CWsWindow * win = scheduler->HeadWindow(); (win!=NULL); win = win->NextScheduled()) sl@0: { sl@0: if(!changeTracking) sl@0: accumulatedDrawing.Union(scheduler->WindowRegion(*win)); sl@0: sl@0: Render(*win, *stageGc, *scheduler); sl@0: } sl@0: sl@0: if(!changeTracking && !accumulatedDrawing.CheckError()) sl@0: { sl@0: //Fade any region of the screen scheduled for fading which has not been redrawn, sl@0: DoQuickFade(stageGc, accumulatedDrawing); sl@0: } sl@0: accumulatedDrawing.Reset(); sl@0: sl@0: //We limit floating sprite drawing to regions already touched sl@0: iScreen.SpriteManager()->DrawFloatingSprites(stageGc, iScreen.ChangeTracking() ? floatingSpriteDirtyRegion : *iAnimationRegion); sl@0: sl@0: iRenderStages->End(aFinished); sl@0: stageGc = NULL; //we're not allowed to draw outside Begin()/End() sl@0: sl@0: #if defined(__WINS__) && defined(_DEBUG) sl@0: MWsDebugBar * debugBar = static_cast(iRenderStages->ResolveObjectInterface(KMWsDebugBar)); sl@0: if (debugBar) //optional for the licensees sl@0: { sl@0: if (CDebugBar* dbg = iScreen.DebugBar()) sl@0: { sl@0: RArray debugText; sl@0: dbg->DebugBarInfo(debugText); sl@0: debugBar->DrawDebugBar(debugText.Array()); sl@0: debugText.Close(); sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: iScheduledWindowList = NULL; sl@0: CWsMemoryManager::Static()->DisableReserve(); sl@0: sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: if (iFrameCapture) sl@0: { sl@0: CaptureFrame(iAnimationRegion); sl@0: } sl@0: #endif sl@0: sl@0: // DEBUG_REGION does not work with render stages. sl@0: // These comments refer to what used to happen. sl@0: sl@0: // At this point, if the DEBUG_REGION is being used, there should usually be only green regions sl@0: // displayed. If we see red or yellow, then something didn't get redrawn that should have been. sl@0: // If we see purple then a window has disobeyed the const setting on the region to draw. sl@0: // Red or yellow is valid - a window can decide it isn't ready to draw yet - purple is very bad. sl@0: sl@0: //iScreen.Update(); sl@0: sl@0: // At this point, if the DEBUG_REGION is being used, there should be no regions visible sl@0: // of any colour. If we see green, then it means an area of the screen was drawn to which sl@0: // wasn't invalid, or the screen update call failed. The former is more likely. sl@0: // If we still see red or yellow it is a region that is not yet ready to draw. sl@0: sl@0: const TRect* rect = iAnimationRegion->RectangleList(); sl@0: TInt pixels = 0; sl@0: for(TInt r = iAnimationRegion->Count(); r>0; r--) sl@0: { sl@0: pixels += (rect->Width()*rect->Height()); sl@0: rect++; sl@0: } sl@0: CWsActiveScheduler::Static()->StopDraw(pixels); sl@0: sl@0: TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion); sl@0: sl@0: iAnimationRegion = NULL; //iAnimationRegion must be reset to NULL before the call stack unwinds. sl@0: iInvalid.Reset(); sl@0: animationRegion.Reset(); sl@0: } sl@0: else sl@0: { sl@0: // There was nothing to compose. Signal that composition is complete. sl@0: if (aFinished) sl@0: { sl@0: *aFinished = KRequestPending; sl@0: User::RequestComplete(aFinished, KErrNone); sl@0: } sl@0: sl@0: CWsActiveScheduler::Static()->CancelPrepare(); sl@0: } sl@0: sl@0: floatingSpriteDirtyRegion.Reset(); sl@0: iInvalid.Reset(); sl@0: iTopElement.Reset(); sl@0: iAnimating = EFalse; sl@0: sl@0: if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled) sl@0: { sl@0: // If this flag is set then it means there were already some animations scheduled when we ran, sl@0: // but they themselves didn't run. We need to make sure we have _something_ scheduled. sl@0: CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime); sl@0: iScheduled = ETrue; sl@0: } sl@0: sl@0: if(iObserver) sl@0: { sl@0: iObserver->ScreenUpdated(iScreen.ScreenNumber()); sl@0: iObserver=NULL; //once signalled we are never going to call it again sl@0: } sl@0: LOG_SCREEN_REDRAW_END sl@0: } sl@0: sl@0: void CScreenRedraw::AddQuickFadeableRegions(TRegion& aRegion) sl@0: { sl@0: if (iQuickFadeList.Count() > 0) sl@0: { sl@0: for (TInt idx = iQuickFadeList.Count() - 1; idx >= 0; idx --) sl@0: { sl@0: CWsWindow* win = iQuickFadeList[ idx ]; sl@0: sl@0: if ( !win->IsDSAHost() ) sl@0: { sl@0: aRegion.Union(win->QuickFadeRegion() ); sl@0: } sl@0: } sl@0: aRegion.Tidy(); sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::DoQuickFade(MWsGraphicsContext* aGc, TRegion& aAccumulatedDrawing) sl@0: { sl@0: if ( iQuickFadeList.Count() > 0 ) sl@0: { sl@0: for ( TInt idx = iQuickFadeList.Count() - 1; idx >= 0 ; idx -- ) sl@0: { sl@0: sl@0: CWsWindow* win = iQuickFadeList[ idx ]; sl@0: sl@0: if ( !win->IsDSAHost() ) sl@0: { sl@0: STACK_REGION winFadeRgn; sl@0: winFadeRgn.Copy( win->QuickFadeRegion() ); sl@0: winFadeRgn.SubRegion( aAccumulatedDrawing ); sl@0: winFadeRgn.Tidy(); sl@0: if ( !winFadeRgn.IsEmpty() && !winFadeRgn.CheckError() ) sl@0: { // now fade any region that has not been redrawn (via win->Render()) sl@0: win->Fade( aGc, winFadeRgn ); sl@0: aAccumulatedDrawing.Union( winFadeRgn ); sl@0: } sl@0: winFadeRgn.Close(); sl@0: } sl@0: } sl@0: sl@0: iQuickFadeList.Reset(); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function will iterate the timed rectangles and find any animation or sprite sl@0: that are due to be scheduled for render now. Then schedule them and remove them sl@0: from iTimedDrawRect. sl@0: @return ETrue if iTimedDrawRect still contains future animations sl@0: */ sl@0: TBool CScreenRedraw::ScheduleTimedRects(TRegion& aScheduledFloatingSpriteRegion) sl@0: { sl@0: iNow.UniversalTime(); sl@0: TInt count(iTimedDrawRect.Count()); sl@0: TBool futureAnimationRequired = EFalse; sl@0: while (0 < count) sl@0: { sl@0: if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64()) sl@0: { sl@0: if (iScreen.ChangeTracking()) sl@0: { sl@0: switch(iTimedDrawRect[0].iType) sl@0: { sl@0: case ECrpAnim: sl@0: { sl@0: CWsWindow* win = iTimedDrawRect[0].iWindow; sl@0: WS_ASSERT_DEBUG(win,EWsPanicWindowNull); sl@0: if(!win->IsTrackingVisibleRegion() || (win->IsTrackingVisibleRegion() && !win->VisibleRegion().IsEmpty())) sl@0: { sl@0: TRegionFix<1> region; sl@0: region.AddRect(iTimedDrawRect[0].iRect); sl@0: win->AddDirtyWindowRegion(region); sl@0: ScheduleWindow(win); sl@0: } sl@0: break; sl@0: } sl@0: case EWindowAnim: sl@0: case ESpriteAnim: sl@0: case ETextCursor: sl@0: case EWindowSprite: sl@0: { sl@0: CWsWindow* win = iTimedDrawRect[0].iWindow; sl@0: WS_ASSERT_DEBUG(win,EWsPanicWindowNull); sl@0: if(!win->IsTrackingVisibleRegion() || (win->IsTrackingVisibleRegion() && !win->VisibleRegion().IsEmpty())) sl@0: { sl@0: TRegionFix<1> region; sl@0: region.AddRect(iTimedDrawRect[0].iRect); sl@0: win->AddDirtySpriteRegion(region); sl@0: ScheduleWindow(win); sl@0: } sl@0: break; sl@0: } sl@0: case EFloatingSprite: sl@0: case EFloatingSpriteAnim: sl@0: { sl@0: aScheduledFloatingSpriteRegion.AddRect(iTimedDrawRect[0].iRect); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: TRect screenRect(iTimedDrawRect[0].iRect); sl@0: if(iTimedDrawRect[0].iWindow) sl@0: { sl@0: screenRect.Move(iTimedDrawRect[0].iWindow->Origin()); // convert to screen coordinates sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // schedule a screen dirty rect sl@0: iInvalid.AddRect(iTimedDrawRect[0].iRect); sl@0: } sl@0: iTimedDrawRect.Remove(0); sl@0: count--; sl@0: } sl@0: else sl@0: { sl@0: futureAnimationRequired = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: return futureAnimationRequired; sl@0: } sl@0: sl@0: void CScreenRedraw::Render(CWsWindow& aWin, MWsGraphicsContext& aGc, const TWalkWindowTreeSchedule& aScheduler) sl@0: { sl@0: const TRegion* windowRegion = &(aScheduler.WindowRegion(aWin)); sl@0: const TRegion* spriteRegion = &(aScheduler.SpriteRegion(aWin)); sl@0: sl@0: if(windowRegion->IsEmpty() && spriteRegion->IsEmpty()) sl@0: return; //Don't call CWsWindow::Render if there is nothing that can be rendered sl@0: sl@0: //Make sure we don't try to draw outside screen sl@0: STACK_REGION clippedWindowRegion; sl@0: if(!windowRegion->IsContainedBy(iScreen.RootWindow()->Abs())) sl@0: { sl@0: TRegionFix<1> screen(iScreen.RootWindow()->Abs()); sl@0: clippedWindowRegion.Intersection(*windowRegion, screen); sl@0: windowRegion = &clippedWindowRegion; sl@0: } sl@0: STACK_REGION clippedSpriteRegion; sl@0: if(!spriteRegion->IsContainedBy(iScreen.RootWindow()->Abs())) sl@0: { sl@0: TRegionFix<1> screen(iScreen.RootWindow()->Abs()); sl@0: clippedSpriteRegion.Intersection(*spriteRegion, screen); sl@0: spriteRegion = &clippedSpriteRegion; sl@0: } sl@0: sl@0: if(!windowRegion->CheckError() && !spriteRegion->CheckError()) sl@0: { sl@0: // Purple regions are about to be drawn sl@0: DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), windowRegion); sl@0: DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), spriteRegion); sl@0: sl@0: aWin.Render(aGc, *windowRegion, *spriteRegion); //When not in ChangeTracking mode, both windowRegion and spriteRegion points to the same region sl@0: aWin.ClearScheduledRegion(); sl@0: aWin.ClearScheduledSpriteRegion(); sl@0: sl@0: // Green regions have been drawn sl@0: DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), windowRegion); sl@0: DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), spriteRegion); sl@0: } sl@0: else sl@0: { sl@0: OomRender(aWin, aGc, aScheduler); sl@0: } sl@0: sl@0: clippedSpriteRegion.Close(); sl@0: clippedWindowRegion.Close(); sl@0: } sl@0: sl@0: void CScreenRedraw::OomRender(CWsWindow& aWin, MWsGraphicsContext& aGc, const TWalkWindowTreeSchedule& aScheduler) sl@0: { sl@0: const TRegion* windowRegion = &(aScheduler.WindowRegion(aWin)); sl@0: const TRegion* spriteRegion = &(aScheduler.SpriteRegion(aWin)); sl@0: sl@0: WS_ASSERT_DEBUG(!(windowRegion->IsEmpty() && spriteRegion->IsEmpty()), EWsPanicRegionNull); sl@0: sl@0: TRect validWindow(aWin.Abs()); sl@0: validWindow.Intersection(iScreen.RootWindow()->Abs()); sl@0: sl@0: TRegionFix<1> fallbackRegion(validWindow); sl@0: sl@0: if(windowRegion->CheckError()) sl@0: windowRegion = &fallbackRegion; sl@0: if(spriteRegion->CheckError()) sl@0: spriteRegion = &fallbackRegion; sl@0: sl@0: // Purple regions are about to be drawn sl@0: DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), windowRegion); sl@0: DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), spriteRegion); sl@0: sl@0: aWin.Render(aGc, *windowRegion, *spriteRegion); //When not in ChangeTracking mode, both windowRegion and spriteRegion points to the same region sl@0: aWin.ClearScheduledRegion(); sl@0: aWin.ClearScheduledSpriteRegion(); sl@0: sl@0: // Green regions have been drawn sl@0: DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), windowRegion); sl@0: DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), spriteRegion); sl@0: } sl@0: sl@0: // sl@0: void CScreenRedraw::DiscardAllSchedules() sl@0: { sl@0: ASSERT(!iAnimating); sl@0: sl@0: iTimedDrawRect.Reset(); sl@0: iInvalid.Reset(); sl@0: } sl@0: sl@0: /** sl@0: Indicates that a window has moved or changed ordinal position so that the visible regions sl@0: of all windows needs to be recalculated sl@0: */ sl@0: void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty) sl@0: { sl@0: if (iScreen.ChangeTracking() && iScreen.WindowVisibilityNotifier()) sl@0: return; sl@0: sl@0: iRegionUpdateScheduled = ETrue; sl@0: ScheduleRedraw(); sl@0: if(!iScreen.ChangeTracking() && aDefinitelyDirty) sl@0: { sl@0: iInvalid.Union(*aDefinitelyDirty); sl@0: // Cyan regions for invalidations caused by this: sl@0: DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Only used in CHANGETRACKING mode. sl@0: Windows are scheduled to: sl@0: - if required, ask client to validate (from lower loop) sl@0: - render the dirty window region sl@0: */ sl@0: void CScreenRedraw::ScheduleWindow(CWsWindow* aWindow) sl@0: { sl@0: // Add a scheduled window to the linked list, ignoring duplicates sl@0: CWsWindow* win = iScheduledWindowList; sl@0: while (win && win != aWindow) sl@0: { sl@0: win = win->NextScheduled(); sl@0: } sl@0: if (!win) sl@0: { sl@0: aWindow->SetNextScheduled(iScheduledWindowList); sl@0: iScheduledWindowList = aWindow; sl@0: } sl@0: ScheduleRedraw(); sl@0: } sl@0: sl@0: void CScreenRedraw::RemoveFromScheduledList(CWsWindow* aWindow) sl@0: { sl@0: // Search for the window sl@0: CWsWindow* win = iScheduledWindowList; sl@0: CWsWindow* previous = NULL; sl@0: while (win && win != aWindow) sl@0: { sl@0: previous = win; sl@0: win = win->NextScheduled(); sl@0: } sl@0: if (win) sl@0: { sl@0: // Found it, remove from list sl@0: if (win == iScheduledWindowList) sl@0: { sl@0: iScheduledWindowList = win->NextScheduled(); sl@0: } sl@0: else sl@0: { sl@0: previous->SetNextScheduled(win->NextScheduled()); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::RemoveFromTimedDrawList(CWsWindow* aWindow) sl@0: { sl@0: if(aWindow) sl@0: { sl@0: TInt count(iTimedDrawRect.Count()); sl@0: TInt index = 0; sl@0: while(index < count) sl@0: { sl@0: if (iTimedDrawRect[index].iWindow == aWindow) sl@0: { sl@0: iTimedDrawRect.Remove(index); sl@0: --count; sl@0: } sl@0: else sl@0: { sl@0: ++index; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Recalculates visible regions and schedules redraws or queues redraw events in response to sl@0: any changes sl@0: */ sl@0: void CScreenRedraw::RegionUpdate() sl@0: { sl@0: TBool somethingScheduled = EFalse; sl@0: sl@0: if (iVisibilityUpdateScheduled) sl@0: { sl@0: iVisibilityUpdateScheduled = EFalse; sl@0: somethingScheduled = ETrue; sl@0: MWsWindowVisibilityNotifier* const notifier = iScreen.WindowVisibilityNotifier(); sl@0: if(notifier) sl@0: { sl@0: notifier->SendVisibilityChanges(); // Should result in one callback to SetWindowVisibility for each window subscribing for visible region updates sl@0: } sl@0: } sl@0: sl@0: if (iRegionUpdateScheduled) sl@0: { sl@0: iRegionUpdateScheduled = EFalse; sl@0: somethingScheduled = ETrue; sl@0: TWalkWindowTreeUpdateRegions updater(iScreen); sl@0: updater.Walk(); sl@0: sl@0: for ( TInt idx = iQuickFadeList.Count() - 1; idx >= 0; idx-- ) sl@0: { sl@0: CWsWindow* win = iQuickFadeList[ idx ]; sl@0: const TRegion& quickFadeRegion = win->QuickFadeRegion(); sl@0: //If QuickFadeRegion().IsEmpty() we should remove the window from iQuickFadeList. sl@0: //And if this window has not been drawn to the screen, then it is not possible to quick fade it. sl@0: if (quickFadeRegion.IsEmpty() || !win->HasBeenDrawnToScreen()) sl@0: { sl@0: iQuickFadeList.Remove( idx ); sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (somethingScheduled) sl@0: { sl@0: TWsPointer::ReLogPointersCurrentWindows(); sl@0: CWsTop::TriggerRedraws(iScreen.RootWindow()); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: To be called by MWsWindowVisibilityNotifier (when running in ChangeTracking mode) sl@0: in response to MWsWindowVisibilityNotifier::SendVisibilityChanges() sl@0: */ sl@0: void CScreenRedraw::SetWindowVisibility(const MWsWindow& aWindow, const TRegion& aVisibleRegion) sl@0: { sl@0: CWsWindow& win = static_cast(const_cast(aWindow)); sl@0: WS_ASSERT_DEBUG(win.IsTrackingVisibleRegion(), EWsPanicVisibleRegionTracking); sl@0: WS_ASSERT_DEBUG(!aVisibleRegion.CheckError(), EWsPanicRegion); sl@0: sl@0: if(aVisibleRegion.IsEmpty() && !win.VisibleRegion().IsEmpty()) sl@0: { sl@0: win.ClearVisibleRegion(); sl@0: } sl@0: else if(!aVisibleRegion.IsEmpty() && !aVisibleRegion.CheckError()) sl@0: { sl@0: // Assert that aVisibleRegion is contained by aWin sl@0: TRect bounds = win.AbsRect(); sl@0: bounds.Resize(1,1); sl@0: WS_ASSERT_DEBUG(bounds.Contains(aVisibleRegion.BoundingRect().iTl), EWsPanicRegion); sl@0: WS_ASSERT_DEBUG(bounds.Contains(aVisibleRegion.BoundingRect().iBr), EWsPanicRegion); sl@0: win.SetVisibleRegion(aVisibleRegion, NULL); sl@0: } sl@0: else if(aVisibleRegion.CheckError()) sl@0: { sl@0: const TRegionFix<1> fallback(win.Abs()); sl@0: win.SetVisibleRegion(fallback, NULL); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: To be called by MWsWindowVisibilityNotifier (when running in ChangeTracking mode) when the sl@0: iVisibleRegion is changed for a window that subscribes for this information. The visible region sl@0: of the window has not been updated yet at the time of this function call, but the new metrics will be retrieved sl@0: from MWsWindowVisibilityNotifier (through a call to MWsWindowVisibilityObserver::SetWindowVisibility()) sl@0: and set to each window next time OnAnimation is called. sl@0: */ sl@0: void CScreenRedraw::VisibilityChanged() sl@0: { sl@0: iVisibilityUpdateScheduled = ETrue; sl@0: ScheduleRedraw(); sl@0: } sl@0: sl@0: void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver) sl@0: { sl@0: iObserver = aObserver; sl@0: } sl@0: sl@0: /** sl@0: Returns ETrue if an update or animation is scheduled. sl@0: sl@0: Note: Now that WSERV surface and composition updates are asynchronous (with NGA) sl@0: it is possible for this method to return EFalse, even if the last update has sl@0: not been completed by the rendering pipeline. This is dependant on the configuration sl@0: and implementation of render stages that make up the rendering pipeline. sl@0: sl@0: If in doubt, it is best to call CScreenRedraw::DoRedrawNow(), which will not return sl@0: untill all updates have been signalled as being complete (note that if signalling sl@0: is not used, then even this cannot guarantee completion). sl@0: */ sl@0: TBool CScreenRedraw::IsUpdatePending() sl@0: { sl@0: if(iScheduled || iAnimating) sl@0: return ETrue; sl@0: else sl@0: return EFalse; sl@0: } sl@0: sl@0: /** sl@0: Overidding MWsObjectProvider sl@0: */ sl@0: TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId) sl@0: { sl@0: TAny* interface = NULL; sl@0: sl@0: switch (aTypeId) sl@0: { sl@0: case KWsScreenRedraw: sl@0: interface = static_cast(this); sl@0: break; sl@0: } sl@0: sl@0: if (!interface) sl@0: { sl@0: interface = iRenderStages->ResolveObjectInterface(aTypeId); sl@0: } sl@0: sl@0: return interface; sl@0: } sl@0: sl@0: const TRegion * CScreenRedraw::AnimationRegion() const sl@0: { sl@0: if (iAnimating) sl@0: return iAnimationRegion; sl@0: else sl@0: return 0; sl@0: } sl@0: sl@0: void CScreenRedraw::UpdateDevice() sl@0: { sl@0: //this used to call iScreen->Update, not needed anymore in NGA sl@0: } sl@0: sl@0: TBool CScreenRedraw::IsQuickFadeScheduled( CWsWindow* aWin ) const sl@0: { sl@0: const TInt idx = iQuickFadeList.Find( aWin ); sl@0: return (idx > KErrNotFound); sl@0: } sl@0: sl@0: void CScreenRedraw::ScheduleQuickFade( CWsWindow* aWin ) sl@0: { sl@0: const TInt idx = iQuickFadeList.Find( aWin ); sl@0: if ( idx == KErrNotFound ) sl@0: { // not yet enlisted sl@0: if ( KErrNone != iQuickFadeList.Append(aWin) ) sl@0: { // out of resources? sl@0: const TRegion& winReg = aWin->VisibleRegion(); sl@0: ScheduleRegionUpdate( &winReg ); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::RemoveFromQuickFadeList( CWsWindow* aWin ) sl@0: { sl@0: const TInt idx = iQuickFadeList.Find( aWin ); sl@0: if ( idx > KErrNotFound ) sl@0: { sl@0: iQuickFadeList.Remove( idx ); sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn ) sl@0: { sl@0: if (aFadeOn) sl@0: { sl@0: if (aWin->WinType() != EWinTypeGroup) sl@0: { sl@0: ScheduleQuickFade(aWin); sl@0: ScheduleRegionUpdate(NULL); sl@0: } sl@0: } sl@0: else sl@0: { // fade off, just initiate redraw sl@0: if ( !aWin->IsDSAHost() ) sl@0: { sl@0: AddRedrawRegion(aWin->VisibleRegion() ); sl@0: ScheduleRegionUpdate(NULL); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: #ifdef USE_DEBUG_FRAME_CAPTURE sl@0: class TTruncateOverflow : public TDesOverflow sl@0: { sl@0: public: //from TDesOverflow sl@0: void Overflow(TDes&) {}; sl@0: }; sl@0: sl@0: void CScreenRedraw::CaptureFrame(const TRegion* aRegion) sl@0: { sl@0: MWsScreenDevice* screenDevice = static_cast(iScreen).ObjectInterface(); sl@0: WS_ASSERT_ALWAYS(screenDevice, EWsPanicScreenDeviceMissing); sl@0: const TSize screenSize(screenDevice->SizeInPixels()); sl@0: const TDisplayMode screenDisplayMode(screenDevice->DisplayMode()); sl@0: sl@0: //copy the whole screen sl@0: TRAPD(err, SetupFrameCaptureResourcesL(screenSize, screenDisplayMode); sl@0: screenDevice->CopyScreenToBitmapL(iDebugBitmap, TRect(screenSize))); sl@0: sl@0: if(err) sl@0: { sl@0: if(wsDebugLog) sl@0: wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, _L("CScreenRedraw::CaptureFrame(): Failed to create resources for screen capture")); sl@0: return; sl@0: } sl@0: sl@0: //remove what's not part of the region sl@0: iDebugBitmapGc->Activate(iDebugBitmapDevice); sl@0: sl@0: if(aRegion && !aRegion->IsEmpty() && !aRegion->CheckError()) sl@0: { sl@0: RWsRegion inverseRegion; sl@0: inverseRegion.AddRect(TRect(screenSize)); sl@0: const TRect* rectList = aRegion->RectangleList(); sl@0: for(TInt i = aRegion->Count() - 1; i >= 0; i--) sl@0: { sl@0: inverseRegion.SubRect(rectList[i]); sl@0: } sl@0: if(!inverseRegion.CheckError()) sl@0: { sl@0: iDebugBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); sl@0: iDebugBitmapGc->SetClippingRegion(inverseRegion); sl@0: iDebugBitmapGc->SetBrushColor(TRgb(55, 55, 55, 0)); sl@0: iDebugBitmapGc->Clear(); sl@0: iDebugBitmapGc->CancelClippingRegion(); sl@0: iDebugBitmapGc->SetDrawMode(CGraphicsContext::EDrawModePEN); sl@0: } sl@0: inverseRegion.Close(); sl@0: } sl@0: sl@0: //save to file sl@0: const TUint timestamp = User::FastCounter(); sl@0: TFileName filename; sl@0: TTruncateOverflow overflow; sl@0: filename.AppendFormat(iFrameCaptureLocation, &overflow); sl@0: filename.AppendFormat(_L("frame_%010u.mbm"), &overflow, timestamp); sl@0: iDebugBitmap->Save(filename); sl@0: sl@0: //log region sl@0: LogRegion(filename, _L(" CScreenRedraw::CaptureFrame() "), aRegion); sl@0: } sl@0: sl@0: void CScreenRedraw::SetupFrameCaptureResourcesL(const TSize& aScreenSize, TDisplayMode aScreenDisplayMode) sl@0: { sl@0: //make sure the existing bitmap has the correct display mode sl@0: if(iDebugBitmap && iDebugBitmap->DisplayMode() != aScreenDisplayMode) sl@0: { sl@0: if(iDebugBitmap->SetDisplayMode(aScreenDisplayMode) != KErrNone) sl@0: { sl@0: delete iDebugBitmap; sl@0: iDebugBitmap = NULL; sl@0: delete iDebugBitmapDevice; sl@0: iDebugBitmapDevice = NULL; sl@0: } sl@0: } sl@0: sl@0: //make sure the existing bitmap has the correct size sl@0: if(iDebugBitmap && iDebugBitmap->SizeInPixels() != aScreenSize) sl@0: { sl@0: if(iDebugBitmap->Resize(aScreenSize) != KErrNone) sl@0: { sl@0: delete iDebugBitmap; sl@0: iDebugBitmap = NULL; sl@0: delete iDebugBitmapDevice; sl@0: iDebugBitmapDevice = NULL; sl@0: } sl@0: } sl@0: sl@0: //make sure the bitmap and bitmap device is created sl@0: if(!iDebugBitmap) sl@0: { sl@0: WS_ASSERT_ALWAYS(!iDebugBitmapDevice, EWsPanicTemp); //this should never occur, they should always be created/destroyed in tandem sl@0: CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; sl@0: CleanupStack::PushL(bitmap); sl@0: User::LeaveIfError(bitmap->Create(aScreenSize, aScreenDisplayMode)); sl@0: sl@0: iDebugBitmapDevice = CFbsBitmapDevice::NewL(bitmap); sl@0: iDebugBitmap = bitmap; sl@0: CleanupStack::Pop(bitmap); sl@0: } sl@0: sl@0: //make sure the gc is created sl@0: if(!iDebugBitmapGc) sl@0: { sl@0: User::LeaveIfError(iDebugBitmapDevice->CreateContext(iDebugBitmapGc)); sl@0: } sl@0: } sl@0: sl@0: void CScreenRedraw::LogRegion(const TDesC& aPrefix, const TDesC& aFunctionName, const TRegion* aRegion) sl@0: { sl@0: if(!wsDebugLog) sl@0: return; sl@0: sl@0: TBuf log; sl@0: TTruncateOverflow overflow; sl@0: TInt rectCount = (aRegion == NULL ? 0 : aRegion->Count()); sl@0: log.AppendFormat(aPrefix, &overflow); sl@0: log.AppendFormat(aFunctionName, &overflow); sl@0: log.AppendFormat(_L("region [%d,"), &overflow, rectCount); sl@0: if (rectCount > 0) sl@0: { sl@0: const TRect* rectangles = aRegion->RectangleList(); sl@0: TBuf<1> comma; sl@0: for (TInt ii = 0; ii < rectCount; ii++) sl@0: { sl@0: TRect current = rectangles[ii]; sl@0: log.AppendFormat(_L("%S{{%d,%d},{%d,%d}}"), &overflow, &comma, sl@0: current.iTl.iX,current.iTl.iY,current.iBr.iX,current.iBr.iY); sl@0: comma = _L(","); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: log.AppendFormat(_L("NULL"), &overflow); sl@0: } sl@0: log.AppendFormat(_L("]"), &overflow); sl@0: wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log); sl@0: } sl@0: #endif //USE_DEBUG_FRAME_CAPTURE sl@0: