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