Line data Source code
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 "nsTArray.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 final
25 : {
26 : ~nsViewManager();
27 : public:
28 : friend class nsView;
29 :
30 : typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
31 : typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
32 :
33 708 : NS_INLINE_DECL_REFCOUNTING(nsViewManager)
34 :
35 : nsViewManager();
36 :
37 : /**
38 : * Initialize the ViewManager
39 : * Note: this instance does not hold a reference to the presshell
40 : * because it holds a reference to this instance.
41 : * @result The result of the initialization, NS_OK if no errors
42 : */
43 : nsresult Init(nsDeviceContext* aContext);
44 :
45 : /**
46 : * Create an ordinary view
47 : * @param aBounds initial bounds for view
48 : * XXX We should eliminate this parameter; you can set the bounds after CreateView
49 : * @param aParent intended parent for view. this is not actually set in the
50 : * nsView through this method. it is only used by the initialization
51 : * code to walk up the view tree, if necessary, to find resources.
52 : * XXX We should eliminate this parameter!
53 : * @param aVisibilityFlag initial visibility state of view
54 : * XXX We should eliminate this parameter; you can set it after CreateView
55 : * @result The new view. Never null.
56 : */
57 : nsView* CreateView(const nsRect& aBounds,
58 : nsView* aParent,
59 : nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow);
60 :
61 : /**
62 : * Get the root of the view tree.
63 : * @result the root view
64 : */
65 16983 : nsView* GetRootView() { return mRootView; }
66 :
67 : /**
68 : * Set the root of the view tree. Does not destroy the current root view.
69 : * aView may have a parent view managed by a different view manager.
70 : * aView may have a widget (anything but printing) or may not (printing).
71 : * @param aView view to set as root
72 : */
73 : void SetRootView(nsView *aView);
74 :
75 : /**
76 : * Get the dimensions of the root window. The dimensions are in
77 : * twips
78 : * @param aWidth out parameter for width of window in twips
79 : * @param aHeight out parameter for height of window in twips
80 : */
81 : void GetWindowDimensions(nscoord *aWidth, nscoord *aHeight);
82 :
83 : /**
84 : * Set the dimensions of the root window.
85 : * Called if the root window is resized. The dimensions are in
86 : * twips
87 : * @param aWidth of window in twips
88 : * @param aHeight of window in twips
89 : */
90 : void SetWindowDimensions(nscoord aWidth, nscoord aHeight,
91 : bool aDelayResize = false);
92 :
93 : /**
94 : * Do any resizes that are pending.
95 : */
96 : void FlushDelayedResize(bool aDoReflow);
97 :
98 : /**
99 : * Called to inform the view manager that the entire area of a view
100 : * is dirty and needs to be redrawn.
101 : * @param aView view to paint. should be root view
102 : */
103 : void InvalidateView(nsView *aView);
104 :
105 : /**
106 : * Called to inform the view manager that some portion of a view is dirty and
107 : * needs to be redrawn. The rect passed in should be in the view's coordinate
108 : * space. Does not check for paint suppression.
109 : * @param aView view to paint. should be root view
110 : * @param rect rect to mark as damaged
111 : */
112 : void InvalidateViewNoSuppression(nsView *aView, const nsRect &aRect);
113 :
114 : /**
115 : * Called to inform the view manager that it should invalidate all views.
116 : */
117 : void InvalidateAllViews();
118 :
119 : /**
120 : * Called to dispatch an event to the appropriate view. Often called
121 : * as a result of receiving a mouse or keyboard event from the widget
122 : * event system.
123 : * @param aEvent event to dispatch
124 : * @param aViewTarget dispatch the event to this view
125 : * @param aStatus event handling status
126 : */
127 : void DispatchEvent(mozilla::WidgetGUIEvent *aEvent,
128 : nsView* aViewTarget,
129 : nsEventStatus* aStatus);
130 :
131 : /**
132 : * Given a parent view, insert another view as its child.
133 : * aSibling and aAbove control the "document order" for the insertion.
134 : * If aSibling is null, the view is inserted at the end of the document order
135 : * if aAfter is true, otherwise it is inserted at the beginning.
136 : * If aSibling is non-null, then if aAfter is true, the view is inserted
137 : * after the sibling in document order (appearing above the sibling unless
138 : * overriden by z-order).
139 : * If it is false, the view is inserted before the sibling.
140 : * The view manager generates the appopriate dirty regions.
141 : * @param aParent parent view
142 : * @param aChild child view
143 : * @param aSibling sibling view
144 : * @param aAfter after or before in the document order
145 : */
146 : void InsertChild(nsView *aParent, nsView *aChild, nsView *aSibling,
147 : bool aAfter);
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 32 : void SetPresShell(nsIPresShell *aPresShell) { mPresShell = aPresShell; }
225 :
226 : /**
227 : * Get the pres shell associated with this manager
228 : */
229 110 : nsIPresShell* GetPresShell() { return mPresShell; }
230 :
231 : /**
232 : * Get the device context associated with this manager
233 : */
234 4 : nsDeviceContext* GetDeviceContext() const
235 : {
236 4 : 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 68 : explicit AutoDisableRefresh(nsViewManager* aVM) {
254 68 : if (aVM) {
255 68 : mRootVM = aVM->IncrementDisableRefreshCount();
256 : }
257 68 : }
258 136 : ~AutoDisableRefresh() {
259 68 : if (mRootVM) {
260 68 : mRootVM->DecrementDisableRefreshCount();
261 : }
262 68 : }
263 : private:
264 : AutoDisableRefresh(const AutoDisableRefresh& aOther);
265 : const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther);
266 :
267 : RefPtr<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 1863 : int32_t AppUnitsPerDevPixel() const
318 : {
319 1863 : return mContext->AppUnitsPerDevPixel();
320 : }
321 :
322 0 : void SetPrintRelated() { mPrintRelated = true; }
323 15 : bool GetPrintRelated() { return mPrintRelated; }
324 :
325 : private:
326 : static uint32_t gLastUserEventTime;
327 :
328 : /* Update the cached RootViewManager pointer on this view manager. */
329 : void InvalidateHierarchy();
330 : void FlushPendingInvalidates();
331 :
332 : void ProcessPendingUpdatesForView(nsView *aView,
333 : bool aFlushDirtyRegion = true);
334 : void ProcessPendingUpdatesRecurse(nsView* aView,
335 : AutoTArray<nsCOMPtr<nsIWidget>, 1>& aWidgets);
336 : void ProcessPendingUpdatesPaint(nsIWidget* aWidget);
337 :
338 : void FlushDirtyRegionToWidget(nsView* aView);
339 : /**
340 : * Call WillPaint() on all view observers under this vm root.
341 : */
342 : void CallWillPaintOnObservers();
343 : void ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget);
344 : void ReparentWidgets(nsView* aView, nsView *aParent);
345 : void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
346 :
347 : void InvalidateViews(nsView *aView);
348 :
349 : // aView is the view for aWidget and aRegion is relative to aWidget.
350 : void Refresh(nsView* aView, const LayoutDeviceIntRegion& aRegion);
351 :
352 : // Utilities
353 :
354 : bool IsViewInserted(nsView *aView);
355 :
356 : /**
357 : * Intersects aRect with aView's bounds and then transforms it from aView's
358 : * coordinate system to the coordinate system of the widget attached to
359 : * aView.
360 : */
361 : LayoutDeviceIntRect ViewToWidget(nsView* aView, const nsRect& aRect) const;
362 :
363 : void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight);
364 : bool ShouldDelayResize() const;
365 :
366 181 : bool IsPainting() const {
367 181 : return RootViewManager()->mPainting;
368 : }
369 :
370 72 : void SetPainting(bool aPainting) {
371 72 : RootViewManager()->mPainting = aPainting;
372 72 : }
373 :
374 : void InvalidateView(nsView *aView, const nsRect &aRect);
375 :
376 1234 : nsViewManager* RootViewManager() const { return mRootViewManager; }
377 338 : bool IsRootVM() const { return this == RootViewManager(); }
378 :
379 : // Whether synchronous painting is allowed at the moment. For example,
380 : // widget geometry changes can cause synchronous painting, so they need to
381 : // be deferred while refresh is disabled.
382 1 : bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; }
383 :
384 : void WillPaintWindow(nsIWidget* aWidget);
385 : bool PaintWindow(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion);
386 : void DidPaintWindow();
387 :
388 : // Call this when you need to let the viewmanager know that it now has
389 : // pending updates.
390 : void PostPendingUpdate();
391 :
392 : RefPtr<nsDeviceContext> mContext;
393 : nsIPresShell *mPresShell;
394 :
395 : // The size for a resize that we delayed until the root view becomes
396 : // visible again.
397 : nsSize mDelayedResize;
398 :
399 : nsView *mRootView;
400 : // mRootViewManager is a strong ref unless it equals |this|. It's
401 : // never null (if we have no ancestors, it will be |this|).
402 : nsViewManager *mRootViewManager;
403 :
404 : // The following members should not be accessed directly except by
405 : // the root view manager. Some have accessor functions to enforce
406 : // this, as noted.
407 :
408 : int32_t mRefreshDisableCount;
409 : // Use IsPainting() and SetPainting() to access mPainting.
410 : bool mPainting;
411 : bool mRecursiveRefreshPending;
412 : bool mHasPendingWidgetGeometryChanges;
413 : bool mPrintRelated;
414 :
415 : //from here to public should be static and locked... MMP
416 :
417 : //list of view managers
418 : static nsTArray<nsViewManager*> *gViewManagers;
419 : };
420 :
421 : /**
422 : Invalidation model:
423 :
424 : 1) Callers call into the view manager and ask it to invalidate a view.
425 :
426 : 2) The view manager finds the "right" widget for the view, henceforth called
427 : the root widget.
428 :
429 : 3) The view manager traverses descendants of the root widget and for each
430 : one that needs invalidation stores the rect to invalidate on the widget's
431 : view (batching).
432 :
433 : 4) The dirty region is flushed to the right widget when
434 : ProcessPendingUpdates is called from the RefreshDriver.
435 :
436 : It's important to note that widgets associated to views outside this view
437 : manager can end up being invalidated during step 3. Therefore, the end of a
438 : view update batch really needs to traverse the entire view tree, to ensure
439 : that those invalidates happen.
440 :
441 : To cope with this, invalidation processing and should only happen on the
442 : root viewmanager.
443 : */
444 :
445 : #endif // nsViewManager_h___
|