~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/view/src/nsViewManager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
 *
 
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/
 
9
 *
 
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
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
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.
 
21
 *
 
22
 * Contributor(s):
 
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>
 
27
 *
 
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.
 
39
 *
 
40
 * ***** END LICENSE BLOCK ***** */
 
41
 
 
42
#include "nsViewManager.h"
 
43
#include "nsUnitConversion.h"
 
44
#include "nsIRenderingContext.h"
 
45
#include "nsIDeviceContext.h"
 
46
#include "nsGfxCIID.h"
 
47
#include "nsIScrollableView.h"
 
48
#include "nsView.h"
 
49
#include "nsISupportsArray.h"
 
50
#include "nsICompositeListener.h"
 
51
#include "nsCOMPtr.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"
 
58
#include "nsRegion.h"
 
59
#include "nsInt64.h"
 
60
#include "nsScrollPortView.h"
 
61
 
 
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);
 
66
 
 
67
/**
 
68
   XXX TODO XXX
 
69
 
 
70
   DeCOMify newly private methods
 
71
   Optimize view storage
 
72
*/
 
73
 
 
74
/**
 
75
   A note about platform assumptions:
 
76
 
 
77
   We assume all native widgets are opaque.
 
78
   
 
79
   We assume that a widget is z-ordered on top of its parent.
 
80
   
 
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.
 
83
*/
 
84
 
 
85
// if defined widget changes like moves and resizes are defered until and done
 
86
// all in one pass.
 
87
//#define CACHE_WIDGET_CHANGES
 
88
 
 
89
// display list flags
 
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
 
100
 
 
101
#define NSCOORD_NONE      PR_INT32_MIN
 
102
 
 
103
#define SUPPORT_TRANSLUCENT_VIEWS
 
104
 
 
105
/*
 
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.
 
110
*/
 
111
class BlendingBuffers {
 
112
public:
 
113
  BlendingBuffers(nsIRenderingContext* aCleanupContext);
 
114
  ~BlendingBuffers();
 
115
 
 
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;
 
123
 
 
124
  PRBool mOwnBlackSurface;
 
125
  // drawing surface for mBlackCX
 
126
  nsDrawingSurface  mBlack;
 
127
  // drawing surface for mWhiteCX
 
128
  nsDrawingSurface  mWhite;
 
129
 
 
130
  // The offset within the current widget at which this buffer will
 
131
  // eventually be composited
 
132
  nsPoint mOffset;
 
133
};
 
134
 
 
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 {
 
140
  nsView*       mView;        
 
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)
 
145
};
 
146
 
 
147
/*
 
148
  IMPLEMENTING Z-INDEX
 
149
 
 
150
  Implementing z-index:auto and negative z-indices properly is hard. Here's how we do it.
 
151
 
 
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
 
161
  order.
 
162
 
 
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)
 
167
     |            +------> V5(1)
 
168
     +---------> V6(1)
 
169
  CreateDisplayList would create the following z-tree (z-order increases from top to bottom)
 
170
    Ta(V0) --> Tb*(V0)
 
171
     +-------> Tc(V1) --> Td*(V1)
 
172
     |          +-------> Te(V2) --> Tf*(V2)
 
173
     |          |          +-------> Tg*(V3)
 
174
     |          |          +-------> Th*(V4)
 
175
     |          +-------> Ti*(V5)
 
176
     +-------> Tj*(V6)
 
177
  (* indicates leaf nodes marked with display list elements)
 
178
 
 
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.
 
187
 
 
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),
 
194
  Ti*(V5)(1) ].
 
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) ].
 
199
*/
 
200
 
 
201
struct DisplayZTreeNode {
 
202
  nsView*              mView;            // Null for tree leaf nodes
 
203
  DisplayZTreeNode*    mZSibling;
 
204
 
 
205
  // We can't have BOTH an mZChild and an mDisplayElement
 
206
  DisplayZTreeNode*    mZChild;          // tree interior nodes
 
207
  DisplayListElement2* mDisplayElement;  // tree leaf nodes
 
208
};
 
209
 
 
210
void nsViewManager::DestroyZTreeNode(DisplayZTreeNode* aNode) 
 
211
{
 
212
  if (aNode) {
 
213
    if (mMapPlaceholderViewToZTreeNode.Count() > 0) {
 
214
       nsVoidKey key(aNode->mView);
 
215
       mMapPlaceholderViewToZTreeNode.Remove(&key);
 
216
    }
 
217
  
 
218
    DestroyZTreeNode(aNode->mZChild);
 
219
    DestroyZTreeNode(aNode->mZSibling);
 
220
    delete aNode->mDisplayElement;
 
221
    delete aNode;
 
222
  }
 
223
}
 
224
 
 
225
#ifdef DEBUG
 
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;
 
232
    nsRect               dim;
 
233
    if (view) {
 
234
      view->GetDimensions(dim);
 
235
    }
 
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;
 
241
 
 
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,
 
245
           v.x, v.y,
 
246
           (void*)parent, (void*)viewMan, zindex, (void*)zParent,
 
247
           rect.x, rect.y, rect.width, rect.height,
 
248
           element->mAbsX, element->mAbsY);
 
249
 
 
250
    PRInt32 newnestcnt = aNestCount;
 
251
 
 
252
    if (flags)
 
253
      {
 
254
        printf("%*s", aNestCount*2, "");
 
255
 
 
256
        if (flags & POP_CLIP) {
 
257
          printf("POP_CLIP ");
 
258
          newnestcnt--;
 
259
        }
 
260
 
 
261
        if (flags & PUSH_CLIP) {
 
262
          printf("PUSH_CLIP ");
 
263
          newnestcnt++;
 
264
        }
 
265
 
 
266
        if (flags & POP_FILTER) {
 
267
          printf("POP_FILTER ");
 
268
          newnestcnt--;
 
269
        }
 
270
 
 
271
        if (flags & PUSH_FILTER) {
 
272
          printf("PUSH_FILTER ");
 
273
          newnestcnt++;
 
274
        }
 
275
 
 
276
        if (flags & VIEW_RENDERED) 
 
277
          printf("VIEW_RENDERED ");
 
278
 
 
279
        if (flags & VIEW_ISSCROLLED)
 
280
          printf("VIEW_ISSCROLLED ");
 
281
 
 
282
        if (flags & VIEW_CLIPPED)
 
283
          printf("VIEW_ISCLIPPED ");
 
284
 
 
285
        if (flags & VIEW_TRANSLUCENT)
 
286
          printf("VIEW_ISTRANSLUCENT ");
 
287
 
 
288
        if (flags & VIEW_TRANSPARENT)
 
289
          printf("VIEW_ISTRANSPARENT ");
 
290
 
 
291
        if (viewFlags & NS_VIEW_FLAG_DONT_BITBLT)
 
292
          printf("NS_VIEW_FLAG_DONT_BITBLT ");
 
293
 
 
294
        printf("\n");
 
295
      }
 
296
    return newnestcnt;
 
297
}
 
298
 
 
299
static void PrintZTreeNode(DisplayZTreeNode* aNode, PRInt32 aIndent) 
 
300
{
 
301
  if (aNode) {
 
302
    printf("%*sDisplayZTreeNode@%p\n", aIndent*2, "", (void*)aNode);
 
303
    if (aNode->mDisplayElement) {
 
304
      PrintDisplayListElement(aNode->mDisplayElement, 0);
 
305
    }
 
306
 
 
307
    aIndent += 2;
 
308
 
 
309
    for (DisplayZTreeNode* child = aNode->mZChild; child;
 
310
         child = child->mZSibling) {
 
311
      PrintZTreeNode(child, aIndent);
 
312
    }
 
313
  }
 
314
}
 
315
#endif
 
316
 
 
317
#ifdef NS_VM_PERF_METRICS
 
318
#include "nsITimeRecorder.h"
 
319
#endif
 
320
 
 
321
//-------------- Begin Invalidate Event Definition ------------------------
 
322
 
 
323
struct nsInvalidateEvent : public PLEvent {
 
324
  nsInvalidateEvent(nsViewManager* aViewManager);
 
325
  ~nsInvalidateEvent() { }
 
326
 
 
327
  void HandleEvent() {  
 
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;
 
335
    PRInt32 index;
 
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) {
 
341
        found = PR_TRUE;
 
342
      }
 
343
    }
 
344
 
 
345
    if (found) {
 
346
      mViewManager->ProcessInvalidateEvent();
 
347
    } else {
 
348
      NS_ASSERTION(PR_FALSE, "bad view manager asked to process invalidate event");
 
349
    }
 
350
  };
 
351
 
 
352
  nsViewManager* mViewManager; // Weak Reference. The viewmanager will destroy any pending
 
353
  // invalidate events in it's destructor.
 
354
};
 
355
 
 
356
static void* PR_CALLBACK HandlePLEvent(PLEvent* aEvent)
 
357
{
 
358
  NS_ASSERTION(nsnull != aEvent,"Event is null");
 
359
  nsInvalidateEvent *event = NS_STATIC_CAST(nsInvalidateEvent*, aEvent);
 
360
  event->HandleEvent();
 
361
  return nsnull;
 
362
}
 
363
 
 
364
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent)
 
365
{
 
366
  NS_ASSERTION(nsnull != aEvent,"Event is null");
 
367
  nsInvalidateEvent *event = NS_STATIC_CAST(nsInvalidateEvent*, aEvent);
 
368
  delete event;
 
369
}
 
370
 
 
371
nsInvalidateEvent::nsInvalidateEvent(nsViewManager* aViewManager)
 
372
{
 
373
  NS_ASSERTION(aViewManager, "null parameter");  
 
374
  mViewManager = aViewManager; // Assign weak reference
 
375
  PL_InitEvent(this, aViewManager, ::HandlePLEvent, ::DestroyPLEvent);  
 
376
}
 
377
 
 
378
//-------------- End Invalidate Event Definition ---------------------------
 
379
 
 
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!)
 
383
// 
 
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
 
387
 
 
388
static PRInt32 CompareZIndex(PRInt32 aZIndex1, PRBool aTopMost1, PRBool aIsAuto1,
 
389
                             PRInt32 aZIndex2, PRBool aTopMost2, PRBool aIsAuto2) 
 
390
{
 
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");
 
393
 
 
394
  if (aZIndex1 != aZIndex2) {
 
395
    return aZIndex1 - aZIndex2;
 
396
  } else {
 
397
    return aTopMost1 - aTopMost2;
 
398
  }
 
399
}
 
400
 
 
401
static PRBool IsViewVisible(nsView *aView)
 
402
{
 
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)
 
409
      return PR_FALSE;
 
410
  }
 
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();
 
417
}
 
418
 
 
419
void
 
420
nsViewManager::PostInvalidateEvent()
 
421
{
 
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");
 
426
 
 
427
  if (eventQueue != mInvalidateEventQueue) {
 
428
    nsInvalidateEvent* ev = new nsInvalidateEvent(this);
 
429
    eventQueue->PostEvent(ev);
 
430
    mInvalidateEventQueue = eventQueue;
 
431
  }
 
432
}
 
433
 
 
434
PRInt32 nsViewManager::mVMCount = 0;
 
435
nsIRenderingContext* nsViewManager::gCleanupContext = nsnull;
 
436
 
 
437
// Weakly held references to all of the view managers
 
438
nsVoidArray* nsViewManager::gViewManagers = nsnull;
 
439
PRUint32 nsViewManager::gLastUserEventTime = 0;
 
440
 
 
441
nsViewManager::nsViewManager()
 
442
  : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
 
443
{
 
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;
 
448
  }
 
449
 
 
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");
 
455
  }
 
456
 
 
457
  gViewManagers->AppendElement(this);
 
458
 
 
459
  mVMCount++;
 
460
  // NOTE:  we use a zeroing operator new, so all data members are
 
461
  // assumed to be cleared here.
 
462
  mX = 0;
 
463
  mY = 0;
 
464
  mCachingWidgetChanges = 0;
 
465
  mDefaultBackgroundColor = NS_RGBA(0, 0, 0, 0);
 
466
  mAllowDoubleBuffering = PR_TRUE; 
 
467
  mHasPendingInvalidates = PR_FALSE;
 
468
  mRecursiveRefreshPending = PR_FALSE;
 
469
}
 
470
 
 
471
nsViewManager::~nsViewManager()
 
472
{
 
473
  if (mRootView) {
 
474
    // Destroy any remaining views
 
475
    mRootView->Destroy();
 
476
    mRootView = nsnull;
 
477
  }
 
478
 
 
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;  
 
485
 
 
486
  NS_IF_RELEASE(mRootWindow);
 
487
 
 
488
  mRootScrollable = nsnull;
 
489
 
 
490
  NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
 
491
  --mVMCount;
 
492
 
 
493
#ifdef DEBUG
 
494
  PRBool removed =
 
495
#endif
 
496
    gViewManagers->RemoveElement(this);
 
497
  NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers");
 
498
 
 
499
  if (0 == mVMCount) {
 
500
    // There aren't any more view managers so
 
501
    // release the global array of view managers
 
502
   
 
503
    NS_ASSERTION(gViewManagers != nsnull, "About to delete null gViewManagers");
 
504
    delete gViewManagers;
 
505
    gViewManagers = nsnull;
 
506
 
 
507
    // Cleanup all of the offscreen drawing surfaces if the last view manager
 
508
    // has been destroyed and there is something to cleanup
 
509
 
 
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.
 
513
 
 
514
    if (gCleanupContext) {
 
515
 
 
516
      gCleanupContext->DestroyCachedBackbuffer();
 
517
    } else {
 
518
      NS_ASSERTION(PR_FALSE, "Cleanup of drawing surfaces + offscreen buffer failed");
 
519
    }
 
520
 
 
521
    NS_IF_RELEASE(gCleanupContext);
 
522
  }
 
523
 
 
524
  mObserver = nsnull;
 
525
  mContext = nsnull;
 
526
 
 
527
  if (nsnull != mCompositeListeners) {
 
528
    mCompositeListeners->Clear();
 
529
    NS_RELEASE(mCompositeListeners);
 
530
  }
 
531
}
 
532
 
 
533
NS_IMPL_ISUPPORTS1(nsViewManager, nsIViewManager)
 
534
 
 
535
nsresult
 
536
nsViewManager::CreateRegion(nsIRegion* *result)
 
537
{
 
538
  nsresult rv;
 
539
 
 
540
  if (!mRegionFactory) {
 
541
    nsCOMPtr<nsIComponentManager> compMgr;
 
542
    rv = NS_GetComponentManager(getter_AddRefs(compMgr));
 
543
 
 
544
    if (NS_SUCCEEDED(rv))
 
545
      rv = compMgr->GetClassObject(kRegionCID,
 
546
                                   NS_GET_IID(nsIFactory),
 
547
                                   getter_AddRefs(mRegionFactory));
 
548
 
 
549
    if (!mRegionFactory) {
 
550
      *result = nsnull;
 
551
      return NS_ERROR_FAILURE;
 
552
    }
 
553
  }
 
554
 
 
555
  nsIRegion* region = nsnull;
 
556
  rv = mRegionFactory->CreateInstance(nsnull, NS_GET_IID(nsIRegion), (void**)&region);
 
557
  if (NS_SUCCEEDED(rv)) {
 
558
    rv = region->Init();
 
559
    *result = region;
 
560
  }
 
561
  return rv;
 
562
}
 
563
 
 
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)
 
567
{
 
568
  NS_PRECONDITION(nsnull != aContext, "null ptr");
 
569
 
 
570
  if (nsnull == aContext) {
 
571
    return NS_ERROR_NULL_POINTER;
 
572
  }
 
573
  if (nsnull != mContext) {
 
574
    return NS_ERROR_ALREADY_INITIALIZED;
 
575
  }
 
576
  mContext = aContext;
 
577
  mTwipsToPixels = mContext->AppUnitsToDevUnits();
 
578
  mPixelsToTwips = mContext->DevUnitsToAppUnits();
 
579
 
 
580
  mRefreshEnabled = PR_TRUE;
 
581
 
 
582
  mMouseGrabber = nsnull;
 
583
  mKeyGrabber = nsnull;
 
584
 
 
585
  if (nsnull == mEventQueueService) {
 
586
    mEventQueueService = do_GetService(kEventQueueServiceCID);
 
587
    NS_ASSERTION(mEventQueueService, "couldn't get event queue service");
 
588
  }
 
589
  
 
590
  return NS_OK;
 
591
}
 
592
 
 
593
NS_IMETHODIMP nsViewManager::GetRootView(nsIView *&aView)
 
594
{
 
595
  aView = mRootView;
 
596
  return NS_OK;
 
597
}
 
598
 
 
599
NS_IMETHODIMP nsViewManager::SetRootView(nsIView *aView, nsIWidget* aWidget)
 
600
{
 
601
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
602
 
 
603
  // Do NOT destroy the current root view. It's the caller's responsibility
 
604
  // to destroy it
 
605
  mRootView = view;
 
606
 
 
607
  //now get the window too.
 
608
  NS_IF_RELEASE(mRootWindow);
 
609
 
 
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
 
615
 
 
616
  if (nsnull != aWidget) {
 
617
    mRootWindow = aWidget;
 
618
    NS_ADDREF(mRootWindow);
 
619
    return NS_OK;
 
620
  }
 
621
 
 
622
  // case b) The aView has a nsIWidget instance
 
623
  if (nsnull != mRootView) {
 
624
    nsView* parent = mRootView->GetParent();
 
625
    if (parent) {
 
626
      parent->InsertChild(mRootView, nsnull);
 
627
    }
 
628
 
 
629
    mRootView->SetZIndex(PR_FALSE, 0, PR_FALSE);
 
630
 
 
631
    mRootWindow = mRootView->GetWidget();
 
632
    if (mRootWindow) {
 
633
      NS_ADDREF(mRootWindow);
 
634
      return NS_OK;
 
635
    }
 
636
  }
 
637
 
 
638
  // case c)  aView has a parent view managed by a different view manager
 
639
 
 
640
  return NS_OK;
 
641
}
 
642
 
 
643
NS_IMETHODIMP nsViewManager::GetWindowOffset(nscoord *aX, nscoord *aY)
 
644
{
 
645
  NS_ASSERTION(aX != nsnull, "aX pointer is null");
 
646
  NS_ASSERTION(aY != nsnull, "aY pointer is null");
 
647
 
 
648
  *aX = mX;
 
649
  *aY = mY;
 
650
  return NS_OK;
 
651
}
 
652
 
 
653
NS_IMETHODIMP nsViewManager::SetWindowOffset(nscoord aX, nscoord aY)
 
654
{
 
655
  mX = aX;
 
656
  mY = aY;
 
657
  return NS_OK;
 
658
}
 
659
 
 
660
NS_IMETHODIMP nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
 
661
{
 
662
  if (nsnull != mRootView) {
 
663
    if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
 
664
      nsRect dim;
 
665
      mRootView->GetDimensions(dim);
 
666
      *aWidth = dim.width;
 
667
      *aHeight = dim.height;
 
668
    } else {
 
669
      *aWidth = mDelayedResize.width;
 
670
      *aHeight = mDelayedResize.height;
 
671
    }
 
672
  }
 
673
  else
 
674
    {
 
675
      *aWidth = 0;
 
676
      *aHeight = 0;
 
677
    }
 
678
  return NS_OK;
 
679
}
 
680
 
 
681
NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
 
682
{
 
683
  if (mRootView) {
 
684
    if (IsViewVisible(mRootView)) {
 
685
      mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
 
686
      DoSetWindowDimensions(aWidth, aHeight);
 
687
    } else {
 
688
      mDelayedResize.SizeTo(aWidth, aHeight);
 
689
    }
 
690
  }
 
691
 
 
692
  return NS_OK;
 
693
}
 
694
 
 
695
NS_IMETHODIMP nsViewManager::ResetScrolling(void)
 
696
{
 
697
  if (nsnull != mRootScrollable)
 
698
    mRootScrollable->ComputeScrollOffsets(PR_TRUE);
 
699
 
 
700
  return NS_OK;
 
701
}
 
702
 
 
703
/* Check the prefs to see whether we should do double buffering or not... */
 
704
static
 
705
PRBool DoDoubleBuffering(void)
 
706
{
 
707
  static PRBool gotDoublebufferPrefs = PR_FALSE;
 
708
  static PRBool doDoublebuffering    = PR_TRUE;  /* Double-buffering is ON by default */
 
709
  
 
710
  if (!gotDoublebufferPrefs) {
 
711
    nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
 
712
    if (prefBranch) {
 
713
      PRBool val;
 
714
      if (NS_SUCCEEDED(prefBranch->GetBoolPref("viewmanager.do_doublebuffering", &val))) {
 
715
        doDoublebuffering = val;
 
716
      }
 
717
    }
 
718
 
 
719
#ifdef DEBUG
 
720
    if (!doDoublebuffering) {
 
721
      printf("nsViewManager: Note: Double-buffering disabled via prefs.\n");
 
722
    }
 
723
#endif /* DEBUG */
 
724
 
 
725
    gotDoublebufferPrefs = PR_TRUE;
 
726
  }
 
727
  
 
728
  return doDoublebuffering;
 
729
}
 
730
 
 
731
static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut,
 
732
                                           nsIDeviceContext* context)
 
733
{
 
734
  nsRegionRectSet* rects = nsnull;
 
735
  aIn->GetRects(&rects);
 
736
  if (!rects)
 
737
    return;
 
738
  
 
739
  float  p2t;
 
740
  p2t = context->DevUnitsToAppUnits();
 
741
 
 
742
  PRUint32 i;
 
743
  for (i = 0; i < rects->mNumRects; i++) {
 
744
    const nsRegionRect& inR = rects->mRects[i];
 
745
    nsRect outR;
 
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);
 
751
  }
 
752
 
 
753
  aIn->FreeRects(rects);
 
754
}
 
755
 
 
756
/**
 
757
   aRegion is given in device coordinates!!
 
758
*/
 
759
void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
 
760
                            nsIRegion *aRegion, PRUint32 aUpdateFlags)
 
761
{
 
762
  NS_ASSERTION(aRegion != nsnull, "Null aRegion");
 
763
 
 
764
  if (PR_FALSE == mRefreshEnabled)
 
765
    return;
 
766
 
 
767
  nsRect viewRect;
 
768
  aView->GetDimensions(viewRect);
 
769
 
 
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);
 
776
 
 
777
  // Clip it to the view; shouldn't be necessary, but do it for sanity
 
778
  damageRegion.And(damageRegion, viewRect);
 
779
  if (damageRegion.IsEmpty()) {
 
780
#ifdef DEBUG_roc
 
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);
 
785
#endif
 
786
    return;
 
787
  }
 
788
 
 
789
#ifdef NS_VM_PERF_METRICS
 
790
  MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this));
 
791
  MOZ_TIMER_RESET(mWatch);
 
792
 
 
793
  MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n"));
 
794
  MOZ_TIMER_START(mWatch);
 
795
#endif
 
796
 
 
797
  NS_ASSERTION(!mPainting, "recursive painting not permitted");
 
798
  if (mPainting) {
 
799
    mRecursiveRefreshPending = PR_TRUE;
 
800
    return;
 
801
  }  
 
802
  mPainting = PR_TRUE;
 
803
 
 
804
  // force double buffering in general
 
805
  aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
 
806
 
 
807
  if (!DoDoubleBuffering())
 
808
    aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
 
809
 
 
810
  // check if the rendering context wants double-buffering or not
 
811
  if (aContext) {
 
812
    PRBool contextWantsBackBuffer = PR_TRUE;
 
813
    aContext->UseBackbuffer(&contextWantsBackBuffer);
 
814
    if (!contextWantsBackBuffer)
 
815
      aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
 
816
  }
 
817
  
 
818
  if (PR_FALSE == mAllowDoubleBuffering) {
 
819
    // Turn off double-buffering of the display
 
820
    aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
 
821
  }
 
822
 
 
823
  nsCOMPtr<nsIRenderingContext> localcx;
 
824
  nsDrawingSurface    ds = nsnull;
 
825
 
 
826
  if (nsnull == aContext)
 
827
    {
 
828
      localcx = getter_AddRefs(CreateRenderingContext(*aView));
 
829
 
 
830
      //couldn't get rendering context. this is ok at init time atleast
 
831
      if (nsnull == localcx) {
 
832
        mPainting = PR_FALSE;
 
833
        return;
 
834
      }
 
835
    } else {
 
836
      // plain assignment grabs another reference.
 
837
      localcx = aContext;
 
838
    }
 
839
 
 
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);
 
848
        }
 
849
      }
 
850
    }
 
851
  }
 
852
 
 
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);
 
859
  float t2p;
 
860
  t2p = mContext->AppUnitsToDevUnits();
 
861
  widgetDamageRectInPixels.ScaleRoundOut(t2p);
 
862
 
 
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;
 
875
        break;
 
876
      }
 
877
    }
 
878
  } 
 
879
 
 
880
  if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)
 
881
  {
 
882
    nsRect maxWidgetSize;
 
883
    GetMaxWidgetBounds(maxWidgetSize);
 
884
 
 
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;
 
889
    }
 
890
  }
 
891
 
 
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
 
897
 
 
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);
 
907
  } else {
 
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);
 
911
  }
 
912
 
 
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
 
916
  // SetClipRect does.
 
917
  PRBool isClipped;
 
918
  localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, isClipped);
 
919
  localcx->SetClipRect(damageRect, nsClipCombine_kIntersect, isClipped);
 
920
 
 
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());
 
926
  }
 
927
  RenderViews(aView, *localcx, damageRegion, ds, displayList);
 
928
 
 
929
  if (usingDoubleBuffer) {
 
930
    // Flush bits back to the screen
 
931
 
 
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);
 
943
  } else {
 
944
    // undo earlier translation
 
945
    localcx->Translate(viewRect.x, viewRect.y);
 
946
  }
 
947
 
 
948
  mPainting = PR_FALSE;
 
949
 
 
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);
 
958
        }
 
959
      }
 
960
    }
 
961
  }
 
962
 
 
963
  if (mRecursiveRefreshPending) {
 
964
    UpdateAllViews(aUpdateFlags);
 
965
    mRecursiveRefreshPending = PR_FALSE;
 
966
  }
 
967
 
 
968
  localcx->ReleaseBackbuffer();
 
969
 
 
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);
 
975
#endif
 
976
 
 
977
}
 
978
 
 
979
void nsViewManager::DefaultRefresh(nsView* aView, const nsRect* aRect)
 
980
{
 
981
  nsCOMPtr<nsIWidget> widget;
 
982
  GetWidgetForView(aView, getter_AddRefs(widget));
 
983
  if (! widget)
 
984
    return;
 
985
 
 
986
  nsCOMPtr<nsIRenderingContext> context
 
987
    = getter_AddRefs(CreateRenderingContext(*aView));
 
988
 
 
989
  if (! context)
 
990
    return;
 
991
 
 
992
  nscolor bgcolor = mDefaultBackgroundColor;
 
993
 
 
994
  if (NS_GET_A(mDefaultBackgroundColor) == 0) {
 
995
    NS_WARNING("nsViewManager: Asked to paint a default background, but no default background color is set!");
 
996
    return;
 
997
  }
 
998
 
 
999
  context->SetColor(bgcolor);
 
1000
  context->FillRect(*aRect);
 
1001
}
 
1002
 
 
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) {
 
1015
          sorted = PR_FALSE;
 
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);
 
1020
        }
 
1021
      }
 
1022
      if (sorted) {
 
1023
        return;
 
1024
      }
 
1025
    }
 
1026
  } else {
 
1027
    // merge sort for the rest
 
1028
    PRInt32 mid = (aEnd + aStart)/2;
 
1029
 
 
1030
    ApplyZOrderStableSort(aBuffer, aMergeTmp, aStart, mid);
 
1031
    ApplyZOrderStableSort(aBuffer, aMergeTmp, mid, aEnd);
 
1032
 
 
1033
    DisplayListElement2* e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid - 1));
 
1034
    DisplayListElement2* e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid));
 
1035
 
 
1036
    // fast common case: the list is already completely sorted
 
1037
    if (e1->mZIndex <= e2->mZIndex) {
 
1038
      return;
 
1039
    }
 
1040
    // we have some merging to do.
 
1041
 
 
1042
    PRInt32 i1 = aStart;
 
1043
    PRInt32 i2 = mid;
 
1044
 
 
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);
 
1050
        i1++;
 
1051
        if (i1 < mid) {
 
1052
          e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i1));
 
1053
        }
 
1054
      } else {
 
1055
        aMergeTmp.AppendElement(e2);
 
1056
        i2++;
 
1057
        if (i2 < aEnd) {
 
1058
          e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i2));
 
1059
        }
 
1060
      }
 
1061
    }
 
1062
 
 
1063
    for (PRInt32 i = aStart; i < aEnd; i++) {
 
1064
      aBuffer.ReplaceElementAt(aMergeTmp.ElementAt(i - aStart), i);
 
1065
    }
 
1066
 
 
1067
    aMergeTmp.Clear();
 
1068
  }
 
1069
}
 
1070
 
 
1071
static nsInt64 BuildExtendedZIndex(nsView* aView) {
 
1072
  return (nsInt64(aView->GetZIndex()) << 1) | nsInt64(aView->IsTopMost() ? 1 : 0);
 
1073
}
 
1074
 
 
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;
 
1083
 
 
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);
 
1088
  }
 
1089
 
 
1090
  if (nsnull == aNode->mZChild) {
 
1091
    if (nsnull != aNode->mDisplayElement) {
 
1092
      aBuffer.AppendElement(aNode->mDisplayElement);
 
1093
      aNode->mDisplayElement->mZIndex = explicitZIndex;
 
1094
      aNode->mDisplayElement = nsnull;
 
1095
    }
 
1096
    return;
 
1097
  }
 
1098
 
 
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);
 
1103
  }
 
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;
 
1110
 
 
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) {
 
1118
        hasClip = PR_TRUE;
 
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));
 
1123
        sortStartIndex++;
 
1124
        sortEndIndex--;
 
1125
      } else if (childElem->mFlags & PUSH_FILTER) {
 
1126
        NS_ASSERTION(!autoZIndex, "FILTER cannot apply to z-index:auto view");
 
1127
        sortStartIndex++;
 
1128
        sortEndIndex--;
 
1129
      } else {
 
1130
        break;
 
1131
      }
 
1132
    } else {
 
1133
      break;
 
1134
    }
 
1135
  }
 
1136
 
 
1137
  if (hasClip) {
 
1138
    ApplyZOrderStableSort(aBuffer, aMergeTmp, sortStartIndex, sortEndIndex);
 
1139
    
 
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));
 
1153
 
 
1154
      ePush->mZIndex = eFirstChild->mZIndex;
 
1155
 
 
1156
      DisplayListElement2* eLastChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(sortEndIndex - 1));
 
1157
 
 
1158
      ePop->mZIndex = eLastChild->mZIndex;
 
1159
 
 
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;
 
1168
 
 
1169
          *newPop = *ePop;
 
1170
          newPop->mZIndex = e->mZIndex;
 
1171
          *newPush = *ePush;
 
1172
          newPush->mZIndex = eNext->mZIndex;
 
1173
          aBuffer.InsertElementAt(newPop, i + 1);
 
1174
          aBuffer.InsertElementAt(newPush, i + 2);
 
1175
          i += 2;
 
1176
          childEndIndex += 2;
 
1177
          sortEndIndex += 2;
 
1178
        }
 
1179
        e = eNext;
 
1180
      }
 
1181
    }
 
1182
  } else if (aForceSort || !autoZIndex) {
 
1183
    ApplyZOrderStableSort(aBuffer, aMergeTmp, sortStartIndex, sortEndIndex);
 
1184
  }
 
1185
 
 
1186
  for (PRInt32 i = childStartIndex; i < childEndIndex; i++) {
 
1187
    DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i));
 
1188
    if (!autoZIndex) {
 
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);
 
1193
    }
 
1194
  }
 
1195
}
 
1196
 
 
1197
static void PushStateAndClip(nsIRenderingContext** aRCs, PRInt32 aCount, nsRect &aRect) {
 
1198
  for (int i = 0; i < aCount; i++) {
 
1199
    if (aRCs[i]) {
 
1200
      PRBool clipEmpty;
 
1201
      aRCs[i]->PushState();
 
1202
      aRCs[i]->SetClipRect(aRect, nsClipCombine_kIntersect, clipEmpty);
 
1203
    }
 
1204
  }
 
1205
}
 
1206
 
 
1207
static void PopState(nsIRenderingContext **aRCs, PRInt32 aCount) {
 
1208
  for (int i = 0; i < aCount; i++) {
 
1209
    if (aRCs[i]) {
 
1210
      PRBool clipEmpty;
 
1211
      aRCs[i]->PopState(clipEmpty);
 
1212
    }
 
1213
  }
 
1214
}
 
1215
 
 
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.
 
1227
  // 
 
1228
  // NB: we must NOT add widgets that correspond to floating views!
 
1229
  // We may be required to paint behind them
 
1230
  aRgn.SetEmpty();
 
1231
 
 
1232
  nsCOMPtr<nsIWidget> widget;
 
1233
  GetWidgetForView(aRootView, getter_AddRefs(widget));
 
1234
  if (!widget) {
 
1235
    return;
 
1236
  }
 
1237
 
 
1238
  nsCOMPtr<nsIEnumerator> children(dont_AddRef(widget->GetChildren()));
 
1239
  if (!children) {
 
1240
    return;
 
1241
  }
 
1242
 
 
1243
  children->First();
 
1244
  do {
 
1245
    nsCOMPtr<nsISupports> child;
 
1246
    if (!NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) {
 
1247
      return;
 
1248
    }
 
1249
 
 
1250
    nsCOMPtr<nsIWidget> childWidget = do_QueryInterface(child);
 
1251
    if (childWidget) {
 
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();
 
1261
            
 
1262
            while (viewParent && viewParent != aRootView) {
 
1263
              viewParent->ConvertToParentCoords(&bounds.x, &bounds.y);
 
1264
              viewParent = viewParent->GetParent();
 
1265
            }
 
1266
            
 
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
 
1270
            if (viewParent) {
 
1271
              aRgn.Or(aRgn, bounds);
 
1272
            }
 
1273
          }
 
1274
        }
 
1275
      }
 
1276
    }
 
1277
  } while (NS_SUCCEEDED(children->Next()));
 
1278
}
 
1279
 
 
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);
 
1284
 
 
1285
  nsRegion opaqueRgn;
 
1286
  AddCoveringWidgetsToOpaqueRegion(opaqueRgn, mContext,
 
1287
                                   NS_STATIC_CAST(nsView*, aRootView));
 
1288
 
 
1289
  nsRect finalTransparentRect;
 
1290
  OptimizeDisplayList(aDisplayList, aRegion, finalTransparentRect, opaqueRgn, PR_FALSE);
 
1291
 
 
1292
#ifdef DEBUG_roc
 
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);
 
1296
  }
 
1297
#endif
 
1298
 
 
1299
  return !finalTransparentRect.IsEmpty();
 
1300
}
 
1301
 
 
1302
/*
 
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.
 
1306
*/
 
1307
void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC,
 
1308
                                const nsRegion& aRegion, nsDrawingSurface aRCSurface,
 
1309
                                const nsVoidArray& aDisplayList)
 
1310
{
 
1311
#ifdef DEBUG_roc
 
1312
  if (getenv("MOZ_SHOW_DISPLAY_LIST")) ShowDisplayList(&aDisplayList);
 
1313
#endif
 
1314
 
 
1315
  PRInt32 index = 0;
 
1316
  nsRect fakeClipRect;
 
1317
  PRBool anyRendered;
 
1318
  OptimizeDisplayListClipping(&aDisplayList, PR_FALSE, fakeClipRect, index, anyRendered);
 
1319
 
 
1320
  index = 0;
 
1321
  OptimizeTranslucentRegions(aDisplayList, &index, nsnull);
 
1322
 
 
1323
  nsIWidget* widget = aRootView->GetWidget();
 
1324
  PRBool translucentWindow = PR_FALSE;
 
1325
  if (widget) {
 
1326
    widget->GetWindowTranslucency(translucentWindow);
 
1327
    if (translucentWindow) {
 
1328
      NS_WARNING("Transparent window enabled");
 
1329
      NS_ASSERTION(aRCSurface, "Cannot support transparent windows with doublebuffering disabled");
 
1330
    }
 
1331
  }
 
1332
 
 
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");
 
1337
  if (!buffers)
 
1338
    return;
 
1339
 
 
1340
  nsAutoVoidArray filterStack;
 
1341
 
 
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));
 
1345
 
 
1346
    nsIRenderingContext* RCs[2] = { buffers->mBlackCX, buffers->mWhiteCX };
 
1347
 
 
1348
    if (element->mFlags & PUSH_CLIP) {
 
1349
      PushStateAndClip(RCs, 2, element->mBounds);
 
1350
    }
 
1351
    if (element->mFlags & PUSH_FILTER) {
 
1352
      NS_ASSERTION(aRCSurface,
 
1353
                   "Cannot support translucent elements with doublebuffering disabled");
 
1354
 
 
1355
      // Save current buffer on the stack and start rendering into a new
 
1356
      // offscreen buffer
 
1357
      filterStack.AppendElement(buffers);
 
1358
      buffers = CreateBlendingBuffers(&aRC, PR_FALSE, nsnull,
 
1359
                                      (element->mFlags & VIEW_TRANSPARENT) != 0,
 
1360
                                      element->mBounds);
 
1361
    }
 
1362
 
 
1363
    if (element->mFlags & VIEW_RENDERED) {
 
1364
      if (element->mFlags & VIEW_CLIPPED) {
 
1365
        PushStateAndClip(RCs, 2, element->mBounds);
 
1366
      }
 
1367
      
 
1368
      RenderDisplayListElement(element, RCs[0]);
 
1369
      // RenderDisplayListElement won't do anything if the context is null
 
1370
      RenderDisplayListElement(element, RCs[1]);
 
1371
 
 
1372
      if (element->mFlags & VIEW_CLIPPED) {
 
1373
        PopState(RCs, 2);
 
1374
      }
 
1375
    }
 
1376
 
 
1377
    if (element->mFlags & POP_FILTER) {
 
1378
      // Pop the last buffer off the stack and composite the current buffer into
 
1379
      // the last buffer
 
1380
      BlendingBuffers* doneBuffers = buffers;
 
1381
      buffers = NS_STATIC_CAST(BlendingBuffers*,
 
1382
                               filterStack.ElementAt(filterStack.Count() - 1));
 
1383
      filterStack.RemoveElementAt(filterStack.Count() - 1);
 
1384
 
 
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++) {
 
1392
          if (targets[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));
 
1399
          }
 
1400
        }
 
1401
      }
 
1402
      // probably should recycle these so we don't eat the cost of graphics memory
 
1403
      // allocation
 
1404
      delete doneBuffers;
 
1405
    }
 
1406
    if (element->mFlags & POP_CLIP) {
 
1407
      PopState(RCs, 2);
 
1408
    }
 
1409
      
 
1410
    delete element;
 
1411
  }
 
1412
    
 
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);
 
1421
    
 
1422
    if (NS_SUCCEEDED(rv)) {
 
1423
      widget->UpdateTranslucentWindowAlpha(r, alphas);
 
1424
    }
 
1425
    delete[] alphas;
 
1426
  }
 
1427
 
 
1428
  delete buffers;
 
1429
}
 
1430
 
 
1431
void nsViewManager::RenderDisplayListElement(DisplayListElement2* element,
 
1432
                                             nsIRenderingContext* aRC) {
 
1433
  if (!aRC)
 
1434
    return;
 
1435
  
 
1436
  PRBool clipEmpty;
 
1437
  nsRect r;
 
1438
  nsView* view = element->mView;
 
1439
 
 
1440
  view->GetDimensions(r);
 
1441
 
 
1442
  aRC->PushState();
 
1443
 
 
1444
  nscoord x = element->mAbsX - r.x, y = element->mAbsY - r.y;
 
1445
  aRC->Translate(x, y);
 
1446
 
 
1447
  nsRect drect(element->mBounds.x - x, element->mBounds.y - y,
 
1448
               element->mBounds.width, element->mBounds.height);
 
1449
  
 
1450
  element->mView->Paint(*aRC, drect, 0, clipEmpty);
 
1451
  
 
1452
  aRC->PopState(clipEmpty);
 
1453
}
 
1454
 
 
1455
void nsViewManager::PaintView(nsView *aView, nsIRenderingContext &aRC, nscoord x, nscoord y,
 
1456
                              const nsRect &aDamageRect)
 
1457
{
 
1458
  aRC.PushState();
 
1459
  aRC.Translate(x, y);
 
1460
  PRBool unused;
 
1461
  aView->Paint(aRC, aDamageRect, 0, unused);
 
1462
  aRC.PopState(unused);
 
1463
}
 
1464
 
 
1465
static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsDrawingSurface surface,
 
1466
                                    const nsRect& aRect, nsIRenderingContext* *aResult)
 
1467
{
 
1468
  nsresult             rv;
 
1469
  nsIRenderingContext *context = nsnull;
 
1470
 
 
1471
  rv = deviceContext->CreateRenderingContext(surface, context);
 
1472
  if (NS_FAILED(rv))
 
1473
    return rv;
 
1474
 
 
1475
  // always initialize clipping, linux won't draw images otherwise.
 
1476
  PRBool clipEmpty;
 
1477
  nsRect clip(0, 0, aRect.width, aRect.height);
 
1478
  context->SetClipRect(clip, nsClipCombine_kReplace, clipEmpty);
 
1479
 
 
1480
  context->Translate(-aRect.x, -aRect.y);
 
1481
  
 
1482
  *aResult = context;
 
1483
  return NS_OK;
 
1484
}
 
1485
 
 
1486
BlendingBuffers::BlendingBuffers(nsIRenderingContext* aCleanupContext) {
 
1487
  mCleanupContext = aCleanupContext;
 
1488
 
 
1489
  mOwnBlackSurface = PR_FALSE;
 
1490
  mWhite = nsnull;
 
1491
  mBlack = nsnull;
 
1492
}
 
1493
 
 
1494
BlendingBuffers::~BlendingBuffers() {
 
1495
  if (mWhite)
 
1496
    mCleanupContext->DestroyDrawingSurface(mWhite);
 
1497
 
 
1498
  if (mBlack && mOwnBlackSurface)
 
1499
    mCleanupContext->DestroyDrawingSurface(mBlack);
 
1500
}
 
1501
 
 
1502
/*
 
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
 
1512
*/
 
1513
BlendingBuffers*
 
1514
nsViewManager::CreateBlendingBuffers(nsIRenderingContext *aRC,
 
1515
                                     PRBool aBorrowContext,
 
1516
                                     nsDrawingSurface aBorrowSurface,
 
1517
                                     PRBool aNeedAlpha,
 
1518
                                     const nsRect& aRect)
 
1519
{
 
1520
  nsresult rv;
 
1521
 
 
1522
  // create a blender, if none exists already.
 
1523
  if (!mBlender) {
 
1524
    mBlender = do_CreateInstance(kBlenderCID, &rv);
 
1525
    if (NS_FAILED(rv))
 
1526
      return nsnull;
 
1527
    rv = mBlender->Init(mContext);
 
1528
    if (NS_FAILED(rv))
 
1529
      return nsnull;
 
1530
  }
 
1531
 
 
1532
  BlendingBuffers* buffers = new BlendingBuffers(aRC);
 
1533
  if (!buffers)
 
1534
    return nsnull;
 
1535
 
 
1536
  buffers->mOffset = nsPoint(aRect.x, aRect.y);
 
1537
 
 
1538
  nsRect offscreenBounds(0, 0, aRect.width, aRect.height);
 
1539
  offscreenBounds.ScaleRoundOut(mTwipsToPixels);
 
1540
 
 
1541
  if (aBorrowContext) {
 
1542
    buffers->mBlackCX = aRC;
 
1543
    buffers->mBlack = aBorrowSurface;
 
1544
  } else {
 
1545
    rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mBlack);
 
1546
    if (NS_FAILED(rv)) {
 
1547
      delete buffers;
 
1548
      return nsnull;
 
1549
    }
 
1550
    buffers->mOwnBlackSurface = PR_TRUE;
 
1551
    
 
1552
    rv = NewOffscreenContext(mContext, buffers->mBlack, aRect, getter_AddRefs(buffers->mBlackCX));
 
1553
    if (NS_FAILED(rv)) {
 
1554
      delete buffers;
 
1555
      return nsnull;
 
1556
    }
 
1557
  }
 
1558
 
 
1559
  if (aNeedAlpha) {
 
1560
    rv = aRC->CreateDrawingSurface(offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, buffers->mWhite);
 
1561
    if (NS_FAILED(rv)) {
 
1562
      delete buffers;
 
1563
      return nsnull;
 
1564
    }
 
1565
    
 
1566
    rv = NewOffscreenContext(mContext, buffers->mWhite, aRect, getter_AddRefs(buffers->mWhiteCX));
 
1567
    if (NS_FAILED(rv)) {
 
1568
      delete buffers;
 
1569
      return nsnull;
 
1570
    }
 
1571
    
 
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);
 
1578
  }
 
1579
 
 
1580
  return buffers;
 
1581
}
 
1582
 
 
1583
void nsViewManager::ProcessPendingUpdates(nsView* aView)
 
1584
{
 
1585
  // Protect against a null-view.
 
1586
  if (!aView) {
 
1587
    return;
 
1588
  }
 
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();
 
1595
    }
 
1596
  }
 
1597
 
 
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);
 
1603
    }
 
1604
  }
 
1605
}
 
1606
 
 
1607
NS_IMETHODIMP nsViewManager::Composite()
 
1608
{
 
1609
  if (mUpdateCnt > 0)
 
1610
    {
 
1611
      if (nsnull != mRootWindow)
 
1612
        mRootWindow->Update();
 
1613
  
 
1614
      mUpdateCnt = 0;
 
1615
    }
 
1616
 
 
1617
  return NS_OK;
 
1618
}
 
1619
 
 
1620
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
 
1621
{
 
1622
  // Mark the entire view as damaged
 
1623
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
1624
 
 
1625
  nsRect bounds = view->GetBounds();
 
1626
  view->ConvertFromParentCoords(&bounds.x, &bounds.y);
 
1627
  return UpdateView(view, bounds, aUpdateFlags);
 
1628
}
 
1629
 
 
1630
 
 
1631
// Invalidate all widgets which overlap the view, other than the view's own widgets.
 
1632
void
 
1633
nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY)
 
1634
{
 
1635
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
1636
 
 
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()) {
 
1641
    return;
 
1642
  }
 
1643
  damageRect.MoveBy(ComputeViewOffset(view));
 
1644
 
 
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()) {
 
1648
    return;
 
1649
  }
 
1650
 
 
1651
  nsView* realRoot = mRootView;
 
1652
  while (realRoot->GetParent()) {
 
1653
    realRoot = realRoot->GetParent();
 
1654
  }
 
1655
 
 
1656
  UpdateWidgetArea(realRoot, damageRect, view);
 
1657
 
 
1658
  Composite();
 
1659
}
 
1660
 
 
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)
 
1666
{
 
1667
  // If the bounds don't overlap at all, there's nothing to do
 
1668
  nsRect bounds;
 
1669
  aWidgetView->GetDimensions(bounds);
 
1670
 
 
1671
  PRBool overlap = bounds.IntersectRect(bounds, aDamagedRect);
 
1672
  if (!overlap) {
 
1673
    return PR_FALSE;
 
1674
  }
 
1675
 
 
1676
  // If the widget is hidden, it don't cover nothing
 
1677
  if (nsViewVisibility_kHide == aWidgetView->GetVisibility()) {
 
1678
#ifdef DEBUG
 
1679
    // Assert if view is hidden but widget is visible
 
1680
    nsCOMPtr<nsIWidget> widget;
 
1681
    GetWidgetForView(aWidgetView, getter_AddRefs(widget));
 
1682
    if (widget) {
 
1683
      PRBool visible;
 
1684
      widget->IsVisible(visible);
 
1685
      NS_ASSERTION(!visible, "View is hidden but widget is visible!");
 
1686
    }
 
1687
#endif
 
1688
    return PR_FALSE;
 
1689
  }
 
1690
 
 
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.
 
1695
    return noCropping;
 
1696
  }
 
1697
 
 
1698
  nsCOMPtr<nsIWidget> widget;
 
1699
  GetWidgetForView(aWidgetView, getter_AddRefs(widget));
 
1700
  if (!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.
 
1704
    return PR_FALSE;
 
1705
  }
 
1706
 
 
1707
  PRBool childCovers = PR_FALSE;
 
1708
  nsCOMPtr<nsIEnumerator> children(dont_AddRef(widget->GetChildren()));
 
1709
  if (children) {
 
1710
    children->First();
 
1711
    do {
 
1712
      nsCOMPtr<nsISupports> child;
 
1713
      if (NS_SUCCEEDED(children->CurrentItem(getter_AddRefs(child)))) {
 
1714
        nsCOMPtr<nsIWidget> childWidget = do_QueryInterface(child);
 
1715
        if (childWidget) {
 
1716
          nsView* view = nsView::GetViewFor(childWidget);
 
1717
          if (nsnull != view) {
 
1718
            nsRect damage = bounds;
 
1719
            nsView* vp = view;
 
1720
            while (vp != aWidgetView && nsnull != vp) {
 
1721
              vp->ConvertFromParentCoords(&damage.x, &damage.y);
 
1722
              vp = vp->GetParent();
 
1723
            }
 
1724
            
 
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;
 
1728
              }
 
1729
            }
 
1730
          }
 
1731
        }
 
1732
      }
 
1733
    } while (NS_SUCCEEDED(children->Next()));
 
1734
  }
 
1735
 
 
1736
  if (!childCovers) {
 
1737
    nsViewManager* vm = aWidgetView->GetViewManager();
 
1738
    ++vm->mUpdateCnt;
 
1739
 
 
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;
 
1744
    } else {
 
1745
      ViewToWidget(aWidgetView, aWidgetView, bounds);
 
1746
      widget->Invalidate(bounds, PR_FALSE);
 
1747
    }
 
1748
  }
 
1749
 
 
1750
  return noCropping;
 
1751
}
 
1752
 
 
1753
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags)
 
1754
{
 
1755
  NS_PRECONDITION(nsnull != aView, "null view");
 
1756
 
 
1757
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
1758
 
 
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()) {
 
1762
    return NS_OK;
 
1763
  }
 
1764
 
 
1765
  nsRect damagedRect;
 
1766
  damagedRect.IntersectRect(aRect, clippedRect);
 
1767
 
 
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) {
 
1776
    return NS_OK;
 
1777
  }
 
1778
 
 
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;
 
1785
 
 
1786
    while (!widgetParent->HasWidget()) {
 
1787
      widgetParent->ConvertToParentCoords(&damagedRect.x, &damagedRect.y);
 
1788
      widgetParent = widgetParent->GetParent();
 
1789
    }
 
1790
 
 
1791
    UpdateWidgetArea(widgetParent, damagedRect, nsnull);
 
1792
  } else {
 
1793
    damagedRect.MoveBy(ComputeViewOffset(view));
 
1794
 
 
1795
    nsView* realRoot = mRootView;
 
1796
    while (realRoot->GetParent()) {
 
1797
      realRoot = realRoot->GetParent();
 
1798
    }
 
1799
 
 
1800
    UpdateWidgetArea(realRoot, damagedRect, nsnull);
 
1801
  }
 
1802
 
 
1803
  ++mUpdateCnt;
 
1804
 
 
1805
  if (!mRefreshEnabled) {
 
1806
    return NS_OK;
 
1807
  }
 
1808
 
 
1809
  // See if we should do an immediate refresh or wait
 
1810
  if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
 
1811
    Composite();
 
1812
  } 
 
1813
 
 
1814
  return NS_OK;
 
1815
}
 
1816
 
 
1817
NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
 
1818
{
 
1819
  UpdateViews(mRootView, aUpdateFlags);
 
1820
  return NS_OK;
 
1821
}
 
1822
 
 
1823
void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
 
1824
{
 
1825
  // update this view.
 
1826
  UpdateView(aView, aUpdateFlags);
 
1827
 
 
1828
  // update all children as well.
 
1829
  nsView* childView = aView->GetFirstChild();
 
1830
  while (nsnull != childView)  {
 
1831
    if (childView->GetViewManager() == this) {
 
1832
      UpdateViews(childView, aUpdateFlags);
 
1833
    }
 
1834
    childView = childView->GetNextSibling();
 
1835
  }
 
1836
}
 
1837
 
 
1838
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus)
 
1839
{
 
1840
  *aStatus = nsEventStatus_eIgnore;
 
1841
 
 
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;
 
1846
 
 
1847
  switch(aEvent->message)
 
1848
    {
 
1849
    case NS_SIZE:
 
1850
      {
 
1851
        nsView* view = nsView::GetViewFor(aEvent->widget);
 
1852
 
 
1853
        if (nsnull != view)
 
1854
          {
 
1855
            nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width;
 
1856
            nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height;
 
1857
            width = ((nsSizeEvent*)aEvent)->mWinWidth;
 
1858
            height = ((nsSizeEvent*)aEvent)->mWinHeight;
 
1859
 
 
1860
            // The root view may not be set if this is the resize associated with
 
1861
            // window creation
 
1862
 
 
1863
            if (view == mRootView)
 
1864
              {
 
1865
                // Convert from pixels to twips
 
1866
                float p2t;
 
1867
                p2t = mContext->DevUnitsToAppUnits();
 
1868
 
 
1869
                //printf("resize: (pix) %d, %d\n", width, height);
 
1870
                SetWindowDimensions(NSIntPixelsToTwips(width, p2t),
 
1871
                                    NSIntPixelsToTwips(height, p2t));
 
1872
                *aStatus = nsEventStatus_eConsumeNoDefault;
 
1873
              }
 
1874
          }
 
1875
 
 
1876
        break;
 
1877
      }
 
1878
 
 
1879
    case NS_PAINT:
 
1880
      {
 
1881
        nsPaintEvent *event = NS_STATIC_CAST(nsPaintEvent*, aEvent);
 
1882
        nsView *view = nsView::GetViewFor(aEvent->widget);
 
1883
 
 
1884
        if (!view || !mContext)
 
1885
          break;
 
1886
 
 
1887
        *aStatus = nsEventStatus_eConsumeNoDefault;
 
1888
 
 
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;
 
1892
        if (!region) {
 
1893
          if (NS_FAILED(CreateRegion(getter_AddRefs(region))))
 
1894
            break;
 
1895
 
 
1896
          const nsRect& damrect = *event->rect;
 
1897
          region->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
 
1898
        }
 
1899
        
 
1900
        if (region->IsEmpty())
 
1901
          break;
 
1902
 
 
1903
        // Refresh the view
 
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);
 
1911
            
 
1912
            // Paint later.
 
1913
            UpdateView(view, NS_VMREFRESH_NO_SYNC);
 
1914
          } else {
 
1915
            //NS_ASSERTION(IsViewVisible(view), "painting an invisible view");
 
1916
            Refresh(view, event->renderingContext, region,
 
1917
                    NS_VMREFRESH_DOUBLE_BUFFER);
 
1918
          }
 
1919
        } else {
 
1920
          // since we got an NS_PAINT event, we need to
 
1921
          // draw something so we don't get blank areas.
 
1922
          nsRect damRect;
 
1923
          region->GetBoundingBox(&damRect.x, &damRect.y, &damRect.width, &damRect.height);
 
1924
          float p2t;
 
1925
          p2t = mContext->DevUnitsToAppUnits();
 
1926
          damRect.ScaleRoundOut(p2t);
 
1927
          DefaultRefresh(view, &damRect);
 
1928
        
 
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.
 
1934
          // 
 
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)
 
1940
          //
 
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.
 
1945
          //
 
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.)
 
1952
          
 
1953
          UpdateView(view, damRect, NS_VMREFRESH_NO_SYNC);
 
1954
        }
 
1955
 
 
1956
        break;
 
1957
      }
 
1958
 
 
1959
    case NS_CREATE:
 
1960
    case NS_DESTROY:
 
1961
    case NS_SETZLEVEL:
 
1962
    case NS_MOVE:
 
1963
      /* Don't pass these events through. Passing them through
 
1964
         causes performance problems on pages with lots of views/frames 
 
1965
         @see bug 112861 */
 
1966
      *aStatus = nsEventStatus_eConsumeNoDefault;
 
1967
      break;
 
1968
 
 
1969
 
 
1970
    case NS_DISPLAYCHANGED:
 
1971
 
 
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();
 
1978
      }
 
1979
      break;
 
1980
 
 
1981
    case NS_SYSCOLORCHANGED:
 
1982
      {
 
1983
        nsView *view = nsView::GetViewFor(aEvent->widget);
 
1984
        nsCOMPtr<nsIViewObserver> obs;
 
1985
        GetViewObserver(*getter_AddRefs(obs));
 
1986
        if (obs) {
 
1987
          PRBool handled;
 
1988
          obs->HandleEvent(view, aEvent, aStatus, PR_TRUE, handled);
 
1989
        }
 
1990
      }
 
1991
      break; 
 
1992
 
 
1993
    default:
 
1994
      {
 
1995
        nsView* baseView;
 
1996
        nsView* view;
 
1997
        nsPoint offset;
 
1998
        PRBool capturedEvent = PR_FALSE;
 
1999
 
 
2000
        if (NS_IS_MOUSE_EVENT(aEvent) || NS_IS_KEY_EVENT(aEvent) ||
 
2001
            NS_IS_IME_EVENT(aEvent)) {
 
2002
          gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
 
2003
        }
 
2004
 
 
2005
        //Find the view whose coordinates system we're in.
 
2006
        baseView = nsView::GetViewFor(aEvent->widget);
 
2007
 
 
2008
        if (aEvent->message == NS_DEACTIVATE)
 
2009
          mMouseGrabber = mKeyGrabber = nsnull;
 
2010
 
 
2011
        //Find the view to which we're initially going to send the event 
 
2012
        //for hittesting.
 
2013
        if (nsnull != mMouseGrabber && (NS_IS_MOUSE_EVENT(aEvent) || (NS_IS_DRAG_EVENT(aEvent)))) {
 
2014
          view = mMouseGrabber;
 
2015
          capturedEvent = PR_TRUE;
 
2016
        }
 
2017
        else if (nsnull != mKeyGrabber && (NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent))) {
 
2018
          view = mKeyGrabber;
 
2019
          capturedEvent = PR_TRUE;
 
2020
        }
 
2021
        else {
 
2022
          view = baseView;
 
2023
        }
 
2024
 
 
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
 
2030
            nsView *parent;
 
2031
 
 
2032
            parent = baseView;
 
2033
            while (mRootView != parent) {
 
2034
              parent->ConvertToParentCoords(&offset.x, &offset.y);
 
2035
              parent = parent->GetParent();
 
2036
            }
 
2037
 
 
2038
            //Subtract back offset from root of view
 
2039
            parent = view;
 
2040
            while (mRootView != parent) {
 
2041
              parent->ConvertFromParentCoords(&offset.x, &offset.y);
 
2042
              parent = parent->GetParent();
 
2043
            }
 
2044
      
 
2045
          }
 
2046
 
 
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;
 
2051
 
 
2052
          nsRect baseViewDimensions;
 
2053
          if (baseView != nsnull) {
 
2054
            baseView->GetDimensions(baseViewDimensions);
 
2055
          }
 
2056
 
 
2057
          float t2p = mContext->AppUnitsToDevUnits();
 
2058
          float p2t = mContext->DevUnitsToAppUnits();
 
2059
 
 
2060
          aEvent->point.x = baseViewDimensions.x + NSIntPixelsToTwips(aEvent->point.x, p2t);
 
2061
          aEvent->point.y = baseViewDimensions.y + NSIntPixelsToTwips(aEvent->point.y, p2t);
 
2062
 
 
2063
          aEvent->point.x += offset.x;
 
2064
          aEvent->point.y += offset.y;
 
2065
 
 
2066
          *aStatus = HandleEvent(view, aEvent, capturedEvent);
 
2067
 
 
2068
          // From here on out, "this" could have been deleted!!!
 
2069
 
 
2070
          aEvent->point.x -= offset.x;
 
2071
          aEvent->point.y -= offset.y;
 
2072
 
 
2073
          aEvent->point.x = NSTwipsToIntPixels(aEvent->point.x - baseViewDimensions.x, t2p);
 
2074
          aEvent->point.y = NSTwipsToIntPixels(aEvent->point.y - baseViewDimensions.y, t2p);
 
2075
 
 
2076
          //
 
2077
          // if the event is an nsTextEvent, we need to map the reply back into platform coordinates
 
2078
          //
 
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);
 
2084
          }
 
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);
 
2091
          }
 
2092
        }
 
2093
    
 
2094
        break;
 
2095
      }
 
2096
    }
 
2097
 
 
2098
  return NS_OK;
 
2099
}
 
2100
 
 
2101
void nsViewManager::ReparentViews(DisplayZTreeNode* aNode) {
 
2102
  if (aNode == nsnull) {
 
2103
    return;
 
2104
  }
 
2105
 
 
2106
  DisplayZTreeNode* child;
 
2107
  DisplayZTreeNode** prev = &aNode->mZChild;
 
2108
  for (child = aNode->mZChild; nsnull != child; child = *prev) {
 
2109
    ReparentViews(child);
 
2110
 
 
2111
    nsZPlaceholderView *zParent = nsnull;
 
2112
    if (nsnull != child->mView) {
 
2113
      zParent = child->mView->GetZParent();
 
2114
    }
 
2115
    if (nsnull != zParent) {
 
2116
      nsVoidKey key(zParent);
 
2117
      DisplayZTreeNode* placeholder = (DisplayZTreeNode *)mMapPlaceholderViewToZTreeNode.Get(&key);
 
2118
 
 
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;
 
2123
      } else {
 
2124
        // unlink the child from the tree
 
2125
        *prev = child->mZSibling;
 
2126
        child->mZSibling = nsnull;
 
2127
        
 
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;
 
2134
          delete child;
 
2135
        } else {
 
2136
          // the placeholder was not added to the display list
 
2137
          // we don't need the real view then, either
 
2138
          DestroyZTreeNode(child);
 
2139
        }
 
2140
      }
 
2141
    } else {
 
2142
      prev = &child->mZSibling;
 
2143
    }
 
2144
  }
 
2145
}
 
2146
 
 
2147
static PRBool ComputePlaceholderContainment(nsView* aView) {
 
2148
  PRBool containsPlaceholder = aView->IsZPlaceholderView();
 
2149
 
 
2150
  nsView* child;
 
2151
  for (child = aView->GetFirstChild(); child != nsnull; child = child->GetNextSibling()) {
 
2152
    if (ComputePlaceholderContainment(child)) {
 
2153
      containsPlaceholder = PR_TRUE;
 
2154
    }
 
2155
  }
 
2156
 
 
2157
  if (containsPlaceholder) {
 
2158
    aView->SetViewFlags(aView->GetViewFlags() | NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
 
2159
  } else {
 
2160
    aView->SetViewFlags(aView->GetViewFlags() & ~NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
 
2161
  }
 
2162
 
 
2163
  return containsPlaceholder;
 
2164
}
 
2165
 
 
2166
/*
 
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.
 
2171
 
 
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.
 
2174
 
 
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.
 
2178
*/
 
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);
 
2183
    
 
2184
  nsView *displayRoot = aView;
 
2185
  if (!aCaptured) {
 
2186
    for (;;) {
 
2187
      nsView *displayParent = displayRoot->GetParent();
 
2188
 
 
2189
      if (nsnull == displayParent) {
 
2190
        break;
 
2191
      }
 
2192
 
 
2193
      if (displayRoot->GetFloating() && !displayParent->GetFloating()) {
 
2194
        break;
 
2195
      }
 
2196
      displayRoot = displayParent;
 
2197
    }
 
2198
  }
 
2199
    
 
2200
  DisplayZTreeNode *zTree;
 
2201
 
 
2202
  nsPoint displayRootOrigin = ComputeViewOffset(displayRoot);
 
2203
  displayRoot->ConvertFromParentCoords(&displayRootOrigin.x, &displayRootOrigin.y);
 
2204
    
 
2205
  // Determine, for each view, whether it is or contains a ZPlaceholderView
 
2206
  ComputePlaceholderContainment(displayRoot);
 
2207
 
 
2208
  // Create the Z-ordered view tree
 
2209
  PRBool paintFloats;
 
2210
  if (aEventProcessing) {
 
2211
    paintFloats = PR_TRUE;
 
2212
  } else {
 
2213
    paintFloats = displayRoot->GetFloating();
 
2214
  }
 
2215
  CreateDisplayList(displayRoot, PR_FALSE, zTree, origin.x, origin.y,
 
2216
                    aView, &aRect, displayRoot, displayRootOrigin.x, displayRootOrigin.y,
 
2217
                    paintFloats, aEventProcessing);
 
2218
 
 
2219
  // Reparent any views that need reparenting in the Z-order tree
 
2220
  ReparentViews(zTree);
 
2221
  mMapPlaceholderViewToZTreeNode.Reset();
 
2222
    
 
2223
  if (nsnull != zTree) {
 
2224
    // Apply proper Z-order handling
 
2225
    nsAutoVoidArray mergeTmp;
 
2226
 
 
2227
    SortByZOrder(zTree, *aDisplayList, mergeTmp, PR_TRUE);
 
2228
  }
 
2229
    
 
2230
  DestroyZTreeNode(zTree);
 
2231
}
 
2232
 
 
2233
void nsViewManager::BuildEventTargetList(nsVoidArray &aTargets, nsView* aView, nsGUIEvent* aEvent,
 
2234
  PRBool aCaptured) {
 
2235
  NS_ASSERTION(!mPainting, "View manager cannot handle events during a paint");
 
2236
  if (mPainting) {
 
2237
    return;
 
2238
  }
 
2239
 
 
2240
  nsRect eventRect(aEvent->point.x, aEvent->point.y, 1, 1);
 
2241
  nsAutoVoidArray displayList;
 
2242
  BuildDisplayList(aView, eventRect, PR_TRUE, aCaptured, &displayList);
 
2243
 
 
2244
#ifdef DEBUG_roc
 
2245
  if (getenv("MOZ_SHOW_DISPLAY_LIST")) ShowDisplayList(&displayList);
 
2246
#endif
 
2247
 
 
2248
  // The display list is in order from back to front. We return the target list in order from
 
2249
  // front to back.
 
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);
 
2254
    } else {
 
2255
      delete element;
 
2256
    }
 
2257
  }
 
2258
}
 
2259
 
 
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);
 
2263
 
 
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));
 
2269
 
 
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;
 
2276
    if (obs) {
 
2277
       PRBool handled;
 
2278
       obs->HandleEvent(aView, aEvent, &status, PR_TRUE, handled);
 
2279
    }
 
2280
    return status;
 
2281
  }
 
2282
    
 
2283
  nsAutoVoidArray targetViews;
 
2284
  nsAutoVoidArray heldRefCountsToOtherVMs;
 
2285
 
 
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);
 
2288
 
 
2289
  nsEventStatus status = nsEventStatus_eIgnore;
 
2290
 
 
2291
  // get a death grip on any view managers' view observers (other than this one)
 
2292
  PRInt32 i;
 
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();
 
2297
    if (vVM != this) {
 
2298
      nsIViewObserver* vobs = nsnull;
 
2299
      vVM->GetViewObserver(vobs);
 
2300
      if (nsnull != vobs) {
 
2301
        heldRefCountsToOtherVMs.AppendElement(vobs);
 
2302
      }
 
2303
    }
 
2304
  }
 
2305
 
 
2306
  for (i = 0; i < targetViews.Count(); i++) {
 
2307
    DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, targetViews.ElementAt(i));
 
2308
    nsView* v = element->mView;
 
2309
 
 
2310
    if (nsnull != v->GetClientData()) {
 
2311
      PRBool handled = PR_FALSE;
 
2312
      nsRect r;
 
2313
      v->GetDimensions(r);
 
2314
 
 
2315
      nscoord x = element->mAbsX - r.x;
 
2316
      nscoord y = element->mAbsY - r.y;
 
2317
 
 
2318
      aEvent->point.x -= x;
 
2319
      aEvent->point.y -= y;
 
2320
 
 
2321
      nsViewManager* vVM = v->GetViewManager();
 
2322
      if (vVM == this) {
 
2323
        if (nsnull != obs) {
 
2324
          obs->HandleEvent(v, aEvent, &status, i == targetViews.Count() - 1, handled);
 
2325
        }
 
2326
      } else {
 
2327
        nsCOMPtr<nsIViewObserver> vobs;
 
2328
        vVM->GetViewObserver(*getter_AddRefs(vobs));
 
2329
        if (vobs) {
 
2330
          vobs->HandleEvent(v, aEvent, &status, i == targetViews.Count() - 1, handled);
 
2331
        }
 
2332
      }
 
2333
 
 
2334
      aEvent->point.x += x;
 
2335
      aEvent->point.y += y;
 
2336
 
 
2337
      if (handled) {
 
2338
        while (i < targetViews.Count()) {
 
2339
          DisplayListElement2* e = NS_STATIC_CAST(DisplayListElement2*, targetViews.ElementAt(i));
 
2340
          delete e;
 
2341
          i++;
 
2342
        }
 
2343
        break;
 
2344
      }
 
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.
 
2347
    }
 
2348
 
 
2349
    delete element;
 
2350
  }
 
2351
 
 
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);
 
2356
  }  
 
2357
 
 
2358
  return status;
 
2359
}
 
2360
 
 
2361
NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult)
 
2362
{
 
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) {
 
2367
    aView = nsnull;
 
2368
  }
 
2369
 
 
2370
#ifdef DEBUG_mjudge
 
2371
  if (aView)
 
2372
    {
 
2373
      printf("capturing mouse events for view %x\n",aView);
 
2374
    }
 
2375
  printf("removing mouse capture from view %x\n",mMouseGrabber);
 
2376
#endif
 
2377
 
 
2378
  mMouseGrabber = NS_STATIC_CAST(nsView*, aView);
 
2379
  aResult = PR_TRUE;
 
2380
  return NS_OK;
 
2381
}
 
2382
 
 
2383
NS_IMETHODIMP nsViewManager::GrabKeyEvents(nsIView *aView, PRBool &aResult)
 
2384
{
 
2385
  mKeyGrabber = NS_STATIC_CAST(nsView*, aView);
 
2386
  aResult = PR_TRUE;
 
2387
  return NS_OK;
 
2388
}
 
2389
 
 
2390
NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView)
 
2391
{
 
2392
  aView = mMouseGrabber;
 
2393
  return NS_OK;
 
2394
}
 
2395
 
 
2396
NS_IMETHODIMP nsViewManager::GetKeyEventGrabber(nsIView *&aView)
 
2397
{
 
2398
  aView = mKeyGrabber;
 
2399
  return NS_OK;
 
2400
}
 
2401
 
 
2402
 
 
2403
// Recursively reparent widgets if necessary 
 
2404
 
 
2405
void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
 
2406
{
 
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!");
 
2417
    }
 
2418
    return;
 
2419
  }
 
2420
 
 
2421
  // Need to check each of the views children to see
 
2422
  // if they have a widget and reparent it.
 
2423
 
 
2424
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2425
  for (nsView *kid = view->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
 
2426
    ReparentChildWidgets(kid, aNewWidget);
 
2427
  }
 
2428
}
 
2429
 
 
2430
// Reparent a view and its descendant views widgets if necessary
 
2431
 
 
2432
void nsViewManager::ReparentWidgets(nsIView* aView, nsIView *aParent)
 
2433
{
 
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));
 
2445
    if (parentWidget) {
 
2446
      ReparentChildWidgets(aView, parentWidget);
 
2447
      return;
 
2448
    }
 
2449
    NS_WARNING("Can not find a widget for the parent view");
 
2450
  }
 
2451
}
 
2452
 
 
2453
NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, nsIView *aSibling,
 
2454
                                         PRBool aAfter)
 
2455
{
 
2456
  nsView* parent = NS_STATIC_CAST(nsView*, aParent);
 
2457
  nsView* child = NS_STATIC_CAST(nsView*, aChild);
 
2458
  nsView* sibling = NS_STATIC_CAST(nsView*, aSibling);
 
2459
  
 
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");
 
2465
 
 
2466
  if ((nsnull != parent) && (nsnull != child))
 
2467
    {
 
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).
 
2470
 
 
2471
#if 1
 
2472
      if (nsnull == aSibling) {
 
2473
        if (aAfter) {
 
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);
 
2478
        } else {
 
2479
          // insert at beginning of document order, i.e., after last view
 
2480
          nsView *kid = parent->GetFirstChild();
 
2481
          nsView *prev = nsnull;
 
2482
          while (kid) {
 
2483
            prev = kid;
 
2484
            kid = kid->GetNextSibling();
 
2485
          }
 
2486
          // prev is last view or null if there are no children
 
2487
          parent->InsertChild(child, prev);
 
2488
          ReparentWidgets(child, parent);
 
2489
        }
 
2490
      } else {
 
2491
        nsView *kid = parent->GetFirstChild();
 
2492
        nsView *prev = nsnull;
 
2493
        while (kid && sibling != kid) {
 
2494
          //get the next sibling view
 
2495
          prev = kid;
 
2496
          kid = kid->GetNextSibling();
 
2497
        }
 
2498
        NS_ASSERTION(kid != nsnull,
 
2499
                     "couldn't find sibling in child list");
 
2500
        if (aAfter) {
 
2501
          // insert after 'kid' in document order, i.e. before in view order
 
2502
          parent->InsertChild(child, prev);
 
2503
          ReparentWidgets(child, parent);
 
2504
        } else {
 
2505
          // insert before 'kid' in document order, i.e. after in view order
 
2506
          parent->InsertChild(child, kid);
 
2507
          ReparentWidgets(child, parent);
 
2508
        }
 
2509
      }
 
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)
 
2514
        {
 
2515
          PRInt32 idx = kid->GetZIndex();
 
2516
 
 
2517
          if (CompareZIndex(zIndex, child->IsTopMost(), child->GetZIndexIsAuto(),
 
2518
                            idx, kid->IsTopMost(), kid->GetZIndexIsAuto()) >= 0)
 
2519
            break;
 
2520
 
 
2521
          prev = kid;
 
2522
          kid = kid->GetNextSibling();
 
2523
        }
 
2524
 
 
2525
      parent->InsertChild(child, prev);
 
2526
      ReparentWidgets(child, parent);
 
2527
#endif
 
2528
 
 
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);
 
2532
 
 
2533
      //and mark this area as dirty if the view is visible...
 
2534
 
 
2535
      if (nsViewVisibility_kHide != child->GetVisibility())
 
2536
        UpdateView(child, NS_VMREFRESH_NO_SYNC);
 
2537
    }
 
2538
  return NS_OK;
 
2539
}
 
2540
 
 
2541
NS_IMETHODIMP nsViewManager::InsertZPlaceholder(nsIView *aParent, nsIView *aChild,
 
2542
                                                nsIView *aSibling, PRBool aAfter)
 
2543
{
 
2544
  nsView* parent = NS_STATIC_CAST(nsView*, aParent);
 
2545
  nsView* child = NS_STATIC_CAST(nsView*, aChild);
 
2546
 
 
2547
  NS_PRECONDITION(nsnull != parent, "null ptr");
 
2548
  NS_PRECONDITION(nsnull != child, "null ptr");
 
2549
 
 
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);
 
2557
  
 
2558
  return InsertChild(parent, placeholder, aSibling, aAfter);
 
2559
}
 
2560
 
 
2561
NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, PRInt32 aZIndex)
 
2562
{
 
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);
 
2567
}
 
2568
 
 
2569
NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *aChild)
 
2570
{
 
2571
  nsView* child = NS_STATIC_CAST(nsView*, aChild);
 
2572
 
 
2573
  NS_PRECONDITION(nsnull != child, "null ptr");
 
2574
 
 
2575
  nsView* parent = child->GetParent();
 
2576
 
 
2577
  if ((nsnull != parent) && (nsnull != child))
 
2578
    {
 
2579
      UpdateView(child, NS_VMREFRESH_NO_SYNC);
 
2580
      parent->RemoveChild(child);
 
2581
    }
 
2582
 
 
2583
  return NS_OK;
 
2584
}
 
2585
 
 
2586
NS_IMETHODIMP nsViewManager::MoveViewBy(nsIView *aView, nscoord aX, nscoord aY)
 
2587
{
 
2588
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2589
 
 
2590
  nsPoint pt = view->GetPosition();
 
2591
  MoveViewTo(view, aX + pt.x, aY + pt.y);
 
2592
  return NS_OK;
 
2593
}
 
2594
 
 
2595
NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
 
2596
{
 
2597
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2598
  nsPoint oldPt = view->GetPosition();
 
2599
  nsRect oldArea = view->GetBounds();
 
2600
  view->SetPosition(aX, aY);
 
2601
 
 
2602
  // only do damage control if the view is visible
 
2603
 
 
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);
 
2609
    }
 
2610
  }
 
2611
  return NS_OK;
 
2612
}
 
2613
 
 
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);
 
2620
  }
 
2621
  if (!aInCutOut && aCutOut.x < aCutOut.XMost()) {
 
2622
    nsRect r(aCutOut.x, aY1, aCutOut.width, height);
 
2623
    UpdateView(aView, r, aUpdateFlags);
 
2624
  }
 
2625
  if (aCutOut.XMost() < aRect.XMost()) {
 
2626
    nsRect r(aCutOut.XMost(), aY1, aRect.XMost() - aCutOut.XMost(), height);
 
2627
    UpdateView(aView, r, aUpdateFlags);
 
2628
  }
 
2629
}
 
2630
 
 
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);
 
2635
  }
 
2636
  if (aCutOut.y < aCutOut.YMost()) {
 
2637
    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.y, aCutOut.YMost(), PR_TRUE);
 
2638
  }
 
2639
  if (aCutOut.YMost() < aRect.YMost()) {
 
2640
    InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.YMost(), aRect.YMost(), PR_FALSE);
 
2641
  }
 
2642
}
 
2643
 
 
2644
NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRBool aRepaintExposedAreaOnly)
 
2645
{
 
2646
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2647
  nsRect oldDimensions;
 
2648
 
 
2649
  view->GetDimensions(oldDimensions);
 
2650
  if (oldDimensions != aRect) {
 
2651
    nsView* parentView = view->GetParent();
 
2652
    if (parentView == nsnull)
 
2653
      parentView = view;
 
2654
 
 
2655
    // resize the view.
 
2656
    // Prevent Invalidation of hidden views 
 
2657
    if (view->GetVisibility() == nsViewVisibility_kHide) {  
 
2658
      view->SetDimensions(aRect, PR_FALSE);
 
2659
    } else {
 
2660
      if (!aRepaintExposedAreaOnly) {
 
2661
        //Invalidate the union of the old and new size
 
2662
        view->SetDimensions(aRect, PR_TRUE);
 
2663
 
 
2664
        UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
 
2665
        view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
 
2666
        UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC);
 
2667
      } else {
 
2668
        view->SetDimensions(aRect, PR_TRUE);
 
2669
 
 
2670
        InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
 
2671
        nsRect r = aRect;
 
2672
        view->ConvertToParentCoords(&r.x, &r.y);
 
2673
        view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
 
2674
        InvalidateRectDifference(parentView, oldDimensions, r, NS_VMREFRESH_NO_SYNC);
 
2675
      } 
 
2676
    }
 
2677
  }
 
2678
 
 
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.
 
2684
 
 
2685
  return NS_OK;
 
2686
}
 
2687
 
 
2688
NS_IMETHODIMP nsViewManager::SetViewChildClipRegion(nsIView *aView, const nsRegion *aRegion)
 
2689
{
 
2690
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2691
 
 
2692
  NS_ASSERTION(!(nsnull == view), "no view");
 
2693
 
 
2694
  const nsRect* oldClipRect = view->GetClipChildrenToRect();
 
2695
 
 
2696
  nsRect newClipRectStorage = view->GetDimensions();
 
2697
  nsRect* newClipRect = nsnull;
 
2698
  if (aRegion) {
 
2699
    newClipRectStorage = aRegion->GetBounds();
 
2700
    newClipRect = &newClipRectStorage;
 
2701
  }
 
2702
 
 
2703
  if ((oldClipRect != nsnull) == (newClipRect != nsnull)
 
2704
      && (!newClipRect || *newClipRect == *oldClipRect)) {
 
2705
    return NS_OK;
 
2706
  }
 
2707
  nsRect oldClipRectStorage =
 
2708
    oldClipRect ? *oldClipRect : view->GetDimensions();
 
2709
 
 
2710
  // Update the view properties
 
2711
  view->SetClipChildrenToRect(newClipRect);
 
2712
 
 
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();
 
2719
    if (parent) {
 
2720
      oldClipRectStorage += view->GetPosition();
 
2721
      newClipRectStorage += view->GetPosition();
 
2722
      InvalidateRectDifference(parent, oldClipRectStorage, newClipRectStorage, NS_VMREFRESH_NO_SYNC);
 
2723
    }
 
2724
  }
 
2725
 
 
2726
  return NS_OK;
 
2727
}
 
2728
 
 
2729
/*
 
2730
  Returns PR_TRUE if and only if aView is a (possibly indirect) child of aAncestor.
 
2731
*/
 
2732
static PRBool IsAncestorOf(const nsView* aAncestor, const nsView* aView) 
 
2733
{
 
2734
  while (nsnull != aView) {
 
2735
    aView = aView->GetParent();
 
2736
    if (aView == aAncestor) {
 
2737
      return PR_TRUE;
 
2738
    }
 
2739
  }
 
2740
  return PR_FALSE;
 
2741
}
 
2742
 
 
2743
/*
 
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.
 
2749
 
 
2750
  The way we check this is quite subtle, because there are all sorts
 
2751
  of complicated things that can happen.
 
2752
 
 
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.
 
2757
 
 
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
 
2763
  the way.
 
2764
 
 
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.
 
2776
 
 
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.
 
2786
 
 
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
 
2790
  PR_FALSE.
 
2791
 
 
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
 
2800
  elements.
 
2801
*/
 
2802
PRBool nsViewManager::CanScrollWithBitBlt(nsView* aView)
 
2803
{
 
2804
  NS_ASSERTION(!mPainting, "View manager shouldn't be scrolling during a paint");
 
2805
  if (mPainting) {
 
2806
    return PR_FALSE; // do the safe thing
 
2807
  }
 
2808
 
 
2809
  nsRect r = aView->GetClippedRect();
 
2810
  // Only check the area that intersects the view's non clipped rectangle
 
2811
  if (r.IsEmpty()) {
 
2812
    return PR_TRUE; // nothing to scroll
 
2813
  }
 
2814
 
 
2815
  nsAutoVoidArray displayList;
 
2816
  BuildDisplayList(aView, r, PR_FALSE, PR_FALSE, &displayList);
 
2817
 
 
2818
  PRInt32 i;
 
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);
 
2824
      }
 
2825
    }
 
2826
  }
 
2827
 
 
2828
  nsRect finalTransparentRect;
 
2829
 
 
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
 
2832
  // child widgets.
 
2833
 
 
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());
 
2851
        }
 
2852
        fixedView = fixedView->GetNextSibling();
 
2853
      }
 
2854
 
 
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);
 
2859
      }
 
2860
      opaqueRegion.MoveBy(-deltaX, -deltaY);
 
2861
    }
 
2862
  }
 
2863
 
 
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.
 
2873
 
 
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
 
2877
  // approach!)
 
2878
 
 
2879
  OptimizeDisplayList(&displayList, nsRegion(r), finalTransparentRect, opaqueRegion, PR_TRUE);
 
2880
 
 
2881
  PRBool anyUnscrolledViews = PR_FALSE;
 
2882
  PRBool anyUnblittableViews = PR_FALSE;
 
2883
 
 
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;
 
2891
      }
 
2892
    }
 
2893
      
 
2894
    delete element;
 
2895
  }
 
2896
 
 
2897
  return !anyUnscrolledViews && !anyUnblittableViews;
 
2898
}
 
2899
 
 
2900
NS_IMETHODIMP nsViewManager::SetViewBitBltEnabled(nsIView *aView, PRBool aEnable)
 
2901
{
 
2902
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2903
 
 
2904
  NS_ASSERTION(!(nsnull == view), "no view");
 
2905
 
 
2906
  if (aEnable) {
 
2907
    view->SetViewFlags(view->GetViewFlags() & ~NS_VIEW_FLAG_DONT_BITBLT);
 
2908
  } else {
 
2909
    view->SetViewFlags(view->GetViewFlags() | NS_VIEW_FLAG_DONT_BITBLT);
 
2910
  }
 
2911
 
 
2912
  return NS_OK;
 
2913
}
 
2914
 
 
2915
NS_IMETHODIMP nsViewManager::SetViewCheckChildEvents(nsIView *aView, PRBool aEnable)
 
2916
{
 
2917
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2918
 
 
2919
  NS_ASSERTION(!(nsnull == view), "no view");
 
2920
 
 
2921
  if (aEnable) {
 
2922
    view->SetViewFlags(view->GetViewFlags() & ~NS_VIEW_FLAG_DONT_CHECK_CHILDREN);
 
2923
  } else {
 
2924
    view->SetViewFlags(view->GetViewFlags() | NS_VIEW_FLAG_DONT_CHECK_CHILDREN);
 
2925
  }
 
2926
 
 
2927
  return NS_OK;
 
2928
}
 
2929
 
 
2930
NS_IMETHODIMP nsViewManager::SetViewFloating(nsIView *aView, PRBool aFloating)
 
2931
{
 
2932
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2933
 
 
2934
  NS_ASSERTION(!(nsnull == view), "no view");
 
2935
 
 
2936
  view->SetFloating(aFloating);
 
2937
 
 
2938
  return NS_OK;
 
2939
}
 
2940
 
 
2941
NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility aVisible)
 
2942
{
 
2943
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2944
 
 
2945
  if (aVisible != view->GetVisibility()) {
 
2946
    view->SetVisibility(aVisible);
 
2947
 
 
2948
    if (IsViewInserted(view)) {
 
2949
      if (!view->HasWidget()) {
 
2950
        if (nsViewVisibility_kHide == aVisible) {
 
2951
          nsView* parentView = view->GetParent();
 
2952
          if (parentView) {
 
2953
            UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
 
2954
          }
 
2955
        }
 
2956
        else {
 
2957
          UpdateView(view, NS_VMREFRESH_NO_SYNC);
 
2958
        }
 
2959
      }
 
2960
    }
 
2961
  }
 
2962
  return NS_OK;
 
2963
}
 
2964
 
 
2965
PRBool nsViewManager::IsViewInserted(nsView *aView)
 
2966
{
 
2967
  if (mRootView == aView) {
 
2968
    return PR_TRUE;
 
2969
  } else if (aView->GetParent() == nsnull) {
 
2970
    return PR_FALSE;
 
2971
  } else {
 
2972
    nsView* view = aView->GetParent()->GetFirstChild();
 
2973
    while (view != nsnull) {
 
2974
      if (view == aView) {
 
2975
        return PR_TRUE;
 
2976
      }        
 
2977
      view = view->GetNextSibling();
 
2978
    }
 
2979
    return PR_FALSE;
 
2980
  }
 
2981
}
 
2982
 
 
2983
NS_IMETHODIMP nsViewManager::SetViewZIndex(nsIView *aView, PRBool aAutoZIndex, PRInt32 aZIndex, PRBool aTopMost)
 
2984
{
 
2985
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
2986
  nsresult  rv = NS_OK;
 
2987
 
 
2988
  NS_ASSERTION((view != nsnull), "no view");
 
2989
 
 
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) {
 
2993
    return rv;
 
2994
  }
 
2995
 
 
2996
  PRBool oldTopMost = view->IsTopMost();
 
2997
  PRBool oldIsAuto = view->GetZIndexIsAuto();
 
2998
 
 
2999
  if (aAutoZIndex) {
 
3000
    aZIndex = 0;
 
3001
  }
 
3002
 
 
3003
  PRInt32 oldidx = view->GetZIndex();
 
3004
  view->SetZIndex(aAutoZIndex, aZIndex, aTopMost);
 
3005
 
 
3006
  if (CompareZIndex(oldidx, oldTopMost, oldIsAuto,
 
3007
                    aZIndex, aTopMost, aAutoZIndex) != 0) {
 
3008
    UpdateView(view, NS_VMREFRESH_NO_SYNC);
 
3009
  }
 
3010
 
 
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
 
3017
  // good order).
 
3018
  if (view->HasWidget()) {
 
3019
    view->GetWidget()->SetZIndex(aZIndex);
 
3020
  }
 
3021
 
 
3022
  nsZPlaceholderView* zParentView = view->GetZParent();
 
3023
  if (nsnull != zParentView) {
 
3024
    SetViewZIndex(zParentView, aAutoZIndex, aZIndex, aTopMost);
 
3025
  }
 
3026
 
 
3027
  return rv;
 
3028
}
 
3029
 
 
3030
NS_IMETHODIMP nsViewManager::SetViewContentTransparency(nsIView *aView, PRBool aTransparent)
 
3031
{
 
3032
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
3033
 
 
3034
  if (view->IsTransparent() != aTransparent) {
 
3035
    view->SetContentTransparency(aTransparent);
 
3036
 
 
3037
    if (IsViewInserted(view)) {
 
3038
      UpdateView(view, NS_VMREFRESH_NO_SYNC);
 
3039
    }
 
3040
  }
 
3041
 
 
3042
  return NS_OK;
 
3043
}
 
3044
 
 
3045
NS_IMETHODIMP nsViewManager::SetViewOpacity(nsIView *aView, float aOpacity)
 
3046
{
 
3047
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
3048
 
 
3049
  if (view->GetOpacity() != aOpacity)
 
3050
    {
 
3051
      view->SetOpacity(aOpacity);
 
3052
 
 
3053
      if (IsViewInserted(view)) {
 
3054
        UpdateView(view, NS_VMREFRESH_NO_SYNC);
 
3055
      }
 
3056
    }
 
3057
 
 
3058
  return NS_OK;
 
3059
}
 
3060
 
 
3061
NS_IMETHODIMP nsViewManager::SetViewObserver(nsIViewObserver *aObserver)
 
3062
{
 
3063
  mObserver = aObserver;
 
3064
  return NS_OK;
 
3065
}
 
3066
 
 
3067
NS_IMETHODIMP nsViewManager::GetViewObserver(nsIViewObserver *&aObserver)
 
3068
{
 
3069
  if (nsnull != mObserver) {
 
3070
    aObserver = mObserver;
 
3071
    NS_ADDREF(mObserver);
 
3072
    return NS_OK;
 
3073
  } else
 
3074
    return NS_ERROR_NO_INTERFACE;
 
3075
}
 
3076
 
 
3077
NS_IMETHODIMP nsViewManager::GetDeviceContext(nsIDeviceContext *&aContext)
 
3078
{
 
3079
  NS_IF_ADDREF(mContext);
 
3080
  aContext = mContext;
 
3081
  return NS_OK;
 
3082
}
 
3083
 
 
3084
void nsViewManager::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const
 
3085
{
 
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;
 
3090
  PRInt32 index = 0;
 
3091
  for (index = 0; index < mVMCount; index++) {
 
3092
 
 
3093
    nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
 
3094
    nsCOMPtr<nsIWidget> rootWidget;
 
3095
 
 
3096
    if(NS_SUCCEEDED(vm->GetWidget(getter_AddRefs(rootWidget))) && rootWidget)
 
3097
      {
 
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);
 
3102
      }
 
3103
  }
 
3104
 
 
3105
  //   printf("WIDGET BOUNDS %d %d\n", aMaxWidgetBounds.width, aMaxWidgetBounds.height);
 
3106
}
 
3107
 
 
3108
PRInt32 nsViewManager::GetViewManagerCount()
 
3109
{
 
3110
  return mVMCount;
 
3111
}
 
3112
 
 
3113
const nsVoidArray* nsViewManager::GetViewManagerArray() 
 
3114
{
 
3115
  return gViewManagers;
 
3116
}
 
3117
 
 
3118
nsIRenderingContext * nsViewManager::CreateRenderingContext(nsView &aView)
 
3119
{
 
3120
  nsView              *par = &aView;
 
3121
  nsIWidget*          win;
 
3122
  nsIRenderingContext *cx = nsnull;
 
3123
  nscoord             ax = 0, ay = 0;
 
3124
 
 
3125
  do
 
3126
    {
 
3127
      win = par->GetWidget();
 
3128
      if (win)
 
3129
        break;
 
3130
 
 
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...
 
3136
 
 
3137
      if (par != &aView)
 
3138
        {
 
3139
          par->ConvertToParentCoords(&ax, &ay);
 
3140
        }
 
3141
 
 
3142
      par = par->GetParent();
 
3143
    }
 
3144
  while (nsnull != par);
 
3145
 
 
3146
  if (nsnull != win)
 
3147
    {
 
3148
      mContext->CreateRenderingContext(&aView, cx);
 
3149
 
 
3150
      if (nsnull != cx)
 
3151
        cx->Translate(ax, ay);
 
3152
    }
 
3153
 
 
3154
  return cx;
 
3155
}
 
3156
 
 
3157
void nsViewManager::AddRectToDirtyRegion(nsView* aView, const nsRect &aRect) const
 
3158
{
 
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);
 
3166
 
 
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);
 
3172
    }
 
3173
  }
 
3174
}
 
3175
 
 
3176
NS_IMETHODIMP nsViewManager::DisableRefresh(void)
 
3177
{
 
3178
  if (mUpdateBatchCnt > 0)
 
3179
    return NS_OK;
 
3180
 
 
3181
  mRefreshEnabled = PR_FALSE;
 
3182
  return NS_OK;
 
3183
}
 
3184
 
 
3185
NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags)
 
3186
{
 
3187
  if (mUpdateBatchCnt > 0)
 
3188
    return NS_OK;
 
3189
 
 
3190
  mRefreshEnabled = PR_TRUE;
 
3191
 
 
3192
  if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
 
3193
    ProcessPendingUpdates(mRootView);
 
3194
    mHasPendingInvalidates = PR_FALSE;
 
3195
    Composite();
 
3196
  } else {
 
3197
    PostInvalidateEvent();
 
3198
  }
 
3199
 
 
3200
  return NS_OK;
 
3201
}
 
3202
 
 
3203
NS_IMETHODIMP nsViewManager::BeginUpdateViewBatch(void)
 
3204
{
 
3205
  nsresult result = NS_OK;
 
3206
  
 
3207
  if (mUpdateBatchCnt == 0)
 
3208
    result = DisableRefresh();
 
3209
 
 
3210
  if (NS_SUCCEEDED(result))
 
3211
    ++mUpdateBatchCnt;
 
3212
 
 
3213
  return result;
 
3214
}
 
3215
 
 
3216
NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags)
 
3217
{
 
3218
  nsresult result = NS_OK;
 
3219
 
 
3220
  --mUpdateBatchCnt;
 
3221
 
 
3222
  NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
 
3223
 
 
3224
  if (mUpdateBatchCnt < 0)
 
3225
    {
 
3226
      mUpdateBatchCnt = 0;
 
3227
      return NS_ERROR_FAILURE;
 
3228
    }
 
3229
 
 
3230
  if (mUpdateBatchCnt == 0)
 
3231
    result = EnableRefresh(aUpdateFlags);
 
3232
 
 
3233
  return result;
 
3234
}
 
3235
 
 
3236
NS_IMETHODIMP nsViewManager::SetRootScrollableView(nsIScrollableView *aScrollable)
 
3237
{
 
3238
  if (mRootScrollable) {
 
3239
    NS_STATIC_CAST(nsScrollPortView*, mRootScrollable)->
 
3240
      SetClipPlaceholdersToBounds(PR_FALSE);
 
3241
  }
 
3242
  mRootScrollable = aScrollable;
 
3243
  if (mRootScrollable) {
 
3244
    NS_STATIC_CAST(nsScrollPortView*, mRootScrollable)->
 
3245
      SetClipPlaceholdersToBounds(PR_TRUE);
 
3246
  }
 
3247
  return NS_OK;
 
3248
}
 
3249
 
 
3250
NS_IMETHODIMP nsViewManager::GetRootScrollableView(nsIScrollableView **aScrollable)
 
3251
{
 
3252
  *aScrollable = mRootScrollable;
 
3253
  return NS_OK;
 
3254
}
 
3255
 
 
3256
NS_IMETHODIMP nsViewManager::Display(nsIView* aView, nscoord aX, nscoord aY, const nsRect& aClipRect)
 
3257
{
 
3258
  nsView              *view = NS_STATIC_CAST(nsView*, aView);
 
3259
  nsIRenderingContext *localcx = nsnull;
 
3260
 
 
3261
  if (PR_FALSE == mRefreshEnabled)
 
3262
    return NS_OK;
 
3263
 
 
3264
  NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted");
 
3265
 
 
3266
  mPainting = PR_TRUE;
 
3267
 
 
3268
  mContext->CreateRenderingContext(localcx);
 
3269
 
 
3270
  //couldn't get rendering context. this is ok if at startup
 
3271
  if (nsnull == localcx)
 
3272
    {
 
3273
      mPainting = PR_FALSE;
 
3274
      return NS_ERROR_FAILURE;
 
3275
    }
 
3276
 
 
3277
  nsRect trect = view->GetBounds();
 
3278
  view->ConvertFromParentCoords(&trect.x, &trect.y);
 
3279
 
 
3280
  localcx->Translate(aX, aY);
 
3281
 
 
3282
  PRBool isClipped;
 
3283
  localcx->SetClipRect(aClipRect, nsClipCombine_kReplace, isClipped);
 
3284
 
 
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);
 
3290
 
 
3291
  NS_RELEASE(localcx);
 
3292
 
 
3293
  mPainting = PR_FALSE;
 
3294
 
 
3295
  return NS_OK;
 
3296
 
 
3297
}
 
3298
 
 
3299
NS_IMETHODIMP nsViewManager::AddCompositeListener(nsICompositeListener* aListener)
 
3300
{
 
3301
  if (nsnull == mCompositeListeners) {
 
3302
    nsresult rv = NS_NewISupportsArray(&mCompositeListeners);
 
3303
    if (NS_FAILED(rv))
 
3304
      return rv;
 
3305
  }
 
3306
  return mCompositeListeners->AppendElement(aListener);
 
3307
}
 
3308
 
 
3309
NS_IMETHODIMP nsViewManager::RemoveCompositeListener(nsICompositeListener* aListener)
 
3310
{
 
3311
  if (nsnull != mCompositeListeners) {
 
3312
    return mCompositeListeners->RemoveElement(aListener);
 
3313
  }
 
3314
  return NS_ERROR_FAILURE;
 
3315
}
 
3316
 
 
3317
NS_IMETHODIMP nsViewManager::GetWidgetForView(nsIView *aView, nsIWidget **aWidget)
 
3318
{
 
3319
  nsView *view = NS_STATIC_CAST(nsView*, aView);
 
3320
 
 
3321
  while (view && !view->HasWidget()) {
 
3322
    view = view->GetParent();
 
3323
  }
 
3324
 
 
3325
  if (view) {
 
3326
    // Widget was found in the view hierarchy
 
3327
    *aWidget = view->GetWidget();
 
3328
    NS_ADDREF(*aWidget);
 
3329
  } else {
 
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);
 
3336
    } else {
 
3337
      *aWidget = nsnull;
 
3338
    }
 
3339
  }
 
3340
 
 
3341
  return NS_OK;
 
3342
}
 
3343
 
 
3344
 
 
3345
NS_IMETHODIMP nsViewManager::GetWidget(nsIWidget **aWidget)
 
3346
{
 
3347
  NS_IF_ADDREF(mRootWindow);
 
3348
  *aWidget = mRootWindow;
 
3349
  return NS_OK;
 
3350
}
 
3351
 
 
3352
NS_IMETHODIMP nsViewManager::ForceUpdate()
 
3353
{
 
3354
  if (mRootWindow)
 
3355
    mRootWindow->Update();
 
3356
  return NS_OK;
 
3357
}
 
3358
 
 
3359
static nsresult EnsureZTreeNodeCreated(nsView* aView, DisplayZTreeNode* &aNode) {
 
3360
  if (nsnull == aNode) {
 
3361
    aNode = new DisplayZTreeNode;
 
3362
 
 
3363
    if (nsnull == aNode) {
 
3364
      return NS_ERROR_OUT_OF_MEMORY;
 
3365
    }
 
3366
    aNode->mView = aView;
 
3367
    aNode->mDisplayElement = nsnull;
 
3368
    aNode->mZChild = nsnull;
 
3369
    aNode->mZSibling = nsnull;
 
3370
  }
 
3371
  return NS_OK;
 
3372
}
 
3373
 
 
3374
/**
 
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
 
3383
 * of aRealView
 
3384
 * @param aTopView the displayRoot, the root of the collection of views
 
3385
 * to be painted
 
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
 
3390
 * this display list
 
3391
 */
 
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)
 
3398
{
 
3399
  PRBool retval = PR_FALSE;
 
3400
 
 
3401
  aResult = nsnull;
 
3402
 
 
3403
  NS_ASSERTION((aView != nsnull), "no view");
 
3404
 
 
3405
  if (nsViewVisibility_kHide == aView->GetVisibility()) {
 
3406
    // bail out if the view is marked invisible; all children are invisible
 
3407
    return retval;
 
3408
  }
 
3409
 
 
3410
  nsRect bounds = aView->GetBounds();
 
3411
  nsPoint pos = aView->GetPosition();
 
3412
 
 
3413
  // -> to global coordinates (relative to aTopView)
 
3414
  bounds.x += aX;
 
3415
  bounds.y += aY;
 
3416
  pos.MoveBy(aX, aY);
 
3417
 
 
3418
  // does this view clip all its children?
 
3419
  PRBool isClipView =
 
3420
    (aView->GetClipChildrenToBounds(PR_FALSE)
 
3421
     && !(aView->GetViewFlags() & NS_VIEW_FLAG_CONTAINS_PLACEHOLDER))
 
3422
    || aView->GetClipChildrenToBounds(PR_TRUE);
 
3423
  PRBool overlap;
 
3424
  nsRect irect;
 
3425
    
 
3426
  // -> to refresh-frame coordinates (relative to aRealView)
 
3427
  bounds.x -= aOriginX;
 
3428
  bounds.y -= aOriginY;
 
3429
  if (aDamageRect) {
 
3430
    overlap = irect.IntersectRect(bounds, *aDamageRect);
 
3431
    if (isClipView) {
 
3432
      aDamageRect = &irect;
 
3433
    }
 
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.
 
3437
      overlap = PR_TRUE;
 
3438
    }
 
3439
  }
 
3440
  else
 
3441
    overlap = PR_TRUE;
 
3442
 
 
3443
  // -> to global coordinates (relative to aTopView)
 
3444
  bounds.x += aOriginX;
 
3445
  bounds.y += aOriginY;
 
3446
 
 
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.
 
3454
  //
 
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)) {
 
3461
    return PR_FALSE;
 
3462
  }
 
3463
 
 
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()) {
 
3469
    return PR_FALSE;
 
3470
  }
 
3471
 
 
3472
  PRBool anyChildren = aView->GetFirstChild() != nsnull;
 
3473
 
 
3474
  if (aEventProcessing
 
3475
      && (aView->GetViewFlags() & NS_VIEW_FLAG_DONT_CHECK_CHILDREN) != 0) {
 
3476
    anyChildren = PR_FALSE;
 
3477
  }
 
3478
 
 
3479
  PRBool hasFilter = aView->GetOpacity() != 1.0f;
 
3480
  if (hasFilter) {
 
3481
    // -> to refresh-frame coordinates (relative to aRealView)
 
3482
    bounds.x -= aOriginX;
 
3483
    bounds.y -= aOriginY;
 
3484
    
 
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);
 
3488
    if (retval)
 
3489
      return retval;
 
3490
    
 
3491
    // -> to global coordinates (relative to aTopView)
 
3492
    bounds.x += aOriginX;
 
3493
    bounds.y += aOriginY;
 
3494
  }
 
3495
 
 
3496
  if (anyChildren) {
 
3497
    if (isClipView) {
 
3498
      // -> to refresh-frame coordinates (relative to aRealView)
 
3499
      bounds.x -= aOriginX;
 
3500
      bounds.y -= aOriginY;
 
3501
 
 
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);
 
3505
 
 
3506
      if (retval)
 
3507
        return retval;
 
3508
 
 
3509
      // -> to global coordinates (relative to aTopView)
 
3510
      bounds.x += aOriginX;
 
3511
      bounds.y += aOriginY;
 
3512
    }
 
3513
 
 
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,
 
3522
                                 aEventProcessing);
 
3523
      if (createdNode != nsnull) {
 
3524
        EnsureZTreeNodeCreated(aView, aResult);
 
3525
        createdNode->mZSibling = aResult->mZChild;
 
3526
        aResult->mZChild = createdNode;
 
3527
      }
 
3528
 
 
3529
      if (retval)
 
3530
        break;
 
3531
    }
 
3532
  }
 
3533
 
 
3534
  if (!retval) {
 
3535
    if (overlap) {
 
3536
      // -> to refresh-frame coordinates (relative to aRealView)
 
3537
      bounds.x -= aOriginX;
 
3538
      bounds.y -= aOriginY;
 
3539
 
 
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)
 
3551
      }
 
3552
 
 
3553
      // -> to global coordinates (relative to aTopView)
 
3554
      bounds.x += aOriginX;
 
3555
      bounds.y += aOriginY;
 
3556
    } else {
 
3557
      if (aView->IsZPlaceholderView()) {
 
3558
        EnsureZTreeNodeCreated(aView, aResult);
 
3559
        nsVoidKey key(aView);
 
3560
        mMapPlaceholderViewToZTreeNode.Put(&key, aResult);
 
3561
      }
 
3562
    }
 
3563
  }
 
3564
 
 
3565
  if (anyChildren && isClipView) {
 
3566
    // -> to refresh-frame coordinates (relative to aRealView)
 
3567
    bounds.x -= aOriginX;
 
3568
    bounds.y -= aOriginY;
 
3569
 
 
3570
    if (AddToDisplayList(aView, aResult, bounds, bounds, PUSH_CLIP,
 
3571
                         aX - aOriginX, aY - aOriginY, PR_TRUE)) {
 
3572
      retval = PR_TRUE;
 
3573
    }
 
3574
    
 
3575
    // -> to global coordinates (relative to aTopView)
 
3576
    bounds.x += aOriginX;
 
3577
    bounds.y += aOriginY;
 
3578
  }
 
3579
 
 
3580
  if (hasFilter) {
 
3581
    // -> to refresh-frame coordinates (relative to aRealView)
 
3582
    bounds.x -= aOriginX;
 
3583
    bounds.y -= aOriginY;
 
3584
    
 
3585
    retval = AddToDisplayList(aView, aResult, bounds, bounds,
 
3586
                              PUSH_FILTER, aX - aOriginX, aY - aOriginY, PR_TRUE);
 
3587
    if (retval)
 
3588
      return retval;
 
3589
    
 
3590
    // -> to global coordinates (relative to aTopView)
 
3591
    bounds.x += aOriginX;
 
3592
    bounds.y += aOriginY;
 
3593
  }
 
3594
 
 
3595
  return retval;
 
3596
}
 
3597
 
 
3598
PRBool nsViewManager::AddToDisplayList(nsView *aView,
 
3599
                                       DisplayZTreeNode* &aParent, nsRect &aClipRect,
 
3600
                                       nsRect& aDirtyRect, PRUint32 aFlags,
 
3601
                                       nscoord aAbsX, nscoord aAbsY,
 
3602
                                       PRBool aAssumeIntersection)
 
3603
{
 
3604
  nsRect clipRect = aView->GetClippedRect();
 
3605
  PRBool clipped = clipRect != aView->GetDimensions();
 
3606
 
 
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;
 
3612
 
 
3613
  if (!clipped) {
 
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;
 
3618
  }
 
3619
 
 
3620
  PRBool overlap = clipRect.IntersectRect(clipRect, aDirtyRect);
 
3621
  if (!overlap && !aAssumeIntersection) {
 
3622
    return PR_FALSE;
 
3623
  }
 
3624
 
 
3625
  DisplayListElement2* element = new DisplayListElement2;
 
3626
  if (element == nsnull) {
 
3627
    return PR_TRUE;
 
3628
  }
 
3629
  DisplayZTreeNode* node = new DisplayZTreeNode;
 
3630
  if (nsnull == node) {
 
3631
    delete element;
 
3632
    return PR_TRUE;
 
3633
  }
 
3634
 
 
3635
  EnsureZTreeNodeCreated(aView, aParent);
 
3636
 
 
3637
  node->mDisplayElement = element;
 
3638
  node->mView = nsnull;
 
3639
  node->mZChild = nsnull;
 
3640
  node->mZSibling = aParent->mZChild;
 
3641
  aParent->mZChild = node;
 
3642
 
 
3643
  element->mView = aView;
 
3644
  element->mBounds = clipRect;
 
3645
  element->mAbsX = aClipRect.x;
 
3646
  element->mAbsY = aClipRect.y;
 
3647
  element->mFlags = aFlags;
 
3648
  if (clipped) { 
 
3649
    element->mFlags |= VIEW_CLIPPED;
 
3650
  }
 
3651
  
 
3652
  return PR_FALSE;
 
3653
}
 
3654
 
 
3655
/**
 
3656
   Walk the display list, looking for opaque views, and remove any views that are behind them
 
3657
   and totally occluded.
 
3658
 
 
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.
 
3664
*/
 
3665
void nsViewManager::OptimizeDisplayList(const nsVoidArray* aDisplayList, const nsRegion& aDamageRegion,
 
3666
                                        nsRect& aFinalTransparentRect,
 
3667
                                        nsRegion &aOpaqueRegion, PRBool aTreatUniformAsOpaque)
 
3668
{
 
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.
 
3672
  PRInt32 i;
 
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) {
 
3678
      ++filterDepth;
 
3679
    }
 
3680
    if (filterDepth > 0 && (element->mFlags & VIEW_RENDERED)) {
 
3681
      element->mFlags |= VIEW_TRANSLUCENT;
 
3682
    }
 
3683
    if (element->mFlags & POP_FILTER) {
 
3684
      --filterDepth;
 
3685
    }
 
3686
  }
 
3687
 
 
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) {
 
3691
      nsRegion tmpRgn;
 
3692
      tmpRgn.Sub(element->mBounds, aOpaqueRegion);
 
3693
      tmpRgn.And(tmpRgn, aDamageRegion);
 
3694
 
 
3695
      if (tmpRgn.IsEmpty()) {
 
3696
        element->mFlags &= ~VIEW_RENDERED;
 
3697
      } else {
 
3698
        element->mBounds = tmpRgn.GetBounds();
 
3699
 
 
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
 
3710
            // translucent.
 
3711
            || (element->mView->HasUniformBackground() && aTreatUniformAsOpaque
 
3712
                && !(element->mFlags & VIEW_TRANSLUCENT))) {
 
3713
          aOpaqueRegion.Or(aOpaqueRegion, element->mBounds);
 
3714
        }
 
3715
      }
 
3716
    }
 
3717
  }
 
3718
 
 
3719
  nsRegion tmpRgn;
 
3720
  tmpRgn.Sub(aDamageRegion, aOpaqueRegion);
 
3721
  aFinalTransparentRect = tmpRgn.GetBounds();
 
3722
}
 
3723
 
 
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)
 
3728
{   
 
3729
  aAnyRendered = PR_FALSE;
 
3730
 
 
3731
  while (aIndex < aDisplayList->Count()) {
 
3732
    DisplayListElement2* element =
 
3733
      NS_STATIC_CAST(DisplayListElement2*, aDisplayList->ElementAt(aIndex));
 
3734
    aIndex++;
 
3735
 
 
3736
    if (element->mFlags & VIEW_RENDERED) {
 
3737
      aAnyRendered = PR_TRUE;
 
3738
 
 
3739
      if (aHaveClip && (element->mFlags & VIEW_CLIPPED)) {
 
3740
        nsRect newClip;
 
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;
 
3745
        }
 
3746
      }
 
3747
    }
 
3748
 
 
3749
    if (element->mFlags & PUSH_CLIP) {
 
3750
      nsRect newClip;
 
3751
      if (aHaveClip) {
 
3752
        newClip.IntersectRect(aClipRect, element->mBounds);
 
3753
      } else {
 
3754
        newClip = element->mBounds;
 
3755
      }
 
3756
 
 
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!");
 
3762
 
 
3763
      if (anyRenderedViews) {
 
3764
        aAnyRendered = PR_TRUE;
 
3765
      }
 
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;
 
3771
      }
 
3772
    }
 
3773
 
 
3774
    if (element->mFlags & POP_CLIP) {
 
3775
      return;
 
3776
    }
 
3777
  }
 
3778
}
 
3779
 
 
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
 
3785
// 255).
 
3786
nsRect nsViewManager::OptimizeTranslucentRegions(
 
3787
  const nsVoidArray& aDisplayList, PRInt32* aIndex, nsRegion* aOpaqueRegion)
 
3788
{
 
3789
  nsRect r;
 
3790
  while (*aIndex < aDisplayList.Count()) {
 
3791
    DisplayListElement2* element =
 
3792
      NS_STATIC_CAST(DisplayListElement2*, aDisplayList.ElementAt(*aIndex));
 
3793
    (*aIndex)++;
 
3794
 
 
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
 
3798
      // region
 
3799
      if (!element->mView->IsTransparent() && aOpaqueRegion) {
 
3800
        aOpaqueRegion->Or(*aOpaqueRegion, element->mBounds);
 
3801
      }
 
3802
    }
 
3803
 
 
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,
 
3809
                                                    &opaqueRegion);
 
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!");
 
3814
 
 
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;
 
3819
      } else {
 
3820
        nsRegion tmpRegion;
 
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;
 
3825
        }
 
3826
      }
 
3827
 
 
3828
      // The filter doesn't paint opaquely, so don't add anything to aOpaqueRegion
 
3829
      r.UnionRect(r, element->mBounds);
 
3830
    }
 
3831
    if (element->mFlags & POP_FILTER) {
 
3832
      return r;
 
3833
    }
 
3834
  }
 
3835
 
 
3836
  return r;
 
3837
}
 
3838
 
 
3839
void nsViewManager::ShowDisplayList(const nsVoidArray* aDisplayList)
 
3840
{
 
3841
#ifdef NS_DEBUG
 
3842
  printf("### display list length=%d ###\n", aDisplayList->Count());
 
3843
 
 
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);
 
3848
  }
 
3849
#endif
 
3850
}
 
3851
 
 
3852
nsPoint nsViewManager::ComputeViewOffset(const nsView *aView)
 
3853
{
 
3854
  nsPoint origin(0, 0);
 
3855
  while (aView) {
 
3856
    origin += aView->GetPosition();
 
3857
    aView = aView->GetParent();
 
3858
  }
 
3859
  return origin;
 
3860
}
 
3861
 
 
3862
PRBool nsViewManager::DoesViewHaveNativeWidget(nsView* aView)
 
3863
{
 
3864
  if (aView->HasWidget())
 
3865
    return (nsnull != aView->GetWidget()->GetNativeData(NS_NATIVE_WIDGET));
 
3866
  return PR_FALSE;
 
3867
}
 
3868
 
 
3869
nsView* nsViewManager::GetWidgetView(nsView *aView)
 
3870
{
 
3871
  while (aView) {
 
3872
    if (aView->HasWidget())
 
3873
      return aView;
 
3874
    aView = aView->GetParent();
 
3875
  }
 
3876
  return nsnull;
 
3877
}
 
3878
 
 
3879
void nsViewManager::ViewToWidget(nsView *aView, nsView* aWidgetView, nsRect &aRect) const
 
3880
{
 
3881
  while (aView != aWidgetView) {
 
3882
    aView->ConvertToParentCoords(&aRect.x, &aRect.y);
 
3883
    aView = aView->GetParent();
 
3884
  }
 
3885
  
 
3886
  // intersect aRect with bounds of aWidgetView, to prevent generating any illegal rectangles.
 
3887
  nsRect bounds;
 
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;
 
3893
  
 
3894
  // finally, convert to device coordinates.
 
3895
  float t2p;
 
3896
  t2p = mContext->AppUnitsToDevUnits();
 
3897
  aRect.ScaleRoundOut(t2p);
 
3898
}
 
3899
 
 
3900
nsresult nsViewManager::GetVisibleRect(nsRect& aVisibleRect)
 
3901
{
 
3902
  nsresult rv = NS_OK;
 
3903
 
 
3904
  // Get the viewport scroller
 
3905
  nsIScrollableView* scrollingView;
 
3906
  GetRootScrollableView(&scrollingView);
 
3907
 
 
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);
 
3913
 
 
3914
    const nsView* clipView = NS_STATIC_CAST(const nsView*, clipViewI);
 
3915
    clipView->GetDimensions(aVisibleRect);
 
3916
 
 
3917
    scrollingView->GetScrollPosition(aVisibleRect.x, aVisibleRect.y);
 
3918
  } else {
 
3919
    rv = NS_ERROR_FAILURE;
 
3920
  }
 
3921
 
 
3922
  return rv;
 
3923
}
 
3924
 
 
3925
nsresult nsViewManager::GetAbsoluteRect(nsView *aView, const nsRect &aRect, 
 
3926
                                        nsRect& aAbsRect)
 
3927
{
 
3928
  nsIScrollableView* scrollingView = nsnull;
 
3929
  GetRootScrollableView(&scrollingView);
 
3930
  if (nsnull == scrollingView) { 
 
3931
    return NS_ERROR_FAILURE;
 
3932
  }
 
3933
 
 
3934
  nsIView* scrolledIView = nsnull;
 
3935
  scrollingView->GetScrolledView(scrolledIView);
 
3936
  
 
3937
  nsView* scrolledView = NS_STATIC_CAST(nsView*, scrolledIView);
 
3938
 
 
3939
  // Calculate the absolute coordinates of the aRect passed in.
 
3940
  // aRects values are relative to aView
 
3941
  aAbsRect = aRect;
 
3942
  nsView *parentView = aView;
 
3943
  while ((parentView != nsnull) && (parentView != scrolledView)) {
 
3944
    parentView->ConvertToParentCoords(&aAbsRect.x, &aAbsRect.y);
 
3945
    parentView = parentView->GetParent();
 
3946
  }
 
3947
 
 
3948
  if (parentView != scrolledView) {
 
3949
    return NS_ERROR_FAILURE;
 
3950
  }
 
3951
 
 
3952
  return NS_OK;
 
3953
}
 
3954
 
 
3955
 
 
3956
NS_IMETHODIMP nsViewManager::GetRectVisibility(nsIView *aView, 
 
3957
                                               const nsRect &aRect,
 
3958
                                               PRUint16 aMinTwips, 
 
3959
                                               nsRectVisibility *aRectVisibility)
 
3960
{
 
3961
  nsView* view = NS_STATIC_CAST(nsView*, aView);
 
3962
 
 
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
 
3965
 
 
3966
  *aRectVisibility = nsRectVisibility_kZeroAreaRect;
 
3967
  if (aRect.width == 0 || aRect.height == 0) {
 
3968
    return NS_OK;
 
3969
  }
 
3970
 
 
3971
  // is this view even visible?
 
3972
  if (view->GetVisibility() == nsViewVisibility_kHide) {
 
3973
    return NS_OK; 
 
3974
  }
 
3975
 
 
3976
  // Calculate the absolute coordinates for the visible rectangle   
 
3977
  nsRect visibleRect;
 
3978
  if (GetVisibleRect(visibleRect) == NS_ERROR_FAILURE) {
 
3979
    *aRectVisibility = nsRectVisibility_kVisible;
 
3980
    return NS_OK;
 
3981
  }
 
3982
 
 
3983
  // Calculate the absolute coordinates of the aRect passed in.
 
3984
  // aRects values are relative to aView
 
3985
  nsRect absRect;
 
3986
  if ((GetAbsoluteRect(view, aRect, absRect)) == NS_ERROR_FAILURE) {
 
3987
    *aRectVisibility = nsRectVisibility_kVisible;
 
3988
    return NS_OK;
 
3989
  }
 
3990
 
 
3991
  /*
 
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))
 
3998
   */
 
3999
 
 
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;
 
4012
  else
 
4013
    *aRectVisibility = nsRectVisibility_kVisible;
 
4014
 
 
4015
  return NS_OK;
 
4016
}
 
4017
 
 
4018
 
 
4019
NS_IMETHODIMP
 
4020
nsViewManager::IsCachingWidgetChanges(PRBool* aCaching)
 
4021
{
 
4022
#ifdef CACHE_WIDGET_CHANGES
 
4023
  *aCaching = (mCachingWidgetChanges > 0);
 
4024
#else
 
4025
  *aCaching = PR_FALSE;
 
4026
#endif
 
4027
 
 
4028
  return NS_OK;
 
4029
}
 
4030
 
 
4031
NS_IMETHODIMP
 
4032
nsViewManager::CacheWidgetChanges(PRBool aCache)
 
4033
{
 
4034
 
 
4035
#ifdef CACHE_WIDGET_CHANGES
 
4036
  if (aCache == PR_TRUE)
 
4037
    mCachingWidgetChanges++;
 
4038
  else
 
4039
    mCachingWidgetChanges--;
 
4040
 
 
4041
  NS_ASSERTION(mCachingWidgetChanges >= 0, "One too many decrements");
 
4042
 
 
4043
  // if we turned it off. Then move and size all the widgets.
 
4044
  if (mCachingWidgetChanges == 0)
 
4045
    ProcessWidgetChanges(mRootView);
 
4046
#endif
 
4047
 
 
4048
  return NS_OK;
 
4049
}
 
4050
 
 
4051
NS_IMETHODIMP
 
4052
nsViewManager::AllowDoubleBuffering(PRBool aDoubleBuffer)
 
4053
{
 
4054
  mAllowDoubleBuffering = aDoubleBuffer;
 
4055
  return NS_OK;
 
4056
}
 
4057
 
 
4058
NS_IMETHODIMP
 
4059
nsViewManager::IsPainting(PRBool& aIsPainting)
 
4060
{
 
4061
  aIsPainting = mPainting;
 
4062
  return NS_OK;
 
4063
}
 
4064
 
 
4065
NS_IMETHODIMP
 
4066
nsViewManager::FlushPendingInvalidates()
 
4067
{
 
4068
  if (mHasPendingInvalidates) {
 
4069
    ProcessPendingUpdates(mRootView);
 
4070
    mHasPendingInvalidates = PR_FALSE;
 
4071
  }
 
4072
  return NS_OK;
 
4073
}
 
4074
 
 
4075
void
 
4076
nsViewManager::ProcessInvalidateEvent()
 
4077
{
 
4078
  FlushPendingInvalidates();
 
4079
  mInvalidateEventQueue = nsnull;
 
4080
}
 
4081
 
 
4082
nsresult
 
4083
nsViewManager::ProcessWidgetChanges(nsView* aView)
 
4084
{
 
4085
  //printf("---------Begin Sync----------\n");
 
4086
  nsresult rv = aView->SynchWidgetSizePosition();
 
4087
  if (NS_FAILED(rv))
 
4088
    return rv;
 
4089
 
 
4090
  nsView *child = aView->GetFirstChild();
 
4091
  while (nsnull != child) {
 
4092
    if (child->GetViewManager() == this) {
 
4093
      rv = ProcessWidgetChanges(child);
 
4094
      if (NS_FAILED(rv))
 
4095
        return rv;
 
4096
    }
 
4097
 
 
4098
    child = child->GetNextSibling();
 
4099
  }
 
4100
 
 
4101
  //printf("---------End Sync----------\n");
 
4102
 
 
4103
  return NS_OK;
 
4104
}
 
4105
 
 
4106
NS_IMETHODIMP
 
4107
nsViewManager::SetDefaultBackgroundColor(nscolor aColor)
 
4108
{
 
4109
  mDefaultBackgroundColor = aColor;
 
4110
  return NS_OK;
 
4111
}
 
4112
 
 
4113
NS_IMETHODIMP
 
4114
nsViewManager::GetDefaultBackgroundColor(nscolor* aColor)
 
4115
{
 
4116
  *aColor = mDefaultBackgroundColor;
 
4117
  return NS_OK;
 
4118
}
 
4119
 
 
4120
 
 
4121
NS_IMETHODIMP
 
4122
nsViewManager::GetLastUserEventTime(PRUint32& aTime)
 
4123
{
 
4124
  aTime = gLastUserEventTime;
 
4125
  return NS_OK;
 
4126
}