1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
23
* Patrick C. Beard <beard@netscape.com>
24
* Kevin McCluskey <kmcclusk@netscape.com>
25
* Robert O'Callahan <roc+@cs.cmu.edu>
26
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
28
* Alternatively, the contents of this file may be used under the terms of
29
* either the GNU General Public License Version 2 or later (the "GPL"), or
30
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31
* in which case the provisions of the GPL or the LGPL are applicable instead
32
* of those above. If you wish to allow use of your version of this file only
33
* under the terms of either the GPL or the LGPL, and not to allow others to
34
* use your version of this file under the terms of the NPL, indicate your
35
* decision by deleting the provisions above and replace them with the notice
36
* and other provisions required by the GPL or the LGPL. If you do not delete
37
* the provisions above, a recipient may use your version of this file under
38
* the terms of any one of the NPL, the GPL or the LGPL.
40
* ***** END LICENSE BLOCK ***** */
42
#include "nsViewManager.h"
43
#include "nsUnitConversion.h"
44
#include "nsIRenderingContext.h"
45
#include "nsIDeviceContext.h"
46
#include "nsGfxCIID.h"
47
#include "nsIScrollableView.h"
49
#include "nsISupportsArray.h"
50
#include "nsICompositeListener.h"
52
#include "nsIEventQueue.h"
53
#include "nsIEventQueueService.h"
54
#include "nsIServiceManager.h"
55
#include "nsGUIEvent.h"
56
#include "nsIPrefBranch.h"
57
#include "nsIPrefService.h"
60
#include "nsScrollPortView.h"
62
static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID);
63
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
64
static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
65
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
70
DeCOMify newly private methods
75
A note about platform assumptions:
77
We assume all native widgets are opaque.
79
We assume that a widget is z-ordered on top of its parent.
81
We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
82
we ask for a specific z-order, we don't assume that widget z-ordering actually works.
85
// if defined widget changes like moves and resizes are defered until and done
87
//#define CACHE_WIDGET_CHANGES
90
#define VIEW_RENDERED 0x00000001
91
#define PUSH_CLIP 0x00000002
92
#define POP_CLIP 0x00000004
93
#define VIEW_TRANSPARENT 0x00000008
94
#define VIEW_TRANSLUCENT 0x00000010
95
#define VIEW_CLIPPED 0x00000020
96
// used only by CanScrollWithBitBlt
97
#define VIEW_ISSCROLLED 0x00000040
98
#define PUSH_FILTER 0x00000080
99
#define POP_FILTER 0x00000100
101
#define NSCOORD_NONE PR_INT32_MIN
103
#define SUPPORT_TRANSLUCENT_VIEWS
106
This class represents an offscreen buffer which may have an alpha channel.
107
Currently, if an alpha channel is required, we implement it by rendering into
108
two buffers: one with a black background, one with a white background. We can
109
recover the alpha values by comparing corresponding final values for each pixel.
111
class BlendingBuffers {
113
BlendingBuffers(nsIRenderingContext* aCleanupContext);
116
// used by the destructor to cleanup resources
117
nsCOMPtr<nsIRenderingContext> mCleanupContext;
118
// The primary rendering context. When an alpha channel is in use, this
119
// holds the black background.
120
nsCOMPtr<nsIRenderingContext> mBlackCX;
121
// Only used when an alpha channel is required; holds the white background.
122
nsCOMPtr<nsIRenderingContext> mWhiteCX;
124
PRBool mOwnBlackSurface;
125
// drawing surface for mBlackCX
126
nsDrawingSurface mBlack;
127
// drawing surface for mWhiteCX
128
nsDrawingSurface mWhite;
130
// The offset within the current widget at which this buffer will
131
// eventually be composited
135
// A DisplayListElement2 records the information needed to paint one view.
136
// Note that child views get their own DisplayListElement2s; painting a view
137
// paints that view's frame and all its child frames EXCEPT for the child frames
138
// that have their own views.
139
struct DisplayListElement2 {
141
nsRect mBounds; // coordinates relative to the view manager root
142
nscoord mAbsX, mAbsY; // coordinates relative to the view that we're Refreshing
143
PRUint32 mFlags; // see above
144
nsInt64 mZIndex; // temporary used during z-index processing (see below)
150
Implementing z-index:auto and negative z-indices properly is hard. Here's how we do it.
152
In CreateDisplayList, the display list elements above are inserted into a tree rather
153
than a simple list. The tree structure mimics the view hierarchy (except for fixed-position
154
stuff, see below for more about that), except that in the tree, only leaf nodes can do
155
actual painting (i.e., correspond to display list elements). Therefore every leaf view
156
(i.e., no child views) has one corresponding leaf tree node containing its
157
DisplayListElement2. OTOH, every non-leaf view corresponds to an interior tree node
158
which contains the tree nodes for the child views, and which also contains a leaf tree
159
node which does the painting for the non-leaf view. Initially sibling tree nodes are
160
ordered in the same order as their views, which Layout should have arranged in document
163
For example, given the view hierarchy and z-indices, and assuming lower-
164
numbered views precede higher-numbered views in the document order,
165
V0(auto) --> V1(0) --> V2(auto) --> V3(0)
166
| | +---------> V4(2)
169
CreateDisplayList would create the following z-tree (z-order increases from top to bottom)
171
+-------> Tc(V1) --> Td*(V1)
172
| +-------> Te(V2) --> Tf*(V2)
173
| | +-------> Tg*(V3)
174
| | +-------> Th*(V4)
177
(* indicates leaf nodes marked with display list elements)
179
Once the Z-tree has been built we call SortByZOrder to compute a real linear display list.
180
It recursively computes a display list for each tree node, by computing the display lists
181
for all child nodes, then concatenating those lists and sorting them by z-index. The trick
182
is that the z-indices for display list elements are updated during the process; after
183
a display list is calculated for a tree node, the elements of the display list are all
184
assigned the z-index specified for the tree node's view (unless the view has z-index
185
'auto'). This ensures that a tree node's display list elements will be sorted correctly
186
relative to the siblings of the tree node.
188
The above example is processed as follows:
189
The child nodes of Te(V2) are display list elements [ Tf*(V2)(0), Tg*(V3)(0), Th*(V4)(2) ].
190
(The display list element for the frames of a non-leaf view always has z-index 0 relative
191
to the children of the view.)
192
Te(V2) is 'auto' so its display list is [ Tf*(V2)(0), Tg*(V3)(0), Th*(V4)(2) ].
193
Tc(V1)'s child display list elements are [ Td*(V1)(0), Tf*(V2)(0), Tg*(V3)(0), Th*(V4)(2),
195
The nodes are sorted and then reassigned z-index 0, so Tc(V1) is replaced with the list
196
[ Td*(V1)(0), Tf*(V2)(0), Tg*(V3)(0), Ti*(V5)(0), Th*(V4)(0) ].
197
Finally we collect the elements for Ta(V0):
198
[ Tb*(V0), Td*(V1)(0), Tf*(V2)(0), Tg*(V3)(0), Ti*(V5)(0), Th*(V4)(0), Tj*(V6)(1) ].
201
struct DisplayZTreeNode {
202
nsView* mView; // Null for tree leaf nodes
203
DisplayZTreeNode* mZSibling;
205
// We can't have BOTH an mZChild and an mDisplayElement
206
DisplayZTreeNode* mZChild; // tree interior nodes
207
DisplayListElement2* mDisplayElement; // tree leaf nodes
210
void nsViewManager::DestroyZTreeNode(DisplayZTreeNode* aNode)
213
if (mMapPlaceholderViewToZTreeNode.Count() > 0) {
214
nsVoidKey key(aNode->mView);
215
mMapPlaceholderViewToZTreeNode.Remove(&key);
218
DestroyZTreeNode(aNode->mZChild);
219
DestroyZTreeNode(aNode->mZSibling);
220
delete aNode->mDisplayElement;
226
static PRInt32 PrintDisplayListElement(DisplayListElement2* element,
227
PRInt32 aNestCount) {
228
nsView* view = element->mView;
229
nsRect rect = element->mBounds;
230
PRUint32 flags = element->mFlags;
231
PRUint32 viewFlags = view ? view->GetViewFlags() : 0;
234
view->GetDimensions(dim);
236
nsPoint v = view ? view->GetPosition() : nsPoint(0, 0);
237
nsView* parent = view ? view->GetParent() : nsnull;
238
PRInt32 zindex = view ? view->GetZIndex() : 0;
239
nsView* zParent = view ? view->GetZParent() : nsnull;
240
nsViewManager* viewMan = view ? view->GetViewManager() : nsnull;
242
printf("%*snsIView@%p{%d,%d,%d,%d @ %d,%d; p=%p,m=%p z=%d,zp=%p} [x=%d, y=%d, w=%d, h=%d, absX=%d, absY=%d]\n",
243
aNestCount*2, "", (void*)view,
244
dim.x, dim.y, dim.width, dim.height,
246
(void*)parent, (void*)viewMan, zindex, (void*)zParent,
247
rect.x, rect.y, rect.width, rect.height,
248
element->mAbsX, element->mAbsY);
250
PRInt32 newnestcnt = aNestCount;
254
printf("%*s", aNestCount*2, "");
256
if (flags & POP_CLIP) {
261
if (flags & PUSH_CLIP) {
262
printf("PUSH_CLIP ");
266
if (flags & POP_FILTER) {
267
printf("POP_FILTER ");
271
if (flags & PUSH_FILTER) {
272
printf("PUSH_FILTER ");
276
if (flags & VIEW_RENDERED)
277
printf("VIEW_RENDERED ");
279
if (flags & VIEW_ISSCROLLED)
280
printf("VIEW_ISSCROLLED ");
282
if (flags & VIEW_CLIPPED)
283
printf("VIEW_ISCLIPPED ");
285
if (flags & VIEW_TRANSLUCENT)
286
printf("VIEW_ISTRANSLUCENT ");
288
if (flags & VIEW_TRANSPARENT)
289
printf("VIEW_ISTRANSPARENT ");
291
if (viewFlags & NS_VIEW_FLAG_DONT_BITBLT)
292
printf("NS_VIEW_FLAG_DONT_BITBLT ");
299
static void PrintZTreeNode(DisplayZTreeNode* aNode, PRInt32 aIndent)
302
printf("%*sDisplayZTreeNode@%p\n", aIndent*2, "", (void*)aNode);
303
if (aNode->mDisplayElement) {
304
PrintDisplayListElement(aNode->mDisplayElement, 0);
309
for (DisplayZTreeNode* child = aNode->mZChild; child;
310
child = child->mZSibling) {
311
PrintZTreeNode(child, aIndent);
317
#ifdef NS_VM_PERF_METRICS
318
#include "nsITimeRecorder.h"
321
//-------------- Begin Invalidate Event Definition ------------------------
323
struct nsInvalidateEvent : public PLEvent {
324
nsInvalidateEvent(nsViewManager* aViewManager);
325
~nsInvalidateEvent() { }
328
NS_ASSERTION(nsnull != mViewManager,"ViewManager is null");
329
// Search for valid view manager before trying to access it
330
// This is just a safety check. We should never have a circumstance
331
// where the view manager has been destroyed and the invalidate event
332
// which it owns is still around. The invalidate event should be destroyed
333
// by the RevokeEvent in the viewmanager's destructor.
334
PRBool found = PR_FALSE;
336
PRInt32 count = nsViewManager::GetViewManagerCount();
337
const nsVoidArray* viewManagers = nsViewManager::GetViewManagerArray();
338
for (index = 0; index < count; index++) {
339
nsViewManager* vm = (nsViewManager*)viewManagers->ElementAt(index);
340
if (vm == mViewManager) {
346
mViewManager->ProcessInvalidateEvent();
348
NS_ASSERTION(PR_FALSE, "bad view manager asked to process invalidate event");
352
nsViewManager* mViewManager; // Weak Reference. The viewmanager will destroy any pending
353
// invalidate events in it's destructor.
356
static void* PR_CALLBACK HandlePLEvent(PLEvent* aEvent)
358
NS_ASSERTION(nsnull != aEvent,"Event is null");
359
nsInvalidateEvent *event = NS_STATIC_CAST(nsInvalidateEvent*, aEvent);
360
event->HandleEvent();
364
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent)
366
NS_ASSERTION(nsnull != aEvent,"Event is null");
367
nsInvalidateEvent *event = NS_STATIC_CAST(nsInvalidateEvent*, aEvent);
371
nsInvalidateEvent::nsInvalidateEvent(nsViewManager* aViewManager)
373
NS_ASSERTION(aViewManager, "null parameter");
374
mViewManager = aViewManager; // Assign weak reference
375
PL_InitEvent(this, aViewManager, ::HandlePLEvent, ::DestroyPLEvent);
378
//-------------- End Invalidate Event Definition ---------------------------
380
// Compare two Z-index values taking into account topmost and
381
// auto flags. the topmost flag is only used when both views are
382
// zindex:auto. (XXXldb Lying!)
384
// returns 0 if equal
385
// > 0 if first z-index is greater than the second
386
// < 0 if first z-index is less than the second
388
static PRInt32 CompareZIndex(PRInt32 aZIndex1, PRBool aTopMost1, PRBool aIsAuto1,
389
PRInt32 aZIndex2, PRBool aTopMost2, PRBool aIsAuto2)
391
NS_ASSERTION(!aIsAuto1 || aZIndex1 == 0,"auto is set and the z-index is not 0");
392
NS_ASSERTION(!aIsAuto2 || aZIndex2 == 0,"auto is set and the z-index is not 0");
394
if (aZIndex1 != aZIndex2) {
395
return aZIndex1 - aZIndex2;
397
return aTopMost1 - aTopMost2;
401
static PRBool IsViewVisible(nsView *aView)
403
for (nsIView *view = aView; view; view = view->GetParent()) {
404
// We don't check widget visibility here because in the future (with
405
// the better approach to this that's in attachment 160801 on bug
406
// 227361), callers of the equivalent to this function should be able
407
// to rely on being notified when the result of this function changes.
408
if (view->GetVisibility() == nsViewVisibility_kHide)
411
// Find out if the root view is visible by asking the view observer
412
// (this won't be needed anymore if we link view trees across chrome /
413
// content boundaries in DocumentViewerImpl::MakeWindow).
414
nsCOMPtr<nsIViewObserver> vo;
415
aView->GetViewManager()->GetViewObserver(*getter_AddRefs(vo));
416
return vo && vo->IsVisible();
420
nsViewManager::PostInvalidateEvent()
422
nsCOMPtr<nsIEventQueue> eventQueue;
423
mEventQueueService->GetSpecialEventQueue(
424
nsIEventQueueService::UI_THREAD_EVENT_QUEUE, getter_AddRefs(eventQueue));
425
NS_ASSERTION(nsnull != eventQueue, "Event queue is null");
427
if (eventQueue != mInvalidateEventQueue) {
428
nsInvalidateEvent* ev = new nsInvalidateEvent(this);
429
eventQueue->PostEvent(ev);
430
mInvalidateEventQueue = eventQueue;
434
PRInt32 nsViewManager::mVMCount = 0;
435
nsIRenderingContext* nsViewManager::gCleanupContext = nsnull;
437
// Weakly held references to all of the view managers
438
nsVoidArray* nsViewManager::gViewManagers = nsnull;
439
PRUint32 nsViewManager::gLastUserEventTime = 0;
441
nsViewManager::nsViewManager()
442
: mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
444
if (gViewManagers == nsnull) {
445
NS_ASSERTION(mVMCount == 0, "View Manager count is incorrect");
446
// Create an array to hold a list of view managers
447
gViewManagers = new nsVoidArray;
450
if (gCleanupContext == nsnull) {
451
/* XXX: This should use a device to create a matching |nsIRenderingContext| object */
452
CallCreateInstance(kRenderingContextCID, &gCleanupContext);
453
NS_ASSERTION(gCleanupContext,
454
"Wasn't able to create a graphics context for cleanup");
457
gViewManagers->AppendElement(this);
460
// NOTE: we use a zeroing operator new, so all data members are
461
// assumed to be cleared here.
464
mCachingWidgetChanges = 0;
465
mDefaultBackgroundColor = NS_RGBA(0, 0, 0, 0);
466
mAllowDoubleBuffering = PR_TRUE;
467
mHasPendingInvalidates = PR_FALSE;
468
mRecursiveRefreshPending = PR_FALSE;
471
nsViewManager::~nsViewManager()
474
// Destroy any remaining views
475
mRootView->Destroy();
479
nsCOMPtr<nsIEventQueue> eventQueue;
480
mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
481
getter_AddRefs(eventQueue));
482
NS_ASSERTION(nsnull != eventQueue, "Event queue is null");
483
eventQueue->RevokeEvents(this);
484
mInvalidateEventQueue = nsnull;
486
NS_IF_RELEASE(mRootWindow);
488
mRootScrollable = nsnull;
490
NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
496
gViewManagers->RemoveElement(this);
497
NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers");
500
// There aren't any more view managers so
501
// release the global array of view managers
503
NS_ASSERTION(gViewManagers != nsnull, "About to delete null gViewManagers");
504
delete gViewManagers;
505
gViewManagers = nsnull;
507
// Cleanup all of the offscreen drawing surfaces if the last view manager
508
// has been destroyed and there is something to cleanup
510
// Note: A global rendering context is needed because it is not possible
511
// to create a nsIRenderingContext during the shutdown of XPCOM. The last
512
// viewmanager is typically destroyed during XPCOM shutdown.
514
if (gCleanupContext) {
516
gCleanupContext->DestroyCachedBackbuffer();
518
NS_ASSERTION(PR_FALSE, "Cleanup of drawing surfaces + offscreen buffer failed");
521
NS_IF_RELEASE(gCleanupContext);
527
if (nsnull != mCompositeListeners) {
528
mCompositeListeners->Clear();
529
NS_RELEASE(mCompositeListeners);
533
NS_IMPL_ISUPPORTS1(nsViewManager, nsIViewManager)
536
nsViewManager::CreateRegion(nsIRegion* *result)
540
if (!mRegionFactory) {
541
nsCOMPtr<nsIComponentManager> compMgr;
542
rv = NS_GetComponentManager(getter_AddRefs(compMgr));
544
if (NS_SUCCEEDED(rv))
545
rv = compMgr->GetClassObject(kRegionCID,
546
NS_GET_IID(nsIFactory),
547
getter_AddRefs(mRegionFactory));
549
if (!mRegionFactory) {
551
return NS_ERROR_FAILURE;
555
nsIRegion* region = nsnull;
556
rv = mRegionFactory->CreateInstance(nsnull, NS_GET_IID(nsIRegion), (void**)®ion);
557
if (NS_SUCCEEDED(rv)) {
564
// We don't hold a reference to the presentation context because it
565
// holds a reference to us.
566
NS_IMETHODIMP nsViewManager::Init(nsIDeviceContext* aContext)
568
NS_PRECONDITION(nsnull != aContext, "null ptr");
570
if (nsnull == aContext) {
571
return NS_ERROR_NULL_POINTER;
573
if (nsnull != mContext) {
574
return NS_ERROR_ALREADY_INITIALIZED;
577
mTwipsToPixels = mContext->AppUnitsToDevUnits();
578
mPixelsToTwips = mContext->DevUnitsToAppUnits();
580
mRefreshEnabled = PR_TRUE;
582
mMouseGrabber = nsnull;
583
mKeyGrabber = nsnull;
585
if (nsnull == mEventQueueService) {
586
mEventQueueService = do_GetService(kEventQueueServiceCID);
587
NS_ASSERTION(mEventQueueService, "couldn't get event queue service");
593
NS_IMETHODIMP nsViewManager::GetRootView(nsIView *&aView)
599
NS_IMETHODIMP nsViewManager::SetRootView(nsIView *aView, nsIWidget* aWidget)
601
nsView* view = NS_STATIC_CAST(nsView*, aView);
603
// Do NOT destroy the current root view. It's the caller's responsibility
607
//now get the window too.
608
NS_IF_RELEASE(mRootWindow);
610
// The window must be specified through one of the following:
611
//* a) The aView has a nsIWidget instance or
612
//* b) the aWidget parameter is an nsIWidget instance to render into
613
//* that is not owned by a view.
614
//* c) aView has a parent view managed by a different view manager or
616
if (nsnull != aWidget) {
617
mRootWindow = aWidget;
618
NS_ADDREF(mRootWindow);
622
// case b) The aView has a nsIWidget instance
623
if (nsnull != mRootView) {
624
nsView* parent = mRootView->GetParent();
626
parent->InsertChild(mRootView, nsnull);
629
mRootView->SetZIndex(PR_FALSE, 0, PR_FALSE);
631
mRootWindow = mRootView->GetWidget();
633
NS_ADDREF(mRootWindow);
638
// case c) aView has a parent view managed by a different view manager
643
NS_IMETHODIMP nsViewManager::GetWindowOffset(nscoord *aX, nscoord *aY)
645
NS_ASSERTION(aX != nsnull, "aX pointer is null");
646
NS_ASSERTION(aY != nsnull, "aY pointer is null");
653
NS_IMETHODIMP nsViewManager::SetWindowOffset(nscoord aX, nscoord aY)
660
NS_IMETHODIMP nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
662
if (nsnull != mRootView) {
663
if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
665
mRootView->GetDimensions(dim);
667
*aHeight = dim.height;
669
*aWidth = mDelayedResize.width;
670
*aHeight = mDelayedResize.height;
681
NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
684
if (IsViewVisible(mRootView)) {
685
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
686
DoSetWindowDimensions(aWidth, aHeight);
688
mDelayedResize.SizeTo(aWidth, aHeight);
695
NS_IMETHODIMP nsViewManager::ResetScrolling(void)
697
if (nsnull != mRootScrollable)
698
mRootScrollable->ComputeScrollOffsets(PR_TRUE);
703
/* Check the prefs to see whether we should do double buffering or not... */
705
PRBool DoDoubleBuffering(void)
707
static PRBool gotDoublebufferPrefs = PR_FALSE;
708
static PRBool doDoublebuffering = PR_TRUE; /* Double-buffering is ON by default */
710
if (!gotDoublebufferPrefs) {
711
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
714
if (NS_SUCCEEDED(prefBranch->GetBoolPref("viewmanager.do_doublebuffering", &val))) {
715
doDoublebuffering = val;
720
if (!doDoublebuffering) {
721
printf("nsViewManager: Note: Double-buffering disabled via prefs.\n");
725
gotDoublebufferPrefs = PR_TRUE;
728
return doDoublebuffering;
731
static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut,
732
nsIDeviceContext* context)
734
nsRegionRectSet* rects = nsnull;
735
aIn->GetRects(&rects);
740
p2t = context->DevUnitsToAppUnits();
743
for (i = 0; i < rects->mNumRects; i++) {
744
const nsRegionRect& inR = rects->mRects[i];
746
outR.x = NSToIntRound(inR.x * p2t);
747
outR.y = NSToIntRound(inR.y * p2t);
748
outR.width = NSToIntRound(inR.width * p2t);
749
outR.height = NSToIntRound(inR.height * p2t);
750
aOut->Or(*aOut, outR);
753
aIn->FreeRects(rects);
757
aRegion is given in device coordinates!!
759
void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
760
nsIRegion *aRegion, PRUint32 aUpdateFlags)
762
NS_ASSERTION(aRegion != nsnull, "Null aRegion");
764
if (PR_FALSE == mRefreshEnabled)
768
aView->GetDimensions(viewRect);
770
// damageRegion is the damaged area, in twips, relative to the view origin
771
nsRegion damageRegion;
772
// convert pixels-relative-to-widget-origin to twips-relative-to-widget-origin
773
ConvertNativeRegionToAppRegion(aRegion, &damageRegion, mContext);
774
// move it from widget coordinates into view coordinates
775
damageRegion.MoveBy(viewRect.x, viewRect.y);
777
// Clip it to the view; shouldn't be necessary, but do it for sanity
778
damageRegion.And(damageRegion, viewRect);
779
if (damageRegion.IsEmpty()) {
781
nsRect damageRect = damageRegion.GetBounds();
782
printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
783
damageRect.x, damageRect.y, damageRect.width, damageRect.height,
784
viewRect.x, viewRect.y, viewRect.width, viewRect.height);
789
#ifdef NS_VM_PERF_METRICS
790
MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this));
791
MOZ_TIMER_RESET(mWatch);
793
MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n"));
794
MOZ_TIMER_START(mWatch);
797
NS_ASSERTION(!mPainting, "recursive painting not permitted");
799
mRecursiveRefreshPending = PR_TRUE;
804
// force double buffering in general
805
aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
807
if (!DoDoubleBuffering())
808
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
810
// check if the rendering context wants double-buffering or not
812
PRBool contextWantsBackBuffer = PR_TRUE;
813
aContext->UseBackbuffer(&contextWantsBackBuffer);
814
if (!contextWantsBackBuffer)
815
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
818
if (PR_FALSE == mAllowDoubleBuffering) {
819
// Turn off double-buffering of the display
820
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
823
nsCOMPtr<nsIRenderingContext> localcx;
824
nsDrawingSurface ds = nsnull;
826
if (nsnull == aContext)
828
localcx = getter_AddRefs(CreateRenderingContext(*aView));
830
//couldn't get rendering context. this is ok at init time atleast
831
if (nsnull == localcx) {
832
mPainting = PR_FALSE;
836
// plain assignment grabs another reference.
840
// notify the listeners.
841
if (nsnull != mCompositeListeners) {
842
PRUint32 listenerCount;
843
if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) {
844
nsCOMPtr<nsICompositeListener> listener;
845
for (PRUint32 i = 0; i < listenerCount; i++) {
846
if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) {
847
listener->WillRefreshRegion(this, aView, aContext, aRegion, aUpdateFlags);
853
// damageRect is the clipped damage area bounds, in twips-relative-to-view-origin
854
nsRect damageRect = damageRegion.GetBounds();
855
// widgetDamageRectInPixels is the clipped damage area bounds,
856
// in pixels-relative-to-widget-origin
857
nsRect widgetDamageRectInPixels = damageRect;
858
widgetDamageRectInPixels.MoveBy(-viewRect.x, -viewRect.y);
860
t2p = mContext->AppUnitsToDevUnits();
861
widgetDamageRectInPixels.ScaleRoundOut(t2p);
863
// On the Mac, we normally turn doublebuffering off because Quartz is
864
// doublebuffering for us. But we need to turn it on anyway if we need
865
// to use our blender, which requires access to the "current pixel values"
866
// when it blends onto the canvas.
867
nsAutoVoidArray displayList;
868
PRBool anyTransparentPixels
869
= BuildRenderingDisplayList(aView, damageRegion, &displayList);
870
if (!(aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)) {
871
for (PRInt32 i = 0; i < displayList.Count(); i++) {
872
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, displayList.ElementAt(i));
873
if (element->mFlags & PUSH_FILTER) {
874
aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
880
if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)
882
nsRect maxWidgetSize;
883
GetMaxWidgetBounds(maxWidgetSize);
885
nsRect r(0, 0, widgetDamageRectInPixels.width, widgetDamageRectInPixels.height);
886
if (NS_FAILED(localcx->GetBackbuffer(r, maxWidgetSize, ds))) {
887
//Failed to get backbuffer so turn off double buffering
888
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
892
// painting will be done in aView's coordinates
893
PRBool usingDoubleBuffer = (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds;
894
if (usingDoubleBuffer) {
895
// Adjust translations because the backbuffer holds just the damaged area,
896
// not the whole widget
898
// RenderViews draws in view coordinates. We want (damageRect.x, damageRect.y)
899
// to be translated to (0,0) in the backbuffer. So:
900
localcx->Translate(-damageRect.x, -damageRect.y);
901
// We're going to reset the clip region for the backbuffer. We can't
902
// just use damageRegion because nsIRenderingContext::SetClipRegion doesn't
903
// translate/scale the coordinates (grrrrrrrrrr)
904
// So we have to translate the region before we use it. aRegion is in
905
// pixels-relative-to-widget-origin, so:
906
aRegion->Offset(-widgetDamageRectInPixels.x, -widgetDamageRectInPixels.y);
908
// RenderViews draws in view coordinates. We want (viewRect.x, viewRect.y)
909
// to be translated to (0,0) in the widget. So:
910
localcx->Translate(-viewRect.x, -viewRect.y);
913
// Note that nsIRenderingContext::SetClipRegion always works in pixel coordinates,
914
// and nsIRenderingContext::SetClipRect always works in app coordinates. Stupid huh?
915
// Also, SetClipRegion doesn't subject its argument to the current transform, but
918
localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, isClipped);
919
localcx->SetClipRect(damageRect, nsClipCombine_kIntersect, isClipped);
921
if (anyTransparentPixels) {
922
// There are some bits here that aren't going to be completely painted unless we do it now.
923
// XXX Which color should we use for these bits?
924
localcx->SetColor(NS_RGB(128, 128, 128));
925
localcx->FillRect(damageRegion.GetBounds());
927
RenderViews(aView, *localcx, damageRegion, ds, displayList);
929
if (usingDoubleBuffer) {
930
// Flush bits back to the screen
932
// Restore aRegion to pixels-relative-to-widget-origin
933
aRegion->Offset(widgetDamageRectInPixels.x, widgetDamageRectInPixels.y);
934
// Restore translation to its previous state (so that (0,0) is the widget origin)
935
localcx->Translate(damageRect.x, damageRect.y);
936
// Make damageRect twips-relative-to-widget-origin
937
damageRect.MoveBy(-viewRect.x, -viewRect.y);
938
// Reset clip region to widget-relative
939
localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, isClipped);
940
localcx->SetClipRect(damageRect, nsClipCombine_kIntersect, isClipped);
941
// neither source nor destination are transformed
942
localcx->CopyOffScreenBits(ds, 0, 0, widgetDamageRectInPixels, NS_COPYBITS_USE_SOURCE_CLIP_REGION);
944
// undo earlier translation
945
localcx->Translate(viewRect.x, viewRect.y);
948
mPainting = PR_FALSE;
950
// notify the listeners.
951
if (nsnull != mCompositeListeners) {
952
PRUint32 listenerCount;
953
if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) {
954
nsCOMPtr<nsICompositeListener> listener;
955
for (PRUint32 i = 0; i < listenerCount; i++) {
956
if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) {
957
listener->DidRefreshRegion(this, aView, aContext, aRegion, aUpdateFlags);
963
if (mRecursiveRefreshPending) {
964
UpdateAllViews(aUpdateFlags);
965
mRecursiveRefreshPending = PR_FALSE;
968
localcx->ReleaseBackbuffer();
970
#ifdef NS_VM_PERF_METRICS
971
MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this));
972
MOZ_TIMER_STOP(mWatch);
973
MOZ_TIMER_LOG(("vm2 Paint time (this=%p): ", this));
974
MOZ_TIMER_PRINT(mWatch);
979
void nsViewManager::DefaultRefresh(nsView* aView, const nsRect* aRect)
981
nsCOMPtr<nsIWidget> widget;
982
GetWidgetForView(aView, getter_AddRefs(widget));
986
nsCOMPtr<nsIRenderingContext> context
987
= getter_AddRefs(CreateRenderingContext(*aView));
992
nscolor bgcolor = mDefaultBackgroundColor;
994
if (NS_GET_A(mDefaultBackgroundColor) == 0) {
995
NS_WARNING("nsViewManager: Asked to paint a default background, but no default background color is set!");
999
context->SetColor(bgcolor);
1000
context->FillRect(*aRect);
1003
// Perform a *stable* sort of the buffer by increasing Z-index. The common case is
1004
// when many or all z-indices are equal and the list is mostly sorted; make sure
1005
// that's fast (should be linear time if all z-indices are equal).
1006
static void ApplyZOrderStableSort(nsVoidArray &aBuffer, nsVoidArray &aMergeTmp, PRInt32 aStart, PRInt32 aEnd) {
1007
if (aEnd - aStart <= 6) {
1008
// do a fast bubble sort for the small sizes
1009
for (PRInt32 i = aEnd - 1; i > aStart; i--) {
1010
PRBool sorted = PR_TRUE;
1011
for (PRInt32 j = aStart; j < i; j++) {
1012
DisplayListElement2* e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(j));
1013
DisplayListElement2* e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(j + 1));
1014
if (e1->mZIndex > e2->mZIndex) {
1016
// We could use aBuffer.MoveElement(), but it wouldn't be much of
1017
// a win if any for swapping two elements.
1018
aBuffer.ReplaceElementAt(e2, j);
1019
aBuffer.ReplaceElementAt(e1, j + 1);
1027
// merge sort for the rest
1028
PRInt32 mid = (aEnd + aStart)/2;
1030
ApplyZOrderStableSort(aBuffer, aMergeTmp, aStart, mid);
1031
ApplyZOrderStableSort(aBuffer, aMergeTmp, mid, aEnd);
1033
DisplayListElement2* e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid - 1));
1034
DisplayListElement2* e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid));
1036
// fast common case: the list is already completely sorted
1037
if (e1->mZIndex <= e2->mZIndex) {
1040
// we have some merging to do.
1042
PRInt32 i1 = aStart;
1045
e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i1));
1046
e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i2));
1047
while (i1 < mid || i2 < aEnd) {
1048
if (i1 < mid && (i2 == aEnd || e1->mZIndex <= e2->mZIndex)) {
1049
aMergeTmp.AppendElement(e1);
1052
e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i1));
1055
aMergeTmp.AppendElement(e2);
1058
e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i2));
1063
for (PRInt32 i = aStart; i < aEnd; i++) {
1064
aBuffer.ReplaceElementAt(aMergeTmp.ElementAt(i - aStart), i);
1071
static nsInt64 BuildExtendedZIndex(nsView* aView) {
1072
return (nsInt64(aView->GetZIndex()) << 1) | nsInt64(aView->IsTopMost() ? 1 : 0);
1075
// The display-element (indirect) children of aNode are extracted and appended to aBuffer in
1076
// z-order, with the bottom-most elements first.
1077
// Their z-index is set to the z-index they will have in aNode's parent.
1078
// I.e. if aNode's view has "z-index: auto", the nodes will keep their z-index, otherwise
1079
// their z-indices will all be equal to the z-index value of aNode's view.
1080
static void SortByZOrder(DisplayZTreeNode *aNode, nsVoidArray &aBuffer, nsVoidArray &aMergeTmp, PRBool aForceSort) {
1081
PRBool autoZIndex = PR_TRUE;
1082
nsInt64 explicitZIndex = 0;
1084
if (nsnull != aNode->mView) {
1085
// Hixie says only non-translucent elements can have z-index:auto
1086
autoZIndex = aNode->mView->GetZIndexIsAuto() && aNode->mView->GetOpacity() == 1.0f;
1087
explicitZIndex = BuildExtendedZIndex(aNode->mView);
1090
if (nsnull == aNode->mZChild) {
1091
if (nsnull != aNode->mDisplayElement) {
1092
aBuffer.AppendElement(aNode->mDisplayElement);
1093
aNode->mDisplayElement->mZIndex = explicitZIndex;
1094
aNode->mDisplayElement = nsnull;
1099
DisplayZTreeNode *child;
1100
PRInt32 childStartIndex = aBuffer.Count();
1101
for (child = aNode->mZChild; nsnull != child; child = child->mZSibling) {
1102
SortByZOrder(child, aBuffer, aMergeTmp, PR_FALSE);
1104
PRInt32 childEndIndex = aBuffer.Count();
1105
PRInt32 sortStartIndex = childStartIndex;
1106
PRInt32 sortEndIndex = childEndIndex;
1107
PRBool hasClip = PR_FALSE;
1108
DisplayListElement2* ePush = nsnull;
1109
DisplayListElement2* ePop = nsnull;
1111
// When we sort the children by z-index, don't sort any PUSH_ or POP_ instructions
1112
// which are bracketing the children.
1113
while (sortEndIndex - sortStartIndex >= 2) {
1114
DisplayListElement2* childElem =
1115
NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortStartIndex));
1116
if (childElem->mView == aNode->mView) {
1117
if (childElem->mFlags & PUSH_CLIP) {
1119
// remember where the push and pop instructions are so we can
1120
// duplicate them later, if necessary
1121
ePush = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortStartIndex));
1122
ePop = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortEndIndex - 1));
1125
} else if (childElem->mFlags & PUSH_FILTER) {
1126
NS_ASSERTION(!autoZIndex, "FILTER cannot apply to z-index:auto view");
1138
ApplyZOrderStableSort(aBuffer, aMergeTmp, sortStartIndex, sortEndIndex);
1140
if (autoZIndex && sortEndIndex - sortStartIndex >= 1) {
1141
// If we're an auto-z-index, then we have to worry about the possibility that some of
1142
// our children may be moved by the z-sorter beyond the bounds of the PUSH...POP clip
1143
// instructions. So basically, we ensure that around every group of children of
1144
// equal z-index, there is a PUSH...POP element pair with the same z-index. The stable
1145
// z-sorter will not break up such a group.
1146
// Note that if we're not an auto-z-index set, then our children will never be broken
1147
// up so we don't need to do this.
1148
// We also don't have to worry if we have no real children.
1149
// We don't have to do the same thing for PUSH_FILTER/POP_FILTER because
1150
// a filter always corresponds to non-auto z-index; there is no way children
1151
// can be sorted beyond the PUSH/POP instructions.
1152
DisplayListElement2* eFirstChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortStartIndex));
1154
ePush->mZIndex = eFirstChild->mZIndex;
1156
DisplayListElement2* eLastChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortEndIndex - 1));
1158
ePop->mZIndex = eLastChild->mZIndex;
1160
DisplayListElement2* e = eFirstChild;
1161
for (PRInt32 i = sortStartIndex; i < sortEndIndex - 1; i++) {
1162
DisplayListElement2* eNext = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i + 1));
1163
NS_ASSERTION(e->mZIndex <= eNext->mZIndex, "Display Z-list is not sorted!!");
1164
if (e->mZIndex != eNext->mZIndex) {
1165
// need to insert a POP for the last sequence and a PUSH for the next sequence
1166
DisplayListElement2* newPop = new DisplayListElement2;
1167
DisplayListElement2* newPush = new DisplayListElement2;
1170
newPop->mZIndex = e->mZIndex;
1172
newPush->mZIndex = eNext->mZIndex;
1173
aBuffer.InsertElementAt(newPop, i + 1);
1174
aBuffer.InsertElementAt(newPush, i + 2);
1182
} else if (aForceSort || !autoZIndex) {
1183
ApplyZOrderStableSort(aBuffer, aMergeTmp, sortStartIndex, sortEndIndex);
1186
for (PRInt32 i = childStartIndex; i < childEndIndex; i++) {
1187
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i));
1189
element->mZIndex = explicitZIndex;
1190
} else if (aNode->mView->IsTopMost()) {
1191
// promote children to topmost if this view is topmost
1192
element->mZIndex |= nsInt64(1);
1197
static void PushStateAndClip(nsIRenderingContext** aRCs, PRInt32 aCount, nsRect &aRect) {
1198
for (int i = 0; i < aCount; i++) {
1201
aRCs[i]->PushState();
1202
aRCs[i]->SetClipRect(aRect, nsClipCombine_kIntersect, clipEmpty);
1207
static void PopState(nsIRenderingContext **aRCs, PRInt32 aCount) {
1208
for (int i = 0; i < aCount; i++) {
1211
aRCs[i]->PopState(clipEmpty);
1216
void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceContext* aContext,
1217
nsView* aRootView) {
1218
// We accumulate the bounds of widgets obscuring aRootView's widget into opaqueRgn.
1219
// In OptimizeDisplayList, display list elements which lie behind obscuring native
1220
// widgets are dropped.
1221
// This shouldn't really be necessary, since the GFX/Widget toolkit should remove these
1222
// covering widgets from the clip region passed into the paint command. But right now
1223
// they only give us a paint rect and not a region, so we can't access that information.
1224
// It's important to identifying areas that are covered by native widgets to avoid
1225
// painting their views many times as we process invalidates from the root widget all the
1226
// way down to the nested widgets.
1228
// NB: we must NOT add widgets that correspond to floating views!
1229
// We may be required to paint behind them
1232
nsCOMPtr<nsIWidget> widget;
1233
GetWidgetForView(aRootView, getter_AddRefs(widget));
1238
nsCOMPtr<nsIEnumerator> children(dont_AddRef(widget->GetChildren()));
1245
nsCOMPtr<nsISupports> child;
1246
if (!NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) {
1250
nsCOMPtr<nsIWidget> childWidget = do_QueryInterface(child);
1252
PRBool widgetVisible;
1253
childWidget->IsVisible(widgetVisible);
1254
if (widgetVisible) {
1255
nsView* view = nsView::GetViewFor(childWidget);
1256
if (view && view->GetVisibility() == nsViewVisibility_kShow
1257
&& !view->GetFloating()) {
1258
nsRect bounds = view->GetBounds();
1259
if (bounds.width > 0 && bounds.height > 0) {
1260
nsView* viewParent = view->GetParent();
1262
while (viewParent && viewParent != aRootView) {
1263
viewParent->ConvertToParentCoords(&bounds.x, &bounds.y);
1264
viewParent = viewParent->GetParent();
1267
// maybe we couldn't get the view into the coordinate
1268
// system of aRootView (maybe it's not a descendant
1269
// view of aRootView?); if so, don't use it
1271
aRgn.Or(aRgn, bounds);
1277
} while (NS_SUCCEEDED(children->Next()));
1280
PRBool nsViewManager::BuildRenderingDisplayList(nsIView* aRootView,
1281
const nsRegion& aRegion, nsVoidArray* aDisplayList) {
1282
BuildDisplayList(NS_STATIC_CAST(nsView*, aRootView),
1283
aRegion.GetBounds(), PR_FALSE, PR_FALSE, aDisplayList);
1286
AddCoveringWidgetsToOpaqueRegion(opaqueRgn, mContext,
1287
NS_STATIC_CAST(nsView*, aRootView));
1289
nsRect finalTransparentRect;
1290
OptimizeDisplayList(aDisplayList, aRegion, finalTransparentRect, opaqueRgn, PR_FALSE);
1293
if (!finalTransparentRect.IsEmpty()) {
1294
printf("XXX: Using final transparent rect, x=%d, y=%d, width=%d, height=%d\n",
1295
finalTransparentRect.x, finalTransparentRect.y, finalTransparentRect.width, finalTransparentRect.height);
1299
return !finalTransparentRect.IsEmpty();
1303
aRCSurface is the drawing surface being used to double-buffer aRC, or null
1304
if no double-buffering is happening. We pass this in here so that we can
1305
blend directly into the double-buffer offscreen memory.
1307
void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC,
1308
const nsRegion& aRegion, nsDrawingSurface aRCSurface,
1309
const nsVoidArray& aDisplayList)
1312
if (getenv("MOZ_SHOW_DISPLAY_LIST")) ShowDisplayList(&aDisplayList);
1316
nsRect fakeClipRect;
1318
OptimizeDisplayListClipping(&aDisplayList, PR_FALSE, fakeClipRect, index, anyRendered);
1321
OptimizeTranslucentRegions(aDisplayList, &index, nsnull);
1323
nsIWidget* widget = aRootView->GetWidget();
1324
PRBool translucentWindow = PR_FALSE;
1326
widget->GetWindowTranslucency(translucentWindow);
1327
if (translucentWindow) {
1328
NS_WARNING("Transparent window enabled");
1329
NS_ASSERTION(aRCSurface, "Cannot support transparent windows with doublebuffering disabled");
1333
// Create a buffer wrapping aRC (which is usually the double-buffering offscreen buffer).
1334
BlendingBuffers* buffers =
1335
CreateBlendingBuffers(&aRC, PR_TRUE, aRCSurface, translucentWindow, aRegion.GetBounds());
1336
NS_ASSERTION(buffers, "Failed to create rendering buffers");
1340
nsAutoVoidArray filterStack;
1342
// draw all views in the display list, from back to front.
1343
for (PRInt32 i = 0; i < aDisplayList.Count(); i++) {
1344
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, aDisplayList.ElementAt(i));
1346
nsIRenderingContext* RCs[2] = { buffers->mBlackCX, buffers->mWhiteCX };
1348
if (element->mFlags & PUSH_CLIP) {
1349
PushStateAndClip(RCs, 2, element->mBounds);
1351
if (element->mFlags & PUSH_FILTER) {
1352
NS_ASSERTION(aRCSurface,
1353
"Cannot support translucent elements with doublebuffering disabled");
1355
// Save current buffer on the stack and start rendering into a new
1357
filterStack.AppendElement(buffers);
1358
buffers = CreateBlendingBuffers(&aRC, PR_FALSE, nsnull,
1359
(element->mFlags & VIEW_TRANSPARENT) != 0,
1363
if (element->mFlags & VIEW_RENDERED) {
1364
if (element->mFlags & VIEW_CLIPPED) {
1365
PushStateAndClip(RCs, 2, element->mBounds);
1368
RenderDisplayListElement(element, RCs[0]);
1369
// RenderDisplayListElement won't do anything if the context is null
1370
RenderDisplayListElement(element, RCs[1]);
1372
if (element->mFlags & VIEW_CLIPPED) {
1377
if (element->mFlags & POP_FILTER) {
1378
// Pop the last buffer off the stack and composite the current buffer into
1380
BlendingBuffers* doneBuffers = buffers;
1381
buffers = NS_STATIC_CAST(BlendingBuffers*,
1382
filterStack.ElementAt(filterStack.Count() - 1));
1383
filterStack.RemoveElementAt(filterStack.Count() - 1);
1385
// perform the blend itself.
1386
nsRect damageRectInPixels = element->mBounds;
1387
damageRectInPixels -= buffers->mOffset;
1388
damageRectInPixels *= mTwipsToPixels;
1389
if (damageRectInPixels.width > 0 && damageRectInPixels.height > 0) {
1390
nsIRenderingContext* targets[2] = { buffers->mBlackCX, buffers->mWhiteCX };
1391
for (int j = 0; j < 2; j++) {
1393
mBlender->Blend(0, 0,
1394
damageRectInPixels.width, damageRectInPixels.height,
1395
doneBuffers->mBlackCX, targets[j],
1396
damageRectInPixels.x, damageRectInPixels.y,
1397
element->mView->GetOpacity(), doneBuffers->mWhiteCX,
1398
NS_RGB(0, 0, 0), NS_RGB(255, 255, 255));
1402
// probably should recycle these so we don't eat the cost of graphics memory
1406
if (element->mFlags & POP_CLIP) {
1413
if (translucentWindow) {
1414
// Get the alpha channel into an array so we can send it to the widget
1415
nsRect r = aRegion.GetBounds();
1416
r *= mTwipsToPixels;
1417
nsRect bufferRect(0, 0, r.width, r.height);
1418
PRUint8* alphas = nsnull;
1419
nsresult rv = mBlender->GetAlphas(bufferRect, buffers->mBlack,
1420
buffers->mWhite, &alphas);
1422
if (NS_SUCCEEDED(rv)) {
1423
widget->UpdateTranslucentWindowAlpha(r, alphas);
1431
void nsViewManager::RenderDisplayListElement(DisplayListElement2* element,
1432
nsIRenderingContext* aRC) {
1438
nsView* view = element->mView;
1440
view->GetDimensions(r);
1444
nscoord x = element->mAbsX - r.x, y = element->mAbsY - r.y;
1445
aRC->Translate(x, y);
1447
nsRect drect(element->mBounds.x - x, element->mBounds.y - y,
1448
element->mBounds.width, element->mBounds.height);
1450
element->mView->Paint(*aRC, drect, 0, clipEmpty);
1452
aRC->PopState(clipEmpty);
1455
void nsViewManager::PaintView(nsView *aView, nsIRenderingContext &aRC, nscoord x, nscoord y,
1456
const nsRect &aDamageRect)
1459
aRC.Translate(x, y);
1461
aView->Paint(aRC, aDamageRect, 0, unused);
1462
aRC.PopState(unused);
1465
static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsDrawingSurface surface,
1466
const nsRect& aRect, nsIRenderingContext* *aResult)
1469
nsIRenderingContext *context = nsnull;
1471
rv = deviceContext->CreateRenderingContext(surface, context);
1475
// always initialize clipping, linux won't draw images otherwise.
1477
nsRect clip(0, 0, aRect.width, aRect.height);
1478
context->SetClipRect(clip, nsClipCombine_kReplace, clipEmpty);
1480
context->Translate(-aRect.x, -aRect.y);
1486
BlendingBuffers::BlendingBuffers(nsIRenderingContext* aCleanupContext) {
1487
mCleanupContext = aCleanupContext;
1489
mOwnBlackSurface = PR_FALSE;
1494
BlendingBuffers::~BlendingBuffers() {
1496
mCleanupContext->DestroyDrawingSurface(mWhite);
1498
if (mBlack && mOwnBlackSurface)
1499
mCleanupContext->DestroyDrawingSurface(mBlack);
1503
@param aBorrowContext set to PR_TRUE if the BlendingBuffers' "black" context
1504
should be just aRC; set to PR_FALSE if we should create a new offscreen context
1505
@param aBorrowSurface if aBorrowContext is PR_TRUE, then this is the offscreen surface
1506
corresponding to aRC, or nsnull if aRC doesn't have one; if aBorrowContext is PR_FALSE,
1507
this parameter is ignored
1508
@param aNeedAlpha set to PR_FALSE if the caller guarantees that every pixel of the
1509
BlendingBuffers will be drawn with opacity 1.0, PR_TRUE otherwise
1510
@param aRect the screen rectangle covered by the new BlendingBuffers, in app units, and
1511
relative to the origin of aRC
1514
nsViewManager::CreateBlendingBuffers(nsIRenderingContext *aRC,
1515
PRBool aBorrowContext,
1516
nsDrawingSurface aBorrowSurface,
1518
const nsRect& aRect)
1522
// create a blender, if none exists already.
1524
mBlender = do_CreateInstance(kBlenderCID, &rv);
1527
rv = mBlender->Init(mContext);
1532
BlendingBuffers* buffers = new BlendingBuffers(aRC);
1536
buffers->mOffset = nsPoint(aRect.x, aRect.y);
1538
nsRect offscreenBounds(0, 0, aRect.width, aRect.height);
1539
offscreenBounds.ScaleRoundOut(mTwipsToPixels);
1541
if (aBorrowContext) {
1542
buffers->mBlackCX = aRC;
1543
buffers->mBlack = aBorrowSurface;
1545
rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mBlack);
1546
if (NS_FAILED(rv)) {
1550
buffers->mOwnBlackSurface = PR_TRUE;
1552
rv = NewOffscreenContext(mContext, buffers->mBlack, aRect, getter_AddRefs(buffers->mBlackCX));
1553
if (NS_FAILED(rv)) {
1560
rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mWhite);
1561
if (NS_FAILED(rv)) {
1566
rv = NewOffscreenContext(mContext, buffers->mWhite, aRect, getter_AddRefs(buffers->mWhiteCX));
1567
if (NS_FAILED(rv)) {
1572
// Note that we only need to fill mBlackCX with black when some pixels are going
1573
// to be transparent.
1574
buffers->mBlackCX->SetColor(NS_RGB(0, 0, 0));
1575
buffers->mBlackCX->FillRect(aRect);
1576
buffers->mWhiteCX->SetColor(NS_RGB(255, 255, 255));
1577
buffers->mWhiteCX->FillRect(aRect);
1583
void nsViewManager::ProcessPendingUpdates(nsView* aView)
1585
// Protect against a null-view.
1589
if (aView->HasWidget()) {
1590
nsCOMPtr<nsIRegion> dirtyRegion;
1591
aView->GetDirtyRegion(*getter_AddRefs(dirtyRegion));
1592
if (dirtyRegion && !dirtyRegion->IsEmpty()) {
1593
aView->GetWidget()->InvalidateRegion(dirtyRegion, PR_FALSE);
1594
dirtyRegion->Init();
1598
// process pending updates in child view.
1599
for (nsView* childView = aView->GetFirstChild(); childView;
1600
childView = childView->GetNextSibling()) {
1601
if (childView->GetViewManager() == this) {
1602
ProcessPendingUpdates(childView);
1607
NS_IMETHODIMP nsViewManager::Composite()
1611
if (nsnull != mRootWindow)
1612
mRootWindow->Update();
1620
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
1622
// Mark the entire view as damaged
1623
nsView* view = NS_STATIC_CAST(nsView*, aView);
1625
nsRect bounds = view->GetBounds();
1626
view->ConvertFromParentCoords(&bounds.x, &bounds.y);
1627
return UpdateView(view, bounds, aUpdateFlags);
1631
// Invalidate all widgets which overlap the view, other than the view's own widgets.
1633
nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY)
1635
nsView* view = NS_STATIC_CAST(nsView*, aView);
1637
// Look at the view's clipped rect. It may be that part of the view is clipped out
1638
// in which case we don't need to worry about invalidating the clipped-out part.
1639
nsRect damageRect = view->GetClippedRect();
1640
if (damageRect.IsEmpty()) {
1643
damageRect.MoveBy(ComputeViewOffset(view));
1645
// if this is a floating view, it isn't covered by any widgets other than
1646
// its children, which are handled by the widget scroller.
1647
if (view->GetFloating()) {
1651
nsView* realRoot = mRootView;
1652
while (realRoot->GetParent()) {
1653
realRoot = realRoot->GetParent();
1656
UpdateWidgetArea(realRoot, damageRect, view);
1661
// Returns true if this view's widget(s) completely cover the rectangle
1662
// The specified rectangle, relative to aWidgetView, is invalidated in every widget child of aWidgetView,
1663
// plus aWidgetView's own widget
1664
// If non-null, the aIgnoreWidgetView's widget and its children are not updated.
1665
PRBool nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRect &aDamagedRect, nsView* aIgnoreWidgetView)
1667
// If the bounds don't overlap at all, there's nothing to do
1669
aWidgetView->GetDimensions(bounds);
1671
PRBool overlap = bounds.IntersectRect(bounds, aDamagedRect);
1676
// If the widget is hidden, it don't cover nothing
1677
if (nsViewVisibility_kHide == aWidgetView->GetVisibility()) {
1679
// Assert if view is hidden but widget is visible
1680
nsCOMPtr<nsIWidget> widget;
1681
GetWidgetForView(aWidgetView, getter_AddRefs(widget));
1684
widget->IsVisible(visible);
1685
NS_ASSERTION(!visible, "View is hidden but widget is visible!");
1691
PRBool noCropping = bounds == aDamagedRect;
1692
if (aWidgetView == aIgnoreWidgetView) {
1693
// the widget for aIgnoreWidgetView (and its children) should be treated as already updated.
1694
// We still need to report whether this widget covers the rectangle.
1698
nsCOMPtr<nsIWidget> widget;
1699
GetWidgetForView(aWidgetView, getter_AddRefs(widget));
1701
// The root view or a scrolling view might not have a widget
1702
// (for example, during printing). We get here when we scroll
1703
// during printing to show selected options in a listbox, for example.
1707
PRBool childCovers = PR_FALSE;
1708
nsCOMPtr<nsIEnumerator> children(dont_AddRef(widget->GetChildren()));
1712
nsCOMPtr<nsISupports> child;
1713
if (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) {
1714
nsCOMPtr<nsIWidget> childWidget = do_QueryInterface(child);
1716
nsView* view = nsView::GetViewFor(childWidget);
1717
if (nsnull != view) {
1718
nsRect damage = bounds;
1720
while (vp != aWidgetView && nsnull != vp) {
1721
vp->ConvertFromParentCoords(&damage.x, &damage.y);
1722
vp = vp->GetParent();
1725
if (nsnull != vp) { // vp == nsnull means it's in a different hierarchy so we ignore it
1726
if (UpdateWidgetArea(view, damage, aIgnoreWidgetView)) {
1727
childCovers = PR_TRUE;
1733
} while (NS_SUCCEEDED(children->Next()));
1737
nsViewManager* vm = aWidgetView->GetViewManager();
1740
if (!vm->mRefreshEnabled) {
1741
// accumulate this rectangle in the view's dirty region, so we can process it later.
1742
vm->AddRectToDirtyRegion(aWidgetView, bounds);
1743
vm->mHasPendingInvalidates = PR_TRUE;
1745
ViewToWidget(aWidgetView, aWidgetView, bounds);
1746
widget->Invalidate(bounds, PR_FALSE);
1753
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags)
1755
NS_PRECONDITION(nsnull != aView, "null view");
1757
nsView* view = NS_STATIC_CAST(nsView*, aView);
1759
// Only Update the rectangle region of the rect that intersects the view's non clipped rectangle
1760
nsRect clippedRect = view->GetClippedRect();
1761
if (clippedRect.IsEmpty()) {
1766
damagedRect.IntersectRect(aRect, clippedRect);
1768
// If the rectangle is not visible then abort
1769
// without invalidating. This is a performance
1770
// enhancement since invalidating a native widget
1771
// can be expensive.
1772
// This also checks for silly request like damagedRect.width = 0 or damagedRect.height = 0
1773
nsRectVisibility rectVisibility;
1774
GetRectVisibility(view, damagedRect, 0, &rectVisibility);
1775
if (rectVisibility != nsRectVisibility_kVisible) {
1779
// if this is a floating view, it isn't covered by any widgets other than
1780
// its children. In that case we walk up to its parent widget and use
1781
// that as the root to update from. This also means we update areas that
1782
// may be outside the parent view(s), which is necessary for floats.
1783
if (view->GetFloating()) {
1784
nsView* widgetParent = view;
1786
while (!widgetParent->HasWidget()) {
1787
widgetParent->ConvertToParentCoords(&damagedRect.x, &damagedRect.y);
1788
widgetParent = widgetParent->GetParent();
1791
UpdateWidgetArea(widgetParent, damagedRect, nsnull);
1793
damagedRect.MoveBy(ComputeViewOffset(view));
1795
nsView* realRoot = mRootView;
1796
while (realRoot->GetParent()) {
1797
realRoot = realRoot->GetParent();
1800
UpdateWidgetArea(realRoot, damagedRect, nsnull);
1805
if (!mRefreshEnabled) {
1809
// See if we should do an immediate refresh or wait
1810
if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
1817
NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
1819
UpdateViews(mRootView, aUpdateFlags);
1823
void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
1825
// update this view.
1826
UpdateView(aView, aUpdateFlags);
1828
// update all children as well.
1829
nsView* childView = aView->GetFirstChild();
1830
while (nsnull != childView) {
1831
if (childView->GetViewManager() == this) {
1832
UpdateViews(childView, aUpdateFlags);
1834
childView = childView->GetNextSibling();
1838
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus)
1840
*aStatus = nsEventStatus_eIgnore;
1842
// Mark all events coming through here as trusted events, as the
1843
// only code that calls this is the widget code that translates OS
1844
// events into mozilla events.
1845
aEvent->internalAppFlags |= NS_APP_EVENT_FLAG_TRUSTED;
1847
switch(aEvent->message)
1851
nsView* view = nsView::GetViewFor(aEvent->widget);
1855
nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width;
1856
nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height;
1857
width = ((nsSizeEvent*)aEvent)->mWinWidth;
1858
height = ((nsSizeEvent*)aEvent)->mWinHeight;
1860
// The root view may not be set if this is the resize associated with
1863
if (view == mRootView)
1865
// Convert from pixels to twips
1867
p2t = mContext->DevUnitsToAppUnits();
1869
//printf("resize: (pix) %d, %d\n", width, height);
1870
SetWindowDimensions(NSIntPixelsToTwips(width, p2t),
1871
NSIntPixelsToTwips(height, p2t));
1872
*aStatus = nsEventStatus_eConsumeNoDefault;
1881
nsPaintEvent *event = NS_STATIC_CAST(nsPaintEvent*, aEvent);
1882
nsView *view = nsView::GetViewFor(aEvent->widget);
1884
if (!view || !mContext)
1887
*aStatus = nsEventStatus_eConsumeNoDefault;
1889
// The rect is in device units, and it's in the coordinate space of its
1890
// associated window.
1891
nsCOMPtr<nsIRegion> region = event->region;
1893
if (NS_FAILED(CreateRegion(getter_AddRefs(region))))
1896
const nsRect& damrect = *event->rect;
1897
region->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
1900
if (region->IsEmpty())
1904
if (mRefreshEnabled) {
1905
// If an ancestor widget was hidden and then shown, we could
1906
// have a delayed resize to handle.
1907
if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
1908
IsViewVisible(mRootView)) {
1909
DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height);
1910
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
1913
UpdateView(view, NS_VMREFRESH_NO_SYNC);
1915
//NS_ASSERTION(IsViewVisible(view), "painting an invisible view");
1916
Refresh(view, event->renderingContext, region,
1917
NS_VMREFRESH_DOUBLE_BUFFER);
1920
// since we got an NS_PAINT event, we need to
1921
// draw something so we don't get blank areas.
1923
region->GetBoundingBox(&damRect.x, &damRect.y, &damRect.width, &damRect.height);
1925
p2t = mContext->DevUnitsToAppUnits();
1926
damRect.ScaleRoundOut(p2t);
1927
DefaultRefresh(view, &damRect);
1929
// Clients like the editor can trigger multiple
1930
// reflows during what the user perceives as a single
1931
// edit operation, so it disables view manager
1932
// refreshing until the edit operation is complete
1933
// so that users don't see the intermediate steps.
1935
// Unfortunately some of these reflows can trigger
1936
// nsScrollPortView and nsScrollingView Scroll() calls
1937
// which in most cases force an immediate BitBlt and
1938
// synchronous paint to happen even if the view manager's
1939
// refresh is disabled. (Bug 97674)
1941
// Calling UpdateView() here, is neccessary to add
1942
// the exposed region specified in the synchronous paint
1943
// event to the view's damaged region so that it gets
1944
// painted properly when refresh is enabled.
1946
// Note that calling UpdateView() here was deemed
1947
// to have the least impact on performance, since the
1948
// other alternative was to make Scroll() post an
1949
// async paint event for the *entire* ScrollPort or
1950
// ScrollingView's viewable area. (See bug 97674 for this
1951
// alternate patch.)
1953
UpdateView(view, damRect, NS_VMREFRESH_NO_SYNC);
1963
/* Don't pass these events through. Passing them through
1964
causes performance problems on pages with lots of views/frames
1966
*aStatus = nsEventStatus_eConsumeNoDefault;
1970
case NS_DISPLAYCHANGED:
1972
//Destroy the cached backbuffer to force a new backbuffer
1973
//be constructed with the appropriate display depth.
1974
//@see bugzilla bug 6061
1975
*aStatus = nsEventStatus_eConsumeDoDefault;
1976
if (gCleanupContext) {
1977
gCleanupContext->DestroyCachedBackbuffer();
1981
case NS_SYSCOLORCHANGED:
1983
nsView *view = nsView::GetViewFor(aEvent->widget);
1984
nsCOMPtr<nsIViewObserver> obs;
1985
GetViewObserver(*getter_AddRefs(obs));
1988
obs->HandleEvent(view, aEvent, aStatus, PR_TRUE, handled);
1998
PRBool capturedEvent = PR_FALSE;
2000
if (NS_IS_MOUSE_EVENT(aEvent) || NS_IS_KEY_EVENT(aEvent) ||
2001
NS_IS_IME_EVENT(aEvent)) {
2002
gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
2005
//Find the view whose coordinates system we're in.
2006
baseView = nsView::GetViewFor(aEvent->widget);
2008
if (aEvent->message == NS_DEACTIVATE)
2009
mMouseGrabber = mKeyGrabber = nsnull;
2011
//Find the view to which we're initially going to send the event
2013
if (nsnull != mMouseGrabber && (NS_IS_MOUSE_EVENT(aEvent) || (NS_IS_DRAG_EVENT(aEvent)))) {
2014
view = mMouseGrabber;
2015
capturedEvent = PR_TRUE;
2017
else if (nsnull != mKeyGrabber && (NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent))) {
2019
capturedEvent = PR_TRUE;
2025
if (nsnull != view) {
2026
//Calculate the proper offset for the view we're going to
2027
offset.x = offset.y = 0;
2028
if (baseView != view) {
2029
//Get offset from root of baseView
2033
while (mRootView != parent) {
2034
parent->ConvertToParentCoords(&offset.x, &offset.y);
2035
parent = parent->GetParent();
2038
//Subtract back offset from root of view
2040
while (mRootView != parent) {
2041
parent->ConvertFromParentCoords(&offset.x, &offset.y);
2042
parent = parent->GetParent();
2047
//Dispatch the event
2048
//Before we start mucking with coords, make sure we know our baseline
2049
aEvent->refPoint.x = aEvent->point.x;
2050
aEvent->refPoint.y = aEvent->point.y;
2052
nsRect baseViewDimensions;
2053
if (baseView != nsnull) {
2054
baseView->GetDimensions(baseViewDimensions);
2057
float t2p = mContext->AppUnitsToDevUnits();
2058
float p2t = mContext->DevUnitsToAppUnits();
2060
aEvent->point.x = baseViewDimensions.x + NSIntPixelsToTwips(aEvent->point.x, p2t);
2061
aEvent->point.y = baseViewDimensions.y + NSIntPixelsToTwips(aEvent->point.y, p2t);
2063
aEvent->point.x += offset.x;
2064
aEvent->point.y += offset.y;
2066
*aStatus = HandleEvent(view, aEvent, capturedEvent);
2068
// From here on out, "this" could have been deleted!!!
2070
aEvent->point.x -= offset.x;
2071
aEvent->point.y -= offset.y;
2073
aEvent->point.x = NSTwipsToIntPixels(aEvent->point.x - baseViewDimensions.x, t2p);
2074
aEvent->point.y = NSTwipsToIntPixels(aEvent->point.y - baseViewDimensions.y, t2p);
2077
// if the event is an nsTextEvent, we need to map the reply back into platform coordinates
2079
if (aEvent->message==NS_TEXT_TEXT) {
2080
((nsTextEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.x, t2p);
2081
((nsTextEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.y, t2p);
2082
((nsTextEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.width, t2p);
2083
((nsTextEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.height, t2p);
2085
if((aEvent->message==NS_COMPOSITION_START) ||
2086
(aEvent->message==NS_COMPOSITION_QUERY)) {
2087
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x,t2p);
2088
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y,t2p);
2089
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width,t2p);
2090
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height,t2p);
2101
void nsViewManager::ReparentViews(DisplayZTreeNode* aNode) {
2102
if (aNode == nsnull) {
2106
DisplayZTreeNode* child;
2107
DisplayZTreeNode** prev = &aNode->mZChild;
2108
for (child = aNode->mZChild; nsnull != child; child = *prev) {
2109
ReparentViews(child);
2111
nsZPlaceholderView *zParent = nsnull;
2112
if (nsnull != child->mView) {
2113
zParent = child->mView->GetZParent();
2115
if (nsnull != zParent) {
2116
nsVoidKey key(zParent);
2117
DisplayZTreeNode* placeholder = (DisplayZTreeNode *)mMapPlaceholderViewToZTreeNode.Get(&key);
2119
if (placeholder == child) {
2120
// don't do anything if we already reparented this node;
2121
// just advance to the next child
2122
prev = &child->mZSibling;
2124
// unlink the child from the tree
2125
*prev = child->mZSibling;
2126
child->mZSibling = nsnull;
2128
if (nsnull != placeholder) {
2129
NS_ASSERTION((placeholder->mDisplayElement == nsnull), "placeholder already has elements?");
2130
NS_ASSERTION((placeholder->mZChild == nsnull), "placeholder already has Z-children?");
2131
placeholder->mDisplayElement = child->mDisplayElement;
2132
placeholder->mView = child->mView;
2133
placeholder->mZChild = child->mZChild;
2136
// the placeholder was not added to the display list
2137
// we don't need the real view then, either
2138
DestroyZTreeNode(child);
2142
prev = &child->mZSibling;
2147
static PRBool ComputePlaceholderContainment(nsView* aView) {
2148
PRBool containsPlaceholder = aView->IsZPlaceholderView();
2151
for (child = aView->GetFirstChild(); child != nsnull; child = child->GetNextSibling()) {
2152
if (ComputePlaceholderContainment(child)) {
2153
containsPlaceholder = PR_TRUE;
2157
if (containsPlaceholder) {
2158
aView->SetViewFlags(aView->GetViewFlags() | NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
2160
aView->SetViewFlags(aView->GetViewFlags() & ~NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
2163
return containsPlaceholder;
2167
Fills aDisplayList with DisplayListElement2* pointers. The caller is responsible
2168
for freeing these structs. The display list elements are ordered by z-order so
2169
that the first element of the array is at the bottom in z-order and the last element
2170
in the array is at the top in z-order.
2172
This should be changed so that the display list array is passed in as a parameter. There
2173
is no need to have the display list as a member of nsViewManager.
2175
aRect is the area in aView which we want to build a display list for.
2176
Set aEventProcesing when the list is required for event processing.
2177
Set aCaptured if the event is being captured by the given view.
2179
void nsViewManager::BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool aEventProcessing,
2180
PRBool aCaptured, nsVoidArray* aDisplayList) {
2181
// compute this view's origin
2182
nsPoint origin = ComputeViewOffset(aView);
2184
nsView *displayRoot = aView;
2187
nsView *displayParent = displayRoot->GetParent();
2189
if (nsnull == displayParent) {
2193
if (displayRoot->GetFloating() && !displayParent->GetFloating()) {
2196
displayRoot = displayParent;
2200
DisplayZTreeNode *zTree;
2202
nsPoint displayRootOrigin = ComputeViewOffset(displayRoot);
2203
displayRoot->ConvertFromParentCoords(&displayRootOrigin.x, &displayRootOrigin.y);
2205
// Determine, for each view, whether it is or contains a ZPlaceholderView
2206
ComputePlaceholderContainment(displayRoot);
2208
// Create the Z-ordered view tree
2210
if (aEventProcessing) {
2211
paintFloats = PR_TRUE;
2213
paintFloats = displayRoot->GetFloating();
2215
CreateDisplayList(displayRoot, PR_FALSE, zTree, origin.x, origin.y,
2216
aView, &aRect, displayRoot, displayRootOrigin.x, displayRootOrigin.y,
2217
paintFloats, aEventProcessing);
2219
// Reparent any views that need reparenting in the Z-order tree
2220
ReparentViews(zTree);
2221
mMapPlaceholderViewToZTreeNode.Reset();
2223
if (nsnull != zTree) {
2224
// Apply proper Z-order handling
2225
nsAutoVoidArray mergeTmp;
2227
SortByZOrder(zTree, *aDisplayList, mergeTmp, PR_TRUE);
2230
DestroyZTreeNode(zTree);
2233
void nsViewManager::BuildEventTargetList(nsVoidArray &aTargets, nsView* aView, nsGUIEvent* aEvent,
2235
NS_ASSERTION(!mPainting, "View manager cannot handle events during a paint");
2240
nsRect eventRect(aEvent->point.x, aEvent->point.y, 1, 1);
2241
nsAutoVoidArray displayList;
2242
BuildDisplayList(aView, eventRect, PR_TRUE, aCaptured, &displayList);
2245
if (getenv("MOZ_SHOW_DISPLAY_LIST")) ShowDisplayList(&displayList);
2248
// The display list is in order from back to front. We return the target list in order from
2250
for (PRInt32 i = displayList.Count() - 1; i >= 0; --i) {
2251
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, displayList.ElementAt(i));
2252
if (element->mFlags & VIEW_RENDERED) {
2253
aTargets.AppendElement(element);
2260
nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured) {
2261
//printf(" %d %d %d %d (%d,%d) \n", this, event->widget, event->widgetSupports,
2262
// event->message, event->point.x, event->point.y);
2264
// Hold a refcount to the observer. The continued existence of the observer will
2265
// delay deletion of this view hierarchy should the event want to cause its
2266
// destruction in, say, some JavaScript event handler.
2267
nsCOMPtr<nsIViewObserver> obs;
2268
GetViewObserver(*getter_AddRefs(obs));
2270
// accessibility events and key events are dispatched directly to the focused view
2271
if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT
2272
|| aEvent->message == NS_CONTEXTMENU_KEY
2273
|| aEvent->message == NS_MOUSE_EXIT
2274
|| NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) || NS_IS_FOCUS_EVENT(aEvent)) {
2275
nsEventStatus status = nsEventStatus_eIgnore;
2278
obs->HandleEvent(aView, aEvent, &status, PR_TRUE, handled);
2283
nsAutoVoidArray targetViews;
2284
nsAutoVoidArray heldRefCountsToOtherVMs;
2286
// In fact, we only need to take this expensive path when the event is a mouse event ... riiiight?
2287
BuildEventTargetList(targetViews, aView, aEvent, aCaptured);
2289
nsEventStatus status = nsEventStatus_eIgnore;
2291
// get a death grip on any view managers' view observers (other than this one)
2293
for (i = 0; i < targetViews.Count(); i++) {
2294
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, targetViews.ElementAt(i));
2295
nsView* v = element->mView;
2296
nsViewManager* vVM = v->GetViewManager();
2298
nsIViewObserver* vobs = nsnull;
2299
vVM->GetViewObserver(vobs);
2300
if (nsnull != vobs) {
2301
heldRefCountsToOtherVMs.AppendElement(vobs);
2306
for (i = 0; i < targetViews.Count(); i++) {
2307
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, targetViews.ElementAt(i));
2308
nsView* v = element->mView;
2310
if (nsnull != v->GetClientData()) {
2311
PRBool handled = PR_FALSE;
2313
v->GetDimensions(r);
2315
nscoord x = element->mAbsX - r.x;
2316
nscoord y = element->mAbsY - r.y;
2318
aEvent->point.x -= x;
2319
aEvent->point.y -= y;
2321
nsViewManager* vVM = v->GetViewManager();
2323
if (nsnull != obs) {
2324
obs->HandleEvent(v, aEvent, &status, i == targetViews.Count() - 1, handled);
2327
nsCOMPtr<nsIViewObserver> vobs;
2328
vVM->GetViewObserver(*getter_AddRefs(vobs));
2330
vobs->HandleEvent(v, aEvent, &status, i == targetViews.Count() - 1, handled);
2334
aEvent->point.x += x;
2335
aEvent->point.y += y;
2338
while (i < targetViews.Count()) {
2339
DisplayListElement2* e = NS_STATIC_CAST(DisplayListElement2*, targetViews.ElementAt(i));
2345
// if the child says "not handled" but did something which deleted the entire view hierarchy,
2346
// we'll crash in the next iteration. Oh well. The old code would have crashed too.
2352
// release death grips
2353
for (i = 0; i < heldRefCountsToOtherVMs.Count(); i++) {
2354
nsIViewObserver* element = NS_STATIC_CAST(nsIViewObserver*, heldRefCountsToOtherVMs.ElementAt(i));
2355
NS_RELEASE(element);
2361
NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult)
2363
// Along with nsView::SetVisibility, we enforce that the mouse grabber
2364
// can never be a hidden view.
2365
if (aView && NS_STATIC_CAST(nsView*, aView)->GetVisibility()
2366
== nsViewVisibility_kHide) {
2373
printf("capturing mouse events for view %x\n",aView);
2375
printf("removing mouse capture from view %x\n",mMouseGrabber);
2378
mMouseGrabber = NS_STATIC_CAST(nsView*, aView);
2383
NS_IMETHODIMP nsViewManager::GrabKeyEvents(nsIView *aView, PRBool &aResult)
2385
mKeyGrabber = NS_STATIC_CAST(nsView*, aView);
2390
NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView)
2392
aView = mMouseGrabber;
2396
NS_IMETHODIMP nsViewManager::GetKeyEventGrabber(nsIView *&aView)
2398
aView = mKeyGrabber;
2403
// Recursively reparent widgets if necessary
2405
void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
2407
if (aView->HasWidget()) {
2408
// Check to see if the parent widget is the
2409
// same as the new parent. If not then reparent
2410
// the widget, otherwise there is nothing more
2411
// to do for the view and its descendants
2412
nsIWidget* widget = aView->GetWidget();
2413
nsCOMPtr<nsIWidget> parentWidget = getter_AddRefs(widget->GetParent());
2414
if (parentWidget.get() != aNewWidget) {
2415
nsresult rv = widget->SetParent(aNewWidget);
2416
NS_ASSERTION(NS_SUCCEEDED(rv), "SetParent failed!");
2421
// Need to check each of the views children to see
2422
// if they have a widget and reparent it.
2424
nsView* view = NS_STATIC_CAST(nsView*, aView);
2425
for (nsView *kid = view->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
2426
ReparentChildWidgets(kid, aNewWidget);
2430
// Reparent a view and its descendant views widgets if necessary
2432
void nsViewManager::ReparentWidgets(nsIView* aView, nsIView *aParent)
2434
// Quickly determine whether the view has pre-existing children or a
2435
// widget. In most cases the view will not have any pre-existing
2436
// children when this is called. Only in the case
2437
// where a view has been reparented by removing it from
2438
// a reinserting it into a new location in the view hierarchy do we
2439
// have to consider reparenting the existing widgets for the view and
2440
// it's descendants.
2441
nsView* view = NS_STATIC_CAST(nsView*, aView);
2442
if (view->HasWidget() || view->GetFirstChild()) {
2443
nsCOMPtr<nsIWidget> parentWidget;
2444
GetWidgetForView(aParent, getter_AddRefs(parentWidget));
2446
ReparentChildWidgets(aView, parentWidget);
2449
NS_WARNING("Can not find a widget for the parent view");
2453
NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, nsIView *aSibling,
2456
nsView* parent = NS_STATIC_CAST(nsView*, aParent);
2457
nsView* child = NS_STATIC_CAST(nsView*, aChild);
2458
nsView* sibling = NS_STATIC_CAST(nsView*, aSibling);
2460
NS_PRECONDITION(nsnull != parent, "null ptr");
2461
NS_PRECONDITION(nsnull != child, "null ptr");
2462
NS_ASSERTION(sibling == nsnull || sibling->GetParent() == parent,
2463
"tried to insert view with invalid sibling");
2464
NS_ASSERTION(!IsViewInserted(child), "tried to insert an already-inserted view");
2466
if ((nsnull != parent) && (nsnull != child))
2468
// if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
2469
// order, otherwise after 'kid' (i.e. before 'kid' in document order).
2472
if (nsnull == aSibling) {
2474
// insert at end of document order, i.e., before first view
2475
// this is the common case, by far
2476
parent->InsertChild(child, nsnull);
2477
ReparentWidgets(child, parent);
2479
// insert at beginning of document order, i.e., after last view
2480
nsView *kid = parent->GetFirstChild();
2481
nsView *prev = nsnull;
2484
kid = kid->GetNextSibling();
2486
// prev is last view or null if there are no children
2487
parent->InsertChild(child, prev);
2488
ReparentWidgets(child, parent);
2491
nsView *kid = parent->GetFirstChild();
2492
nsView *prev = nsnull;
2493
while (kid && sibling != kid) {
2494
//get the next sibling view
2496
kid = kid->GetNextSibling();
2498
NS_ASSERTION(kid != nsnull,
2499
"couldn't find sibling in child list");
2501
// insert after 'kid' in document order, i.e. before in view order
2502
parent->InsertChild(child, prev);
2503
ReparentWidgets(child, parent);
2505
// insert before 'kid' in document order, i.e. after in view order
2506
parent->InsertChild(child, kid);
2507
ReparentWidgets(child, parent);
2510
#else // don't keep consistent document order, but order things by z-index instead
2511
// essentially we're emulating the old InsertChild(parent, child, zindex)
2512
PRInt32 zIndex = child->GetZIndex();
2513
while (nsnull != kid)
2515
PRInt32 idx = kid->GetZIndex();
2517
if (CompareZIndex(zIndex, child->IsTopMost(), child->GetZIndexIsAuto(),
2518
idx, kid->IsTopMost(), kid->GetZIndexIsAuto()) >= 0)
2522
kid = kid->GetNextSibling();
2525
parent->InsertChild(child, prev);
2526
ReparentWidgets(child, parent);
2529
// if the parent view is marked as "floating", make the newly added view float as well.
2530
if (parent->GetFloating())
2531
child->SetFloating(PR_TRUE);
2533
//and mark this area as dirty if the view is visible...
2535
if (nsViewVisibility_kHide != child->GetVisibility())
2536
UpdateView(child, NS_VMREFRESH_NO_SYNC);
2541
NS_IMETHODIMP nsViewManager::InsertZPlaceholder(nsIView *aParent, nsIView *aChild,
2542
nsIView *aSibling, PRBool aAfter)
2544
nsView* parent = NS_STATIC_CAST(nsView*, aParent);
2545
nsView* child = NS_STATIC_CAST(nsView*, aChild);
2547
NS_PRECONDITION(nsnull != parent, "null ptr");
2548
NS_PRECONDITION(nsnull != child, "null ptr");
2550
nsZPlaceholderView* placeholder = new nsZPlaceholderView();
2551
nsRect bounds(0, 0, 0, 0);
2552
// mark the placeholder as "shown" so that it will be included in a built display list
2553
placeholder->Init(this, bounds, parent, nsViewVisibility_kShow);
2554
placeholder->SetReparentedView(child);
2555
placeholder->SetZIndex(child->GetZIndexIsAuto(), child->GetZIndex(), child->IsTopMost());
2556
child->SetZParent(placeholder);
2558
return InsertChild(parent, placeholder, aSibling, aAfter);
2561
NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, PRInt32 aZIndex)
2563
// no-one really calls this with anything other than aZIndex == 0 on a fresh view
2564
// XXX this method should simply be eliminated and its callers redirected to the real method
2565
SetViewZIndex(aChild, PR_FALSE, aZIndex, PR_FALSE);
2566
return InsertChild(aParent, aChild, nsnull, PR_TRUE);
2569
NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *aChild)
2571
nsView* child = NS_STATIC_CAST(nsView*, aChild);
2573
NS_PRECONDITION(nsnull != child, "null ptr");
2575
nsView* parent = child->GetParent();
2577
if ((nsnull != parent) && (nsnull != child))
2579
UpdateView(child, NS_VMREFRESH_NO_SYNC);
2580
parent->RemoveChild(child);
2586
NS_IMETHODIMP nsViewManager::MoveViewBy(nsIView *aView, nscoord aX, nscoord aY)
2588
nsView* view = NS_STATIC_CAST(nsView*, aView);
2590
nsPoint pt = view->GetPosition();
2591
MoveViewTo(view, aX + pt.x, aY + pt.y);
2595
NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
2597
nsView* view = NS_STATIC_CAST(nsView*, aView);
2598
nsPoint oldPt = view->GetPosition();
2599
nsRect oldArea = view->GetBounds();
2600
view->SetPosition(aX, aY);
2602
// only do damage control if the view is visible
2604
if ((aX != oldPt.x) || (aY != oldPt.y)) {
2605
if (view->GetVisibility() != nsViewVisibility_kHide) {
2606
nsView* parentView = view->GetParent();
2607
UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC);
2608
UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
2614
void nsViewManager::InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
2615
PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, PRBool aInCutOut) {
2616
nscoord height = aY2 - aY1;
2617
if (aRect.x < aCutOut.x) {
2618
nsRect r(aRect.x, aY1, aCutOut.x - aRect.x, height);
2619
UpdateView(aView, r, aUpdateFlags);
2621
if (!aInCutOut && aCutOut.x < aCutOut.XMost()) {
2622
nsRect r(aCutOut.x, aY1, aCutOut.width, height);
2623
UpdateView(aView, r, aUpdateFlags);
2625
if (aCutOut.XMost() < aRect.XMost()) {
2626
nsRect r(aCutOut.XMost(), aY1, aRect.XMost() - aCutOut.XMost(), height);
2627
UpdateView(aView, r, aUpdateFlags);
2631
void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
2632
PRUint32 aUpdateFlags) {
2633
if (aRect.y < aCutOut.y) {
2634
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aRect.y, aCutOut.y, PR_FALSE);
2636
if (aCutOut.y < aCutOut.YMost()) {
2637
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.y, aCutOut.YMost(), PR_TRUE);
2639
if (aCutOut.YMost() < aRect.YMost()) {
2640
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.YMost(), aRect.YMost(), PR_FALSE);
2644
NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRBool aRepaintExposedAreaOnly)
2646
nsView* view = NS_STATIC_CAST(nsView*, aView);
2647
nsRect oldDimensions;
2649
view->GetDimensions(oldDimensions);
2650
if (oldDimensions != aRect) {
2651
nsView* parentView = view->GetParent();
2652
if (parentView == nsnull)
2656
// Prevent Invalidation of hidden views
2657
if (view->GetVisibility() == nsViewVisibility_kHide) {
2658
view->SetDimensions(aRect, PR_FALSE);
2660
if (!aRepaintExposedAreaOnly) {
2661
//Invalidate the union of the old and new size
2662
view->SetDimensions(aRect, PR_TRUE);
2664
UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
2665
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
2666
UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC);
2668
view->SetDimensions(aRect, PR_TRUE);
2670
InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
2672
view->ConvertToParentCoords(&r.x, &r.y);
2673
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
2674
InvalidateRectDifference(parentView, oldDimensions, r, NS_VMREFRESH_NO_SYNC);
2679
// Note that if layout resizes the view and the view has a custom clip
2680
// region set, then we expect layout to update the clip region too. Thus
2681
// in the case where mClipRect has been optimized away to just be a null
2682
// pointer, and this resize is implicitly changing the clip rect, it's OK
2683
// because layout will change it back again if necessary.
2688
NS_IMETHODIMP nsViewManager::SetViewChildClipRegion(nsIView *aView, const nsRegion *aRegion)
2690
nsView* view = NS_STATIC_CAST(nsView*, aView);
2692
NS_ASSERTION(!(nsnull == view), "no view");
2694
const nsRect* oldClipRect = view->GetClipChildrenToRect();
2696
nsRect newClipRectStorage = view->GetDimensions();
2697
nsRect* newClipRect = nsnull;
2699
newClipRectStorage = aRegion->GetBounds();
2700
newClipRect = &newClipRectStorage;
2703
if ((oldClipRect != nsnull) == (newClipRect != nsnull)
2704
&& (!newClipRect || *newClipRect == *oldClipRect)) {
2707
nsRect oldClipRectStorage =
2708
oldClipRect ? *oldClipRect : view->GetDimensions();
2710
// Update the view properties
2711
view->SetClipChildrenToRect(newClipRect);
2713
if (IsViewInserted(view)) {
2714
// Invalidate changed areas
2715
// Paint (new - old) in the current view
2716
InvalidateRectDifference(view, newClipRectStorage, oldClipRectStorage, NS_VMREFRESH_NO_SYNC);
2717
// Paint (old - new) in the parent view, since it'll be clipped out of the current view
2718
nsView* parent = view->GetParent();
2720
oldClipRectStorage += view->GetPosition();
2721
newClipRectStorage += view->GetPosition();
2722
InvalidateRectDifference(parent, oldClipRectStorage, newClipRectStorage, NS_VMREFRESH_NO_SYNC);
2730
Returns PR_TRUE if and only if aView is a (possibly indirect) child of aAncestor.
2732
static PRBool IsAncestorOf(const nsView* aAncestor, const nsView* aView)
2734
while (nsnull != aView) {
2735
aView = aView->GetParent();
2736
if (aView == aAncestor) {
2744
This function returns TRUE only if we are sure that scrolling
2745
aView's widget and moving its child widgets, followed by
2746
UpdateViewAfterScroll, will result in correct painting (i.e. the
2747
same results as just invalidating the entire view). If we're not
2748
sure then we return FALSE to cause a full update of the view's area.
2750
The way we check this is quite subtle, because there are all sorts
2751
of complicated things that can happen.
2753
Conceptually what we do is compute the display list for the "after
2754
scrolling" situation and compare it to a translation of the display
2755
list for the "before scrolling" situation. If the two lists are
2756
equal then we return TRUE.
2758
We could implement this directly, but that would be rather
2759
complex. In particular it's hard to build the display list for the
2760
"before scrolling" situation since this function is called after
2761
scrolling. So instead we just build the "after scrolling" display
2762
list and do some analysis of it, making some approximations along
2765
Display list elements for aView's descendants will always be the
2766
same "before" (plus translation) and "after", because they get
2767
scrolled by the same amount as the translation. Display list
2768
elements for other views will be in different positions "before"
2769
(plus translation) and "after" because they don't get
2770
scrolled. These elements are the ones that force us to return
2771
PR_FALSE. Unfortunately we can't just scan the "after" display list
2772
and ensure no elements are not descendants of aView: there could
2773
have been some non-aView-descendant which appeared in the "before"
2774
list but does not show up in the "after" list because it ended up
2775
completely hidden by some opaque aView-descendant.
2777
So here's what we have to do: we compute an "after" display list but
2778
before performing the optimization pass to eliminate completely
2779
covered views, we mark all aView-descendant display list elements as
2780
transparent. Thus we can be sure that any non-aView-descendant
2781
display list elements that would have shown up in the translated "before"
2782
list will still show up in the "after" list (since the only views which
2783
can cover them are non-aView-descendants, which haven't moved). Then
2784
we check the final display list to make sure only aView-descendant
2785
display list elements are included.
2787
NOTE: We also scan the "after" display list to find views whose contents
2788
depend on their scroll position (e.g., CSS attachment-fixed backgrounds),
2789
which are flagged with NS_VIEW_FLAG_DONT_BITBLT. If any are found, we return
2792
XXX Post-1.0 we should consider instead of returning a boolean,
2793
actually computing a rectangle or region which can be safely
2794
scrolled with bitblt. This would be the area which is aView's
2795
rectangle minus the area covered by any non-aView-descendant views
2796
in the translated "before" or "after" lists. Then we could scroll
2797
that area and explicitly invalidate the rest. This would give us
2798
high performance scrolling even in the presence of overlapping
2799
content and eliminate the need for native widgets for fixed position
2802
PRBool nsViewManager::CanScrollWithBitBlt(nsView* aView)
2804
NS_ASSERTION(!mPainting, "View manager shouldn't be scrolling during a paint");
2806
return PR_FALSE; // do the safe thing
2809
nsRect r = aView->GetClippedRect();
2810
// Only check the area that intersects the view's non clipped rectangle
2812
return PR_TRUE; // nothing to scroll
2815
nsAutoVoidArray displayList;
2816
BuildDisplayList(aView, r, PR_FALSE, PR_FALSE, &displayList);
2819
for (i = 0; i < displayList.Count(); i++) {
2820
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, displayList.ElementAt(i));
2821
if ((element->mFlags & VIEW_RENDERED) != 0) {
2822
if (IsAncestorOf(aView, element->mView)) {
2823
element->mFlags |= (VIEW_ISSCROLLED | VIEW_TRANSPARENT);
2828
nsRect finalTransparentRect;
2830
// We DON'T use AddCoveringWidgetsToOpaqueRegion here. Our child widgets are going to be moved
2831
// as if they were scrolled, so we need to examine the display list elements that might be covered by
2834
// However, we do want to ignore areas that are covered by widgets which have not moved.
2835
// Unfortunately figuring out that area is not easy, because we don't yet trust the native
2836
// widget layer to tell us the correct z-order of native widgets.
2837
// We still have to handle at least one case well:
2838
// widgets for fixed-position elements when we are scrolling the root scrollable (or something inside
2839
// the root scrollable) are on top.
2840
nsRegion opaqueRegion;
2841
if (mRootScrollable != nsnull) {
2842
const nsIView* scrollableClipView;
2843
mRootScrollable->GetClipView(&scrollableClipView);
2844
if (IsAncestorOf(NS_STATIC_CAST(const nsView*, scrollableClipView), aView)) {
2845
// add areas of fixed views to the opaque area.
2846
// This is a bit of a hack. We should not be doing special case processing for fixed views.
2847
nsView* fixedView = mRootView->GetFirstChild();
2848
while (fixedView != nsnull) {
2849
if (fixedView->GetZParent() != nsnull && fixedView->GetZIndex() >= 0) {
2850
opaqueRegion.Or(opaqueRegion, fixedView->GetBounds());
2852
fixedView = fixedView->GetNextSibling();
2855
// get the region into the coordinates of aView
2856
nscoord deltaX = 0, deltaY = 0;
2857
for (nsView* v = aView; v; v = v->GetParent()) {
2858
v->ConvertToParentCoords(&deltaX, &deltaY);
2860
opaqueRegion.MoveBy(-deltaX, -deltaY);
2864
// We DO need to use OptimizeDisplayList here to eliminate views
2865
// that are covered by views we know are opaque. Typically aView's
2866
// scrolled view is opaque and we want to eliminate views behind it,
2867
// such as aView itself, that aren't being moved and would otherwise
2868
// cause us to decide not to blit. Note that if for some view,
2869
// view->HasUniformBackground(), that's also sufficient to ignore
2870
// views behind 'view'; we've been promised that they produce only a
2871
// uniform background, which is still blittable. So we can treat
2872
// 'view' as opaque.
2874
// (Note that it's possible for aView's parent to actually be in
2875
// front of aView (if aView has a negative z-index) but if so, this
2876
// code still does the right thing. Yay for the display list based
2879
OptimizeDisplayList(&displayList, nsRegion(r), finalTransparentRect, opaqueRegion, PR_TRUE);
2881
PRBool anyUnscrolledViews = PR_FALSE;
2882
PRBool anyUnblittableViews = PR_FALSE;
2884
for (i = 0; i < displayList.Count(); i++) {
2885
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, displayList.ElementAt(i));
2886
if ((element->mFlags & VIEW_RENDERED) != 0) {
2887
if ((element->mFlags & VIEW_ISSCROLLED) == 0 && element->mView != aView) {
2888
anyUnscrolledViews = PR_TRUE;
2889
} else if ((element->mView->GetViewFlags() & NS_VIEW_FLAG_DONT_BITBLT) != 0) {
2890
anyUnblittableViews = PR_TRUE;
2897
return !anyUnscrolledViews && !anyUnblittableViews;
2900
NS_IMETHODIMP nsViewManager::SetViewBitBltEnabled(nsIView *aView, PRBool aEnable)
2902
nsView* view = NS_STATIC_CAST(nsView*, aView);
2904
NS_ASSERTION(!(nsnull == view), "no view");
2907
view->SetViewFlags(view->GetViewFlags() & ~NS_VIEW_FLAG_DONT_BITBLT);
2909
view->SetViewFlags(view->GetViewFlags() | NS_VIEW_FLAG_DONT_BITBLT);
2915
NS_IMETHODIMP nsViewManager::SetViewCheckChildEvents(nsIView *aView, PRBool aEnable)
2917
nsView* view = NS_STATIC_CAST(nsView*, aView);
2919
NS_ASSERTION(!(nsnull == view), "no view");
2922
view->SetViewFlags(view->GetViewFlags() & ~NS_VIEW_FLAG_DONT_CHECK_CHILDREN);
2924
view->SetViewFlags(view->GetViewFlags() | NS_VIEW_FLAG_DONT_CHECK_CHILDREN);
2930
NS_IMETHODIMP nsViewManager::SetViewFloating(nsIView *aView, PRBool aFloating)
2932
nsView* view = NS_STATIC_CAST(nsView*, aView);
2934
NS_ASSERTION(!(nsnull == view), "no view");
2936
view->SetFloating(aFloating);
2941
NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility aVisible)
2943
nsView* view = NS_STATIC_CAST(nsView*, aView);
2945
if (aVisible != view->GetVisibility()) {
2946
view->SetVisibility(aVisible);
2948
if (IsViewInserted(view)) {
2949
if (!view->HasWidget()) {
2950
if (nsViewVisibility_kHide == aVisible) {
2951
nsView* parentView = view->GetParent();
2953
UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
2957
UpdateView(view, NS_VMREFRESH_NO_SYNC);
2965
PRBool nsViewManager::IsViewInserted(nsView *aView)
2967
if (mRootView == aView) {
2969
} else if (aView->GetParent() == nsnull) {
2972
nsView* view = aView->GetParent()->GetFirstChild();
2973
while (view != nsnull) {
2974
if (view == aView) {
2977
view = view->GetNextSibling();
2983
NS_IMETHODIMP nsViewManager::SetViewZIndex(nsIView *aView, PRBool aAutoZIndex, PRInt32 aZIndex, PRBool aTopMost)
2985
nsView* view = NS_STATIC_CAST(nsView*, aView);
2986
nsresult rv = NS_OK;
2988
NS_ASSERTION((view != nsnull), "no view");
2990
// don't allow the root view's z-index to be changed. It should always be zero.
2991
// This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
2992
if (aView == mRootView) {
2996
PRBool oldTopMost = view->IsTopMost();
2997
PRBool oldIsAuto = view->GetZIndexIsAuto();
3003
PRInt32 oldidx = view->GetZIndex();
3004
view->SetZIndex(aAutoZIndex, aZIndex, aTopMost);
3006
if (CompareZIndex(oldidx, oldTopMost, oldIsAuto,
3007
aZIndex, aTopMost, aAutoZIndex) != 0) {
3008
UpdateView(view, NS_VMREFRESH_NO_SYNC);
3011
// Native widgets ultimately just can't deal with the awesome power
3012
// of CSS2 z-index. However, we set the z-index on the widget anyway
3013
// because in many simple common cases the widgets do end up in the
3014
// right order. Even if they don't, we'll still render correctly as
3015
// long as there are no plugins around (although there may be more
3016
// flickering and other perf issues than if the widgets were in a
3018
if (view->HasWidget()) {
3019
view->GetWidget()->SetZIndex(aZIndex);
3022
nsZPlaceholderView* zParentView = view->GetZParent();
3023
if (nsnull != zParentView) {
3024
SetViewZIndex(zParentView, aAutoZIndex, aZIndex, aTopMost);
3030
NS_IMETHODIMP nsViewManager::SetViewContentTransparency(nsIView *aView, PRBool aTransparent)
3032
nsView* view = NS_STATIC_CAST(nsView*, aView);
3034
if (view->IsTransparent() != aTransparent) {
3035
view->SetContentTransparency(aTransparent);
3037
if (IsViewInserted(view)) {
3038
UpdateView(view, NS_VMREFRESH_NO_SYNC);
3045
NS_IMETHODIMP nsViewManager::SetViewOpacity(nsIView *aView, float aOpacity)
3047
nsView* view = NS_STATIC_CAST(nsView*, aView);
3049
if (view->GetOpacity() != aOpacity)
3051
view->SetOpacity(aOpacity);
3053
if (IsViewInserted(view)) {
3054
UpdateView(view, NS_VMREFRESH_NO_SYNC);
3061
NS_IMETHODIMP nsViewManager::SetViewObserver(nsIViewObserver *aObserver)
3063
mObserver = aObserver;
3067
NS_IMETHODIMP nsViewManager::GetViewObserver(nsIViewObserver *&aObserver)
3069
if (nsnull != mObserver) {
3070
aObserver = mObserver;
3071
NS_ADDREF(mObserver);
3074
return NS_ERROR_NO_INTERFACE;
3077
NS_IMETHODIMP nsViewManager::GetDeviceContext(nsIDeviceContext *&aContext)
3079
NS_IF_ADDREF(mContext);
3080
aContext = mContext;
3084
void nsViewManager::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const
3086
// Go through the list of viewmanagers and get the maximum width and
3087
// height of their widgets
3088
aMaxWidgetBounds.width = 0;
3089
aMaxWidgetBounds.height = 0;
3091
for (index = 0; index < mVMCount; index++) {
3093
nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
3094
nsCOMPtr<nsIWidget> rootWidget;
3096
if(NS_SUCCEEDED(vm->GetWidget(getter_AddRefs(rootWidget))) && rootWidget)
3098
nsRect widgetBounds;
3099
rootWidget->GetBounds(widgetBounds);
3100
aMaxWidgetBounds.width = PR_MAX(aMaxWidgetBounds.width, widgetBounds.width);
3101
aMaxWidgetBounds.height = PR_MAX(aMaxWidgetBounds.height, widgetBounds.height);
3105
// printf("WIDGET BOUNDS %d %d\n", aMaxWidgetBounds.width, aMaxWidgetBounds.height);
3108
PRInt32 nsViewManager::GetViewManagerCount()
3113
const nsVoidArray* nsViewManager::GetViewManagerArray()
3115
return gViewManagers;
3118
nsIRenderingContext * nsViewManager::CreateRenderingContext(nsView &aView)
3120
nsView *par = &aView;
3122
nsIRenderingContext *cx = nsnull;
3123
nscoord ax = 0, ay = 0;
3127
win = par->GetWidget();
3131
//get absolute coordinates of view, but don't
3132
//add in view pos since the first thing you ever
3133
//need to do when painting a view is to translate
3134
//the rendering context by the views pos and other parts
3135
//of the code do this for us...
3139
par->ConvertToParentCoords(&ax, &ay);
3142
par = par->GetParent();
3144
while (nsnull != par);
3148
mContext->CreateRenderingContext(&aView, cx);
3151
cx->Translate(ax, ay);
3157
void nsViewManager::AddRectToDirtyRegion(nsView* aView, const nsRect &aRect) const
3159
// Find a view with an associated widget. We'll transform this rect from the
3160
// current view's coordinate system to a "heavyweight" parent view, then convert
3161
// the rect to pixel coordinates, and accumulate the rect into that view's dirty region.
3162
nsView* widgetView = GetWidgetView(aView);
3163
if (widgetView != nsnull) {
3164
nsRect widgetRect = aRect;
3165
ViewToWidget(aView, widgetView, widgetRect);
3167
// Get the dirty region associated with the widget view
3168
nsCOMPtr<nsIRegion> dirtyRegion;
3169
if (NS_SUCCEEDED(widgetView->GetDirtyRegion(*getter_AddRefs(dirtyRegion)))) {
3170
// add this rect to the widget view's dirty region.
3171
dirtyRegion->Union(widgetRect.x, widgetRect.y, widgetRect.width, widgetRect.height);
3176
NS_IMETHODIMP nsViewManager::DisableRefresh(void)
3178
if (mUpdateBatchCnt > 0)
3181
mRefreshEnabled = PR_FALSE;
3185
NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags)
3187
if (mUpdateBatchCnt > 0)
3190
mRefreshEnabled = PR_TRUE;
3192
if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
3193
ProcessPendingUpdates(mRootView);
3194
mHasPendingInvalidates = PR_FALSE;
3197
PostInvalidateEvent();
3203
NS_IMETHODIMP nsViewManager::BeginUpdateViewBatch(void)
3205
nsresult result = NS_OK;
3207
if (mUpdateBatchCnt == 0)
3208
result = DisableRefresh();
3210
if (NS_SUCCEEDED(result))
3216
NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags)
3218
nsresult result = NS_OK;
3222
NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
3224
if (mUpdateBatchCnt < 0)
3226
mUpdateBatchCnt = 0;
3227
return NS_ERROR_FAILURE;
3230
if (mUpdateBatchCnt == 0)
3231
result = EnableRefresh(aUpdateFlags);
3236
NS_IMETHODIMP nsViewManager::SetRootScrollableView(nsIScrollableView *aScrollable)
3238
if (mRootScrollable) {
3239
NS_STATIC_CAST(nsScrollPortView*, mRootScrollable)->
3240
SetClipPlaceholdersToBounds(PR_FALSE);
3242
mRootScrollable = aScrollable;
3243
if (mRootScrollable) {
3244
NS_STATIC_CAST(nsScrollPortView*, mRootScrollable)->
3245
SetClipPlaceholdersToBounds(PR_TRUE);
3250
NS_IMETHODIMP nsViewManager::GetRootScrollableView(nsIScrollableView **aScrollable)
3252
*aScrollable = mRootScrollable;
3256
NS_IMETHODIMP nsViewManager::Display(nsIView* aView, nscoord aX, nscoord aY, const nsRect& aClipRect)
3258
nsView *view = NS_STATIC_CAST(nsView*, aView);
3259
nsIRenderingContext *localcx = nsnull;
3261
if (PR_FALSE == mRefreshEnabled)
3264
NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted");
3266
mPainting = PR_TRUE;
3268
mContext->CreateRenderingContext(localcx);
3270
//couldn't get rendering context. this is ok if at startup
3271
if (nsnull == localcx)
3273
mPainting = PR_FALSE;
3274
return NS_ERROR_FAILURE;
3277
nsRect trect = view->GetBounds();
3278
view->ConvertFromParentCoords(&trect.x, &trect.y);
3280
localcx->Translate(aX, aY);
3283
localcx->SetClipRect(aClipRect, nsClipCombine_kReplace, isClipped);
3285
// Paint the view. The clipping rect was set above set don't clip again.
3286
//aView->Paint(*localcx, trect, NS_VIEW_FLAG_CLIP_SET, result);
3287
nsAutoVoidArray displayList;
3288
BuildRenderingDisplayList(view, nsRegion(trect), &displayList);
3289
RenderViews(view, *localcx, nsRegion(trect), PR_FALSE, displayList);
3291
NS_RELEASE(localcx);
3293
mPainting = PR_FALSE;
3299
NS_IMETHODIMP nsViewManager::AddCompositeListener(nsICompositeListener* aListener)
3301
if (nsnull == mCompositeListeners) {
3302
nsresult rv = NS_NewISupportsArray(&mCompositeListeners);
3306
return mCompositeListeners->AppendElement(aListener);
3309
NS_IMETHODIMP nsViewManager::RemoveCompositeListener(nsICompositeListener* aListener)
3311
if (nsnull != mCompositeListeners) {
3312
return mCompositeListeners->RemoveElement(aListener);
3314
return NS_ERROR_FAILURE;
3317
NS_IMETHODIMP nsViewManager::GetWidgetForView(nsIView *aView, nsIWidget **aWidget)
3319
nsView *view = NS_STATIC_CAST(nsView*, aView);
3321
while (view && !view->HasWidget()) {
3322
view = view->GetParent();
3326
// Widget was found in the view hierarchy
3327
*aWidget = view->GetWidget();
3328
NS_ADDREF(*aWidget);
3330
// No widget was found in the view hierachy, so use try to use the mRootWindow
3331
if (nsnull != mRootWindow) {
3332
NS_ASSERTION(this == view->GetViewManager(),
3333
"Must use the view instance's view manager when calling GetWidgetForView");
3334
*aWidget = mRootWindow;
3335
NS_ADDREF(mRootWindow);
3345
NS_IMETHODIMP nsViewManager::GetWidget(nsIWidget **aWidget)
3347
NS_IF_ADDREF(mRootWindow);
3348
*aWidget = mRootWindow;
3352
NS_IMETHODIMP nsViewManager::ForceUpdate()
3355
mRootWindow->Update();
3359
static nsresult EnsureZTreeNodeCreated(nsView* aView, DisplayZTreeNode* &aNode) {
3360
if (nsnull == aNode) {
3361
aNode = new DisplayZTreeNode;
3363
if (nsnull == aNode) {
3364
return NS_ERROR_OUT_OF_MEMORY;
3366
aNode->mView = aView;
3367
aNode->mDisplayElement = nsnull;
3368
aNode->mZChild = nsnull;
3369
aNode->mZSibling = nsnull;
3375
* XXX this needs major simplification and cleanup
3376
* @param aView the view are visiting to create display list element(s) for
3377
* @param aReparentedViewsPresent unused, always PR_FALSE
3378
* @param aResult insert display list elements under here
3379
* @param aOriginX/aOriginY the offset from the origin of aTopView
3380
* to the origin of the view that is being painted (aRealView)
3381
* @param aRealView the view that is being painted
3382
* @param aDamageRect the rect that needs to be painted, relative to the origin
3384
* @param aTopView the displayRoot, the root of the collection of views
3386
* @param aX/aY the offset from aTopView to the origin of the parent of aView
3387
* @param aPaintFloats PR_TRUE if we should paint floating views, PR_FALSE
3388
* if we should avoid descending into any floating views
3389
* @param aEventProcessing PR_TRUE if we intend to do event processing with
3392
PRBool nsViewManager::CreateDisplayList(nsView *aView, PRBool aReparentedViewsPresent,
3393
DisplayZTreeNode* &aResult,
3394
nscoord aOriginX, nscoord aOriginY, nsView *aRealView,
3395
const nsRect *aDamageRect, nsView *aTopView,
3396
nscoord aX, nscoord aY, PRBool aPaintFloats,
3397
PRBool aEventProcessing)
3399
PRBool retval = PR_FALSE;
3403
NS_ASSERTION((aView != nsnull), "no view");
3405
if (nsViewVisibility_kHide == aView->GetVisibility()) {
3406
// bail out if the view is marked invisible; all children are invisible
3410
nsRect bounds = aView->GetBounds();
3411
nsPoint pos = aView->GetPosition();
3413
// -> to global coordinates (relative to aTopView)
3418
// does this view clip all its children?
3420
(aView->GetClipChildrenToBounds(PR_FALSE)
3421
&& !(aView->GetViewFlags() & NS_VIEW_FLAG_CONTAINS_PLACEHOLDER))
3422
|| aView->GetClipChildrenToBounds(PR_TRUE);
3426
// -> to refresh-frame coordinates (relative to aRealView)
3427
bounds.x -= aOriginX;
3428
bounds.y -= aOriginY;
3430
overlap = irect.IntersectRect(bounds, *aDamageRect);
3432
aDamageRect = &irect;
3434
if (aEventProcessing && aRealView == aView) {
3435
// Always deliver an event somewhere, at least to the top-level target.
3436
// There may be mouse capturing going on.
3443
// -> to global coordinates (relative to aTopView)
3444
bounds.x += aOriginX;
3445
bounds.y += aOriginY;
3447
// if there's no overlap between the dirty area and the bounds of
3448
// the view, we should be able to ignore the view and all its
3449
// children. Unfortunately there is the possibility of reparenting:
3450
// some other view in the tree might want to be reparented to one of
3451
// our children, and that view might lie outside our
3452
// bounds. Typically we need to go ahead and add this view and its
3453
// children to the ZTree in case someone wants to reparent into it.
3455
// We can avoid this in two cases: if we clip our children to our
3456
// bounds, then even if a view is reparented under us, none of its
3457
// visible area can lie outside our bounds, so it can't intersect
3458
// the dirty area. Also, if we don't contain any placeholder views,
3459
// then there is no way for anyone to reparent below us.
3460
if (!overlap && !(aView->GetViewFlags() & NS_VIEW_FLAG_CONTAINS_PLACEHOLDER)) {
3464
// Don't paint floating views unless the root view being painted is a floating view.
3465
// This is important because we may be asked to paint
3466
// a window that's behind a transient float; in this case we must paint the real window
3467
// contents, not the float contents (bug 63496)
3468
if (!aPaintFloats && aView->GetFloating()) {
3472
PRBool anyChildren = aView->GetFirstChild() != nsnull;
3474
if (aEventProcessing
3475
&& (aView->GetViewFlags() & NS_VIEW_FLAG_DONT_CHECK_CHILDREN) != 0) {
3476
anyChildren = PR_FALSE;
3479
PRBool hasFilter = aView->GetOpacity() != 1.0f;
3481
// -> to refresh-frame coordinates (relative to aRealView)
3482
bounds.x -= aOriginX;
3483
bounds.y -= aOriginY;
3485
// Add POP first because the z-tree is in reverse order
3486
retval = AddToDisplayList(aView, aResult, bounds, bounds,
3487
POP_FILTER, aX - aOriginX, aY - aOriginY, PR_TRUE);
3491
// -> to global coordinates (relative to aTopView)
3492
bounds.x += aOriginX;
3493
bounds.y += aOriginY;
3498
// -> to refresh-frame coordinates (relative to aRealView)
3499
bounds.x -= aOriginX;
3500
bounds.y -= aOriginY;
3502
// Add POP first because the z-tree is in reverse order
3503
retval = AddToDisplayList(aView, aResult, bounds, bounds,
3504
POP_CLIP, aX - aOriginX, aY - aOriginY, PR_TRUE);
3509
// -> to global coordinates (relative to aTopView)
3510
bounds.x += aOriginX;
3511
bounds.y += aOriginY;
3514
// Put in all the children before we add this view itself.
3515
// This preserves document order.
3516
nsView *childView = nsnull;
3517
for (childView = aView->GetFirstChild(); nsnull != childView;
3518
childView = childView->GetNextSibling()) {
3519
DisplayZTreeNode* createdNode;
3520
retval = CreateDisplayList(childView, aReparentedViewsPresent, createdNode,
3521
aOriginX, aOriginY, aRealView, aDamageRect, aTopView, pos.x, pos.y, aPaintFloats,
3523
if (createdNode != nsnull) {
3524
EnsureZTreeNodeCreated(aView, aResult);
3525
createdNode->mZSibling = aResult->mZChild;
3526
aResult->mZChild = createdNode;
3536
// -> to refresh-frame coordinates (relative to aRealView)
3537
bounds.x -= aOriginX;
3538
bounds.y -= aOriginY;
3540
if (aEventProcessing || aView->GetOpacity() > 0.0f) {
3541
PRUint32 flags = VIEW_RENDERED;
3542
if (aView->IsTransparent())
3543
flags |= VIEW_TRANSPARENT;
3544
retval = AddToDisplayList(aView, aResult, bounds, irect, flags,
3545
aX - aOriginX, aY - aOriginY,
3546
aEventProcessing && aTopView == aView);
3547
// We're forcing AddToDisplayList to pick up the view only
3548
// during event processing, and only when aView is back at the
3549
// root of the tree of acceptable views (note that when event
3550
// capturing is in effect, aTopView is the capturing view)
3553
// -> to global coordinates (relative to aTopView)
3554
bounds.x += aOriginX;
3555
bounds.y += aOriginY;
3557
if (aView->IsZPlaceholderView()) {
3558
EnsureZTreeNodeCreated(aView, aResult);
3559
nsVoidKey key(aView);
3560
mMapPlaceholderViewToZTreeNode.Put(&key, aResult);
3565
if (anyChildren && isClipView) {
3566
// -> to refresh-frame coordinates (relative to aRealView)
3567
bounds.x -= aOriginX;
3568
bounds.y -= aOriginY;
3570
if (AddToDisplayList(aView, aResult, bounds, bounds, PUSH_CLIP,
3571
aX - aOriginX, aY - aOriginY, PR_TRUE)) {
3575
// -> to global coordinates (relative to aTopView)
3576
bounds.x += aOriginX;
3577
bounds.y += aOriginY;
3581
// -> to refresh-frame coordinates (relative to aRealView)
3582
bounds.x -= aOriginX;
3583
bounds.y -= aOriginY;
3585
retval = AddToDisplayList(aView, aResult, bounds, bounds,
3586
PUSH_FILTER, aX - aOriginX, aY - aOriginY, PR_TRUE);
3590
// -> to global coordinates (relative to aTopView)
3591
bounds.x += aOriginX;
3592
bounds.y += aOriginY;
3598
PRBool nsViewManager::AddToDisplayList(nsView *aView,
3599
DisplayZTreeNode* &aParent, nsRect &aClipRect,
3600
nsRect& aDirtyRect, PRUint32 aFlags,
3601
nscoord aAbsX, nscoord aAbsY,
3602
PRBool aAssumeIntersection)
3604
nsRect clipRect = aView->GetClippedRect();
3605
PRBool clipped = clipRect != aView->GetDimensions();
3607
// get clipRect into the coordinate system of aView's parent. aAbsX and
3608
// aAbsY give an offset to the origin of aView's parent.
3609
clipRect.MoveBy(aView->GetPosition());
3610
clipRect.x += aAbsX;
3611
clipRect.y += aAbsY;
3614
// XXX this code can't be right. If we're only clipped by one pixel,
3615
// then that's no reason to use a whole different rectangle.
3616
NS_ASSERTION(clipRect == aClipRect, "gah!!!");
3617
clipRect = aClipRect;
3620
PRBool overlap = clipRect.IntersectRect(clipRect, aDirtyRect);
3621
if (!overlap && !aAssumeIntersection) {
3625
DisplayListElement2* element = new DisplayListElement2;
3626
if (element == nsnull) {
3629
DisplayZTreeNode* node = new DisplayZTreeNode;
3630
if (nsnull == node) {
3635
EnsureZTreeNodeCreated(aView, aParent);
3637
node->mDisplayElement = element;
3638
node->mView = nsnull;
3639
node->mZChild = nsnull;
3640
node->mZSibling = aParent->mZChild;
3641
aParent->mZChild = node;
3643
element->mView = aView;
3644
element->mBounds = clipRect;
3645
element->mAbsX = aClipRect.x;
3646
element->mAbsY = aClipRect.y;
3647
element->mFlags = aFlags;
3649
element->mFlags |= VIEW_CLIPPED;
3656
Walk the display list, looking for opaque views, and remove any views that are behind them
3657
and totally occluded.
3659
@param aFinalTransparentRect
3660
Receives a rectangle enclosing all pixels in the damage rectangle
3661
which will not be opaquely painted over by the display list.
3662
Usually this will be empty, but nothing really prevents someone
3663
from creating a set of views that are (for example) all transparent.
3665
void nsViewManager::OptimizeDisplayList(const nsVoidArray* aDisplayList, const nsRegion& aDamageRegion,
3666
nsRect& aFinalTransparentRect,
3667
nsRegion &aOpaqueRegion, PRBool aTreatUniformAsOpaque)
3669
// Mark all views inside a PUSH_FILTER/POP_FILTER as being translucent.
3670
// If we don't do this, we'll incorrectly optimize by thinking views are
3671
// opaque when they really aren't.
3673
PRInt32 filterDepth = 0;
3674
for (i = 0; i < aDisplayList->Count(); ++i) {
3675
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*,
3676
aDisplayList->ElementAt(i));
3677
if (element->mFlags & PUSH_FILTER) {
3680
if (filterDepth > 0 && (element->mFlags & VIEW_RENDERED)) {
3681
element->mFlags |= VIEW_TRANSLUCENT;
3683
if (element->mFlags & POP_FILTER) {
3688
for (i = aDisplayList->Count() - 1; i >= 0; --i) {
3689
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, aDisplayList->ElementAt(i));
3690
if (element->mFlags & VIEW_RENDERED) {
3692
tmpRgn.Sub(element->mBounds, aOpaqueRegion);
3693
tmpRgn.And(tmpRgn, aDamageRegion);
3695
if (tmpRgn.IsEmpty()) {
3696
element->mFlags &= ~VIEW_RENDERED;
3698
element->mBounds = tmpRgn.GetBounds();
3700
// a view is opaque if it is neither transparent nor transluscent
3701
if (!(element->mFlags & (VIEW_TRANSPARENT | VIEW_TRANSLUCENT))
3702
// also, treat it as opaque if it's drawn onto a uniform background
3703
// and we're doing scrolling analysis; if the background is uniform,
3704
// we don't care what's under it. But the background might be translucent
3705
// because of some enclosing opacity group, in which case we do care
3706
// what's under it. Unfortunately we don't know exactly where the
3707
// background comes from ... it may not even have a view ... but
3708
// the side condition on SetHasUniformBackground ensures that
3709
// if the background is translucent, then this view is also marked
3711
|| (element->mView->HasUniformBackground() && aTreatUniformAsOpaque
3712
&& !(element->mFlags & VIEW_TRANSLUCENT))) {
3713
aOpaqueRegion.Or(aOpaqueRegion, element->mBounds);
3720
tmpRgn.Sub(aDamageRegion, aOpaqueRegion);
3721
aFinalTransparentRect = tmpRgn.GetBounds();
3724
// Remove redundant PUSH/POP_CLIP pairs. These could be expensive.
3725
void nsViewManager::OptimizeDisplayListClipping(const nsVoidArray* aDisplayList,
3726
PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex,
3727
PRBool& aAnyRendered)
3729
aAnyRendered = PR_FALSE;
3731
while (aIndex < aDisplayList->Count()) {
3732
DisplayListElement2* element =
3733
NS_STATIC_CAST(DisplayListElement2*, aDisplayList->ElementAt(aIndex));
3736
if (element->mFlags & VIEW_RENDERED) {
3737
aAnyRendered = PR_TRUE;
3739
if (aHaveClip && (element->mFlags & VIEW_CLIPPED)) {
3741
newClip.IntersectRect(aClipRect, element->mBounds);
3742
// no need to clip if the clip rect doesn't change
3743
if (newClip == aClipRect) {
3744
element->mFlags &= ~VIEW_CLIPPED;
3749
if (element->mFlags & PUSH_CLIP) {
3752
newClip.IntersectRect(aClipRect, element->mBounds);
3754
newClip = element->mBounds;
3757
PRBool anyRenderedViews = PR_FALSE;
3758
OptimizeDisplayListClipping(aDisplayList, PR_TRUE, newClip, aIndex, anyRenderedViews);
3759
DisplayListElement2* popElement =
3760
NS_STATIC_CAST(DisplayListElement2*, aDisplayList->ElementAt(aIndex - 1));
3761
NS_ASSERTION(popElement->mFlags & POP_CLIP, "Must end with POP!");
3763
if (anyRenderedViews) {
3764
aAnyRendered = PR_TRUE;
3766
if (!anyRenderedViews || (aHaveClip && newClip == aClipRect)) {
3767
// no need to clip if nothing's going to be rendered
3768
// ... or if the clip rect didn't change
3769
element->mFlags &= ~PUSH_CLIP;
3770
popElement->mFlags &= ~POP_CLIP;
3774
if (element->mFlags & POP_CLIP) {
3780
// Compute the bounds what's rendered between each PUSH_FILTER/POP_FILTER. Also
3781
// compute the region of what's rendered that's actually opaque. Then we can
3782
// decide for each PUSH_FILTER/POP_FILTER pair whether the contents are partially
3783
// transparent or fully opaque. Detecting the fully opaque case is important
3784
// because it's much faster to composite a fully opaque element (i.e., all alphas
3786
nsRect nsViewManager::OptimizeTranslucentRegions(
3787
const nsVoidArray& aDisplayList, PRInt32* aIndex, nsRegion* aOpaqueRegion)
3790
while (*aIndex < aDisplayList.Count()) {
3791
DisplayListElement2* element =
3792
NS_STATIC_CAST(DisplayListElement2*, aDisplayList.ElementAt(*aIndex));
3795
if (element->mFlags & VIEW_RENDERED) {
3796
r.UnionRect(r, element->mBounds);
3797
// the bounds of a non-transparent element are added to the opaque
3799
if (!element->mView->IsTransparent() && aOpaqueRegion) {
3800
aOpaqueRegion->Or(*aOpaqueRegion, element->mBounds);
3804
if (element->mFlags & PUSH_FILTER) {
3805
// the region inside the PUSH/POP pair that's painted opaquely
3806
nsRegion opaqueRegion;
3807
// save the bounds of the area that's painted by elements between the PUSH/POP
3808
element->mBounds = OptimizeTranslucentRegions(aDisplayList, aIndex,
3810
DisplayListElement2* popElement =
3811
NS_STATIC_CAST(DisplayListElement2*, aDisplayList.ElementAt(*aIndex - 1));
3812
popElement->mBounds = element->mBounds;
3813
NS_ASSERTION(popElement->mFlags & POP_FILTER, "Must end with POP!");
3815
// don't bother with filters if nothing is visible inside the filter
3816
if (element->mBounds.IsEmpty()) {
3817
element->mFlags &= ~PUSH_FILTER;
3818
popElement->mFlags &= ~POP_FILTER;
3821
tmpRegion.Sub(element->mBounds, opaqueRegion);
3822
if (!tmpRegion.IsEmpty()) {
3823
// remember whether this PUSH_FILTER/POP_FILTER contents are fully opaque or not
3824
element->mFlags |= VIEW_TRANSPARENT;
3828
// The filter doesn't paint opaquely, so don't add anything to aOpaqueRegion
3829
r.UnionRect(r, element->mBounds);
3831
if (element->mFlags & POP_FILTER) {
3839
void nsViewManager::ShowDisplayList(const nsVoidArray* aDisplayList)
3842
printf("### display list length=%d ###\n", aDisplayList->Count());
3844
PRInt32 nestcnt = 0;
3845
for (PRInt32 cnt = 0; cnt < aDisplayList->Count(); cnt++) {
3846
DisplayListElement2* element = (DisplayListElement2*)aDisplayList->ElementAt(cnt);
3847
nestcnt = PrintDisplayListElement(element, nestcnt);
3852
nsPoint nsViewManager::ComputeViewOffset(const nsView *aView)
3854
nsPoint origin(0, 0);
3856
origin += aView->GetPosition();
3857
aView = aView->GetParent();
3862
PRBool nsViewManager::DoesViewHaveNativeWidget(nsView* aView)
3864
if (aView->HasWidget())
3865
return (nsnull != aView->GetWidget()->GetNativeData(NS_NATIVE_WIDGET));
3869
nsView* nsViewManager::GetWidgetView(nsView *aView)
3872
if (aView->HasWidget())
3874
aView = aView->GetParent();
3879
void nsViewManager::ViewToWidget(nsView *aView, nsView* aWidgetView, nsRect &aRect) const
3881
while (aView != aWidgetView) {
3882
aView->ConvertToParentCoords(&aRect.x, &aRect.y);
3883
aView = aView->GetParent();
3886
// intersect aRect with bounds of aWidgetView, to prevent generating any illegal rectangles.
3888
aWidgetView->GetDimensions(bounds);
3889
aRect.IntersectRect(aRect, bounds);
3890
// account for the view's origin not lining up with the widget's
3891
aRect.x -= bounds.x;
3892
aRect.y -= bounds.y;
3894
// finally, convert to device coordinates.
3896
t2p = mContext->AppUnitsToDevUnits();
3897
aRect.ScaleRoundOut(t2p);
3900
nsresult nsViewManager::GetVisibleRect(nsRect& aVisibleRect)
3902
nsresult rv = NS_OK;
3904
// Get the viewport scroller
3905
nsIScrollableView* scrollingView;
3906
GetRootScrollableView(&scrollingView);
3908
if (scrollingView) {
3909
// Determine the visible rect in the scrolled view's coordinate space.
3910
// The size of the visible area is the clip view size
3911
const nsIView* clipViewI;
3912
scrollingView->GetClipView(&clipViewI);
3914
const nsView* clipView = NS_STATIC_CAST(const nsView*, clipViewI);
3915
clipView->GetDimensions(aVisibleRect);
3917
scrollingView->GetScrollPosition(aVisibleRect.x, aVisibleRect.y);
3919
rv = NS_ERROR_FAILURE;
3925
nsresult nsViewManager::GetAbsoluteRect(nsView *aView, const nsRect &aRect,
3928
nsIScrollableView* scrollingView = nsnull;
3929
GetRootScrollableView(&scrollingView);
3930
if (nsnull == scrollingView) {
3931
return NS_ERROR_FAILURE;
3934
nsIView* scrolledIView = nsnull;
3935
scrollingView->GetScrolledView(scrolledIView);
3937
nsView* scrolledView = NS_STATIC_CAST(nsView*, scrolledIView);
3939
// Calculate the absolute coordinates of the aRect passed in.
3940
// aRects values are relative to aView
3942
nsView *parentView = aView;
3943
while ((parentView != nsnull) && (parentView != scrolledView)) {
3944
parentView->ConvertToParentCoords(&aAbsRect.x, &aAbsRect.y);
3945
parentView = parentView->GetParent();
3948
if (parentView != scrolledView) {
3949
return NS_ERROR_FAILURE;
3956
NS_IMETHODIMP nsViewManager::GetRectVisibility(nsIView *aView,
3957
const nsRect &aRect,
3959
nsRectVisibility *aRectVisibility)
3961
nsView* view = NS_STATIC_CAST(nsView*, aView);
3963
// The parameter aMinTwips determines how many rows/cols of pixels must be visible on each side of the element,
3964
// in order to be counted as visible
3966
*aRectVisibility = nsRectVisibility_kZeroAreaRect;
3967
if (aRect.width == 0 || aRect.height == 0) {
3971
// is this view even visible?
3972
if (view->GetVisibility() == nsViewVisibility_kHide) {
3976
// Calculate the absolute coordinates for the visible rectangle
3978
if (GetVisibleRect(visibleRect) == NS_ERROR_FAILURE) {
3979
*aRectVisibility = nsRectVisibility_kVisible;
3983
// Calculate the absolute coordinates of the aRect passed in.
3984
// aRects values are relative to aView
3986
if ((GetAbsoluteRect(view, aRect, absRect)) == NS_ERROR_FAILURE) {
3987
*aRectVisibility = nsRectVisibility_kVisible;
3992
* If aMinTwips > 0, ensure at least aMinTwips of space around object is visible
3993
* The object is not visible if:
3994
* ((objectTop < windowTop && objectBottom < windowTop) ||
3995
* (objectBottom > windowBottom && objectTop > windowBottom) ||
3996
* (objectLeft < windowLeft && objectRight < windowLeft) ||
3997
* (objectRight > windowRight && objectLeft > windowRight))
4000
if (absRect.y < visibleRect.y &&
4001
absRect.y + absRect.height < visibleRect.y + aMinTwips)
4002
*aRectVisibility = nsRectVisibility_kAboveViewport;
4003
else if (absRect.y + absRect.height > visibleRect.y + visibleRect.height &&
4004
absRect.y > visibleRect.y + visibleRect.height - aMinTwips)
4005
*aRectVisibility = nsRectVisibility_kBelowViewport;
4006
else if (absRect.x < visibleRect.x &&
4007
absRect.x + absRect.width < visibleRect.x + aMinTwips)
4008
*aRectVisibility = nsRectVisibility_kLeftOfViewport;
4009
else if (absRect.x + absRect.width > visibleRect.x + visibleRect.width &&
4010
absRect.x > visibleRect.x + visibleRect.width - aMinTwips)
4011
*aRectVisibility = nsRectVisibility_kRightOfViewport;
4013
*aRectVisibility = nsRectVisibility_kVisible;
4020
nsViewManager::IsCachingWidgetChanges(PRBool* aCaching)
4022
#ifdef CACHE_WIDGET_CHANGES
4023
*aCaching = (mCachingWidgetChanges > 0);
4025
*aCaching = PR_FALSE;
4032
nsViewManager::CacheWidgetChanges(PRBool aCache)
4035
#ifdef CACHE_WIDGET_CHANGES
4036
if (aCache == PR_TRUE)
4037
mCachingWidgetChanges++;
4039
mCachingWidgetChanges--;
4041
NS_ASSERTION(mCachingWidgetChanges >= 0, "One too many decrements");
4043
// if we turned it off. Then move and size all the widgets.
4044
if (mCachingWidgetChanges == 0)
4045
ProcessWidgetChanges(mRootView);
4052
nsViewManager::AllowDoubleBuffering(PRBool aDoubleBuffer)
4054
mAllowDoubleBuffering = aDoubleBuffer;
4059
nsViewManager::IsPainting(PRBool& aIsPainting)
4061
aIsPainting = mPainting;
4066
nsViewManager::FlushPendingInvalidates()
4068
if (mHasPendingInvalidates) {
4069
ProcessPendingUpdates(mRootView);
4070
mHasPendingInvalidates = PR_FALSE;
4076
nsViewManager::ProcessInvalidateEvent()
4078
FlushPendingInvalidates();
4079
mInvalidateEventQueue = nsnull;
4083
nsViewManager::ProcessWidgetChanges(nsView* aView)
4085
//printf("---------Begin Sync----------\n");
4086
nsresult rv = aView->SynchWidgetSizePosition();
4090
nsView *child = aView->GetFirstChild();
4091
while (nsnull != child) {
4092
if (child->GetViewManager() == this) {
4093
rv = ProcessWidgetChanges(child);
4098
child = child->GetNextSibling();
4101
//printf("---------End Sync----------\n");
4107
nsViewManager::SetDefaultBackgroundColor(nscolor aColor)
4109
mDefaultBackgroundColor = aColor;
4114
nsViewManager::GetDefaultBackgroundColor(nscolor* aColor)
4116
*aColor = mDefaultBackgroundColor;
4122
nsViewManager::GetLastUserEventTime(PRUint32& aTime)
4124
aTime = gLastUserEventTime;