|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsViewManager_h___ |
|
7 #define nsViewManager_h___ |
|
8 |
|
9 #include "nscore.h" |
|
10 #include "nsView.h" |
|
11 #include "nsCOMPtr.h" |
|
12 #include "nsCRT.h" |
|
13 #include "nsVoidArray.h" |
|
14 #include "nsDeviceContext.h" |
|
15 #include "nsTArray.h" |
|
16 #include "mozilla/EventForwards.h" |
|
17 |
|
18 class nsIWidget; |
|
19 struct nsRect; |
|
20 class nsRegion; |
|
21 class nsDeviceContext; |
|
22 class nsIPresShell; |
|
23 |
|
24 class nsViewManager MOZ_FINAL |
|
25 { |
|
26 public: |
|
27 friend class nsView; |
|
28 |
|
29 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW |
|
30 |
|
31 NS_INLINE_DECL_REFCOUNTING(nsViewManager) |
|
32 |
|
33 nsViewManager(); |
|
34 ~nsViewManager(); |
|
35 |
|
36 /** |
|
37 * Initialize the ViewManager |
|
38 * Note: this instance does not hold a reference to the presshell |
|
39 * because it holds a reference to this instance. |
|
40 * @result The result of the initialization, NS_OK if no errors |
|
41 */ |
|
42 nsresult Init(nsDeviceContext* aContext); |
|
43 |
|
44 /** |
|
45 * Create an ordinary view |
|
46 * @param aBounds initial bounds for view |
|
47 * XXX We should eliminate this parameter; you can set the bounds after CreateView |
|
48 * @param aParent intended parent for view. this is not actually set in the |
|
49 * nsView through this method. it is only used by the initialization |
|
50 * code to walk up the view tree, if necessary, to find resources. |
|
51 * XXX We should eliminate this parameter! |
|
52 * @param aVisibilityFlag initial visibility state of view |
|
53 * XXX We should eliminate this parameter; you can set it after CreateView |
|
54 * @result The new view. Never null. |
|
55 */ |
|
56 nsView* CreateView(const nsRect& aBounds, |
|
57 nsView* aParent, |
|
58 nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow); |
|
59 |
|
60 /** |
|
61 * Get the root of the view tree. |
|
62 * @result the root view |
|
63 */ |
|
64 nsView* GetRootView() { return mRootView; } |
|
65 |
|
66 /** |
|
67 * Set the root of the view tree. Does not destroy the current root view. |
|
68 * aView may have a parent view managed by a different view manager. |
|
69 * aView may have a widget (anything but printing) or may not (printing). |
|
70 * @param aView view to set as root |
|
71 */ |
|
72 void SetRootView(nsView *aView); |
|
73 |
|
74 /** |
|
75 * Get the dimensions of the root window. The dimensions are in |
|
76 * twips |
|
77 * @param aWidth out parameter for width of window in twips |
|
78 * @param aHeight out parameter for height of window in twips |
|
79 */ |
|
80 void GetWindowDimensions(nscoord *aWidth, nscoord *aHeight); |
|
81 |
|
82 /** |
|
83 * Set the dimensions of the root window. |
|
84 * Called if the root window is resized. The dimensions are in |
|
85 * twips |
|
86 * @param aWidth of window in twips |
|
87 * @param aHeight of window in twips |
|
88 */ |
|
89 void SetWindowDimensions(nscoord aWidth, nscoord aHeight); |
|
90 |
|
91 /** |
|
92 * Do any resizes that are pending. |
|
93 */ |
|
94 void FlushDelayedResize(bool aDoReflow); |
|
95 |
|
96 /** |
|
97 * Called to inform the view manager that the entire area of a view |
|
98 * is dirty and needs to be redrawn. |
|
99 * @param aView view to paint. should be root view |
|
100 */ |
|
101 void InvalidateView(nsView *aView); |
|
102 |
|
103 /** |
|
104 * Called to inform the view manager that some portion of a view is dirty and |
|
105 * needs to be redrawn. The rect passed in should be in the view's coordinate |
|
106 * space. Does not check for paint suppression. |
|
107 * @param aView view to paint. should be root view |
|
108 * @param rect rect to mark as damaged |
|
109 */ |
|
110 void InvalidateViewNoSuppression(nsView *aView, const nsRect &aRect); |
|
111 |
|
112 /** |
|
113 * Called to inform the view manager that it should invalidate all views. |
|
114 */ |
|
115 void InvalidateAllViews(); |
|
116 |
|
117 /** |
|
118 * Called to dispatch an event to the appropriate view. Often called |
|
119 * as a result of receiving a mouse or keyboard event from the widget |
|
120 * event system. |
|
121 * @param aEvent event to dispatch |
|
122 * @param aViewTarget dispatch the event to this view |
|
123 * @param aStatus event handling status |
|
124 */ |
|
125 void DispatchEvent(mozilla::WidgetGUIEvent *aEvent, |
|
126 nsView* aViewTarget, |
|
127 nsEventStatus* aStatus); |
|
128 |
|
129 /** |
|
130 * Given a parent view, insert another view as its child. |
|
131 * aSibling and aAbove control the "document order" for the insertion. |
|
132 * If aSibling is null, the view is inserted at the end of the document order |
|
133 * if aAfter is true, otherwise it is inserted at the beginning. |
|
134 * If aSibling is non-null, then if aAfter is true, the view is inserted |
|
135 * after the sibling in document order (appearing above the sibling unless |
|
136 * overriden by z-order). |
|
137 * If it is false, the view is inserted before the sibling. |
|
138 * The view manager generates the appopriate dirty regions. |
|
139 * @param aParent parent view |
|
140 * @param aChild child view |
|
141 * @param aSibling sibling view |
|
142 * @param aAfter after or before in the document order |
|
143 */ |
|
144 void InsertChild(nsView *aParent, nsView *aChild, nsView *aSibling, |
|
145 bool aAfter); |
|
146 |
|
147 void InsertChild(nsView *aParent, nsView *aChild, int32_t aZIndex); |
|
148 |
|
149 /** |
|
150 * Remove a specific child view from its parent. This will NOT remove its placeholder |
|
151 * if there is one. |
|
152 * The view manager generates the appropriate dirty regions. |
|
153 * @param aParent parent view |
|
154 * @param aChild child view |
|
155 */ |
|
156 void RemoveChild(nsView *aChild); |
|
157 |
|
158 /** |
|
159 * Move a view to the specified position, provided in parent coordinates. |
|
160 * The new position is the (0, 0) origin for the view's coordinate system. |
|
161 * The view's bounds may extend above or to the left of this point. |
|
162 * The view manager generates the appropriate dirty regions. |
|
163 * @param aView view to move |
|
164 * @param aX x value for new view position |
|
165 * @param aY y value for new view position |
|
166 */ |
|
167 void MoveViewTo(nsView *aView, nscoord aX, nscoord aY); |
|
168 |
|
169 /** |
|
170 * Resize a view. In addition to setting the width and height, you can |
|
171 * set the x and y of its bounds relative to its position. Negative x and y |
|
172 * will let the view extend above and to the left of the (0,0) point in its |
|
173 * coordinate system. |
|
174 * The view manager generates the appropriate dirty regions. |
|
175 * @param aView view to move |
|
176 * @param the new bounds relative to the current position |
|
177 * @param RepaintExposedAreaOnly |
|
178 * if true Repaint only the expanded or contracted region, |
|
179 * if false Repaint the union of the old and new rectangles. |
|
180 */ |
|
181 void ResizeView(nsView *aView, const nsRect &aRect, |
|
182 bool aRepaintExposedAreaOnly = false); |
|
183 |
|
184 /** |
|
185 * Set the visibility of a view. Hidden views have the effect of hiding |
|
186 * their descendants as well. This does not affect painting, so layout |
|
187 * is responsible for ensuring that content in hidden views is not |
|
188 * painted nor handling events. It does affect the visibility of widgets; |
|
189 * if a view is hidden, descendant views with widgets have their widgets |
|
190 * hidden. |
|
191 * The view manager generates the appropriate dirty regions. |
|
192 * @param aView view to change visibility state of |
|
193 * @param visible new visibility state |
|
194 */ |
|
195 void SetViewVisibility(nsView *aView, nsViewVisibility aVisible); |
|
196 |
|
197 /** |
|
198 * Set the z-index of a view. Positive z-indices mean that a view |
|
199 * is above its parent in z-order. Negative z-indices mean that a |
|
200 * view is below its parent. |
|
201 * The view manager generates the appropriate dirty regions. |
|
202 * @param aAutoZIndex indicate that the z-index of a view is "auto". An "auto" z-index |
|
203 * means that the view does not define a new stacking context, |
|
204 * which means that the z-indicies of the view's children are |
|
205 * relative to the view's siblings. |
|
206 * @param aView view to change z depth of |
|
207 * @param aZindex explicit z depth |
|
208 */ |
|
209 void SetViewZIndex(nsView *aView, bool aAutoZIndex, int32_t aZindex); |
|
210 |
|
211 /** |
|
212 * Set whether the view "floats" above all other views, |
|
213 * which tells the compositor not to consider higher views in |
|
214 * the view hierarchy that would geometrically intersect with |
|
215 * this view. This is a hack, but it fixes some problems with |
|
216 * views that need to be drawn in front of all other views. |
|
217 */ |
|
218 void SetViewFloating(nsView *aView, bool aFloatingView); |
|
219 |
|
220 /** |
|
221 * Set the presshell associated with this manager |
|
222 * @param aPresShell - new presshell |
|
223 */ |
|
224 void SetPresShell(nsIPresShell *aPresShell) { mPresShell = aPresShell; } |
|
225 |
|
226 /** |
|
227 * Get the pres shell associated with this manager |
|
228 */ |
|
229 nsIPresShell* GetPresShell() { return mPresShell; } |
|
230 |
|
231 /** |
|
232 * Get the device context associated with this manager |
|
233 */ |
|
234 nsDeviceContext* GetDeviceContext() const |
|
235 { |
|
236 return mContext; |
|
237 } |
|
238 |
|
239 /** |
|
240 * A stack class for disallowing changes that would enter painting. For |
|
241 * example, popup widgets shouldn't be resized during reflow, since doing so |
|
242 * might cause synchronous painting inside reflow which is forbidden. |
|
243 * While refresh is disabled, widget geometry changes are deferred and will |
|
244 * be handled later, either from the refresh driver or from an NS_WILL_PAINT |
|
245 * event. |
|
246 * We don't want to defer widget geometry changes all the time. Resizing a |
|
247 * popup from script doesn't need to be deferred, for example, especially |
|
248 * since popup widget geometry is observable from script and expected to |
|
249 * update synchronously. |
|
250 */ |
|
251 class MOZ_STACK_CLASS AutoDisableRefresh { |
|
252 public: |
|
253 AutoDisableRefresh(nsViewManager* aVM) { |
|
254 if (aVM) { |
|
255 mRootVM = aVM->IncrementDisableRefreshCount(); |
|
256 } |
|
257 } |
|
258 ~AutoDisableRefresh() { |
|
259 if (mRootVM) { |
|
260 mRootVM->DecrementDisableRefreshCount(); |
|
261 } |
|
262 } |
|
263 private: |
|
264 AutoDisableRefresh(const AutoDisableRefresh& aOther); |
|
265 const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther); |
|
266 |
|
267 nsRefPtr<nsViewManager> mRootVM; |
|
268 }; |
|
269 |
|
270 private: |
|
271 friend class AutoDisableRefresh; |
|
272 |
|
273 nsViewManager* IncrementDisableRefreshCount(); |
|
274 void DecrementDisableRefreshCount(); |
|
275 |
|
276 public: |
|
277 /** |
|
278 * Retrieve the widget at the root of the nearest enclosing |
|
279 * view manager whose root view has a widget. |
|
280 */ |
|
281 void GetRootWidget(nsIWidget **aWidget); |
|
282 |
|
283 /** |
|
284 * Indicate whether the viewmanager is currently painting |
|
285 * |
|
286 * @param aPainting true if the viewmanager is painting |
|
287 * false otherwise |
|
288 */ |
|
289 void IsPainting(bool& aIsPainting); |
|
290 |
|
291 /** |
|
292 * Retrieve the time of the last user event. User events |
|
293 * include mouse and keyboard events. The viewmanager |
|
294 * saves the time of the last user event. |
|
295 * |
|
296 * @param aTime Last user event time in microseconds |
|
297 */ |
|
298 void GetLastUserEventTime(uint32_t& aTime); |
|
299 |
|
300 /** |
|
301 * Find the nearest display root view for the view aView. This is the view for |
|
302 * the nearest enclosing popup or the root view for the root document. |
|
303 */ |
|
304 static nsView* GetDisplayRootFor(nsView* aView); |
|
305 |
|
306 /** |
|
307 * Flush the accumulated dirty region to the widget and update widget |
|
308 * geometry. |
|
309 */ |
|
310 void ProcessPendingUpdates(); |
|
311 |
|
312 /** |
|
313 * Just update widget geometry without flushing the dirty region |
|
314 */ |
|
315 void UpdateWidgetGeometry(); |
|
316 |
|
317 int32_t AppUnitsPerDevPixel() const |
|
318 { |
|
319 return mContext->AppUnitsPerDevPixel(); |
|
320 } |
|
321 |
|
322 private: |
|
323 static uint32_t gLastUserEventTime; |
|
324 |
|
325 /* Update the cached RootViewManager pointer on this view manager. */ |
|
326 void InvalidateHierarchy(); |
|
327 void FlushPendingInvalidates(); |
|
328 |
|
329 void ProcessPendingUpdatesForView(nsView *aView, |
|
330 bool aFlushDirtyRegion = true); |
|
331 void ProcessPendingUpdatesRecurse(nsView* aView, |
|
332 nsTArray<nsCOMPtr<nsIWidget> >& aWidgets); |
|
333 void ProcessPendingUpdatesPaint(nsIWidget* aWidget); |
|
334 |
|
335 void FlushDirtyRegionToWidget(nsView* aView); |
|
336 /** |
|
337 * Call WillPaint() on all view observers under this vm root. |
|
338 */ |
|
339 void CallWillPaintOnObservers(); |
|
340 void ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget); |
|
341 void ReparentWidgets(nsView* aView, nsView *aParent); |
|
342 void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion); |
|
343 |
|
344 void InvalidateViews(nsView *aView); |
|
345 |
|
346 // aView is the view for aWidget and aRegion is relative to aWidget. |
|
347 void Refresh(nsView *aView, const nsIntRegion& aRegion); |
|
348 |
|
349 // Utilities |
|
350 |
|
351 bool IsViewInserted(nsView *aView); |
|
352 |
|
353 /** |
|
354 * Intersects aRect with aView's bounds and then transforms it from aView's |
|
355 * coordinate system to the coordinate system of the widget attached to |
|
356 * aView. |
|
357 */ |
|
358 nsIntRect ViewToWidget(nsView *aView, const nsRect &aRect) const; |
|
359 |
|
360 void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight); |
|
361 |
|
362 bool IsPainting() const { |
|
363 return RootViewManager()->mPainting; |
|
364 } |
|
365 |
|
366 void SetPainting(bool aPainting) { |
|
367 RootViewManager()->mPainting = aPainting; |
|
368 } |
|
369 |
|
370 void InvalidateView(nsView *aView, const nsRect &aRect); |
|
371 |
|
372 nsViewManager* RootViewManager() const { return mRootViewManager; } |
|
373 bool IsRootVM() const { return this == RootViewManager(); } |
|
374 |
|
375 // Whether synchronous painting is allowed at the moment. For example, |
|
376 // widget geometry changes can cause synchronous painting, so they need to |
|
377 // be deferred while refresh is disabled. |
|
378 bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; } |
|
379 |
|
380 void WillPaintWindow(nsIWidget* aWidget); |
|
381 bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion); |
|
382 void DidPaintWindow(); |
|
383 |
|
384 // Call this when you need to let the viewmanager know that it now has |
|
385 // pending updates. |
|
386 void PostPendingUpdate(); |
|
387 |
|
388 nsRefPtr<nsDeviceContext> mContext; |
|
389 nsIPresShell *mPresShell; |
|
390 |
|
391 // The size for a resize that we delayed until the root view becomes |
|
392 // visible again. |
|
393 nsSize mDelayedResize; |
|
394 |
|
395 nsView *mRootView; |
|
396 // mRootViewManager is a strong ref unless it equals |this|. It's |
|
397 // never null (if we have no ancestors, it will be |this|). |
|
398 nsViewManager *mRootViewManager; |
|
399 |
|
400 // The following members should not be accessed directly except by |
|
401 // the root view manager. Some have accessor functions to enforce |
|
402 // this, as noted. |
|
403 |
|
404 int32_t mRefreshDisableCount; |
|
405 // Use IsPainting() and SetPainting() to access mPainting. |
|
406 bool mPainting; |
|
407 bool mRecursiveRefreshPending; |
|
408 bool mHasPendingWidgetGeometryChanges; |
|
409 bool mInScroll; |
|
410 |
|
411 //from here to public should be static and locked... MMP |
|
412 static int32_t mVMCount; //number of viewmanagers |
|
413 |
|
414 //list of view managers |
|
415 static nsVoidArray *gViewManagers; |
|
416 }; |
|
417 |
|
418 /** |
|
419 Invalidation model: |
|
420 |
|
421 1) Callers call into the view manager and ask it to invalidate a view. |
|
422 |
|
423 2) The view manager finds the "right" widget for the view, henceforth called |
|
424 the root widget. |
|
425 |
|
426 3) The view manager traverses descendants of the root widget and for each |
|
427 one that needs invalidation stores the rect to invalidate on the widget's |
|
428 view (batching). |
|
429 |
|
430 4) The dirty region is flushed to the right widget when |
|
431 ProcessPendingUpdates is called from the RefreshDriver. |
|
432 |
|
433 It's important to note that widgets associated to views outside this view |
|
434 manager can end up being invalidated during step 3. Therefore, the end of a |
|
435 view update batch really needs to traverse the entire view tree, to ensure |
|
436 that those invalidates happen. |
|
437 |
|
438 To cope with this, invalidation processing and should only happen on the |
|
439 root viewmanager. |
|
440 */ |
|
441 |
|
442 #endif // nsViewManager_h___ |