diff options
Diffstat (limited to '')
-rw-r--r-- | view/nsViewManager.h | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/view/nsViewManager.h b/view/nsViewManager.h new file mode 100644 index 0000000000..332d1c2f9a --- /dev/null +++ b/view/nsViewManager.h @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsViewManager_h___ +#define nsViewManager_h___ + +#include "nscore.h" +#include "nsView.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsTArray.h" +#include "nsDeviceContext.h" +#include "nsTArray.h" +#include "mozilla/Attributes.h" +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/EventForwards.h" + +class nsIWidget; +struct nsRect; +class nsRegion; +class nsDeviceContext; + +namespace mozilla { +class PresShell; +} // namespace mozilla + +class nsViewManager final { + ~nsViewManager(); + + public: + friend class nsView; + + typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; + typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion; + + NS_INLINE_DECL_REFCOUNTING(nsViewManager) + + nsViewManager(); + + /** + * Initialize the ViewManager + * Note: this instance does not hold a reference to the presshell + * because it holds a reference to this instance. + * @result The result of the initialization, NS_OK if no errors + */ + nsresult Init(nsDeviceContext* aContext); + + /** + * Create an ordinary view + * @param aBounds initial bounds for view + * XXX We should eliminate this parameter; you can set the bounds + * after CreateView + * @param aParent intended parent for view. this is not actually set in the + * nsView through this method. it is only used by the initialization + * code to walk up the view tree, if necessary, to find resources. + * XXX We should eliminate this parameter! + * @param aVisibilityFlag initial visibility state of view + * XXX We should eliminate this parameter; you can set it after + * CreateView + * @result The new view. Never null. + */ + nsView* CreateView(const nsRect& aBounds, nsView* aParent, + ViewVisibility aVisibilityFlag = ViewVisibility::Show); + + /** + * Get the root of the view tree. + * @result the root view + */ + nsView* GetRootView() { return mRootView; } + + /** + * Set the root of the view tree. Does not destroy the current root view. + * aView may have a parent view managed by a different view manager. + * aView may have a widget (anything but printing) or may not (printing). + * @param aView view to set as root + */ + void SetRootView(nsView* aView); + + /** + * Get the dimensions of the root window. The dimensions are in + * twips + * @param aWidth out parameter for width of window in twips + * @param aHeight out parameter for height of window in twips + */ + void GetWindowDimensions(nscoord* aWidth, nscoord* aHeight); + + /** + * Set the dimensions of the root window. + * Called if the root window is resized. The dimensions are in + * twips + * @param aWidth of window in twips + * @param aHeight of window in twips + */ + void SetWindowDimensions(nscoord aWidth, nscoord aHeight, + bool aDelayResize = false); + + /** + * Do any resizes that are pending. + */ + void FlushDelayedResize(); + + /** + * Called to inform the view manager that the entire area of a view + * is dirty and needs to be redrawn. + * @param aView view to paint. should be root view + */ + void InvalidateView(nsView* aView); + + /** + * Called to inform the view manager that some portion of a view is dirty and + * needs to be redrawn. The rect passed in should be in the view's coordinate + * space. Does not check for paint suppression. + * @param aView view to paint. should be root view + * @param rect rect to mark as damaged + */ + void InvalidateViewNoSuppression(nsView* aView, const nsRect& aRect); + + /** + * Called to inform the view manager that it should invalidate all views. + */ + void InvalidateAllViews(); + + /** + * Called to dispatch an event to the appropriate view. Often called + * as a result of receiving a mouse or keyboard event from the widget + * event system. + * @param aEvent event to dispatch + * @param aViewTarget dispatch the event to this view + * @param aStatus event handling status + */ + MOZ_CAN_RUN_SCRIPT + void DispatchEvent(mozilla::WidgetGUIEvent* aEvent, nsView* aViewTarget, + nsEventStatus* aStatus); + + /** + * Given a parent view, insert another view as its child. + * aSibling and aAbove control the "document order" for the insertion. + * If aSibling is null, the view is inserted at the end of the document order + * if aAfter is true, otherwise it is inserted at the beginning. + * If aSibling is non-null, then if aAfter is true, the view is inserted + * after the sibling in document order (appearing above the sibling unless + * overriden by z-order). + * If it is false, the view is inserted before the sibling. + * The view manager generates the appopriate dirty regions. + * @param aParent parent view + * @param aChild child view + * @param aSibling sibling view + * @param aAfter after or before in the document order + */ + void InsertChild(nsView* aParent, nsView* aChild, nsView* aSibling, + bool aAfter); + + /** + * Remove a specific child view from its parent. This will NOT remove its + * placeholder if there is one. The view manager generates the appropriate + * dirty regions. + * @param aParent parent view + * @param aChild child view + */ + void RemoveChild(nsView* aChild); + + /** + * Move a view to the specified position, provided in parent coordinates. + * The new position is the (0, 0) origin for the view's coordinate system. + * The view's bounds may extend above or to the left of this point. + * The view manager generates the appropriate dirty regions. + * @param aView view to move + * @param aX x value for new view position + * @param aY y value for new view position + */ + void MoveViewTo(nsView* aView, nscoord aX, nscoord aY); + + /** + * Resize a view. In addition to setting the width and height, you can + * set the x and y of its bounds relative to its position. Negative x and y + * will let the view extend above and to the left of the (0,0) point in its + * coordinate system. + * The view manager generates the appropriate dirty regions. + * @param aView view to move + * @param the new bounds relative to the current position + * @param RepaintExposedAreaOnly + * if true Repaint only the expanded or contracted region, + * if false Repaint the union of the old and new rectangles. + */ + void ResizeView(nsView* aView, const nsRect& aRect, + bool aRepaintExposedAreaOnly = false); + + /** + * Set the visibility of a view. Hidden views have the effect of hiding + * their descendants as well. This does not affect painting, so layout + * is responsible for ensuring that content in hidden views is not + * painted nor handling events. It does affect the visibility of widgets; + * if a view is hidden, descendant views with widgets have their widgets + * hidden. + * The view manager generates the appropriate dirty regions. + * @param aView view to change visibility state of + * @param visible new visibility state + */ + void SetViewVisibility(nsView* aView, ViewVisibility aVisible); + + /** + * Set the z-index of a view. Positive z-indices mean that a view + * is above its parent in z-order. Negative z-indices mean that a + * view is below its parent. + * The view manager generates the appropriate dirty regions. + * @param aAutoZIndex indicate that the z-index of a view is "auto". An + * "auto" z-index means that the view does not define a new stacking + * context, which means that the z-indicies of the view's children are + * relative to the view's siblings. + * @param aView view to change z depth of + * @param aZindex explicit z depth + */ + void SetViewZIndex(nsView* aView, bool aAutoZIndex, int32_t aZindex); + + /** + * Set whether the view "floats" above all other views, + * which tells the compositor not to consider higher views in + * the view hierarchy that would geometrically intersect with + * this view. This is a hack, but it fixes some problems with + * views that need to be drawn in front of all other views. + */ + void SetViewFloating(nsView* aView, bool aFloatingView); + + /** + * Set the presshell associated with this manager + * @param aPresShell - new presshell + */ + void SetPresShell(mozilla::PresShell* aPresShell) { mPresShell = aPresShell; } + + /** + * Get the pres shell associated with this manager + */ + mozilla::PresShell* GetPresShell() const { return mPresShell; } + + /** + * Get the device context associated with this manager + */ + nsDeviceContext* GetDeviceContext() const { return mContext; } + + /** + * A stack class for disallowing changes that would enter painting. For + * example, popup widgets shouldn't be resized during reflow, since doing so + * might cause synchronous painting inside reflow which is forbidden. + * While refresh is disabled, widget geometry changes are deferred and will + * be handled later, either from the refresh driver or from an NS_WILL_PAINT + * event. + * We don't want to defer widget geometry changes all the time. Resizing a + * popup from script doesn't need to be deferred, for example, especially + * since popup widget geometry is observable from script and expected to + * update synchronously. + */ + class MOZ_STACK_CLASS AutoDisableRefresh { + public: + explicit AutoDisableRefresh(nsViewManager* aVM) { + if (aVM) { + mRootVM = aVM->IncrementDisableRefreshCount(); + } + } + ~AutoDisableRefresh() { + if (mRootVM) { + mRootVM->DecrementDisableRefreshCount(); + } + } + + private: + AutoDisableRefresh(const AutoDisableRefresh& aOther); + const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther); + + RefPtr<nsViewManager> mRootVM; + }; + + private: + friend class AutoDisableRefresh; + + nsViewManager* IncrementDisableRefreshCount(); + void DecrementDisableRefreshCount(); + + public: + /** + * Retrieve the widget at the root of the nearest enclosing + * view manager whose root view has a widget. + */ + nsIWidget* GetRootWidget() const; + + /** + * Indicate whether the viewmanager is currently painting + * + * @param aPainting true if the viewmanager is painting + * false otherwise + */ + void IsPainting(bool& aIsPainting); + + /** + * Retrieve the time of the last user event. User events + * include mouse and keyboard events. The viewmanager + * saves the time of the last user event. + * + * @param aTime Last user event time in microseconds + */ + void GetLastUserEventTime(uint32_t& aTime); + + /** + * Find the nearest display root view for the view aView. This is the view for + * the nearest enclosing popup or the root view for the root document. + */ + static nsView* GetDisplayRootFor(nsView* aView); + + /** + * Flush the accumulated dirty region to the widget and update widget + * geometry. + */ + MOZ_CAN_RUN_SCRIPT void ProcessPendingUpdates(); + + /** + * Just update widget geometry without flushing the dirty region + */ + MOZ_CAN_RUN_SCRIPT void UpdateWidgetGeometry(); + + int32_t AppUnitsPerDevPixel() const { + return mContext->AppUnitsPerDevPixel(); + } + + private: + static uint32_t gLastUserEventTime; + + /* Update the cached RootViewManager pointer on this view manager. */ + void InvalidateHierarchy(); + void FlushPendingInvalidates(); + + MOZ_CAN_RUN_SCRIPT + void ProcessPendingUpdatesForView(nsView* aView, + bool aFlushDirtyRegion = true); + void ProcessPendingUpdatesRecurse( + nsView* aView, AutoTArray<nsCOMPtr<nsIWidget>, 1>& aWidgets); + MOZ_CAN_RUN_SCRIPT + void ProcessPendingUpdatesPaint(nsIWidget* aWidget); + + void FlushDirtyRegionToWidget(nsView* aView); + /** + * Call WillPaint() on all view observers under this vm root. + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY void CallWillPaintOnObservers(); + static void CollectVMsForWillPaint(nsView* aView, nsViewManager* aParentVM, + nsTArray<RefPtr<nsViewManager>>& aVMs); + + void ReparentChildWidgets(nsView* aView, nsIWidget* aNewWidget); + void ReparentWidgets(nsView* aView, nsView* aParent); + void InvalidateWidgetArea(nsView* aWidgetView, + const nsRegion& aDamagedRegion); + + void InvalidateViews(nsView* aView); + + // aView is the view for aWidget and aRegion is relative to aWidget. + MOZ_CAN_RUN_SCRIPT + void Refresh(nsView* aView, const LayoutDeviceIntRegion& aRegion); + + // Utilities + + bool IsViewInserted(nsView* aView); + + /** + * Intersects aRect with aView's bounds and then transforms it from aView's + * coordinate system to the coordinate system of the widget attached to + * aView. + */ + LayoutDeviceIntRect ViewToWidget(nsView* aView, const nsRect& aRect) const; + + MOZ_CAN_RUN_SCRIPT_BOUNDARY + void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight); + bool ShouldDelayResize() const; + + bool IsPainting() const { return RootViewManager()->mPainting; } + + void SetPainting(bool aPainting) { RootViewManager()->mPainting = aPainting; } + + void InvalidateView(nsView* aView, const nsRect& aRect); + + nsViewManager* RootViewManager() const { + return mRootViewManager ? mRootViewManager.get() + : const_cast<nsViewManager*>(this); + } + bool IsRootVM() const { return !mRootViewManager; } + + // Whether synchronous painting is allowed at the moment. For example, + // widget geometry changes can cause synchronous painting, so they need to + // be deferred while refresh is disabled. + bool IsPaintingAllowed() { + return RootViewManager()->mRefreshDisableCount == 0; + } + + MOZ_CAN_RUN_SCRIPT void WillPaintWindow(nsIWidget* aWidget); + MOZ_CAN_RUN_SCRIPT + bool PaintWindow(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion); + MOZ_CAN_RUN_SCRIPT void DidPaintWindow(); + + // Call this when you need to let the viewmanager know that it now has + // pending updates. + void PostPendingUpdate(); + + RefPtr<nsDeviceContext> mContext; + mozilla::PresShell* mPresShell; + + // The size for a resize that we delayed until the root view becomes + // visible again. + nsSize mDelayedResize; + + nsView* mRootView; + + // mRootViewManager is a strong reference to the root view manager, unless + // |this| is the root, in which case mRootViewManager is null. Callers + // should use RootViewManager() (which handles that case) rather than using + // mRootViewManager directly. + RefPtr<nsViewManager> mRootViewManager; + + // The following members should not be accessed directly except by + // the root view manager. Some have accessor functions to enforce + // this, as noted. + + int32_t mRefreshDisableCount; + // Use IsPainting() and SetPainting() to access mPainting. + bool mPainting; + bool mRecursiveRefreshPending; + bool mHasPendingWidgetGeometryChanges; + + // from here to public should be static and locked... MMP +}; + +/** + Invalidation model: + + 1) Callers call into the view manager and ask it to invalidate a view. + + 2) The view manager finds the "right" widget for the view, henceforth called + the root widget. + + 3) The view manager traverses descendants of the root widget and for each + one that needs invalidation stores the rect to invalidate on the widget's + view (batching). + + 4) The dirty region is flushed to the right widget when + ProcessPendingUpdates is called from the RefreshDriver. + + It's important to note that widgets associated to views outside this view + manager can end up being invalidated during step 3. Therefore, the end of a + view update batch really needs to traverse the entire view tree, to ensure + that those invalidates happen. + + To cope with this, invalidation processing and should only happen on the + root viewmanager. +*/ + +#endif // nsViewManager_h___ |