windowing/windowserver/nonnga/SERVER/redrawmsgwindow.cpp
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Window redraw code, three sorts of redrawing are supported
       
    15 // CRedrawMsgWindow handles it via sending a redraw message to the client
       
    16 // 
       
    17 //
       
    18 
       
    19 #include "redrawmsgwindow.h"
       
    20 #include "gc.h"
       
    21 #include "playbackgc.h"
       
    22 #include "inifile.h"
       
    23 #include "rootwin.h"
       
    24 #include "wstop.h"
       
    25 #include "ANIM.H"
       
    26 #include "EVQUEUE.H"
       
    27 #include <s32mem.h>
       
    28 #include <gdi.h>
       
    29 #include "panics.h"
       
    30 #include "rootwin.h"
       
    31 #include "EVENT.H"
       
    32 #include "wsfont.h"
       
    33 #include <graphics/wsgraphicdrawerinterface.h>
       
    34 #include "../debuglog/DEBUGLOG.H"
       
    35 
       
    36 const TUint KDrawBufferGranularity = 240;
       
    37 const TInt KRedrawRegionGranularity = 8;
       
    38 const TInt KReadBufferMaxLen=0x100;
       
    39 const TInt KRegionCompressThreshold = 6; // number of rectangles in region at which we try to compress it
       
    40 
       
    41 /** Max number of non-redraw segments allowed before starting to throw away the oldest */
       
    42 const TInt KNonRedrawSegMaxLimit = 16;
       
    43 /** The number of non-redraw segments to spare from deletion once their number 
       
    44     have grown beyond KNonRedrawSegMaxLimit */
       
    45 const TInt KNonRedrawSegThreshold = 8;
       
    46 
       
    47 TInt CWsRedrawMsgWindow::iNonRedrawAgeLimit = 0;
       
    48 CWsRedrawMsgWindow::TAtomicityType CWsRedrawMsgWindow::iAtomicity = ENoAtomicity;
       
    49 
       
    50 #if defined(__WINS__) && defined(_DEBUG)
       
    51 #   include "offscreenbitmap.h"
       
    52 #	define DEBUGOSB { CWsOffScreenBitmap * ofb = Screen()->OffScreenBitmap(); if (ofb) ofb->Update(); }
       
    53 #else
       
    54 #	define DEBUGOSB
       
    55 #endif
       
    56 
       
    57 #ifndef _DEBUG
       
    58 
       
    59 #define LOG_WINDOW_REDRAW_START(wswin,region)
       
    60 #define LOG_WINDOW_REDRAW_END(wswin)
       
    61 #define LOG_REDRAW_SEGMENT(segmentIndex,segmentType) 
       
    62 #define LOG_REDRAW_SEGMENT_REGION(region)
       
    63 #define LOG_PLAYBACK_GC_COMMAND(opcode,data)
       
    64 
       
    65 #else
       
    66 
       
    67 #define LOG_WINDOW_REDRAW_START(wswin,region) LogDrawCommandsStart(wswin,region)
       
    68 #define LOG_WINDOW_REDRAW_END(wswin) LogDrawCommandsEnd(wswin)
       
    69 #define LOG_REDRAW_SEGMENT(segmentIndex,segmentType) LogRedrawSegment(segmentIndex, segmentType)
       
    70 #define LOG_REDRAW_SEGMENT_REGION(region) {if(wsDebugLog){ LogRegion(region);}}
       
    71 #define LOG_PLAYBACK_GC_COMMAND(opcode,data)    {if (wsDebugLog) {wsDebugLog->Command(WS_HANDLE_GC, opcode, data, NULL);}}
       
    72 
       
    73 extern CDebugLogBase *wsDebugLog;
       
    74 
       
    75 class TTruncateOverflow : public TDesOverflow
       
    76 	{
       
    77 	public:
       
    78 	virtual void Overflow(TDes&) {};
       
    79 	};
       
    80 
       
    81 LOCAL_C void LogRedrawSegment(TUint aSegmentIndex, CWsRedrawMsgWindow::TRedrawSegmentType aSegmentType)
       
    82 	{
       
    83 	if (wsDebugLog)
       
    84 		{
       
    85 		TBuf<LogTBufSize> log;
       
    86 		TTruncateOverflow overflow;
       
    87 		_LIT(KLogRedrawSegment, ">> CRedrawSegment[%d] ");
       
    88 		log.AppendFormat(KLogRedrawSegment, &overflow, aSegmentIndex);
       
    89 		_LIT(KLogRedrawSegmentPending, "Pending");
       
    90 		_LIT(KLogRedrawSegmentRedraw, "Redraw");
       
    91 		_LIT(KLogRedrawSegmentNonRedraw, "NonRedraw");
       
    92 		switch(aSegmentType)
       
    93 			{
       
    94 			case CWsRedrawMsgWindow::ESegmentTypePendingRedraw :
       
    95 				log.AppendFormat(KLogRedrawSegmentPending, &overflow);
       
    96 				break;
       
    97 			case CWsRedrawMsgWindow::ESegmentTypeRedraw :
       
    98 				log.AppendFormat(KLogRedrawSegmentRedraw, &overflow);
       
    99 				break;
       
   100 			case CWsRedrawMsgWindow::ESegmentTypeNonRedraw :
       
   101 				log.AppendFormat(KLogRedrawSegmentNonRedraw, &overflow);
       
   102 			break;
       
   103 			default :
       
   104 				{
       
   105 				}
       
   106 			}
       
   107 		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
       
   108 		}
       
   109 	}
       
   110 
       
   111 LOCAL_C void LogRegion(const TRegion* aRegion)
       
   112 	{
       
   113 	TBuf<LogTBufSize> log;
       
   114 	TTruncateOverflow overflow;
       
   115 	TInt rectCount = (aRegion == NULL ? 0 : aRegion->Count());
       
   116 	log.AppendFormat(_L("region [%d,"), &overflow, rectCount);
       
   117 	if (rectCount > 0)
       
   118 		{
       
   119 		const TRect* rectangles = aRegion->RectangleList();
       
   120 		TBuf<1> comma;
       
   121 		for (TInt ii = 0; ii < rectCount; ii++)
       
   122 			{
       
   123 			TRect current = rectangles[ii];
       
   124 			log.AppendFormat(_L("%S{{%d,%d},{%d,%d}}"), &overflow, &comma,
       
   125 	                         current.iTl.iX,current.iTl.iY,current.iBr.iX,current.iBr.iY);
       
   126 			comma = _L(",");
       
   127 			}
       
   128 		}
       
   129 	else
       
   130 		{
       
   131 		log.AppendFormat(_L("NULL"), &overflow);
       
   132 		}
       
   133 	log.AppendFormat(_L("]"), &overflow);
       
   134 	wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
       
   135 	}
       
   136 
       
   137 LOCAL_C void LogDrawCommandsStart(const CWsWindow* aWsWin, const TRegion* aRegion)
       
   138 	{
       
   139 	if (wsDebugLog)
       
   140 		{
       
   141 		_LIT(KLogDrawCommandsStart, ">> CWsRedrawMsgWindow::DrawCommandsL() [%S][app %d] RWindow[%d]");
       
   142 		const TDesC& clientName = aWsWin->WsOwner()->Client().FullName();
       
   143 		TBuf<LogTBufSize> log;
       
   144 		TTruncateOverflow overflow;
       
   145 		log.AppendFormat(KLogDrawCommandsStart, &overflow, &clientName, aWsWin->WsOwner()->ConnectionHandle(), aWsWin->LogHandle());
       
   146 		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
       
   147 		LogRegion(aRegion);
       
   148 		}
       
   149 	}
       
   150 
       
   151 LOCAL_C void LogDrawCommandsEnd(const CWsWindow* aWsWin)
       
   152 	{
       
   153 	if (wsDebugLog)
       
   154 		{
       
   155 		_LIT(KLogDrawCommandsEnd, "<< CWsRedrawMsgWindow::DrawCommandsL() [%S][app %d] RWindow[%d]");
       
   156 		const TDesC& clientName = aWsWin->WsOwner()->Client().FullName();
       
   157 		TBuf<LogTBufSize> log;
       
   158 		TTruncateOverflow overflow;
       
   159 		log.AppendFormat(KLogDrawCommandsEnd, &overflow, &clientName, aWsWin->WsOwner()->ConnectionHandle(), aWsWin->LogHandle());		
       
   160 		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
       
   161 		}
       
   162 	}
       
   163 
       
   164 #endif
       
   165 
       
   166 //
       
   167 // Redraw windows //
       
   168 //
       
   169 
       
   170 CWsRedrawMsgWindow::CRedrawSegment::CRedrawSegment()
       
   171 	{
       
   172 	}
       
   173 
       
   174 CWsRedrawMsgWindow::CRedrawSegment* CWsRedrawMsgWindow::CRedrawSegment::NewLC(const TRect& aRect, TRedrawSegmentType aNewRegionType)
       
   175 	{
       
   176 	CRedrawSegment* self = new (ELeave) CRedrawSegment();
       
   177 	CleanupStack::PushL(self);
       
   178 	self->ConstructL(aRect, aNewRegionType);
       
   179 	return self;
       
   180 	}
       
   181 
       
   182 void CWsRedrawMsgWindow::StaticInitL()
       
   183 	{
       
   184 	_LIT(KNonRedrawAgeLimit, "NONREDRAWAGELIMIT");
       
   185 	const TInt KDefaultNonRedrawAgeLimit = 1000000;
       
   186 	if (!WsIniFile->FindVar(KNonRedrawAgeLimit, iNonRedrawAgeLimit))
       
   187 		iNonRedrawAgeLimit = KDefaultNonRedrawAgeLimit;
       
   188 	
       
   189 	_LIT(KAtomicRedraws,"ATOMICREDRAWS");
       
   190 	_LIT(KAtomicSegment,"SEGMENT");
       
   191 	_LIT(KAtomicWindow,"WINDOW");
       
   192 
       
   193 	TPtrC atomicityTypeString;
       
   194 	if (WsIniFile->FindVar(KAtomicRedraws,atomicityTypeString))
       
   195 		{
       
   196 		if(atomicityTypeString.CompareF(KAtomicSegment)==0 || atomicityTypeString.Length()==0)
       
   197 			iAtomicity = ESegment;
       
   198 		else if(atomicityTypeString.CompareF(KAtomicWindow)==0)
       
   199 			iAtomicity = EWindow;
       
   200 		}
       
   201 	}
       
   202 
       
   203 void CWsRedrawMsgWindow::CRedrawSegment::ReleaseFontsAndBitmaps()
       
   204 	{
       
   205 	// release Bitmap and Font handles
       
   206 	TInt count = iWsBitmapArray.Count();
       
   207 	TInt ii;
       
   208 	for (ii = count - 1; ii >= 0; ii--)
       
   209 		{
       
   210 		iWsBitmapArray[ii]->DecRefCount();
       
   211 		iWsBitmapArray.Remove(ii);
       
   212 		}
       
   213 
       
   214 	count = iWsFontArray.Count();
       
   215 	for (ii = count - 1; ii >= 0; --ii)
       
   216 		{
       
   217 		CWsFontCache::Instance()->ReleaseFont(iWsFontArray[ii]);
       
   218 		iWsFontArray.Remove(ii);
       
   219 		}
       
   220 
       
   221 	count = iFbsBitmapArray.Count();
       
   222 	for(ii = count - 1 ; ii >= 0; ii--)
       
   223 		{
       
   224 		delete iFbsBitmapArray[ii];
       
   225 		iFbsBitmapArray.Remove(ii);
       
   226 		}
       
   227 	}
       
   228 
       
   229 /* Set new rectangle and region type for initial or reset redraw region
       
   230  @leave KErrNoMemory no memory to update region details
       
   231  */
       
   232 void CWsRedrawMsgWindow::CRedrawSegment::ConstructL(const TRect& aRect, TRedrawSegmentType aNewRegionType)
       
   233 	{
       
   234 	iDrawCommands = CBufSeg::NewL(KDrawBufferGranularity);
       
   235 	iCreationTime.UniversalTime();
       
   236 
       
   237 	iRegion.AddRect(aRect);
       
   238 	if (iRegion.CheckError())
       
   239 		{
       
   240 		User::Leave(KErrNoMemory);
       
   241 		}
       
   242 	iRedrawSegmentType = aNewRegionType;
       
   243 	}
       
   244 
       
   245 CWsRedrawMsgWindow::CRedrawSegment::~CRedrawSegment()
       
   246 	{
       
   247 	delete iDrawCommands;
       
   248 
       
   249 	iRegion.Close();
       
   250 
       
   251 	// Release Font and Bitmap handles, close arrays
       
   252 	ReleaseFontsAndBitmaps();
       
   253 	iFbsBitmapArray.Close();
       
   254 	iWsBitmapArray.Close();
       
   255 	iWsFontArray.Close();
       
   256 	iDrawerArray.Close();
       
   257 	}
       
   258 
       
   259 void CWsRedrawMsgWindow::WindowClosing()
       
   260 	{
       
   261 	iWsWin->WsOwner()->RedrawQueue()->RemoveInvalid(this);
       
   262 	}
       
   263 
       
   264 
       
   265 TInt CWsRedrawMsgWindow::CRedrawSegment::SizeInBytes() const
       
   266 	{
       
   267 	TInt size = sizeof(CWsRedrawMsgWindow::CRedrawSegment);
       
   268 	size += iDrawCommands->Size();
       
   269 	size += iFbsBitmapArray.Count() * sizeof(CFbsBitmap);
       
   270 	size += iWsBitmapArray.Count() * sizeof(DWsBitmap);
       
   271 	size += iWsFontArray.Count() * sizeof(CWsFbsFont);
       
   272 	size += iDrawerArray.Count() * sizeof(TGraphicDrawerId);
       
   273 	return size;
       
   274 	}
       
   275 
       
   276 CWsRedrawMsgWindow::CWsRedrawMsgWindow(CWsWindow *aWin)
       
   277 	:CWsWindowRedraw(aWin), iBackColor(aWin->RootWindow()->DefaultBackgroundColor()), iFlags(EBackgroundClear|EStoringEntireWindow),
       
   278 	iRedrawSegments(KRedrawRegionGranularity),
       
   279 	iCurrentSegment(0),
       
   280 	iOSBStatus(ETrue)
       
   281 	{
       
   282 	}
       
   283 
       
   284 void CWsRedrawMsgWindow::ConstructL()
       
   285 	{
       
   286 	CWsWindowRedraw::ConstructL();
       
   287 	Invalidate(&WsWin()->Rel());
       
   288 	iWsWin->WsOwner()->RedrawQueue()->ReCalcOrder();
       
   289 	}
       
   290 	
       
   291 CWsRedrawMsgWindow::~CWsRedrawMsgWindow()
       
   292 	{
       
   293 	WS_ASSERT_DEBUG(iMemoryLock == 0, EWsPanicMemoryLock);
       
   294 	RemoveFromRedrawQueueIfEmpty();
       
   295 	iInvalid.Close();
       
   296 	iLocalRedrawRegion.Close();
       
   297 	iRedrawSegments.ResetAndDestroy();
       
   298 	iCurrentSegment=NULL;
       
   299 	}
       
   300 
       
   301 /**
       
   302 These three functions actually check for a value they have already asserted on.  This is intentional.
       
   303 */
       
   304 void CWsRedrawMsgWindow::ExpandCommandBufferL(TInt aLength)
       
   305 	{
       
   306 	WS_ASSERT_DEBUG(iCurrentSegment != NULL, EWsPanicRedrawSegmentsInvalidState);
       
   307 	
       
   308 	if (iCurrentSegment)
       
   309 		{
       
   310 		// need more space?
       
   311 		if (iCurrentSegment->iCurrentCommandBufferWritePos + aLength > iCurrentSegment->iDrawCommands->Size())
       
   312 			{
       
   313 			iCurrentSegment->iDrawCommands->ResizeL(iCurrentSegment->iCurrentCommandBufferWritePos + aLength);
       
   314 			}
       
   315 		}
       
   316 	}
       
   317 
       
   318 void CWsRedrawMsgWindow::CommandBufferWrite(const TDesC8& aDes, TInt aLength)
       
   319 	{
       
   320 	WS_ASSERT_DEBUG(iCurrentSegment != NULL, EWsPanicRedrawSegmentsInvalidState);
       
   321 	WS_ASSERT_DEBUG(iCurrentSegment->iCurrentCommandBufferWritePos + aLength <= iCurrentSegment->iDrawCommands->Size(), EWsPanicDrawCommandsInvalidState);
       
   322 	if (iCurrentSegment)
       
   323 		{
       
   324 		iCurrentSegment->iDrawCommands->Write(iCurrentSegment->iCurrentCommandBufferWritePos, aDes, aLength);
       
   325 		iCurrentSegment->iCurrentCommandBufferWritePos += aLength;
       
   326 		}
       
   327 	}
       
   328 
       
   329 void CWsRedrawMsgWindow::CommandBufferWrite(const TAny* aPtr,TInt aLength)
       
   330 	{
       
   331 	WS_ASSERT_DEBUG(iCurrentSegment != NULL, EWsPanicRedrawSegmentsInvalidState);
       
   332 	WS_ASSERT_DEBUG(iCurrentSegment->iCurrentCommandBufferWritePos + aLength <= iCurrentSegment->iDrawCommands->Size(), EWsPanicDrawCommandsInvalidState);
       
   333 	if (iCurrentSegment)
       
   334 		{
       
   335 		iCurrentSegment->iDrawCommands->Write(iCurrentSegment->iCurrentCommandBufferWritePos, aPtr, aLength);
       
   336 		iCurrentSegment->iCurrentCommandBufferWritePos += aLength;
       
   337 		}
       
   338 	}
       
   339 
       
   340 /*------------------------------------------------------------------------------
       
   341   Description: Processes draw commands. These are received as opcodes.
       
   342  -----------------------------------------------------------------------------*/
       
   343 TBool CWsRedrawMsgWindow::CommandL(TInt aOpcode, TWsWinCmdUnion &aCmd)
       
   344 	{
       
   345 	switch(aOpcode)
       
   346 		{
       
   347 		case EWsWinOpEnableOSB:
       
   348 			iOSBStatus = ETrue;
       
   349 			break;
       
   350 		case EWsWinOpDisableOSB:
       
   351 			iOSBStatus = EFalse;
       
   352 			break;
       
   353 		case EWsWinOpSetBackgroundColor:
       
   354 			iBackColor = *aCmd.rgb;
       
   355 			iFlags |= EBackgroundClear;
       
   356 			break;
       
   357 		case EWsWinOpSetNoBackgroundColor:
       
   358 			iFlags &= ~EBackgroundClear;
       
   359 			break;
       
   360 		case EWsWinOpInvalidate:
       
   361 			Invalidate(aCmd.rect);
       
   362 			break;
       
   363 		case EWsWinOpInvalidateFull:
       
   364 			Invalidate();
       
   365 			break;
       
   366 		case EWsWinOpBeginRedraw:
       
   367 			BeginRedraw(aCmd.rect);
       
   368 			ValidateRect(aCmd.rect);
       
   369 			break;
       
   370 		case EWsWinOpBeginRedrawFull:
       
   371 			BeginRedraw(NULL);
       
   372 			ValidateRect(NULL);
       
   373 			break;
       
   374 		case EWsWinOpEndRedraw:
       
   375 			EndRedraw();
       
   376 			break;
       
   377 		case EWsWinOpGetInvalidRegionCount:
       
   378 			{				
       
   379 			SetReply(iInvalid.Count());
       
   380 			}
       
   381 			break;
       
   382 		case EWsWinOpGetInvalidRegion:
       
   383 			{
       
   384 			if ((*aCmd.Int) <= 0)
       
   385 				OwnerPanic(EWservPanicInvalidRegionCount);
       
   386 			if ((!iInvalid.CheckError()) && iInvalid.Count() == (*aCmd.Int))
       
   387 				{
       
   388 				CWsClient::ReplyBuf(iInvalid.RectangleList(),(*aCmd.Int) * sizeof(TRect));
       
   389 				SetReply(EFalse);				
       
   390 				}
       
   391 			else
       
   392 				SetReply(ETrue);
       
   393 			}
       
   394 			break;
       
   395 		case EWsWinOpStoreDrawCommands:
       
   396 			/* If the client asks us not to store commands, we still store the commands
       
   397 			for the region of the window which can be seen through the parent, but
       
   398 			won't attempt to obtain the entire window.
       
   399 			*/
       
   400 			if (*aCmd.Bool)
       
   401 				{
       
   402 				SetScope(EStoreEntireWindow);
       
   403 				}
       
   404 			else
       
   405 				{
       
   406 				// Clients that turn their redraw store off will still get one,
       
   407 				// but it will only attempt to store the current viewport.
       
   408 				SetScope(EStoreViewport);
       
   409 				}
       
   410 			break;
       
   411 		case EWsWinOpHandleTransparencyUpdate:  // deprecated
       
   412 		case EWsWinOpSetTransparencyBitmap:	    // deprecated
       
   413 		case EWsWinOpSetTransparencyFactor:		// deprecated
       
   414 		case EWsWinOpSetTransparencyBitmapCWs:  // deprecated
       
   415 			break;    // do nothing.
       
   416 		case EWsWinOpIsRedrawStoreEnabled:
       
   417 			SetReply(ETrue);
       
   418 			break;
       
   419 		case EWsWinOpClearRedrawStore:
       
   420 			DiscardStoredCommands();
       
   421 			break;
       
   422 		default:
       
   423 			return(EFalse);
       
   424 		}
       
   425 	return(ETrue);
       
   426 	}
       
   427 
       
   428 /**
       
   429 */
       
   430 void CWsRedrawMsgWindow::BeginRedraw(const TRect* aRect)
       
   431 	{
       
   432 	if(InRedraw())
       
   433 		OwnerPanic(EWservPanicDrawCommandsInvalidState);
       
   434 	iFlags|=EBeginEndRedraw;
       
   435 	TRAPD(err,DoBeginRedrawL(aRect));
       
   436 	DiscardStoredCommandsIfError(err);
       
   437 	}
       
   438 
       
   439 void CWsRedrawMsgWindow::DoBeginRedrawL(const TRect* aRect)
       
   440 	{
       
   441 	const TRect redrawRect = (aRect ? *aRect : TRect(WsWin()->Size()));
       
   442 	if (redrawRect.IsEmpty())
       
   443 		{
       
   444 		//Skip empty rects since they are not added to the region
       
   445 		iCurrentSegment = NULL;
       
   446 		}
       
   447 	else
       
   448 		{
       
   449 		CreateNewSegmentL(redrawRect, CWsRedrawMsgWindow::ESegmentTypePendingRedraw);
       
   450 		if (iAtomicity==ENoAtomicity)
       
   451 			PromoteLastPendingSegment();
       
   452 		}
       
   453 	}
       
   454 
       
   455 void CWsRedrawMsgWindow::Invalidate(const TRect * aRect)
       
   456 	{
       
   457     //The memory allocation in this function can trigger a call to ReleaseMemory(), which would
       
   458     //recursively call this function again. This would cause a memory leak. To avoid this
       
   459     //we call Lock() to block ReleaseMemory() from this object while executing this function.
       
   460     Lock();
       
   461 	if (!aRect)
       
   462 		{
       
   463 		iInvalid.Clear();
       
   464 		iInvalid.Copy(iWsWin->WindowArea());
       
   465 		iInvalid.Offset(-iWsWin->Origin());
       
   466 		}
       
   467 	else if((!aRect->IsEmpty()) && aRect->IsNormalized())
       
   468 		{
       
   469 		iInvalid.AddRect(*aRect);
       
   470 		iInvalid.Tidy();		
       
   471 		}
       
   472 	if (iWsWin->IsVisible())
       
   473 		{
       
   474 		QueueRedraw();
       
   475 		iWsWin->WsOwner()->TriggerRedraw(); //wtf isn't the redrawq already scheduling itself?
       
   476 		}
       
   477 	Unlock();
       
   478 	}
       
   479 
       
   480 /**
       
   481 If a draw command is received outside a begin/end redraw pair, then it is stored in a non-redraw
       
   482 segment.  This function creates such a segment if it isn't already available.
       
   483 */
       
   484 void CWsRedrawMsgWindow::HandleNonRedrawCommand(TWsGcOpcodes aOpcode)
       
   485 	{
       
   486 	// calling code should check the Window State
       
   487 	WS_ASSERT_DEBUG(!InRedraw(), EWsPanicDrawCommandsInvalidState);
       
   488 	
       
   489 	// Attempting to draw part of a polygon in a new segment - only a very bad client can do this:
       
   490 	TBool canCreate = !(aOpcode == EWsGcOpSegmentedDrawPolygonData || aOpcode == EWsGcOpDrawSegmentedPolygon);
       
   491 	if ((!iCurrentSegment) && (!canCreate))
       
   492 		{
       
   493 		OwnerPanic(EWservPanicBadPolyData);
       
   494 		}
       
   495 
       
   496 	if (canCreate)
       
   497 		AgeNonRedrawSegments();
       
   498 	
       
   499 	// If current redraw region is not for Non-Redraw drawing, add a region corresponding to the
       
   500 	// full window to the redraw store.  Need to make sure that this is done 
       
   501 	// before the AppendCommand, or bitmap/font handles are recorded, in StoreDrawCommandL
       
   502 	TInt err = KErrNone;
       
   503 	if ((!iCurrentSegment) || iCurrentSegment->iRedrawSegmentType != ESegmentTypeNonRedraw)
       
   504 		{
       
   505 		TRAP(err,CreateNewSegmentL(TRect(WsWin()->Size()), ESegmentTypeNonRedraw));
       
   506 		}
       
   507 
       
   508 	if (err != KErrNone)
       
   509 		{
       
   510 		Invalidate();
       
   511 		}
       
   512 
       
   513 	if(iWsWin->VisibleRegion().CheckError())
       
   514 		iWsWin->Screen()->AddRedrawRegion(iWsWin->WindowArea());
       
   515 	else if(iWsWin->VisibleRegion().Count())
       
   516 		iWsWin->Screen()->AddRedrawRegion(iWsWin->VisibleRegion());
       
   517 	else if(!iWsWin->HasBeenDrawnToScreen())
       
   518 		CliWin()->ScheduleRegionUpdate(&iWsWin->VisibleRegion());
       
   519 	}
       
   520 
       
   521 /**
       
   522 This function attempts to prevent non-redraw segments from growing indefinitely by requesting redraws 
       
   523 and throwing away old ones.
       
   524 */
       
   525 void CWsRedrawMsgWindow::AgeNonRedrawSegments()
       
   526   	{
       
   527 	if (!iRedrawSegments.Count())
       
   528 		return;
       
   529 	
       
   530 	//Count the number of non-redraw segs
       
   531 	TInt nonRedrawSegCount = 0;
       
   532 	for (TInt i = iRedrawSegments.Count()-1; i >= 0; --i)
       
   533 		{
       
   534 		CRedrawSegment* segment = iRedrawSegments[i];
       
   535 		if (segment->iRedrawSegmentType == ESegmentTypeNonRedraw)
       
   536 			{
       
   537 			++nonRedrawSegCount; 
       
   538 			}
       
   539 		}
       
   540 	
       
   541 	TBool callInvalidate = EFalse;
       
   542 	
       
   543 	//To prevent the number of non redraw segements to grow indefinitely,
       
   544 	//delete the oldest if their number exceeds KNonRedrawSegMaxLimit
       
   545 	if (nonRedrawSegCount > KNonRedrawSegMaxLimit)
       
   546 		{
       
   547 		TInt keep = KNonRedrawSegThreshold; // keep this many, the most recent ones
       
   548 		for (TInt i = iRedrawSegments.Count()-1; i >= 0; --i)
       
   549 			{
       
   550 			CRedrawSegment* segment = iRedrawSegments[i];
       
   551 			if (segment->iRedrawSegmentType == ESegmentTypeNonRedraw)
       
   552 				{
       
   553 				if (keep-- > 0)
       
   554 					{
       
   555 					continue;
       
   556 					}
       
   557 				else if (segment!=iCurrentSegment) //never delete the current segment
       
   558 					{
       
   559 					callInvalidate = ETrue;
       
   560 					iRedrawSegments.Remove(i);
       
   561 					delete segment;
       
   562 					}
       
   563 				}
       
   564 			}
       
   565 		}
       
   566 
       
   567 	if(iCurrentSegment && iCurrentSegment->iRedrawSegmentType == ESegmentTypeNonRedraw)
       
   568 		{
       
   569 		// If the current segment is an old non-redraw segment, try to get rid of it
       
   570 		TTime now;
       
   571 		now.UniversalTime();
       
   572 		TTimeIntervalMicroSeconds age = now.MicroSecondsFrom(iCurrentSegment->iCreationTime);
       
   573 		if (age > iNonRedrawAgeLimit)
       
   574 			{
       
   575 			// First, find any even older non redraw segments and discard them.
       
   576 			for (TInt seg = iRedrawSegments.Count() - 2; seg >= 0; --seg)
       
   577 				{
       
   578 				CRedrawSegment * segment = iRedrawSegments[seg];
       
   579 				if (segment->iRedrawSegmentType == ESegmentTypeNonRedraw)
       
   580 					{
       
   581 					age = now.MicroSecondsFrom(segment->iCreationTime);
       
   582 					if ((age > iNonRedrawAgeLimit * 2) && (segment!=iCurrentSegment))
       
   583 						{
       
   584 						iRedrawSegments.Remove(seg);
       
   585 						delete segment;
       
   586 						}
       
   587 					}
       
   588 				}
       
   589 			
       
   590 			// Then force the creation of a new segment, so that the current one can be allowed to age and eventually vanish.
       
   591 			iCurrentSegment->iCreationTime = now;
       
   592 			iCurrentSegment = NULL;
       
   593 			callInvalidate = ETrue;
       
   594 			}
       
   595 		}
       
   596 	
       
   597 	if(callInvalidate)
       
   598 		Invalidate(); // Invalidate the window so that a complete redraw should occur
       
   599   	}
       
   600 
       
   601 /**
       
   602 Obtains a region from the redraw store, intersects it with the global redraw region which
       
   603 we have been asked to draw to, and returns the intersection.
       
   604 */
       
   605 const TRegion * CWsRedrawMsgWindow::ReadRegion(const TInt aRegionNum)
       
   606 	{
       
   607 	// Catch anyone calling this without first deciding where they want to draw
       
   608 	WS_ASSERT_DEBUG(iWsWin->ScheduledRegion(), EWsPanicScheduledRedraw);
       
   609 
       
   610 	// We are drawing to the global region, and we have a region in the redraw store to clip to.
       
   611 	// We want the intersection of these to actually draw to.
       
   612 	// Andy - this allocates memory during drawing, which is bad in OOM conditions.
       
   613 	iLocalRedrawRegion.Copy(iRedrawSegments[aRegionNum]->iRegion);
       
   614 	iLocalRedrawRegion.Offset(WsWin()->Origin());
       
   615 	iLocalRedrawRegion.Intersect(*iGlobalRedrawRegion);
       
   616 	iLocalRedrawRegion.Tidy();
       
   617 
       
   618 	// If the resulting region is empty there is no point drawing its corresponding commands
       
   619 	if (iLocalRedrawRegion.IsEmpty())
       
   620 		return NULL;
       
   621 	else
       
   622 		return &iLocalRedrawRegion;
       
   623 	}
       
   624 
       
   625 TInt CWsRedrawMsgWindow::SubtractRectFromSegmentArray(const TRect& aRect)
       
   626 	{
       
   627 	TInt numOfRegionsRemoved =0;
       
   628 	for (TInt regionNum = iRedrawSegments.Count() - 1; regionNum >= 0; --regionNum)
       
   629 		{
       
   630 		if (iRedrawSegments[regionNum]->iRedrawSegmentType != ESegmentTypePendingRedraw)
       
   631 			{
       
   632 			RWsRegion& region = iRedrawSegments[regionNum]->iRegion;
       
   633 			region.SubRect(aRect);
       
   634 			if (region.CheckError())
       
   635 				{
       
   636 				// Ouch. Drop the now broken segment and ask for a full redraw
       
   637 				// Andy - This is an error condition and needs to check for infinite loops
       
   638 				delete iRedrawSegments[regionNum];
       
   639 				iRedrawSegments.Remove(regionNum);
       
   640 				numOfRegionsRemoved++;
       
   641 				Invalidate();
       
   642 				}
       
   643 			else
       
   644 				{
       
   645 				// check if region has zero uncovered rectangles left
       
   646 				if (region.IsEmpty())
       
   647 					{ // delete draw commands, release bitmaps and fonts
       
   648 					delete iRedrawSegments[regionNum];
       
   649 					iRedrawSegments.Remove(regionNum);
       
   650 					numOfRegionsRemoved++;
       
   651 					}
       
   652 				else
       
   653 					{
       
   654 					if (region.Count() > KRegionCompressThreshold)
       
   655 						{ // tidy up the rectangles
       
   656 						region.Tidy();
       
   657 						}
       
   658 					}
       
   659 				}
       
   660 			}
       
   661 		}
       
   662 	return numOfRegionsRemoved;
       
   663 	}
       
   664 
       
   665 /*------------------------------------------------------------------------------
       
   666   Description: Clears out the command buffer if aError indicates an
       
   667                error has occurred whilst storing commands.
       
   668  -----------------------------------------------------------------------------*/
       
   669 void CWsRedrawMsgWindow::DiscardStoredCommandsIfError(TInt aError)
       
   670 	{
       
   671 	if (aError != KErrNone)
       
   672 		{
       
   673 		// Discard stored commands by clearing out the command buffer
       
   674 		DiscardStoredCommands();
       
   675 
       
   676 		if (!(iFlags&ENoRepeatRedraw))
       
   677 			Invalidate();
       
   678 		iFlags |= ENoRepeatRedraw;
       
   679 		}
       
   680 	}
       
   681 
       
   682 /*------------------------------------------------------------------------------
       
   683   Description: If the graphics context has changed and we are currently storing
       
   684                commands, store the data given by aCmdData.
       
   685                
       
   686  -----------------------------------------------------------------------------*/
       
   687 TBool CWsRedrawMsgWindow::DrawCommand(CWsGc* aGc,const TAny *aCmdData)
       
   688 	{
       
   689 	// Store commands, clearing out buffer if error occurs.
       
   690 	TRAPD(err,StoreDrawCommandL(aGc,aCmdData));
       
   691 	DiscardStoredCommandsIfError(err);
       
   692 	return EFalse;
       
   693 	}
       
   694 
       
   695 void CWsRedrawMsgWindow::GcAttributeChange(CWsGc* aGc,const TAny *aCmdData)
       
   696 	{
       
   697 	if (iLastDrawGc == aGc && iCurrentSegment)
       
   698 		{
       
   699 		TInt err = KErrNone;
       
   700 		if (IsWsFontOperation(CWsClient::iCurrentCommand.iOpcode))
       
   701 			{
       
   702 			TWsGcCmdUnion pData;
       
   703 			pData.any=aCmdData;
       
   704 			TRAP(err,AddWsFontL(*pData.UInt));
       
   705 			}
       
   706 		if (KErrNone == err)
       
   707 			TRAP(err,AppendCommandL(aCmdData));
       
   708 		DiscardStoredCommandsIfError(err);
       
   709 		}
       
   710 	
       
   711 	// INC135845: 
       
   712 	// Retain the bitmap handle for the lifetime of the redraw store
       
   713 	// If the client destroys it, we will still have a reference to it
       
   714 	if (iCurrentSegment && CWsClient::iCurrentCommand.iOpcode == EWsGcOpUseBrushPattern)
       
   715 		{
       
   716 		TInt err = KErrNone;
       
   717 		TWsGcCmdUnion pData;
       
   718 		pData.any=aCmdData;
       
   719 		TRAP(err, AddFbsBitmapsL(*pData.handle, 0));
       
   720 		DiscardStoredCommandsIfError(err);
       
   721 		}
       
   722 	}
       
   723 
       
   724 void CWsRedrawMsgWindow::GcDeactivate(CWsGc* aGc)
       
   725 	{
       
   726 	if (iLastDrawGc==aGc)
       
   727 		iLastDrawGc=NULL;
       
   728 	}
       
   729 
       
   730 inline TBool CWsRedrawMsgWindow::IsFbsBitmapOperation(TInt aOpCode) const
       
   731 	{
       
   732 	WS_ASSERT_DEBUG((EWsGcOpGdiBlt3==EWsGcOpGdiBlt2+1)&&(EWsGcOpGdiBltMasked==EWsGcOpGdiBlt3+1)
       
   733 				&&(EWsGcOpDrawBitmap2==EWsGcOpDrawBitmap+1)&&(EWsGcOpDrawBitmap3==EWsGcOpDrawBitmap2+1)&&(EWsGcOpDrawBitmapMasked==EWsGcOpDrawBitmap3+1),EWsPanicBitmapOpcodeInvalid);
       
   734 	return (aOpCode>=EWsGcOpGdiBlt2&&aOpCode<=EWsGcOpGdiBltMasked)||(aOpCode>=EWsGcOpDrawBitmap&&aOpCode<=EWsGcOpDrawBitmapMasked)||(aOpCode==EWsGcOpGdiAlphaBlendBitmaps);
       
   735 	}
       
   736 
       
   737 inline TBool CWsRedrawMsgWindow::IsWsBitmapOperation(TInt aOpCode) const
       
   738 	{
       
   739 	WS_ASSERT_DEBUG((EWsGcOpGdiBlt3==EWsGcOpGdiBlt2+1)&&(EWsGcOpGdiBltMasked==EWsGcOpGdiBlt3+1)
       
   740 				&&(EWsGcOpDrawBitmap2==EWsGcOpDrawBitmap+1)&&(EWsGcOpDrawBitmap3==EWsGcOpDrawBitmap2+1)&&(EWsGcOpDrawBitmapMasked==EWsGcOpDrawBitmap3+1),EWsPanicBitmapOpcodeInvalid);
       
   741 	return (aOpCode>=EWsGcOpGdiWsBlt2&&aOpCode<=EWsGcOpGdiWsBltMasked)||(aOpCode==EWsGcOpGdiWsAlphaBlendBitmaps)||(aOpCode==EWsGcOpWsDrawBitmapMasked);
       
   742 	}
       
   743 
       
   744 inline TBool CWsRedrawMsgWindow::IsWsFontOperation(TInt aOpCode) const
       
   745 	{
       
   746 	return aOpCode==EWsGcOpUseFont;
       
   747 	}
       
   748 
       
   749 inline TBool CWsRedrawMsgWindow::IsDrawWsGraphicOperation(TInt aOpCode) const
       
   750 	{
       
   751 	return (aOpCode == EWsGcOpDrawWsGraphic) || (aOpCode == EWsGcOpDrawWsGraphicPtr);
       
   752 	}
       
   753 
       
   754 void CWsRedrawMsgWindow::ReplaceAndAppendCommandL(TInt aOpcode,const TAny* aCmdData)
       
   755 	{
       
   756 	const TInt KCharWidthInBytes = 2; // # of bytes for a Unicode character
       
   757 	CWsClient* owner=iWsWin->WsOwner();
       
   758 	WS_ASSERT_DEBUG(owner,EWsPanicDrawCommandsNullSession);
       
   759 
       
   760 	// aCmdData doesn't contain data, it should be retrieved from client space using remote read
       
   761 	TWsGcCmdUnion cmd;
       
   762 	cmd.any=aCmdData;
       
   763 	TUint16 newOpcode=EWsGcOpDrawText;
       
   764 	TInt strLen=0;
       
   765 	switch (aOpcode)
       
   766 		{
       
   767 		case EWsGcOpDrawTextPtr:
       
   768 			newOpcode=EWsGcOpDrawText;
       
   769 			strLen=cmd.DrawText->length;
       
   770 			break;
       
   771 		case EWsGcOpDrawTextVerticalPtr:
       
   772 			newOpcode=EWsGcOpDrawTextVertical;
       
   773 			strLen=cmd.DrawTextVertical->length;
       
   774 			break;
       
   775 		case EWsGcOpDrawBoxTextPtr:
       
   776 			newOpcode=EWsGcOpDrawBoxText;
       
   777 			strLen=cmd.BoxText->length;
       
   778 			break;
       
   779 		case EWsGcOpDrawBoxTextVerticalPtr:
       
   780 			newOpcode=EWsGcOpDrawBoxTextVertical;
       
   781 			strLen=cmd.DrawBoxTextVertical->length;
       
   782  			break;
       
   783 		}
       
   784 	TInt strSize = strLen * KCharWidthInBytes;
       
   785 	TInt oldCmdLen=CWsClient::iCurrentCommand.iCmdLength;
       
   786 	TInt newCmdLen=sizeof(TWsCmdHeaderBase)+oldCmdLen+strSize;
       
   787 	// resize buffer
       
   788 	ExpandCommandBufferL(newCmdLen);
       
   789 	// update current command to reflect the new command and data
       
   790 	CWsClient::iCurrentCommand.iOpcode=newOpcode;
       
   791 	CWsClient::iCurrentCommand.iOpcode|=EWsGcOpFlagDrawOp;
       
   792 	CWsClient::iCurrentCommand.iCmdLength=(TInt16)(oldCmdLen+strSize);
       
   793 	// write command header
       
   794 	CommandBufferWrite(&CWsClient::iCurrentCommand, sizeof(TWsCmdHeaderBase));
       
   795 	// write command
       
   796 	CommandBufferWrite(aCmdData, oldCmdLen);
       
   797 
       
   798 	// remote read
       
   799 	TBuf<KReadBufferMaxLen> buf;
       
   800 	TInt len=KReadBufferMaxLen;
       
   801 	TInt bufOffset=0;
       
   802 	TInt toGo=strLen;
       
   803 	while(toGo>0)
       
   804 		{
       
   805 		if (len>toGo)
       
   806 			len=toGo;
       
   807 		owner->RemoteRead(buf,bufOffset);
       
   808 		CommandBufferWrite(buf.Ptr(), len * KCharWidthInBytes);
       
   809 		bufOffset+=len;
       
   810 		toGo-=len;
       
   811 		}
       
   812 	}
       
   813 
       
   814 /*------------------------------------------------------------------------------
       
   815   Description: Stores drawing related commands into the command buffer
       
   816  -----------------------------------------------------------------------------*/
       
   817 void CWsRedrawMsgWindow::StoreDrawCommandL(CWsGc* aGc,const TAny *aCmdData)
       
   818 	{
       
   819 	TWsGcOpcodes currentOpcode = static_cast<TWsGcOpcodes>(CWsClient::iCurrentCommand.iOpcode);
       
   820 
       
   821 	// If we get an extra command after the redraw has finished then redraw strategy needs to know
       
   822 	if (!InRedraw())
       
   823 		{
       
   824 #ifdef __WINS__
       
   825 		TBool isDrawingCommand = (currentOpcode != EWsGcOpSegmentedDrawPolygonData) && (currentOpcode != EWsGcOpDrawSegmentedPolygon);
       
   826 
       
   827 		if( CWsClient::DebugEnforceRedrawCallingConvention() && isDrawingCommand)
       
   828 			CWsClient::PanicCurrentClient(EWservPanicWindowBeginRedrawNotCalled);
       
   829 #endif
       
   830 		HandleNonRedrawCommand(currentOpcode);
       
   831 		}
       
   832 
       
   833 	// If there is no current segment then we have discarded it at some point
       
   834 	// since beginning this redraw.  
       
   835 	if (iCurrentSegment)
       
   836 		{
       
   837 		TWsGcCmdUnion pData;
       
   838 		pData.any = aCmdData;
       
   839 		if (IsFbsBitmapOperation(currentOpcode))
       
   840 			{
       
   841 			TInt maskHandle = 0;
       
   842 			TInt handle = aGc->FbsBitmapHandle(currentOpcode, pData, maskHandle);
       
   843 			AddFbsBitmapsL(handle, maskHandle);
       
   844 			}
       
   845 		else if (IsWsBitmapOperation(currentOpcode))
       
   846 			{
       
   847 			TInt maskHandle = 0;
       
   848 			TInt handle = aGc->WsBitmapHandle(currentOpcode, pData, maskHandle);
       
   849 			AddWsBitmapsL(handle, maskHandle);
       
   850 			}
       
   851 		else if (IsDrawWsGraphicOperation(currentOpcode))
       
   852 			{
       
   853 			TGraphicDrawerId drawerId;
       
   854 			drawerId.iId = pData.WsGraphic->iId;
       
   855 			drawerId.iIsUid = (pData.WsGraphic->iFlags & EWsGraphicIdUid);
       
   856 			iCurrentSegment->AddDrawerL(drawerId);
       
   857 			}
       
   858 
       
   859 		// If the graphics context has changed since last time store the new graphics
       
   860 		// context attributes.
       
   861 		if (aGc != iLastDrawGc)
       
   862 			{
       
   863 			StoreAllGcAttributesL(aGc);
       
   864 			iLastDrawGc = aGc;
       
   865 			}
       
   866 
       
   867 		// For operation which requires remote read from client space, we must retrieve that data and store
       
   868 		// it in command buffer at server side and change opcode if necessary e.g EWsGcOpDrawTextPtr to EWsGcOpDrawText
       
   869 		// to avoid remote read during DoDrawing operation
       
   870 		if (IsRemoteReadRequired(currentOpcode))
       
   871 			ReplaceAndAppendCommandL(currentOpcode,aCmdData);
       
   872 		else
       
   873 			// Append the command data to the command buffer
       
   874 			AppendCommandL(aCmdData, EWsGcOpFlagDrawOp);
       
   875 		}
       
   876 	}
       
   877 
       
   878 /*------------------------------------------------------------------------------
       
   879   Description: Stores given drawing command data into the command buffer.
       
   880  -----------------------------------------------------------------------------*/
       
   881 void CWsRedrawMsgWindow::AppendCommandL(const TAny* aCmdData, const TUint16 aOpcodeFlags)
       
   882 	{
       
   883 	if (CWsClient::iCurrentCommand.iOpcode == EWsGcOpSetClippingRegion)
       
   884 		{
       
   885 		// The client is defining a clipping region
       
   886 
       
   887 		// make room for the header
       
   888 		ExpandCommandBufferL(sizeof(TWsCmdHeaderBase));
       
   889 
       
   890 		// Externalize the clipping region data from position after the header
       
   891 		RBufWriteStream bufWriteStream;
       
   892 		bufWriteStream.Open(*CurrentDrawCommandBuffer(), CurrentCommandBufferWritePos() + sizeof(TWsCmdHeaderBase));
       
   893 		CleanupClosePushL(bufWriteStream);
       
   894 		TInt dataLen = iLastDrawGc->ExternalizeClippingRegionL(bufWriteStream);
       
   895 
       
   896 		// Setup the clipping region data header
       
   897 		CWsClient::iCurrentCommand.iOpcode = EWsStoreClippingRegion;
       
   898 		CWsClient::iCurrentCommand.iCmdLength = REINTERPRET_CAST(TInt16&,dataLen);
       
   899 
       
   900 		// Store command header for clipping region data at current write position
       
   901 		CommandBufferWrite(&CWsClient::iCurrentCommand,sizeof(TWsCmdHeaderBase));
       
   902 
       
   903 		// Update write position for command data
       
   904 		iCurrentSegment->iCurrentCommandBufferWritePos += dataLen;
       
   905 		
       
   906 		CleanupStack::PopAndDestroy(&bufWriteStream);
       
   907 		}
       
   908 	else
       
   909 		{		
       
   910 		TUint16 opcode = CWsClient::iCurrentCommand.iOpcode;
       
   911 		CWsClient::iCurrentCommand.iOpcode |= aOpcodeFlags;
       
   912 
       
   913 		// ensure room in command buffer
       
   914 		ExpandCommandBufferL(sizeof(TWsCmdHeaderBase) + CWsClient::iCurrentCommand.iCmdLength);
       
   915 
       
   916 		// Store command header to current position
       
   917 		CommandBufferWrite(&CWsClient::iCurrentCommand, sizeof(TWsCmdHeaderBase));
       
   918 
       
   919 		// If there's command data (other than header), store it
       
   920 		if (CWsClient::iCurrentCommand.iCmdLength > 0)
       
   921 			{
       
   922 			CommandBufferWrite(aCmdData, CWsClient::iCurrentCommand.iCmdLength);
       
   923 			}
       
   924 
       
   925 		CWsClient::iCurrentCommand.iOpcode = opcode;
       
   926 		}
       
   927 	}
       
   928 
       
   929 
       
   930 /*------------------------------------------------------------------------------
       
   931   Description: Stores graphics context information into the command buffer
       
   932                from the current write position.
       
   933  -----------------------------------------------------------------------------*/
       
   934 void CWsRedrawMsgWindow::StoreAllGcAttributesL(CWsGc* aGc)
       
   935 	{
       
   936 	// In order for the externalize below to work correctly from
       
   937 	// a non-zero position we have to create the header placeholder
       
   938 	ExpandCommandBufferL(sizeof(TWsCmdHeaderBase));
       
   939 
       
   940 	// Externalise GC attribute data. We do this before writing the
       
   941 	// header as we do not know the size of the data yet and it is
       
   942 	// part of the header.
       
   943 	TInt numOfBytesAdded = aGc->ExternalizeL(*CurrentDrawCommandBuffer(),
       
   944 				CurrentCommandBufferWritePos() + sizeof(TWsCmdHeaderBase));
       
   945 
       
   946 	// Setup the header
       
   947 	TWsCmdHeaderBase cmdHeader;
       
   948 	cmdHeader.iCmdLength = (TInt16) numOfBytesAdded;		// as calculated above
       
   949 	cmdHeader.iOpcode = (TInt16) EWsStoreAllGcAttributes;
       
   950 
       
   951 	// Store the header for the GC data into the space we created
       
   952 	CommandBufferWrite(&cmdHeader, sizeof(TWsCmdHeaderBase));
       
   953 
       
   954 	// Update write position for command data
       
   955 	iCurrentSegment->iCurrentCommandBufferWritePos += numOfBytesAdded;
       
   956 	}
       
   957 
       
   958 /*------------------------------------------------------------------------------
       
   959   Description: Loops through the whole of the current command buffer, processing
       
   960                each in turn.
       
   961  -----------------------------------------------------------------------------*/
       
   962 void CWsRedrawMsgWindow::DrawCommandsL()
       
   963 	{
       
   964 	LOG_WINDOW_REDRAW_START(WsWin(), iGlobalRedrawRegion);
       
   965 	WS_ASSERT_DEBUG(iMemoryLock > 0, EWsPanicMemoryLock);
       
   966 	static TBuf8<EClientBufferMaxSize> buf;
       
   967 	TInt regionCount = iRedrawSegments.Count();
       
   968 	
       
   969 	for (TInt regionNum = 0; regionNum < regionCount; ++regionNum)
       
   970 		{
       
   971 		CRedrawSegment* segment = iRedrawSegments[regionNum];
       
   972 		LOG_REDRAW_SEGMENT(regionNum, segment->iRedrawSegmentType);
       
   973 		if (segment->iRedrawSegmentType == ESegmentTypePendingRedraw)
       
   974 			continue;
       
   975 		
       
   976 		// The amount of commands we process is given by the value of the
       
   977 		// current write position rather than the size of the command buffer.
       
   978 		// Note: the write position is incremented as each command is stored and
       
   979 		// will typically be less than the buffer size.
       
   980 		const TInt length = segment->iCurrentCommandBufferWritePos;
       
   981 
       
   982 		// need to draw this region?
       
   983 		const TRegion * localDrawRegion = 0;
       
   984 		if (length)
       
   985 		 	localDrawRegion = ReadRegion(regionNum);
       
   986 		if (localDrawRegion)
       
   987 			{
       
   988 			CPlaybackGc::Instance()->SetTargetRegion(localDrawRegion);
       
   989 			LOG_REDRAW_SEGMENT_REGION(localDrawRegion)
       
   990 			
       
   991 			TWsCmdHeaderBase header;
       
   992 			TInt pos = 0; // Set to first command position in buffer
       
   993 			CBufSeg* drawCmdBuffer = segment->iDrawCommands;
       
   994 
       
   995 #ifdef _DEBUG
       
   996 			// Read the first command header. The associated opcode must always be
       
   997 			// EWsStoreAllGcAttributes as this is always the first stored item.
       
   998 			drawCmdBuffer->Read(pos,&header,sizeof(TWsCmdHeaderBase));
       
   999 			WS_ASSERT_DEBUG(header.iOpcode == EWsStoreAllGcAttributes, EWsPanicDrawCommandsBufferCorrupt);
       
  1000 #endif
       
  1001 
       
  1002 			// Read through remaining commands
       
  1003 			while (pos < length)
       
  1004 				{
       
  1005 				// Get header of command
       
  1006 				drawCmdBuffer->Read(pos, &header, sizeof(TWsCmdHeaderBase));
       
  1007 				pos += sizeof(TWsCmdHeaderBase);
       
  1008 
       
  1009 				switch(header.iOpcode)
       
  1010 					{
       
  1011 					case EWsStoreAllGcAttributes:
       
  1012 						{
       
  1013 						// Header indicates command encapsulates gc data
       
  1014 						CPlaybackGc::Instance()->Reset();
       
  1015 
       
  1016 						// Read gc data
       
  1017 						CPlaybackGc::Instance()->InternalizeL(*drawCmdBuffer,pos);
       
  1018 
       
  1019 						}
       
  1020 						break;
       
  1021 					case EWsStoreClippingRegion:
       
  1022 						{
       
  1023 						// Clipping region data read in from current position via stream
       
  1024 						RBufReadStream bufReadStream;
       
  1025 						bufReadStream.Open(*drawCmdBuffer,pos);
       
  1026 						CleanupClosePushL(bufReadStream);
       
  1027 						CPlaybackGc::Instance()->InternalizeClippingRegionL(bufReadStream);
       
  1028 						CleanupStack::PopAndDestroy(&bufReadStream);
       
  1029 						}
       
  1030 						break;
       
  1031 					default:
       
  1032 						{
       
  1033 						// Another type of command. Read it.
       
  1034 						CWsClient::iCurrentCommand.iCmdLength = header.iCmdLength;
       
  1035 						drawCmdBuffer->Read(pos,buf,header.iCmdLength);
       
  1036 
       
  1037 						TInt opcode = header.iOpcode;
       
  1038 
       
  1039 						// Drawing command?
       
  1040 						if (opcode & EWsGcOpFlagDrawOp)
       
  1041 							{
       
  1042 							opcode &= ~EWsGcOpFlagDrawOp;
       
  1043 							}
       
  1044 						if (opcode > -1)
       
  1045 							{
       
  1046 							LOG_PLAYBACK_GC_COMMAND(opcode, buf.Ptr())
       
  1047 							CPlaybackGc::Instance()->CommandL(static_cast<TWsGcOpcodes>(opcode),buf);
       
  1048 							}
       
  1049 						}
       
  1050 						break;
       
  1051 					}
       
  1052 				pos += header.iCmdLength; // Move on, header indicates length
       
  1053 				}
       
  1054 			DEBUGOSB // per-redraw-segment debug osb updates
       
  1055 			}
       
  1056 		}
       
  1057 	LOG_WINDOW_REDRAW_END(WsWin());
       
  1058 	}
       
  1059 
       
  1060 /*------------------------------------------------------------------------------
       
  1061   Description: Called when the currently stored graphics commands
       
  1062                are no longer required.
       
  1063  -----------------------------------------------------------------------------*/
       
  1064 void CWsRedrawMsgWindow::DiscardStoredCommands()
       
  1065 	{
       
  1066 	iCurrentSegment = NULL;
       
  1067 	if (iRedrawSegments.Count() > 0)
       
  1068 		{
       
  1069 		// First of all, if we have any redraws pending, update the screen with
       
  1070 		// whatever commands we have before we throw them away:
       
  1071 		if (iFlags & EPendingScheduledDraw)
       
  1072 			{
       
  1073 			Screen()->DoRedrawNow();
       
  1074 			}
       
  1075 	
       
  1076 		// for all regions or just Partial Redraw regions > index 0: delete bitmaps and draw commands
       
  1077 		iRedrawSegments.ResetAndDestroy();
       
  1078 
       
  1079 		iLastDrawGc = NULL;
       
  1080 		}
       
  1081 	}
       
  1082 
       
  1083 void CWsRedrawMsgWindow::CreateNewSegmentL(const TRect& aRect, TRedrawSegmentType aNewRedrawRegionType)
       
  1084 	{
       
  1085 	CWsRedrawMsgWindow::CRedrawSegment* newRegion = CWsRedrawMsgWindow::CRedrawSegment::NewLC(aRect, aNewRedrawRegionType);
       
  1086 
       
  1087 	iRedrawSegments.AppendL(newRegion);
       
  1088 	iCurrentSegment = newRegion;
       
  1089 	CleanupStack::Pop(newRegion);
       
  1090 
       
  1091 	// Set iLastDrawGc to NULL. This will cause all GC attributes to be stored
       
  1092 	// in redraw store when the window receives the next command
       
  1093 	iLastDrawGc = NULL;
       
  1094 	}
       
  1095 
       
  1096 static TInt FindBitmapByHandle(const TInt* aKey, const CFbsBitmap& aBitmap)
       
  1097 	{ // compare handles
       
  1098 	return *aKey - aBitmap.Handle();
       
  1099 	}
       
  1100 
       
  1101 static TInt InsertBitmapByHandle(const CFbsBitmap& aFirst, const CFbsBitmap& aSecond)
       
  1102 	{
       
  1103 	return aFirst.Handle() - aSecond.Handle();
       
  1104 	}
       
  1105 
       
  1106 void CWsRedrawMsgWindow::AddFbsBitmapsL(TInt aHandle, TInt aMaskHandle)
       
  1107 	{
       
  1108 	iCurrentSegment->AddFbsBitmapL(aHandle, this);
       
  1109 	if (aMaskHandle)
       
  1110 		{
       
  1111 		iCurrentSegment->AddFbsBitmapL(aMaskHandle, this);
       
  1112 		}
       
  1113 	}
       
  1114 
       
  1115 void CWsRedrawMsgWindow::CRedrawSegment::AddFbsBitmapL(TInt aHandle, CWsRedrawMsgWindow* aWindow)
       
  1116 	{
       
  1117 	if (iFbsBitmapArray.FindInOrder(aHandle, &FindBitmapByHandle) >= 0)
       
  1118 		{
       
  1119 		// Bitmap already in the store
       
  1120 		return;
       
  1121 		}
       
  1122 
       
  1123 	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
       
  1124 	CleanupStack::PushL(bitmap);
       
  1125 	if (bitmap->Duplicate(aHandle)!=KErrNone)
       
  1126 		aWindow->OwnerPanic(EWservPanicBitmap);
       
  1127 	iFbsBitmapArray.InsertInOrderL(bitmap, TLinearOrder<CFbsBitmap>(InsertBitmapByHandle));
       
  1128 	CleanupStack::Pop(bitmap);
       
  1129 	}
       
  1130 
       
  1131 void CWsRedrawMsgWindow::AddWsBitmapsL(TInt aHandle, TInt aMaskHandle)
       
  1132 	{
       
  1133 	if (iWsWin->WsOwner() == NULL)
       
  1134 		Panic(EWsPanicDrawCommandsInvalidState);
       
  1135 	DWsBitmap * bmp = static_cast<DWsBitmap*>(iWsWin->WsOwner()->HandleToObj(aHandle, WS_HANDLE_BITMAP));
       
  1136 	if (!bmp)
       
  1137 		OwnerPanic(EWservPanicBitmap);
       
  1138 	iCurrentSegment->AddWsBitmapL(bmp);
       
  1139 	if (aMaskHandle)
       
  1140 		{
       
  1141 		bmp = static_cast<DWsBitmap*>(iWsWin->WsOwner()->HandleToObj(aMaskHandle, WS_HANDLE_BITMAP));
       
  1142 		if (!bmp)
       
  1143 			OwnerPanic(EWservPanicBitmap);
       
  1144 		iCurrentSegment->AddWsBitmapL(bmp);
       
  1145 		}
       
  1146 	}
       
  1147 
       
  1148 void CWsRedrawMsgWindow::CRedrawSegment::AddWsBitmapL(DWsBitmap* bitmap)
       
  1149 	{
       
  1150 	iWsBitmapArray.AppendL(bitmap);
       
  1151 	bitmap->IncRefCount();
       
  1152 	}
       
  1153 
       
  1154 void CWsRedrawMsgWindow::AddWsFontL(TInt aHandle)
       
  1155 	{
       
  1156 	if (iWsWin->WsOwner()==NULL)
       
  1157 		Panic(EWsPanicDrawCommandsInvalidState);
       
  1158 	TDblQueIter<CWsFbsFont> iter(CWsFontCache::List());
       
  1159 	CWsFbsFont* font=NULL;
       
  1160 	while((font=iter++)!=NULL)
       
  1161 		{
       
  1162 		if (font->Handle()==aHandle)
       
  1163 			break;
       
  1164 		}
       
  1165 	if (font)
       
  1166 		{
       
  1167 		iCurrentSegment->iWsFontArray.AppendL(font);
       
  1168 		++(font->iCount);
       
  1169 		}
       
  1170 	}
       
  1171 
       
  1172 void CWsRedrawMsgWindow::CRedrawSegment::AddDrawerL(TGraphicDrawerId aDrawerId)
       
  1173 	{
       
  1174 	TInt error = iDrawerArray.InsertInOrder(aDrawerId, TLinearOrder<TGraphicDrawerId>(TGraphicDrawerId::Compare));
       
  1175 	if (error != KErrAlreadyExists && error != KErrNone)
       
  1176 		{
       
  1177 		User::Leave(error);
       
  1178 		}
       
  1179 	}
       
  1180 
       
  1181 TBool CWsRedrawMsgWindow::CRedrawSegment::ContainsDrawers(const TArray<TGraphicDrawerId>& aDrawers,const TRegion& aRegion) const
       
  1182 	{
       
  1183 	TBool result = EFalse;
       
  1184 	if (iDrawerArray.Count() > 0)
       
  1185 		{
       
  1186 		STACK_REGION tempRegion;
       
  1187 		tempRegion.Intersection(iRegion, aRegion);
       
  1188 		if (tempRegion.CheckError() || (tempRegion.Count() > 0) )
       
  1189 			{ // regions do intersect, (presumed if region had an error); so check for a matching Id
       
  1190 			const TInt drawersCount = aDrawers.Count();
       
  1191 			for (TInt idx = 0; idx < drawersCount; ++idx)
       
  1192 				{ // (iDrawerArray is kept sorted)
       
  1193 				if (KErrNotFound != iDrawerArray.FindInOrder(aDrawers[idx], TLinearOrder<TGraphicDrawerId>(TGraphicDrawerId::Compare)))
       
  1194 					{
       
  1195 					result = ETrue;
       
  1196 					break;
       
  1197 					}
       
  1198  					
       
  1199 				const TInt count = iDrawerArray.Count();
       
  1200 				for(TInt i = 0; i < count; i++)
       
  1201 					{
       
  1202 					const CWsGraphicDrawer* drawer = CWsTop::WindowServer()->ResolveGraphic(iDrawerArray[i]);
       
  1203 					if(drawer && drawer->Contains(aDrawers))
       
  1204 						{
       
  1205 						result = ETrue;
       
  1206 						break;
       
  1207 						}
       
  1208 					}
       
  1209 				}
       
  1210 			}
       
  1211 		tempRegion.Close();
       
  1212 		}
       
  1213 	return result;
       
  1214 	}
       
  1215 
       
  1216 inline TBool CWsRedrawMsgWindow::NoBuffer() const
       
  1217 	{
       
  1218 	return (iRedrawSegments.Count() == 0);
       
  1219 	}
       
  1220 
       
  1221 void CWsRedrawMsgWindow::ClientExposing()
       
  1222 	{
       
  1223 	Invalidate();
       
  1224 	}
       
  1225 
       
  1226 /*------------------------------------------------------------------------------
       
  1227   Description: If a complete set of drawing commands have been stored
       
  1228                this method attempts to draw ALL the commands via DrawCommandsL().
       
  1229                It also draws the window in the background colour if the window is
       
  1230                opaque.
       
  1231  -----------------------------------------------------------------------------*/
       
  1232 void CWsRedrawMsgWindow::DrawWindow()
       
  1233 	{
       
  1234 	iFlags &= ~EPendingScheduledDraw;
       
  1235 	// This is a happy window - it can draw itself whenever we ask.
       
  1236 	if(iFlags&EBackgroundClear)
       
  1237 		{
       
  1238 		DrawBackgroundColor(iGlobalRedrawRegion);
       
  1239 		}
       
  1240 	// If valid commands have been stored, draw them.
       
  1241 	if (iRedrawSegments.Count() > 0)
       
  1242 		{
       
  1243 		Lock();
       
  1244 		TRAP_IGNORE(DrawCommandsL());
       
  1245 		Unlock();
       
  1246 		}
       
  1247 	}
       
  1248 
       
  1249 void CWsRedrawMsgWindow::RemoveFromRedrawQueueIfEmpty()
       
  1250 	{
       
  1251 	if (iInvalid.Count()==0)
       
  1252 		{
       
  1253 		iInvalid.Clear();	// Ensures heap cell is freed, otherwise may be left as an empty cell
       
  1254 		iWsWin->WsOwner()->RedrawQueue()->RemoveInvalid(this);
       
  1255 		}
       
  1256 	}
       
  1257 
       
  1258 TBool CWsRedrawMsgWindow::NeedsRedraw() const
       
  1259 // If iInvalid has an persistant error it will not be reported as needing a redraw,
       
  1260 // this is needed as otherwise cases where validation of a window results
       
  1261 // in iInvalid having an error will get into an endless cycle of redraws.
       
  1262 // The down side of this is that sometimes a window will not be sent a redraw
       
  1263 // message when it needs it, some things can't be perfect!
       
  1264 //
       
  1265 	{
       
  1266 	if ((!iWsWin->IsVisible()) || iInvalid.IsEmpty())
       
  1267 		return EFalse;
       
  1268 	
       
  1269 	TRect nextRedrawRect;
       
  1270 	return GetRedrawRect(nextRedrawRect);
       
  1271 	}
       
  1272 
       
  1273 TBool CWsRedrawMsgWindow::GetRedrawRect(TRect &aRect) const
       
  1274 	{
       
  1275 	if (iWsWin->ClientSetInvisible())
       
  1276 		return EFalse;
       
  1277 	
       
  1278 	if(InRedraw())
       
  1279 		{
       
  1280 		aRect = iRedrawRect;
       
  1281 		return (!aRect.IsEmpty());
       
  1282 		}
       
  1283 	else if(iInvalid.CheckError())
       
  1284 		{
       
  1285 		if (iFlags & EStoringEntireWindow || iWsWin->VisibleRegion().CheckError())
       
  1286 			{
       
  1287 			aRect = iWsWin->AbsRect();
       
  1288 			}
       
  1289 		else
       
  1290 			{
       
  1291 			aRect = iWsWin->VisibleRegion().BoundingRect();
       
  1292 			}
       
  1293 		if (!(iFlags & EStoringEntireWindow))
       
  1294 			iWsWin->ClipRectToViewport(aRect);
       
  1295 		aRect.Move(-iWsWin->Origin());
       
  1296 		return (!aRect.IsEmpty());
       
  1297 		}
       
  1298 	else if(iInvalid.Count())
       
  1299 		{
       
  1300 		if (iFlags & EStoringEntireWindow)
       
  1301 			{
       
  1302 			aRect = iInvalid.BoundingRect();
       
  1303 			}
       
  1304 		else
       
  1305 			{
       
  1306 			RWsRegion region;
       
  1307 			region.Copy(iInvalid);
       
  1308 			region.Offset(iWsWin->Origin());
       
  1309 			region.Intersect(iWsWin->VisibleRegion());
       
  1310 			if (region.CheckError())
       
  1311 				{
       
  1312 				aRect = iInvalid.BoundingRect();
       
  1313 				aRect.Move(iWsWin->Origin());
       
  1314 				}
       
  1315 			else
       
  1316 				{
       
  1317 				aRect = region.BoundingRect();
       
  1318 				}
       
  1319 			region.Close();
       
  1320 			iWsWin->ClipRectToViewport(aRect);
       
  1321 			aRect.Move(-iWsWin->Origin());
       
  1322 			}
       
  1323 		return (!aRect.IsEmpty());
       
  1324 		}
       
  1325 	else
       
  1326 		{
       
  1327 		return EFalse;
       
  1328 		}
       
  1329 	}
       
  1330 
       
  1331 void CWsRedrawMsgWindow::ClipInvalidRegion(const TRect &aRect)
       
  1332 	{
       
  1333 	if (iInvalid.Count()>0)
       
  1334 		{
       
  1335 		iInvalid.ClipRect(aRect);
       
  1336 		RemoveFromRedrawQueueIfEmpty();
       
  1337 		}
       
  1338 	}
       
  1339 
       
  1340 void CWsRedrawMsgWindow::EndRedraw()
       
  1341 	{
       
  1342 	++iCount;
       
  1343 	if(!InRedraw())
       
  1344 		OwnerPanic(EWservPanicDrawCommandsInvalidState);
       
  1345 	if (iCurrentSegment)
       
  1346 		{
       
  1347 		iCurrentSegment->iDrawCommands->Compress();
       
  1348 		if (iAtomicity==ENoAtomicity)
       
  1349 			{
       
  1350 			ScheduleUpdateOfSegment(iCurrentSegment);
       
  1351 			}
       
  1352 		else if(iAtomicity==ESegment)
       
  1353 			{
       
  1354 			PromoteLastPendingSegment();
       
  1355 			ScheduleUpdateOfSegment(iCurrentSegment);
       
  1356 			}
       
  1357 		else if(iAtomicity==EWindow)
       
  1358 			{
       
  1359 			//only promote all pending segments when there are no invalid regions left in the window.
       
  1360 			STACK_REGION regionAwaitingRedraws;
       
  1361 			regionAwaitingRedraws.Copy(WsWin()->VisibleRegion());
       
  1362 			regionAwaitingRedraws.Offset(-WsWin()->Origin());
       
  1363 			regionAwaitingRedraws.Intersect(iInvalid);
       
  1364 			if(regionAwaitingRedraws.IsEmpty())
       
  1365 				PromoteAndUpdateAllPendingSegments();
       
  1366 			regionAwaitingRedraws.Close();
       
  1367 			}
       
  1368 		}
       
  1369 
       
  1370 	iCurrentSegment = NULL;
       
  1371 	iFlags&=~(ENoRepeatRedraw|EBeginEndRedraw);
       
  1372 	}
       
  1373 
       
  1374 void CWsRedrawMsgWindow::ScheduleUpdateOfSegment(CRedrawSegment* aSegment)
       
  1375 	{
       
  1376 	// Schedule an update of the area of the screen we just drew to:
       
  1377 	iFlags |= EPendingScheduledDraw;
       
  1378 	if(iWsWin->VisibleRegion().Count() || iWsWin->VisibleRegion().CheckError())
       
  1379 		{
       
  1380 		STACK_REGION draw; //### in low memory where VisibleRegion() is intact we can degrade much better than this!
       
  1381 		draw.Copy(aSegment->iRegion);
       
  1382 		draw.Offset(iWsWin->Origin());
       
  1383 		draw.Intersect(iWsWin->VisibleRegion());
       
  1384 		if(!draw.CheckError())
       
  1385 			Screen()->AddRedrawRegion(draw);
       
  1386 		else
       
  1387 			Screen()->AddRedrawRegion(iWsWin->VisibleRegion());
       
  1388 		draw.Close();
       
  1389 		}
       
  1390 	}
       
  1391 	
       
  1392 void CWsRedrawMsgWindow::ValidateRect(const TRect *aRect)
       
  1393 	{
       
  1394 	if (!WsWin()->BaseParent())
       
  1395 		OwnerPanic(EWservPanicParentDeleted);
       
  1396 	if (aRect)
       
  1397 		iRedrawRect = *aRect;
       
  1398 	if (!iInvalid.IsEmpty())
       
  1399 		{
       
  1400 		STACK_REGION validated;
       
  1401 		validated.Copy(iInvalid);
       
  1402 		if (aRect)
       
  1403 			validated.ClipRect(iRedrawRect);
       
  1404 		
       
  1405 		if (iInvalid.CheckError())
       
  1406 			{
       
  1407 			iInvalid.Copy(iWsWin->VisibleRegion());
       
  1408 			iInvalid.Offset(-iWsWin->Origin());
       
  1409 			}
       
  1410 		iInvalid.SubRegion(validated);
       
  1411 		validated.Close();		
       
  1412 		}
       
  1413 	RemoveFromRedrawQueueIfEmpty();
       
  1414 	}
       
  1415 
       
  1416 TRgb CWsRedrawMsgWindow::BackColor() const
       
  1417 	{
       
  1418 	return(iBackColor);
       
  1419 	}
       
  1420 
       
  1421 /**
       
  1422 This function used to be quite clever about what it invalidated and what it redrew by copying
       
  1423 rectangles of the screen around.  This is a lot less subtle, and makes calling Scroll pretty much
       
  1424 pointless, but it IS functionally correct.
       
  1425 */
       
  1426 void CWsRedrawMsgWindow::Scroll(const TRect &aClipRect, const TPoint &aOffset,const TRect &aRect)
       
  1427 	{
       
  1428 	TRect rect = aRect;
       
  1429 	rect.Intersection(aClipRect);	
       
  1430 	Invalidate(&rect);
       
  1431 	rect = aRect;
       
  1432 	rect.Move(aOffset);
       
  1433 	rect.Intersection(aClipRect);
       
  1434 	Invalidate(&rect);
       
  1435 	}
       
  1436 
       
  1437 void CWsRedrawMsgWindow::ClearRedrawStore(TBool aClearPendingRedraw)
       
  1438 	{
       
  1439 	if(aClearPendingRedraw && (iFlags & EPendingScheduledDraw))
       
  1440 		iFlags &= ~EPendingScheduledDraw;
       
  1441 
       
  1442 	DiscardStoredCommands();
       
  1443 	Invalidate();
       
  1444 	}
       
  1445 
       
  1446 
       
  1447 void CWsRedrawMsgWindow::PrepareForResizeL(const TSize& aSize, TSize& /*aOldSize*/)
       
  1448 	{
       
  1449 	TBool anyIncreases(EFalse);
       
  1450 	if (aSize.iWidth>iWsWin->Size().iWidth||aSize.iHeight>iWsWin->Size().iHeight)
       
  1451 		{
       
  1452 		anyIncreases = ETrue;
       
  1453 		}
       
  1454 
       
  1455 	TRect newWinRect(TPoint(0,0),aSize);
       
  1456 	iInvalid.ClipRect(newWinRect);
       
  1457 	if (anyIncreases)
       
  1458 		{
       
  1459 		// add new invalid region to iInvalid
       
  1460 		iInvalid.AddRect(newWinRect);
       
  1461 		QueueRedraw();
       
  1462 		iWsWin->WsOwner()->TriggerRedraw();
       
  1463 		}
       
  1464 	}
       
  1465 
       
  1466 void CWsRedrawMsgWindow::Moved()
       
  1467 	{
       
  1468 	if (!(iFlags & EStoringEntireWindow))
       
  1469 		{
       
  1470 		DiscardSegmentsOutsideViewport();
       
  1471 		}
       
  1472 	if (iInvalid.Count())
       
  1473 		{
       
  1474 		QueueRedraw();
       
  1475 		iWsWin->WsOwner()->TriggerRedraw();
       
  1476 		}
       
  1477 	}
       
  1478 
       
  1479 TBool CWsRedrawMsgWindow::Contains(const TArray<TGraphicDrawerId>& aDrawers,const TRegion& aRegion) const
       
  1480 	{
       
  1481 	if (iRedrawSegments.Count() > 0)
       
  1482 		{
       
  1483 		// scan redraw store: calls Contains() on every region drawing commands are stored for,
       
  1484 		// looking for a DrawWsGraphic command that intersects the aRegion
       
  1485 		TBool contains = EFalse;
       
  1486 		const TInt regionCount = iRedrawSegments.Count();
       
  1487 		// loop through regions, stops when a match is found
       
  1488 		for (TInt regionNum = 0; (regionNum < regionCount) && !contains; ++regionNum)
       
  1489 			{
       
  1490 			contains = iRedrawSegments[regionNum]->ContainsDrawers(aDrawers, aRegion);
       
  1491 			}
       
  1492 		return contains;
       
  1493 		}
       
  1494 	else
       
  1495 		{
       
  1496 		return CWsWindowRedraw::Contains(aDrawers,aRegion);
       
  1497 		}
       
  1498 	}
       
  1499 
       
  1500 
       
  1501 void CWsRedrawMsgWindow::SetScope(TScope aScope)
       
  1502 	{
       
  1503 	if (aScope == EStoreEntireWindow)
       
  1504 		{
       
  1505 		if (!(iFlags & EStoringEntireWindow))
       
  1506 			{
       
  1507 			iFlags |= EStoringEntireWindow;
       
  1508 			Invalidate();
       
  1509 			}
       
  1510 		}
       
  1511 	else
       
  1512 		{
       
  1513 		if (iFlags & EStoringEntireWindow)
       
  1514 			{
       
  1515 			iFlags &= ~ EStoringEntireWindow;
       
  1516 			DiscardSegmentsOutsideViewport();
       
  1517 			}
       
  1518 		}
       
  1519 	}
       
  1520 
       
  1521 /**
       
  1522 Removes all segments from the redraw store which are outside the viewport onto the window.
       
  1523 Note that this doesn't clip the regions of those segments which are partly outside, since
       
  1524 this wouldn't actually achieve anything useful.
       
  1525 
       
  1526 This function allocates memory so it is not suitable to run as part of ReleaseMemory.
       
  1527 */
       
  1528 TBool CWsRedrawMsgWindow::DiscardSegmentsOutsideViewport()
       
  1529 	{
       
  1530 	TBool discarded = EFalse;
       
  1531 	TInt count = iRedrawSegments.Count();
       
  1532 	STACK_REGION viewport;
       
  1533 	CliWin()->SetClippedBaseArea(viewport);
       
  1534 	viewport.Offset(-iWsWin->Origin());
       
  1535 	STACK_REGION intersect;
       
  1536 	for (TInt idx = count - 1; idx >= 0; --idx)
       
  1537 		{
       
  1538 		CRedrawSegment * segment = iRedrawSegments[idx];
       
  1539 		intersect.Intersection(segment->iRegion, viewport);
       
  1540 		if (!intersect.CheckError() && intersect.IsEmpty())
       
  1541 			{
       
  1542 			iInvalid.Union(segment->iRegion);
       
  1543 			delete segment;
       
  1544 			iRedrawSegments.Remove(idx);
       
  1545 			if (iCurrentSegment == segment)
       
  1546 				iCurrentSegment = NULL;
       
  1547 			discarded = ETrue;
       
  1548 			}
       
  1549 		}
       
  1550 	intersect.Close();
       
  1551 	viewport.Close();
       
  1552 	return discarded;
       
  1553 	}
       
  1554 
       
  1555 /**
       
  1556 Statements encapsulated in between Lock() and Unlock() is guaranteed to execute in an 
       
  1557 atomic way without being interupted by a call to ReleaseMemory from CWsMemoryManager. 
       
  1558 Locking will prevent memory belonging to this object to be freed during a 
       
  1559 memory alloc/realloc originating from self.
       
  1560 */
       
  1561 void CWsRedrawMsgWindow::Lock()
       
  1562 	{
       
  1563 	++iMemoryLock;
       
  1564 	}
       
  1565 	
       
  1566 void CWsRedrawMsgWindow::Unlock()
       
  1567 	{
       
  1568 	--iMemoryLock;
       
  1569 	WS_ASSERT_DEBUG(iMemoryLock >= 0, EWsPanicMemoryLock);
       
  1570 	}
       
  1571 
       
  1572 TBool CWsRedrawMsgWindow::ReleaseMemory(MWsMemoryRelease::TMemoryReleaseLevel aLevel)
       
  1573 	{
       
  1574 	//When this function is called, wserv is in the middle of executing something.
       
  1575 	//Therefore we can not safely do anything that alters the state of any shared 
       
  1576 	//resouces (like e.g. CScreenRedraw::iInvalid).
       
  1577 	//In addition, we should refrain from anything that might try to allocate memory.
       
  1578 	TBool released = EFalse;
       
  1579 	//Don't release iRedrawSegments from this win if its currently being rendered, 
       
  1580 	//is releasing memory or is receiving drawcommands.
       
  1581 	if (iMemoryLock == 0 && !iCurrentSegment)
       
  1582 		{
       
  1583 		Lock();
       
  1584 		switch (aLevel)
       
  1585 			{
       
  1586 			case MWsMemoryRelease::ELow:
       
  1587 				break;
       
  1588 			case MWsMemoryRelease::EMedium:
       
  1589 				break;
       
  1590 			case MWsMemoryRelease::EHigh:
       
  1591 				//Only release memory from background windows.
       
  1592 				if (iRedrawSegments.Count() > 0 && iWsWin->VisibleRegion().IsEmpty())
       
  1593 					{
       
  1594 					ReleaseRedrawSegments();
       
  1595 					released = ETrue;
       
  1596 					}
       
  1597 				break;
       
  1598 			}
       
  1599 		Unlock();
       
  1600 		}
       
  1601 	return released;
       
  1602 	}
       
  1603 
       
  1604 void CWsRedrawMsgWindow::ReleaseRedrawSegments()
       
  1605 	{
       
  1606  	iLastDrawGc = NULL;
       
  1607  	iCurrentSegment = NULL;
       
  1608  	iRedrawSegments.ResetAndDestroy();
       
  1609  	
       
  1610  	//The call to ResetAndDestroy just freed some memory so it should be 
       
  1611  	//possible to call Invalidate() now.
       
  1612  	Invalidate(); 
       
  1613  	
       
  1614  	//Releasing the same window over and over again could quickly end up in 
       
  1615  	//a never ending loop with a high-prio client before we find the window
       
  1616  	//that has nicked all memory. So call accessed now to prevent that.
       
  1617  	iWsWin->Accessed(); 
       
  1618    	}
       
  1619 
       
  1620 void CWsRedrawMsgWindow::VisibleRegionChange()
       
  1621 	{
       
  1622 	if (!iFlags & EStoringEntireWindow)
       
  1623 		{
       
  1624 		DiscardSegmentsOutsideViewport();
       
  1625 		}
       
  1626 	if ((!iInvalid.IsEmpty()) && (!iWsWin->VisibleRegion().IsEmpty()))
       
  1627 		{
       
  1628 		STACK_REGION exposed;
       
  1629 		exposed.Copy(iInvalid);
       
  1630 		exposed.Offset(iWsWin->Origin());
       
  1631 		exposed.Intersect(iWsWin->VisibleRegion());
       
  1632 		if (!exposed.IsEmpty())
       
  1633 			{
       
  1634 			QueueRedraw();
       
  1635 			}
       
  1636 		exposed.Close();
       
  1637 		}
       
  1638 	}
       
  1639 	
       
  1640 TBool CWsRedrawMsgWindow::ReadyToDraw() const
       
  1641 	{
       
  1642 	//We are only ready to draw when we have a complete segment.
       
  1643 	if (iWsWin->HasBeenDrawnToScreen())
       
  1644 		return ETrue;
       
  1645 	
       
  1646 	if (iRedrawSegments.Count() == 0)
       
  1647 		return EFalse;
       
  1648 	
       
  1649 	if (iRedrawSegments.Count() > 1)
       
  1650 		return ETrue;
       
  1651 	
       
  1652 	if (iRedrawSegments[0]->iRedrawSegmentType == ESegmentTypePendingRedraw)
       
  1653 		return EFalse;
       
  1654 	
       
  1655 	return ETrue;
       
  1656 	}
       
  1657 
       
  1658 TInt CWsRedrawMsgWindow::SizeInBytes() const
       
  1659 	{
       
  1660 	TInt size = sizeof(CWsRedrawMsgWindow);
       
  1661 	for(TInt i = iRedrawSegments.Count()-1; i >= 0; i--)
       
  1662 		{
       
  1663 		size += iRedrawSegments[i]->SizeInBytes();
       
  1664 		}
       
  1665 	size += iInvalid.Count() * sizeof(TRect);
       
  1666 	size += iLocalRedrawRegion.Count() * sizeof(TRect);
       
  1667 	return size;
       
  1668 	}
       
  1669 
       
  1670 void CWsRedrawMsgWindow::PromoteLastPendingSegment()
       
  1671 	{
       
  1672 	if (iRedrawSegments.Count() > 0 && iRedrawSegments[iRedrawSegments.Count() - 1]->iRedrawSegmentType == ESegmentTypePendingRedraw)
       
  1673 		{
       
  1674 		CRedrawSegment * segment = iRedrawSegments[iRedrawSegments.Count() - 1];
       
  1675 		const TRect * rect = segment->iRegion.RectangleList();
       
  1676 		// when we get here there should only ever be one rectangle in the region, but we are playing safe
       
  1677 		for (TInt r = 0; r < segment->iRegion.Count(); ++r)
       
  1678 			{
       
  1679 			SubtractRectFromSegmentArray(*rect);			
       
  1680 			++rect;
       
  1681 			}
       
  1682 		segment->iRedrawSegmentType = ESegmentTypeRedraw;
       
  1683 		}
       
  1684 	}
       
  1685 	
       
  1686 void CWsRedrawMsgWindow::PromoteAndUpdateAllPendingSegments()
       
  1687 	{
       
  1688 	for(TInt i =0; i<iRedrawSegments.Count(); i++)
       
  1689 		{
       
  1690 		CRedrawSegment * segment = iRedrawSegments[i];
       
  1691 		if (segment->iRedrawSegmentType == ESegmentTypePendingRedraw)
       
  1692 			{
       
  1693 			const TRect * rect = segment->iRegion.RectangleList();
       
  1694 			TInt totalRemovedSegments = 0;
       
  1695 			for (TInt r = 0; r < segment->iRegion.Count(); ++r)
       
  1696 				{
       
  1697 				totalRemovedSegments += SubtractRectFromSegmentArray(*rect);			
       
  1698 				++rect;
       
  1699 				}
       
  1700 			//we need to decrement the loop count to take into account any removed segments so we
       
  1701 			//make sure we iterate over every segment in the array.
       
  1702 			i-=totalRemovedSegments;
       
  1703 			segment->iRedrawSegmentType = ESegmentTypeRedraw;
       
  1704 			ScheduleUpdateOfSegment(segment);
       
  1705 			}
       
  1706 		}
       
  1707 	}