Chop out the code that handles "additional _E32Dll entry point after last ordinal position". I can't agree with that as how the DLL is supposed to work, and gives errors for me. Maybe the scripts to re-generate the jump tables have not been tried recently so its not a problem that's been hit by others.
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// SCREEN_REDRAW.CPP
//
//
#include "ScreenRedraw.h"
#include <hal.h>
#include "debugbar.h"
#include "screen.h"
#include "inifile.h"
#include "offscreenbitmap.h"
#include "wspluginmanager.h"
#include "pointer.h"
#include "rootwin.h"
#include "walkwindowtree.h"
#include "wstop.h"
#include "WsMemMgr.h"
#include "Graphics/WsRenderStageFactory.h"
#include "Graphics/WsRenderStage.h"
#include "EVENT.H"
GLREF_D CDebugLogBase *wsDebugLog;
#ifdef USE_DEBUG_REGIONS
# define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg)
# define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect)
#else
# define DEBUG_REGION(col,fill,reg)
# define DEBUG_RECT(col,fill,rect)
#endif
#if defined(__WINS__) && defined(_DEBUG)
# define DEBUGOSB { CWsOffScreenBitmap * ofb = iScreen.OffScreenBitmap(); if (ofb) ofb->Update(); }
#else
# define DEBUGOSB
#endif
#ifdef _DEBUG
# define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}}
# define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}}
#else
# define LOG_SCREEN_REDRAW_START
# define LOG_SCREEN_REDRAW_END
#endif
CScreenRedraw::TTimedRect::TTimedRect(const TRect& aRect, const TTime& aTime):
iRect(aRect), iTime(aTime)
{
}
TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther)
{
if(aOne.iTime < aOther.iTime)
return -1;
else if(aOne.iTime > aOther.iTime)
return 1;
else
return 0;
}
CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen)
{
CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen)
{
}
CScreenRedraw::~CScreenRedraw()
{
CWsRenderStage * stage = iRenderStages;
while (stage!=NULL)
{
CWsRenderStage *next=stage->Next();
delete stage;
stage=next;
}
iTimedDrawRect.Close();
iInvalid.Close();
iTopLayer.Close();
iBannedRegion.Close();
}
void CScreenRedraw::ConstructL()
{
CWsPluginManager * pluginMgr = CWsTop::WindowServer()->PluginManager();
// Setup the render stages for this screen:
_LIT(KDefaultRenderStages, "std");
_LIT(KDefaultFlickerFreeRenderStages, "flickerbuffer std");
_LIT(KRenderStages,"RENDERSTAGES");
TPtrC stagesString;
const TBool customStages = WsIniFile->FindVar(iScreen.ScreenNumber(),KRenderStages,stagesString);
// If noone specifies stages for this screen, assume the standard implementation:
const TDesC * stages;
if (customStages)
stages = &stagesString;
else if (iScreen.OffScreenBitmap())
stages = &KDefaultFlickerFreeRenderStages();
else
stages = &KDefaultRenderStages();
CWsRenderStage * lastStage = 0;
// Parse the string for implementation IDs:
TLex lex(*stages);
while(true)
{
TPtrC ptr = lex.NextToken();
if (ptr.Length() > 0)
{
TInt err = KErrNone;
MWsRenderStageFactory * factory = pluginMgr->FindNamedImplementation<MWsRenderStageFactory>(ptr);
if (factory)
{
CWsRenderStage * stage = 0;
TRAP(err, stage = factory->CreateStageL(static_cast<MWsScreen*>(&iScreen), this));
if (err == KErrNone)
{
if (!stage)
{
err = KErrNotFound;
}
else
{
if (lastStage)
lastStage->SetNext(stage);
else
iRenderStages = stage;
lastStage = stage;
}
}
}
else
{
err = KErrNotFound;
}
if (wsDebugLog)
{
TBuf<64> buf;
if (err == KErrNone)
{
_LIT(KAddedRenderStage,"Added render stage: ");
buf.Append(KAddedRenderStage);
buf.Append(ptr);
wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf);
}
else
{
_LIT(KMissingRenderStage,"Failed to add render stage (%d): ");
buf.Append(KMissingRenderStage);
buf.Append(ptr);
wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf,err);
}
}
}
else
{
break;
}
}
}
const TTime& CScreenRedraw::Now() const
{
if(!iAnimating)
{
iNow.UniversalTime();
}
return iNow;
}
void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow)
{
iRenderScheduled = ETrue;
TTime then(Now() + aFromNow);
if ((!iScheduled) || then < iNext)
iNext = then;
iScheduled = ETrue;
CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
}
void CScreenRedraw::ScheduleRedraw()
{
iNext = Now();
iScheduled = ETrue;
// The other scheduler also removes future animations which this one encompasses.
// We choose not to do the region calculations needed to achieve that here.
MWsAnimationScheduler* animSched=CWsTop::WindowServer()->AnimationScheduler();
if (animSched)
{
animSched->ScheduleRedraw(iScreen,iNext);
}
}
void CScreenRedraw::ScheduleAnimation(const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/)
{
TRect test(aRect);
test.Intersection(iScreen.DrawableArea());
if(!test.IsEmpty())
{
const TTime then(Now() + aFromNow);
TTimedRect tRect(aRect, then);
const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare);
if (KErrNone == error)
{
if (iScheduled)
{
if (then < iNext)
{
iNext = then;
}
}
else
{
iNext = then;
iScheduled = ETrue;
}
// remove further futures that are completely contained
TInt count = iTimedDrawRect.Count();
for(TInt i=0; i<count; i++)
{
const TTimedRect& future = iTimedDrawRect[i];
if(future.iTime.Int64() > then.Int64())
{
TRect rect(aRect);
rect.BoundingRect(future.iRect);
if(rect == aRect) // future is completely contained within aRect
{
iTimedDrawRect.Remove(i);
count--;
i--;
}
}
}
CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
// Blue rectangles for scheduled animations
DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect);
}
}
}
// This adds a region to the stored invalid region.
// The invalid region is the area of the screen that needs to be redrawn in addition to any animations.
// The draw region is the area of the screen on which only the top window needs to be redrawn.
// If the top window has transparency, this can only be true when it has been made newly visible.
// The value of aSchedule could be determined automatically from iAnimating, but passing it this way
// allows us to have the assert, which is a very valuable assert.
void CScreenRedraw::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth)
{
WS_ASSERT_DEBUG(!iAnimating || !aSchedule, EWsPanicScheduledRedraw);
if(aRegion.CheckError())
{
iInvalid.ForceError();
if (aSchedule)
ScheduleRedraw();
}
else if(aRegion.Count()) // often called despite window not being visible
{
if (aDepth == ERedrawAll)
{
// red lines for an invalid region which is ready to be drawn
DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x20),&aRegion);
iInvalid.Union(aRegion);
if (aSchedule)
ScheduleRedraw();
}
else
{
// yellow lines for a valid region which we will draw on top of
DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x20),&aRegion);
iTopLayer.Union(aRegion);
if (aSchedule)
ScheduleRedraw();
}
}
}
// This causes any asynchronously scheduled redraw to happen immediately
// It should be avoided where possible for performance reasons, but is
// needed whenever the redraw store is discarded for a window which still
// has a redraw region pending.
void CScreenRedraw::DoRedrawNow()
{
if(!iAnimating)
CWsTop::WindowServer()->AnimationScheduler()->DoRedrawNow(iScreen);
}
#ifdef USE_DEBUG_REGIONS
void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect)
{
if (aRect)
{
CFbsBitGc * gc = iScreen.GetBitGc();
gc->SetPenColor(aColor);
gc->SetPenStyle(CGraphicsContext::ESolidPen);
gc->SetPenSize(TSize(2,2));
gc->SetBrushColor(aFill);
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
TRect smaller = *aRect;
smaller.iBr.iX -= 1;
smaller.iBr.iY -= 1;
gc->DrawRect(smaller);
iScreen.Update();
}
}
void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion)
{
if (aRegion)
{
CFbsBitGc * gc = iScreen.GetBitGc();
gc->SetPenColor(aColor);
gc->SetPenStyle(CGraphicsContext::ESolidPen);
gc->SetPenSize(TSize(2,2));
gc->SetBrushColor(aFill);
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect)
{
TRect smaller = *rect;
smaller.iBr.iX -= 1;
smaller.iBr.iY -= 1;
gc->DrawRect(smaller);
}
iScreen.Update();
}
}
#endif
void CScreenRedraw::OnAnimation()
{
LOG_SCREEN_REDRAW_START
ASSERT(!iAnimating);
ASSERT(iScheduled);
iAnimating = ETrue;
iScheduled = EFalse;
TBool futureAnimationRequired = EFalse;
CWsActiveScheduler::Static()->PrepareDraw();
// Calculate any updates required by region changes:
RegionUpdate();
// Add the timed rectangles to the invalid region:
iNow.UniversalTime();
TInt count(iTimedDrawRect.Count());
while (0 < count)
{
if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64())
{
iInvalid.AddRect(iTimedDrawRect[0].iRect);
iTimedDrawRect.Remove(0);
count--;
}
else
{
futureAnimationRequired = ETrue;
break;
}
}
// Animating rectangles could cause iInvalid to overlap iTopLayer,
// in which case iTopLayer won't work.
iTopLayer.SubRegion(iInvalid);
iTopLayer.Intersect(iScreen.RootWindow()->WindowArea());
iTopLayer.Tidy();
// Anything in the top layer is implcitly invalid
iInvalid.Union(iTopLayer);
iInvalid.Intersect(iScreen.RootWindow()->WindowArea());
/*
if (const CDebugBar* dbg = iScreen.DebugBar())
{
iTopLayer.SubRect(dbg->Rect());
iInvalid.SubRect(dbg->Rect());
}
*/
iInvalid.Tidy();
if(iInvalid.CheckError()) //Will: agree with Andy, want bounding rects instead!
{
iTopLayer.Clear();
iInvalid.Clear();
iInvalid.Copy(iScreen.RootWindow()->WindowArea()); // assumed cannot fail, all regions can contain at least 1 rect..
}
iInvalid.SubRegion( iBannedRegion );
iInvalid.Tidy();
iTopLayer.SubRegion( iBannedRegion );
iTopLayer.Tidy();
STACK_REGION invalidCopy;
invalidCopy.Copy(iInvalid);
TWalkWindowTreeScheduleRegions regionScheduler(&invalidCopy, iTopLayer);
TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap());
TWalkWindowTreeSchedule * scheduler = ®ionScheduler;
// At this point, if the DEBUG_REGION is being used:
// Red represents invalid regions that need to be redrawn completely.
// Yellow represents regions that only need the top window to be drawn.
// Blue represents regions which are being animated server side.
if (iRenderScheduled || !iInvalid.IsEmpty())
{
iRenderScheduled = EFalse;
// invalidCopy.ForceError(); //### DEBUG
iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren);
if (!regionScheduler.ScheduledRegionsOk())
{
// our region calculations for what to draw failed at some point.
// From this point on we MUST NOT rely on allocating memory
// Andy - localRedrawRegion allocates
// Andy - setPenSize allocates (even if you don't call it)
// Andy - all draw commands add to a gdi dirty region (which allocates)
// Andy - combining client clipping regions with window clipping regions allocates
scheduler = &fallbackScheduler;
iScreen.FallbackMap()->Prepare();
iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren);
}
CWsActiveScheduler::Static()->StartDraw();
CWsMemoryManager::Static()->EnableReserve();
if (&fallbackScheduler == scheduler)
iAnimationRegion = iScreen.FallbackMap()->Region();
else
iAnimationRegion = &iInvalid;
// Redraw debug regions more brightly than before:
DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),&iInvalid);
DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopLayer);
RWsRegion accumulatedDrawing;
// Pipe the drawing into the first render stage:
CFbsBitGc * stageGc = iRenderStages->Begin();
for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
{
const TRegion * targetRegion = scheduler->Region(win);
const TRect * screenRect = 0;
if ((&fallbackScheduler == scheduler) && !targetRegion->IsContainedBy(iScreen.RootWindow()->Abs()))
{
screenRect = &iScreen.RootWindow()->Abs();
}
if (!screenRect)
{
// Purple regions are about to be drawn
DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),targetRegion);
// Do the drawing
stageGc->Reset();
win->Render(stageGc, *targetRegion);
accumulatedDrawing.Union(*targetRegion);
// Green regions have been drawn
DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),targetRegion);
}
else
{
// Our region overlaps the edges of the screen, and we have no memory
// to create a clipped one, so we will use a single-rect region for each rect
// and call Draw multiple times.
TRegionFix<1> rectRegion;
for (const TRect * rect = targetRegion->RectangleList() + targetRegion->Count() - 1; rect >= targetRegion->RectangleList(); --rect)
{
rectRegion.Clear();
TRect combined(*screenRect);
combined.Intersection(*rect);
rectRegion.AddRect(combined);
// Purple regions are about to be drawn
DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),&rectRegion);
// Do the drawing
stageGc->Reset();
win->Render(stageGc, rectRegion);
accumulatedDrawing.AddRect(combined);
// Green regions have been drawn
DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),&rectRegion);
}
}
DEBUGOSB
}
DEBUGOSB
iScreen.SpriteManager()->DrawFloatingSprites(stageGc,accumulatedDrawing); // we limit sprite drawing over only actually affected ares but necessary to all "planned" for redraw
if (!accumulatedDrawing.CheckError() && iScreen.SpriteManager()->SpriteCount() == 0)
{
iAnimationRegion = &accumulatedDrawing;
}
// Tell the render stage we've finished:
iRenderStages->End();
// We nolonger need the regions
for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
{
win->ClearScheduledRegion();
}
CWsMemoryManager::Static()->DisableReserve();
if (const CDebugBar* dbg = iScreen.DebugBar())
{
dbg->RedrawDebugBar();
}
// At this point, if the DEBUG_REGION is being used, there should usually be only green regions
// displayed. If we see red or yellow, then something didn't get redrawn that should have been.
// If we see purple then a window has disobeyed the const setting on the region to draw.
// Red or yellow is valid - a window can decide it isn't ready to draw yet - purple is very bad.
iScreen.Update();
// At this point, if the DEBUG_REGION is being used, there should be no regions visible
// of any colour. If we see green, then it means an area of the screen was drawn to which
// wasn't invalid, or the screen update call failed. The former is more likely.
// If we still see red or yellow it is a region that is not yet ready to draw.
const TRect* rect = iAnimationRegion->RectangleList();
TInt pixels = 0;
for(TInt r = iAnimationRegion->Count(); r>0; r--)
{
pixels += (rect->Width()*rect->Height());
rect++;
}
CWsActiveScheduler::Static()->StopDraw(pixels);
TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion);
iAnimationRegion = 0;
accumulatedDrawing.Close();
iInvalid.Clear();
}
else
{
CWsActiveScheduler::Static()->CancelPrepare();
}
iInvalid.Clear();
iTopLayer.Clear();
invalidCopy.Close();
iAnimating = EFalse;
if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled)
{
// If this flag is set then it means there were already some animations scheduled when we ran,
// but they themselves didn't run. We need to make sure we have _something_ scheduled.
CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime);
iScheduled = ETrue;
}
if(iObserver)
{
iObserver->ScreenUpdated(iScreen.ScreenNumber());
iObserver=NULL; //once signalled we are never going to call it again
}
LOG_SCREEN_REDRAW_END
}
//
void CScreenRedraw::DiscardAllSchedules()
{
ASSERT(!iAnimating);
iTimedDrawRect.Reset();
iInvalid.Clear();
iInvalid.Tidy();
}
/**
Indicates that a window has moved or changed ordinal position so that the visible regions
of all windows needs to be recalculated
*/
void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty)
{
iRegionUpdateScheduled = ETrue;
ScheduleRedraw();
if(aDefinitelyDirty)
{
iInvalid.Union(*aDefinitelyDirty);
// Cyan regions for invalidations caused by this:
DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty);
}
}
/**
Recalculates visible regions and schedules redraws or queues redraw events in response to
any changes
*/
void CScreenRedraw::RegionUpdate()
{
if (iRegionUpdateScheduled)
{
iRegionUpdateScheduled = EFalse;
TWalkWindowTreeUpdateRegions updater(iScreen);
updater.Walk();
WsPointer::ReLogCurrentWindow();
CWsTop::TriggerRedraws(iScreen.RootWindow());
}
}
void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver)
{
iObserver = aObserver;
}
TBool CScreenRedraw::IsUpdatePending()
{
if(iScheduled || iAnimating)
return ETrue;
else
return EFalse;
}
/**
Overidding MWsObjectProvider
*/
TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId)
{
TAny* interface = NULL;
switch (aTypeId)
{
case KWsScreenRedraw:
interface = static_cast<MWsScreenRedraw*>(this);
break;
}
if (!interface)
{
interface = iRenderStages->ResolveObjectInterface(aTypeId);
}
return interface;
}
const TRegion * CScreenRedraw::AnimationRegion() const
{
if (iAnimating)
return iAnimationRegion;
else
return 0;
}
void CScreenRedraw::UpdateDevice()
{
iScreen.Update();
}
void CScreenRedraw::BanThisRegionUpdate( TRegion& aForbiddenRegion )
{
iBannedRegion.Union( aForbiddenRegion );
iBannedRegion.Tidy();
}
void CScreenRedraw::LiftRegionUpdateBan( TRegion& aFormerForbiddenRegion )
{
iBannedRegion.SubRegion( aFormerForbiddenRegion );
iBannedRegion.Tidy();
}
void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn, TBool aFadeBehind, TBool aIncludeChildren )
{
if ( aFadeOn )
{
TWalkWindowTreeScheduleFadeNoRedraw walkerFadeNoRedraw;
if ( aFadeBehind )
{
aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkBehind );
}
else
{
if(aWin->WinType() != EWinTypeGroup)
{
ScheduleRegionUpdate( aWin->VisibleRegionIfValid() );
}
if ( aIncludeChildren )
{
aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkChildren );
}
}
}
else
{ // fade off, just initiate redraw
TWalkWindowTreeScheduleRedraws walkerRedraw( TWalkWindowTreeScheduleRedraws::ERedrawFilterOmitDSA ) ;
if ( aFadeBehind )
{
aWin->WalkWindowTree( walkerRedraw, EWalkBehind );
}
else
{ // fade this win not behind
if ( !aWin->IsDSAHost() )
{
AddRedrawRegion( aWin->VisibleRegion() );
}
if ( aIncludeChildren )
{
aWin->WalkWindowTree( walkerRedraw, EWalkChildren );
}
}
}
ScheduleRegionUpdate(NULL);
}