diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /layout/base/PresShell.h | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/base/PresShell.h')
-rw-r--r-- | layout/base/PresShell.h | 3227 |
1 files changed, 3227 insertions, 0 deletions
diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h new file mode 100644 index 0000000000..35409f91d1 --- /dev/null +++ b/layout/base/PresShell.h @@ -0,0 +1,3227 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +/* a presentation of a document, part 2 */ + +#ifndef mozilla_PresShell_h +#define mozilla_PresShell_h + +#include "DepthOrderedFrameList.h" +#include "mozilla/PresShellForwards.h" + +#include <stdio.h> // for FILE definition +#include "FrameMetrics.h" +#include "LayoutConstants.h" +#include "TouchManager.h" +#include "Units.h" +#include "Visibility.h" +#include "mozilla/ArenaObjectID.h" +#include "mozilla/Attributes.h" +#include "mozilla/FlushType.h" +#include "mozilla/Logging.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/ScrollTypes.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" +#include "mozilla/dom/DocumentBinding.h" +#include "mozilla/layers/FocusTarget.h" +#include "mozilla/layout/LayoutTelemetryTools.h" +#include "mozilla/widget/ThemeChangeKind.h" +#include "nsColor.h" +#include "nsCOMArray.h" +#include "nsCoord.h" +#include "nsDOMNavigationTiming.h" +#include "nsFrameManager.h" +#include "nsFrameState.h" +#include "nsIContent.h" +#include "nsIObserver.h" +#include "nsISelectionController.h" +#include "nsQueryFrame.h" +#include "nsPresArena.h" +#include "nsPresContext.h" +#include "nsRect.h" +#include "nsRefreshObservers.h" +#include "nsStringFwd.h" +#include "nsStubDocumentObserver.h" +#include "nsTHashSet.h" +#include "nsThreadUtils.h" +#include "nsWeakReference.h" +#ifdef ACCESSIBILITY +# include "nsAccessibilityService.h" +#endif + +class AutoPointerEventTargetUpdater; +class AutoWeakFrame; +class gfxContext; +class MobileViewportManager; +class nsAutoCauseReflowNotifier; +class nsCanvasFrame; +class nsCaret; +class nsCSSFrameConstructor; +class nsDocShell; +class nsFrameSelection; +class nsIDocShell; +class nsIFrame; +class nsILayoutHistoryState; +class nsINode; +class nsPageSequenceFrame; +class nsIReflowCallback; +class nsIScrollableFrame; +class nsITimer; +class nsPIDOMWindowOuter; +class nsPresShellEventCB; +class nsRange; +class nsRefreshDriver; +class nsRegion; +class nsView; +class nsViewManager; +class nsWindowSizes; +struct RangePaintInfo; +#ifdef MOZ_REFLOW_PERF +class ReflowCountMgr; +#endif +class WeakFrame; +class ZoomConstraintsClient; + +struct nsCallbackEventRequest; + +namespace mozilla { +class nsDisplayList; +class nsDisplayListBuilder; +class FallbackRenderer; + +class AccessibleCaretEventHub; +class GeckoMVMContext; +class OverflowChangedTracker; +class StyleSheet; + +class ProfileChunkedBuffer; + +#ifdef ACCESSIBILITY +namespace a11y { +class DocAccessible; +} // namespace a11y +#endif + +namespace dom { +class BrowserParent; +class Element; +class Event; +class HTMLSlotElement; +class Selection; +} // namespace dom + +namespace gfx { +class SourceSurface; +} // namespace gfx + +namespace layers { +class LayerManager; +struct LayersId; +} // namespace layers + +namespace layout { +class ScrollAnchorContainer; +} // namespace layout + +// 039d8ffc-fa55-42d7-a53a-388cb129b052 +#define NS_PRESSHELL_IID \ + { \ + 0x039d8ffc, 0xfa55, 0x42d7, { \ + 0xa5, 0x3a, 0x38, 0x8c, 0xb1, 0x29, 0xb0, 0x52 \ + } \ + } + +#undef NOISY_INTERRUPTIBLE_REFLOW + +/** + * Presentation shell. Presentation shells are the controlling point for + * managing the presentation of a document. The presentation shell holds a + * live reference to the document, the presentation context, the style + * manager, the style set and the root frame. + * + * When this object is Release'd, it will release the document, the + * presentation context, the style manager, the style set and the root frame. + */ + +class PresShell final : public nsStubDocumentObserver, + public nsISelectionController, + public nsIObserver, + public nsSupportsWeakReference { + typedef dom::Document Document; + typedef dom::Element Element; + typedef gfx::SourceSurface SourceSurface; + typedef layers::FocusTarget FocusTarget; + typedef layers::FrameMetrics FrameMetrics; + typedef layers::LayerManager LayerManager; + + // A set type for tracking visible frames, for use by the visibility code in + // PresShell. The set contains nsIFrame* pointers. + typedef nsTHashSet<nsIFrame*> VisibleFrames; + + public: + explicit PresShell(Document* aDocument); + + // nsISupports + NS_DECL_ISUPPORTS + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_PRESSHELL_IID) + + static bool AccessibleCaretEnabled(nsIDocShell* aDocShell); + + /** + * Return the active content currently capturing the mouse if any. + */ + static nsIContent* GetCapturingContent() { + return sCapturingContentInfo.mContent; + } + + /** + */ + static dom::BrowserParent* GetCapturingRemoteTarget() { + MOZ_ASSERT(XRE_IsParentProcess()); + return sCapturingContentInfo.mRemoteTarget; + } + + /** + * Allow or disallow mouse capturing. + */ + static void AllowMouseCapture(bool aAllowed) { + sCapturingContentInfo.mAllowed = aAllowed; + } + + /** + * Returns true if there is an active mouse capture that wants to prevent + * drags. + */ + static bool IsMouseCapturePreventingDrag() { + return sCapturingContentInfo.mPreventDrag && sCapturingContentInfo.mContent; + } + + static void ClearMouseCaptureOnView(nsView* aView); + + // Clear the capture content if it exists in this process. + static void ClearMouseCapture(); + + // If a frame in the subtree rooted at aFrame is capturing the mouse then + // clears that capture. + // + // NOTE(emilio): This is needed only so that mouse events captured by a remote + // frame don't remain being captured by the frame while hidden, see + // dom/events/test/browser_mouse_enterleave_switch_tab.js, which is the only + // test that meaningfully exercises this code path. + // + // We could consider maybe removing this, since the capturing content gets + // reset on mouse/pointerdown? Or maybe exposing an API so that the front-end + // does this. + static void ClearMouseCapture(nsIFrame* aFrame); + +#ifdef ACCESSIBILITY + /** + * Return the document accessible for this PresShell if there is one. + */ + a11y::DocAccessible* GetDocAccessible() const { return mDocAccessible; } + + /** + * Set the document accessible for this PresShell. + */ + void SetDocAccessible(a11y::DocAccessible* aDocAccessible) { + mDocAccessible = aDocAccessible; + } +#endif // #ifdef ACCESSIBILITY + + /** + * See `mLastOverWindowPointerLocation`. + */ + const nsPoint& GetLastOverWindowPointerLocation() const { + return mLastOverWindowPointerLocation; + } + + void Init(nsPresContext*, nsViewManager*); + + /** + * All callers are responsible for calling |Destroy| after calling + * |EndObservingDocument|. It needs to be separate only because form + * controls incorrectly store their data in the frames rather than the + * content model and printing calls |EndObservingDocument| multiple + * times to make form controls behave nicely when printed. + */ + void Destroy(); + + bool IsDestroying() { return mIsDestroying; } + + /** + * All frames owned by the shell are allocated from an arena. They + * are also recycled using free lists. Separate free lists are + * maintained for each frame type (aID), which must always correspond + * to the same aSize value. AllocateFrame is infallible and will abort + * on out-of-memory. + */ + void* AllocateFrame(nsQueryFrame::FrameIID aID, size_t aSize) { +#define FRAME_ID(classname, ...) \ + static_assert(size_t(nsQueryFrame::FrameIID::classname##_id) == \ + size_t(eArenaObjectID_##classname), \ + ""); +#define ABSTRACT_FRAME_ID(classname) \ + static_assert(size_t(nsQueryFrame::FrameIID::classname##_id) == \ + size_t(eArenaObjectID_##classname), \ + ""); +#include "mozilla/FrameIdList.h" +#undef FRAME_ID +#undef ABSTRACT_FRAME_ID + return AllocateByObjectID(ArenaObjectID(size_t(aID)), aSize); + } + + void FreeFrame(nsQueryFrame::FrameIID aID, void* aPtr) { + return FreeByObjectID(ArenaObjectID(size_t(aID)), aPtr); + } + + void* AllocateByObjectID(ArenaObjectID aID, size_t aSize) { + void* result = mFrameArena.Allocate(aID, aSize); + RecordAlloc(result); + return result; + } + + void FreeByObjectID(ArenaObjectID aID, void* aPtr) { + RecordFree(aPtr); + if (!mIsDestroying) { + mFrameArena.Free(aID, aPtr); + } + } + + Document* GetDocument() const { return mDocument; } + + nsPresContext* GetPresContext() const { return mPresContext; } + + nsViewManager* GetViewManager() const { return mViewManager; } + + nsRefreshDriver* GetRefreshDriver() const; + + nsCSSFrameConstructor* FrameConstructor() const { + return mFrameConstructor.get(); + } + + /** + * FrameSelection will return the Frame based selection API. + * You cannot go back and forth anymore with QI between nsIDOM sel and + * nsIFrame sel. + */ + already_AddRefed<nsFrameSelection> FrameSelection(); + + /** + * ConstFrameSelection returns an object which methods are safe to use for + * example in nsIFrame code. + */ + const nsFrameSelection* ConstFrameSelection() const { return mSelection; } + + // Start receiving notifications from our document. If called after Destroy, + // this will be ignored. + void BeginObservingDocument(); + + // Stop receiving notifications from our document. If called after Destroy, + // this will be ignored. + void EndObservingDocument(); + + bool IsObservingDocument() const { return mIsObservingDocument; } + + /** + * Return whether Initialize() was previously called. + */ + bool DidInitialize() const { return mDidInitialize; } + + /** + * Perform initialization. Constructs the frame for the root content + * object and then enqueues a reflow of the frame model. + * + * Callers of this method must hold a reference to this shell that + * is guaranteed to survive through arbitrary script execution. + * Calling Initialize can execute arbitrary script. + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult Initialize(); + + /** + * Schedule a reflow for the frame model into a new width and height. The + * coordinates for aWidth and aHeight must be in standard nscoord's. + * + * Returns whether layout might have changed. + */ + MOZ_CAN_RUN_SCRIPT void ResizeReflow( + nscoord aWidth, nscoord aHeight, + ResizeReflowOptions = ResizeReflowOptions::NoOption); + MOZ_CAN_RUN_SCRIPT bool ResizeReflowIgnoreOverride( + nscoord aWidth, nscoord aHeight, + ResizeReflowOptions = ResizeReflowOptions::NoOption); + + /** + * Add this pres shell to the refresh driver to be observed for resize + * event if applicable. + */ + void AddResizeEventFlushObserverIfNeeded(); + + /** + * Returns true if the document hosted by this presShell is in a devtools + * Responsive Design Mode browsing context. + */ + bool InRDMPane(); + +#if defined(MOZ_WIDGET_ANDROID) + /** + * If the dynamic toolbar is not expanded, notify the app to do so. + */ + void MaybeNotifyShowDynamicToolbar(); +#endif // defined(MOZ_WIDGET_ANDROID) + + void RefreshZoomConstraintsForScreenSizeChange(); + + private: + /** + * This is what ResizeReflowIgnoreOverride does when not shrink-wrapping (that + * is, when ResizeReflowOptions::BSizeLimit is not specified). + */ + bool SimpleResizeReflow(nscoord aWidth, nscoord aHeight); + + public: + /** + * Updates pending layout, assuming reasonable (up-to-date, or mid-update for + * container queries) styling of the page. Returns whether a reflow did not + * get interrupted (and thus layout should be considered fully up-to-date). + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY bool DoFlushLayout(bool aInterruptible); + + /** + * Note that the assumptions that determine whether we need a mobile viewport + * manager may have changed. + */ + void MaybeRecreateMobileViewportManager(bool aAfterInitialization); + + /** + * Returns true if this document uses mobile viewport sizing (including + * processing of <meta name="viewport"> tags). + * + * Note that having a MobileViewportManager does not necessarily mean using + * mobile viewport sizing, as with desktop zooming we can have a + * MobileViewportManager on desktop, but we only want to do mobile viewport + * sizing on mobile. (TODO: Rename MobileViewportManager to reflect its more + * general role.) + */ + bool UsesMobileViewportSizing() const; + + /** + * Get the MobileViewportManager used to manage the document's mobile + * viewport. Will return null in situations where we don't have a mobile + * viewport, and for documents that are not the root content document. + */ + RefPtr<MobileViewportManager> GetMobileViewportManager() const; + + /** + * Return true if the presshell expects layout flush. + */ + bool IsLayoutFlushObserver(); + + /** + * Called when document load completes. + */ + void LoadComplete(); + /** + * This calls through to the frame manager to get the root frame. + */ + nsIFrame* GetRootFrame() const { return mFrameManager->GetRootFrame(); } + + /* + * Get root scroll frame from FrameManager()->GetRootFrame(). + */ + nsIFrame* GetRootScrollFrame() const; + + /* + * The same as GetRootScrollFrame, but returns an nsIScrollableFrame + */ + nsIScrollableFrame* GetRootScrollFrameAsScrollable() const; + + /** + * Get the current focused content or DOM selection that should be the + * target for scrolling. + */ + already_AddRefed<nsIContent> GetContentForScrolling() const; + + /** + * Get the DOM selection that should be the target for scrolling, if there + * is no focused content. + */ + already_AddRefed<nsIContent> GetSelectedContentForScrolling() const; + + /** + * Gets nearest scrollable frame from the specified content node. The frame + * is scrollable with overflow:scroll or overflow:auto in some direction when + * aDirection is eEither. Otherwise, this returns a nearest frame that is + * scrollable in the specified direction. + */ + nsIScrollableFrame* GetScrollableFrameToScrollForContent( + nsIContent* aContent, layers::ScrollDirections aDirections); + + /** + * Gets nearest scrollable frame from current focused content or DOM + * selection if there is no focused content. The frame is scrollable with + * overflow:scroll or overflow:auto in some direction when aDirection is + * eEither. Otherwise, this returns a nearest frame that is scrollable in + * the specified direction. + */ + nsIScrollableFrame* GetScrollableFrameToScroll( + layers::ScrollDirections aDirections); + + /** + * Returns the page sequence frame associated with the frame hierarchy. + * Returns nullptr if not a paginated view. + */ + nsPageSequenceFrame* GetPageSequenceFrame() const; + + /** + * Returns the canvas frame associated with the frame hierarchy. + * Returns nullptr if is XUL document. + */ + nsCanvasFrame* GetCanvasFrame() const; + + void PostPendingScrollAnchorSelection( + layout::ScrollAnchorContainer* aContainer); + void FlushPendingScrollAnchorSelections(); + void PostPendingScrollAnchorAdjustment( + layout::ScrollAnchorContainer* aContainer); + + void PostPendingScrollResnap(nsIScrollableFrame* aScrollableFrame); + void FlushPendingScrollResnap(); + + void CancelAllPendingReflows(); + + MOZ_CAN_RUN_SCRIPT_BOUNDARY void NotifyCounterStylesAreDirty(); + + bool FrameIsAncestorOfDirtyRoot(nsIFrame* aFrame) const; + + /** + * Destroy the frames for aElement, and reconstruct them asynchronously if + * needed. + * + * Note that this may destroy frames for an arbitrary ancestor, depending on + * the frame tree structure. + */ + void DestroyFramesForAndRestyle(Element* aElement); + + /** + * Called when a ShadowRoot will be attached to an element (and thus the flat + * tree children will go away). + */ + void ShadowRootWillBeAttached(Element& aElement); + + /** + * Handles all the layout stuff needed when the slot assignment for an element + * is about to change. + * + * Only called when the slot attribute of the element changes, the rest of + * the changes should be handled in ShadowRoot. + */ + void SlotAssignmentWillChange(Element& aElement, + dom::HTMLSlotElement* aOldSlot, + dom::HTMLSlotElement* aNewSlot); + + void PostRecreateFramesFor(Element*); + void RestyleForAnimation(Element*, RestyleHint); + + /** + * Determine if it is safe to flush all pending notifications. + */ + bool IsSafeToFlush() const; + + /** + * Informs the document's FontFaceSet that the refresh driver ticked, + * flushing style and layout. + */ + void NotifyFontFaceSetOnRefresh(); + + // Removes ourself from the list of layout / style / and resize refresh driver + // observers. + // + // Right now this is only used for documents in the BFCache, so if you want to + // use this for anything else you need to ensure we don't end up in those + // lists after calling this, but before calling StartObservingRefreshDriver + // again. + // + // That is handled by the mDocument->GetBFCacheEntry checks in + // DoObserve*Flushes functions, though that could conceivably become a boolean + // member in the shell if needed. + // + // Callers are responsible of manually calling StartObservingRefreshDriver + // again. + void StopObservingRefreshDriver(); + void StartObservingRefreshDriver(); + + bool ObservingStyleFlushes() const { return mObservingStyleFlushes; } + bool ObservingLayoutFlushes() const { return mObservingLayoutFlushes; } + + void ObserveStyleFlushes() { + if (!ObservingStyleFlushes()) { + DoObserveStyleFlushes(); + } + } + + /** + * Callbacks will be called even if reflow itself fails for + * some reason. + */ + nsresult PostReflowCallback(nsIReflowCallback* aCallback); + void CancelReflowCallback(nsIReflowCallback* aCallback); + + void ScheduleBeforeFirstPaint(); + void UnsuppressAndInvalidate(); + + void ClearFrameRefs(nsIFrame* aFrame); + + // Clears the selection of the older focused frame selection if any. + void FrameSelectionWillTakeFocus(nsFrameSelection&); + + // Clears and repaint mFocusedFrameSelection if it matches the argument. + void FrameSelectionWillLoseFocus(nsFrameSelection&); + + /** + * Get a reference rendering context. This is a context that should not + * be rendered to, but is suitable for measuring text and performing + * other non-rendering operations. Guaranteed to return non-null. + */ + already_AddRefed<gfxContext> CreateReferenceRenderingContext(); + + /** + * Scrolls the view of the document so that the given area of a frame + * is visible, if possible. Layout is not flushed before scrolling. + * + * @param aRect Relative to aTargetFrame. If none, the bounding box of + * aTargetFrame will be used. The rect edges will be respected even if the + * rect is empty. + * @param aVertical see ScrollContentIntoView and ScrollAxis + * @param aHorizontal see ScrollContentIntoView and ScrollAxis + * @param aScrollFlags if ScrollFirstAncestorOnly is set, only the + * nearest scrollable ancestor is scrolled, otherwise all + * scrollable ancestors may be scrolled if necessary + * if ScrollOverflowHidden is set then we may scroll in a direction + * even if overflow:hidden is specified in that direction; otherwise + * we will not scroll in that direction when overflow:hidden is + * set for that direction + * If ScrollNoParentFrames is set then we only scroll + * nodes in this document, not in any parent documents which + * contain this document in a iframe or the like. + * @return true if any scrolling happened, false if no scrolling happened + */ + MOZ_CAN_RUN_SCRIPT + bool ScrollFrameIntoView(nsIFrame* aTargetFrame, + const Maybe<nsRect>& aKnownRectRelativeToTarget, + ScrollAxis aVertical, ScrollAxis aHorizontal, + ScrollFlags aScrollFlags); + + /** + * Suppress notification of the frame manager that frames are + * being destroyed. + */ + void SetIgnoreFrameDestruction(bool aIgnore); + + /** + * Get the AccessibleCaretEventHub, if it exists. AddRefs it. + */ + already_AddRefed<AccessibleCaretEventHub> GetAccessibleCaretEventHub() const; + + /** + * Get the caret, if it exists. AddRefs it. + */ + already_AddRefed<nsCaret> GetCaret() const; + + /** + * Set the current caret to a new caret. To undo this, call RestoreCaret. + */ + void SetCaret(nsCaret* aNewCaret); + + /** + * Restore the caret to the original caret that this pres shell was created + * with. + */ + void RestoreCaret(); + + dom::Selection* GetCurrentSelection(SelectionType aSelectionType); + + /** + * Gets the last selection that took focus in this document. This is basically + * the frame selection that's visible to the user. + */ + nsFrameSelection* GetLastFocusedFrameSelection(); + + /** + * Interface to dispatch events via the presshell + * @note The caller must have a strong reference to the PresShell. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame, + nsIContent* aContent, + nsEventStatus* aEventStatus, + bool aIsHandlingNativeEvent = false, + nsIContent** aTargetContent = nullptr, + nsIContent* aOverrideClickTarget = nullptr) { + MOZ_ASSERT(aEvent); + EventHandler eventHandler(*this); + return eventHandler.HandleEventWithTarget( + aEvent, aFrame, aContent, aEventStatus, aIsHandlingNativeEvent, + aTargetContent, aOverrideClickTarget); + } + + /** + * Dispatch event to content only (NOT full processing) + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleDOMEventWithTarget(nsIContent* aTargetContent, + WidgetEvent* aEvent, + nsEventStatus* aStatus); + + /** + * Dispatch event to content only (NOT full processing) + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleDOMEventWithTarget(nsIContent* aTargetContent, + dom::Event* aEvent, nsEventStatus* aStatus); + + /** + * Return whether or not the event is valid to be dispatched + */ + bool CanDispatchEvent(const WidgetGUIEvent* aEvent = nullptr) const; + + /** + * Gets the current target event frame from the PresShell + */ + nsIFrame* GetCurrentEventFrame(); + + /** + * Gets the current target event frame from the PresShell + */ + already_AddRefed<nsIContent> GetEventTargetContent(WidgetEvent* aEvent); + + /** + * Get and set the history state for the current document + */ + nsresult CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState); + + /** + * Determine if reflow is currently locked + * returns true if reflow is locked, false otherwise + */ + bool IsReflowLocked() const { return mIsReflowing; } + + /** + * Called to find out if painting is suppressed for this presshell. If it is + * suppressd, we don't allow the painting of any layer but the background, and + * we don't recur into our children. + */ + bool IsPaintingSuppressed() const { return mPaintingSuppressed; } + + void TryUnsuppressPaintingSoon(); + + void UnsuppressPainting(); + void InitPaintSuppressionTimer(); + void CancelPaintSuppressionTimer(); + + /** + * Reconstruct frames for all elements in the document + */ + MOZ_CAN_RUN_SCRIPT void ReconstructFrames(); + + /** + * See if reflow verification is enabled. To enable reflow verification add + * "verifyreflow:1" to your MOZ_LOG environment variable (any non-zero + * debug level will work). Or, call SetVerifyReflowEnable with true. + */ + static bool GetVerifyReflowEnable(); + + /** + * Set the verify-reflow enable flag. + */ + static void SetVerifyReflowEnable(bool aEnabled); + + nsIFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame); + +#ifdef MOZ_REFLOW_PERF + void DumpReflows(); + void CountReflows(const char* aName, nsIFrame* aFrame); + void PaintCount(const char* aName, gfxContext* aRenderingContext, + nsPresContext* aPresContext, nsIFrame* aFrame, + const nsPoint& aOffset, uint32_t aColor); + void SetPaintFrameCount(bool aOn); + bool IsPaintingFrameCounts(); +#endif // #ifdef MOZ_REFLOW_PERF + + // Debugging hooks +#ifdef DEBUG + void ListComputedStyles(FILE* out, int32_t aIndent = 0); +#endif +#if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER) + void ListStyleSheets(FILE* out, int32_t aIndent = 0); +#endif + + /** + * Stop all refresh drivers and carets in this presentation and + * in the presentations of subdocuments. Resets painting to a suppressed + * state. + * XXX this should include image animations + */ + void Freeze(bool aIncludeSubDocuments = true); + bool IsFrozen() { return mFrozen; } + + /** + * Restarts refresh drivers in this presentation and in the + * presentations of subdocuments, then do a full invalidate of the content + * area. + */ + void Thaw(bool aIncludeSubDocuments = true); + + void FireOrClearDelayedEvents(bool aFireEvents); + + /** + * When this shell is disconnected from its containing docshell, we + * lose our container pointer. However, we'd still like to be able to target + * user events at the docshell's parent. This pointer allows us to do that. + * It should not be used for any other purpose. + */ + void SetForwardingContainer(const WeakPtr<nsDocShell>& aContainer); + + /** + * Render the document into an arbitrary gfxContext + * Designed for getting a picture of a document or a piece of a document + * Note that callers will generally want to call FlushPendingNotifications + * to get an up-to-date view of the document + * @param aRect is the region to capture into the offscreen buffer, in the + * root frame's coordinate system (if aIgnoreViewportScrolling is false) + * or in the root scrolled frame's coordinate system + * (if aIgnoreViewportScrolling is true). The coordinates are in appunits. + * @param aFlags see below; + * set RenderDocumentFlags::IsUntrusted if the contents may be passed to + * malicious agents. E.g. we might choose not to paint the contents of + * sensitive widgets such as the file name in a file upload widget, and we + * might choose not to paint themes. + * set RenderDocumentFlags::IgnoreViewportScrolling to ignore clipping and + * scrollbar painting due to scrolling in the viewport + * set RenderDocumentFlags::ResetViewportScrolling to temporarily set the + * viewport scroll position to 0 so that position:fixed elements are drawn + * at their initial position. + * set RenderDocumentFlags::DrawCaret to draw the caret if one would be + * visible (by default the caret is never drawn) + * set RenderDocumentFlags::UseWidgetLayers to force rendering to go + * through the layer manager for the window. This may be unexpectedly slow + * (if the layer manager must read back data from the GPU) or low-quality + * (if the layer manager reads back pixel data and scales it + * instead of rendering using the appropriate scaling). It may also + * slow everything down if the area rendered does not correspond to the + * normal visible area of the window. + * set RenderDocumentFlags::AsyncDecodeImages to avoid having images + * synchronously decoded during rendering. + * (by default images decode synchronously with RenderDocument) + * set RenderDocumentFlags::DocumentRelative to render the document as if + * there has been no scrolling and interpret |aRect| relative to the document + * instead of the CSS viewport. Only considered if + * RenderDocumentFlags::IgnoreViewportScrolling is set or the document is in + * ignore viewport scrolling mode + * (PresShell::SetIgnoreViewportScrolling/IgnoringViewportScrolling). + * set RenderDocumentFlags::UseHighQualityScaling to enable downscale on + * decode for images. + * @param aBackgroundColor a background color to render onto + * @param aRenderedContext the gfxContext to render to. We render so that + * one CSS pixel in the source document is rendered to one unit in the current + * transform. + */ + nsresult RenderDocument(const nsRect& aRect, RenderDocumentFlags aFlags, + nscolor aBackgroundColor, + gfxContext* aRenderedContext); + + /** + * Renders a node aNode to a surface and returns it. The aRegion may be used + * to clip the rendering. This region is measured in CSS pixels from the + * edge of the presshell area. The aPoint, aScreenRect and aFlags arguments + * function in a similar manner as RenderSelection. + */ + already_AddRefed<SourceSurface> RenderNode(nsINode* aNode, + const Maybe<CSSIntRegion>& aRegion, + const LayoutDeviceIntPoint aPoint, + LayoutDeviceIntRect* aScreenRect, + RenderImageFlags aFlags); + + /** + * Renders a selection to a surface and returns it. This method is primarily + * intended to create the drag feedback when dragging a selection. + * + * aScreenRect will be filled in with the bounding rectangle of the + * selection area on screen. + * + * If the area of the selection is large and the RenderImageFlags::AutoScale + * is set, the image will be scaled down. The argument aPoint is used in this + * case as a reference point when determining the new screen rectangle after + * scaling. Typically, this will be the mouse position, so that the screen + * rectangle is positioned such that the mouse is over the same point in the + * scaled image as in the original. When scaling does not occur, the mouse + * point isn't used because the position can be determined from the displayed + * frames. + */ + already_AddRefed<SourceSurface> RenderSelection( + dom::Selection* aSelection, const LayoutDeviceIntPoint aPoint, + LayoutDeviceIntRect* aScreenRect, RenderImageFlags aFlags); + + void AddAutoWeakFrame(AutoWeakFrame* aWeakFrame); + void AddWeakFrame(WeakFrame* aWeakFrame); + + void RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame); + void RemoveWeakFrame(WeakFrame* aWeakFrame); + + /** + * Stop or restart non synthetic test mouse event handling on *all* + * presShells. + * + * @param aDisable If true, disable all non synthetic test mouse + * events on all presShells. Otherwise, enable them. + */ + void DisableNonTestMouseEvents(bool aDisable); + + /** + * Record the background color of the most recently drawn canvas. This color + * is composited on top of the user's default background color and then used + * to draw the background color of the canvas. See PresShell::Paint, + * PresShell::PaintDefaultBackground, and nsDocShell::SetupNewViewer; + * bug 488242, bug 476557 and other bugs mentioned there. + */ + void SetCanvasBackground(nscolor aColor) { mCanvasBackgroundColor = aColor; } + nscolor GetCanvasBackground() const { return mCanvasBackgroundColor; } + + /** + * Use the current frame tree (if it exists) to update the background color of + * the most recently drawn canvas. + */ + struct CanvasBackground { + nscolor mColor = 0; + bool mCSSSpecified = false; + }; + CanvasBackground ComputeCanvasBackground() const; + void UpdateCanvasBackground(); + + /** + * Add a solid color item to the bottom of aList with frame aFrame and + * bounds aBounds representing the dark grey background behind the page of a + * print preview presentation. + */ + void AddPrintPreviewBackgroundItem(nsDisplayListBuilder* aBuilder, + nsDisplayList* aList, nsIFrame* aFrame, + const nsRect& aBounds); + + /** + * Computes the backstop color for the view: transparent if in a transparent + * widget, otherwise the PresContext default background color. This color is + * only visible if the contents of the view as a whole are translucent. + */ + nscolor ComputeBackstopColor(nsView* aDisplayRoot); + + void ObserveNativeAnonMutationsForPrint(bool aObserve) { + mObservesMutationsForPrint = aObserve; + } + bool ObservesNativeAnonMutationsForPrint() { + return mObservesMutationsForPrint; + } + + void ActivenessMaybeChanged(); + // See ComputeActiveness() for details of these two booleans. + bool IsActive() const { return mIsActive; } + bool IsInActiveTab() const { return mIsInActiveTab; } + + /** + * Keep track of how many times this presshell has been rendered to + * a window. + */ + uint64_t GetPaintCount() { return mPaintCount; } + void IncrementPaintCount() { ++mPaintCount; } + + /** + * Get the root DOM window of this presShell. + */ + already_AddRefed<nsPIDOMWindowOuter> GetRootWindow(); + + /** + * This returns the focused DOM window under our top level window. + * I.e., when we are deactive, this returns the *last* focused DOM window. + */ + already_AddRefed<nsPIDOMWindowOuter> GetFocusedDOMWindowInOurWindow(); + + /** + * Get the focused content under this window. + */ + already_AddRefed<nsIContent> GetFocusedContentInOurWindow() const; + + /** + * Get the window renderer for the widget of the root view, if it has + * one. + */ + WindowRenderer* GetWindowRenderer(); + + /** + * Return true iff there is a widget rendering this presShell and that + * widget is APZ-enabled. + */ + bool AsyncPanZoomEnabled(); + + /** + * Track whether we're ignoring viewport scrolling for the purposes + * of painting. If we are ignoring, then layers aren't clipped to + * the CSS viewport and scrollbars aren't drawn. + */ + bool IgnoringViewportScrolling() const { + return !!(mRenderingStateFlags & + RenderingStateFlags::IgnoringViewportScrolling); + } + + float GetResolution() const { return mResolution.valueOr(1.0); } + float GetCumulativeResolution() const; + + /** + * Accessors for a flag that tracks whether the most recent change to + * the pres shell's resolution was originated by the main thread. + */ + bool IsResolutionUpdated() const { return mResolutionUpdated; } + void SetResolutionUpdated(bool aUpdated) { mResolutionUpdated = aUpdated; } + + /** + * Returns true if the resolution has ever been changed by APZ. + */ + bool IsResolutionUpdatedByApz() const { return mResolutionUpdatedByApz; } + + /** + * Used by session restore code to restore a resolution before the first + * paint. + */ + void SetRestoreResolution(float aResolution, + LayoutDeviceIntSize aDisplaySize); + + /** + * Returns whether we are in a DrawWindow() call that used the + * DRAWWINDOW_DO_NOT_FLUSH flag. + */ + bool InDrawWindowNotFlushing() const { + return !!(mRenderingStateFlags & + RenderingStateFlags::DrawWindowNotFlushing); + } + + /** + * Set the isFirstPaint flag. + */ + void SetIsFirstPaint(bool aIsFirstPaint) { mIsFirstPaint = aIsFirstPaint; } + + /** + * Get the isFirstPaint flag. + */ + bool GetIsFirstPaint() const { return mIsFirstPaint; } + + uint32_t GetPresShellId() { return mPresShellId; } + + /** + * Dispatch a mouse move event based on the most recent mouse position if + * this PresShell is visible. This is used when the contents of the page + * moved (aFromScroll is false) or scrolled (aFromScroll is true). + */ + void SynthesizeMouseMove(bool aFromScroll); + + MOZ_CAN_RUN_SCRIPT + nsresult HandleEvent(nsIFrame* aFrame, WidgetGUIEvent* aEvent, + bool aDontRetargetEvents, nsEventStatus* aEventStatus); + bool ShouldIgnoreInvalidation(); + /** + * Notify that we called Paint with PaintFlags::PaintComposite. + * Fires on the presshell for the painted widget. + * This is issued at a time when it's safe to modify widget geometry. + */ + MOZ_CAN_RUN_SCRIPT void DidPaintWindow(); + + bool IsVisible() const; + bool IsUnderHiddenEmbedderElement() const { + return mUnderHiddenEmbedderElement; + } + void SetIsUnderHiddenEmbedderElement(bool aUnderHiddenEmbedderElement); + MOZ_CAN_RUN_SCRIPT + void DispatchSynthMouseMove(WidgetGUIEvent* aEvent); + + /* Temporarily ignore the Displayport for better paint performance. We + * trigger a repaint once suppression is disabled. Without that + * the displayport may get left at the suppressed size for an extended + * period of time and result in unnecessary checkerboarding (see bug + * 1255054). */ + void SuppressDisplayport(bool aEnabled); + + /* Whether or not displayport suppression should be turned on. Note that + * this only affects the return value of |IsDisplayportSuppressed()|, and + * doesn't change the value of the internal counter. + */ + void RespectDisplayportSuppression(bool aEnabled); + + /* Whether or not the displayport is currently suppressed. */ + bool IsDisplayportSuppressed(); + + void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const; + + /** + * Methods that retrieve the cached font inflation preferences. + */ + uint32_t FontSizeInflationEmPerLine() const { + return mFontSizeInflationEmPerLine; + } + + uint32_t FontSizeInflationMinTwips() const { + return mFontSizeInflationMinTwips; + } + + uint32_t FontSizeInflationLineThreshold() const { + return mFontSizeInflationLineThreshold; + } + + bool FontSizeInflationForceEnabled() const { + return mFontSizeInflationForceEnabled; + } + + bool FontSizeInflationDisabledInMasterProcess() const { + return mFontSizeInflationDisabledInMasterProcess; + } + + bool FontSizeInflationEnabled() const { return mFontSizeInflationEnabled; } + + /** + * Recomputes whether font-size inflation is enabled. + */ + void RecomputeFontSizeInflationEnabled(); + + /** + * Return true if the most recent interruptible reflow was interrupted. + */ + bool IsReflowInterrupted() const { return mWasLastReflowInterrupted; } + + /** + * Return true if the the interruptible reflows have to be suppressed. + * This may happen only if if the most recent reflow was interrupted. + */ + bool SuppressInterruptibleReflows() const { + return mWasLastReflowInterrupted; + } + + ////////////////////////////////////////////////////////////////////////////// + // Approximate frame visibility tracking public API. + ////////////////////////////////////////////////////////////////////////////// + + /** + * Schedule an update of the list of approximately visible frames "soon". + * This lets the refresh driver know that we want a visibility update in the + * near future. The refresh driver applies its own heuristics and throttling + * to decide when to actually perform the visibility update. + */ + void ScheduleApproximateFrameVisibilityUpdateSoon(); + + /** + * Schedule an update of the list of approximately visible frames "now". The + * update runs asynchronously, but it will be posted to the event loop + * immediately. Prefer the "soon" variation of this method when possible, as + * this variation ignores the refresh driver's heuristics. + */ + void ScheduleApproximateFrameVisibilityUpdateNow(); + + /** + * Clears the current list of approximately visible frames on this pres shell + * and replaces it with frames that are in the display list @aList. + */ + void RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList); + void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr, + bool aRemoveOnly = false); + + /** + * Ensures @aFrame is in the list of approximately visible frames. + */ + void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame); + + /// Removes @aFrame from the list of approximately visible frames if present. + void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame); + + /// Whether we should assume all frames are visible. + bool AssumeAllFramesVisible(); + + /** + * Returns whether the document's style set's rule processor for the + * specified level of the cascade is shared by multiple style sets. + * + * @param aSheetType One of the nsIStyleSheetService.*_SHEET constants. + */ + nsresult HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType, + bool* aRetVal); + + /** + * Returns whether or not the document has ever handled user input + */ + bool HasHandledUserInput() const { return mHasHandledUserInput; } + + MOZ_CAN_RUN_SCRIPT void FireResizeEvent(); + MOZ_CAN_RUN_SCRIPT void FireResizeEventSync(); + + void NativeAnonymousContentRemoved(nsIContent* aAnonContent); + + /** + * See HTMLDocument.setKeyPressEventModel() in HTMLDocument.webidl for the + * detail. + */ + void SetKeyPressEventModel(uint16_t aKeyPressEventModel) { + mForceUseLegacyKeyCodeAndCharCodeValues |= + aKeyPressEventModel == + dom::Document_Binding::KEYPRESS_EVENT_MODEL_SPLIT; + } + + bool AddRefreshObserver(nsARefreshObserver* aObserver, FlushType aFlushType, + const char* aObserverDescription); + bool RemoveRefreshObserver(nsARefreshObserver* aObserver, + FlushType aFlushType); + + bool AddPostRefreshObserver(nsAPostRefreshObserver*); + bool AddPostRefreshObserver(mozilla::ManagedPostRefreshObserver*) = delete; + bool RemovePostRefreshObserver(nsAPostRefreshObserver*); + bool RemovePostRefreshObserver(mozilla::ManagedPostRefreshObserver*) = delete; + + // Represents an update to the visual scroll offset that will be sent to APZ. + // The update type is used to determine priority compared to other scroll + // updates. + struct VisualScrollUpdate { + nsPoint mVisualScrollOffset; + FrameMetrics::ScrollOffsetUpdateType mUpdateType; + bool mAcknowledged = false; + }; + + // Ask APZ in the next transaction to scroll to the given visual viewport + // offset (relative to the document). + // This is intended to be used when desired in cases where the browser + // internally triggers scrolling; scrolling triggered explicitly by web + // content (such as via window.scrollTo() should scroll the layout viewport + // only). + // If scrolling "far away", i.e. not just within the existing layout + // viewport, it's recommended to use both nsIScrollableFrame.ScrollTo*() + // (via window.scrollTo if calling from JS) *and* this function; otherwise, + // temporary checkerboarding may result. If doing this: + // * Be sure to call ScrollTo*() first, as a subsequent layout scroll + // in the same transaction will cancel the pending visual scroll. + // * Keep in mind that ScrollTo*() can tear down the pres shell and + // frame tree. Depending on how the pres shell is obtained for the + // subsequent ScrollToVisual() call, AutoWeakFrame or similar may + // need to be used. + // Please request APZ review if adding a new call site. + void ScrollToVisual(const nsPoint& aVisualViewportOffset, + FrameMetrics::ScrollOffsetUpdateType aUpdateType, + ScrollMode aMode); + void AcknowledgePendingVisualScrollUpdate(); + void ClearPendingVisualScrollUpdate(); + const Maybe<VisualScrollUpdate>& GetPendingVisualScrollUpdate() const { + return mPendingVisualScrollUpdate; + } + + nsPoint GetLayoutViewportOffset() const; + nsSize GetLayoutViewportSize() const; + + /** + * Documents belonging to an invisible DocShell must not be painted ever. + */ + bool IsNeverPainting() { return mIsNeverPainting; } + + void SetNeverPainting(bool aNeverPainting) { + mIsNeverPainting = aNeverPainting; + } + + /** + * True if a reflow event has been scheduled, or is going to be scheduled + * to run in the future. + */ + bool HasPendingReflow() const { + return mObservingLayoutFlushes || mReflowContinueTimer; + } + + void SyncWindowProperties(nsView* aView); + + Document* GetPrimaryContentDocument(); + + struct MOZ_RAII AutoAssertNoFlush { + explicit AutoAssertNoFlush(PresShell& aPresShell) + : mPresShell(aPresShell), mOldForbidden(mPresShell.mForbiddenToFlush) { + mPresShell.mForbiddenToFlush = true; + } + + ~AutoAssertNoFlush() { mPresShell.mForbiddenToFlush = mOldForbidden; } + + PresShell& mPresShell; + const bool mOldForbidden; + }; + + NS_IMETHOD GetSelectionFromScript(RawSelectionType aRawSelectionType, + dom::Selection** aSelection) override; + dom::Selection* GetSelection(RawSelectionType aRawSelectionType) override; + + NS_IMETHOD SetDisplaySelection(int16_t aToggle) override; + NS_IMETHOD GetDisplaySelection(int16_t* aToggle) override; + NS_IMETHOD ScrollSelectionIntoView(RawSelectionType aRawSelectionType, + SelectionRegion aRegion, + int16_t aFlags) override; + NS_IMETHOD RepaintSelection(RawSelectionType aRawSelectionType) override; + void SelectionWillTakeFocus() override; + void SelectionWillLoseFocus() override; + + // Implements the "focus fix-up rule". Returns true if the focus moved (in + // which case we might need to update layout again). + // See https://github.com/whatwg/html/issues/8225 + MOZ_CAN_RUN_SCRIPT bool FixUpFocus(); + + /** + * Set a "resolution" for the document, which if not 1.0 will + * allocate more or fewer pixels for rescalable content by a factor + * of |resolution| in both dimensions. Return NS_OK iff the + * resolution bounds are sane, and the resolution of this was + * actually updated. + * + * Also increase the scale of the content by the same amount + * (that's the "AndScaleTo" part). + * + * The resolution defaults to 1.0. + * + * |aOrigin| specifies who originated the resolution change. For changes + * sent by APZ, pass ResolutionChangeOrigin::Apz. For changes sent by + * the main thread, pass ResolutionChangeOrigin::MainThreadAdjustment (similar + * to the |aOrigin| parameter of nsIScrollableFrame::ScrollToCSSPixels()). + */ + nsresult SetResolutionAndScaleTo(float aResolution, + ResolutionChangeOrigin aOrigin); + + ResolutionChangeOrigin GetLastResolutionChangeOrigin() { + return mLastResolutionChangeOrigin; + } + + // Widget notificiations + void WindowSizeMoveDone(); + + void BackingScaleFactorChanged() { mPresContext->UIResolutionChangedSync(); } + + /** + * Does any painting work required to update retained paint state, and pushes + * it the compositor (if any). Requests a composite, either by scheduling a + * remote composite, or invalidating the widget so that we get a call to + * SyncPaintFallback from the widget paint event. + */ + MOZ_CAN_RUN_SCRIPT + void PaintAndRequestComposite(nsView* aView, PaintFlags aFlags); + + /** + * Does an immediate paint+composite using the FallbackRenderer (which must + * be the current WindowRenderer for the root frame's widget). + */ + MOZ_CAN_RUN_SCRIPT + void SyncPaintFallback(nsView* aView); + + /** + * Notify that we're going to call Paint with PaintFlags::PaintLayers + * on the pres shell for a widget (which might not be this one, since + * WillPaint is called on all presshells in the same toplevel window as the + * painted widget). This is issued at a time when it's safe to modify + * widget geometry. + */ + MOZ_CAN_RUN_SCRIPT void WillPaint(); + + /** + * Ensures that the refresh driver is running, and schedules a view + * manager flush on the next tick. + */ + void ScheduleViewManagerFlush(); + + // caret handling + NS_IMETHOD SetCaretEnabled(bool aInEnable) override; + NS_IMETHOD SetCaretReadOnly(bool aReadOnly) override; + NS_IMETHOD GetCaretEnabled(bool* aOutEnabled) override; + NS_IMETHOD SetCaretVisibilityDuringSelection(bool aVisibility) override; + NS_IMETHOD GetCaretVisible(bool* _retval) override; + + /** + * Should the images have borders etc. Actual visual effects are determined + * by the frames. Visual effects may not effect layout, only display. + * Takes effect on next repaint, does not force a repaint itself. + * + * @param aFlags may be multiple of nsISelectionDisplay::DISPLAY_*. + */ + NS_IMETHOD SetSelectionFlags(int16_t aFlags) override; + NS_IMETHOD GetSelectionFlags(int16_t* aFlags) override; + + /** + * Gets the current state of non text selection effects + * @return current state of non text selection, + * as set by SetDisplayNonTextSelection + */ + int16_t GetSelectionFlags() const { return mSelectionFlags; } + + // nsISelectionController + + NS_IMETHOD PhysicalMove(int16_t aDirection, int16_t aAmount, + bool aExtend) override; + NS_IMETHOD CharacterMove(bool aForward, bool aExtend) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD WordMove(bool aForward, + bool aExtend) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD LineMove(bool aForward, + bool aExtend) override; + NS_IMETHOD IntraLineMove(bool aForward, bool aExtend) override; + MOZ_CAN_RUN_SCRIPT + NS_IMETHOD PageMove(bool aForward, bool aExtend) override; + NS_IMETHOD ScrollPage(bool aForward) override; + NS_IMETHOD ScrollLine(bool aForward) override; + NS_IMETHOD ScrollCharacter(bool aRight) override; + NS_IMETHOD CompleteScroll(bool aForward) override; + MOZ_CAN_RUN_SCRIPT NS_IMETHOD CompleteMove(bool aForward, + bool aExtend) override; + + // Notifies that the state of the document has changed. + void DocumentStatesChanged(dom::DocumentState); + + // nsIDocumentObserver + NS_DECL_NSIDOCUMENTOBSERVER_BEGINLOAD + NS_DECL_NSIDOCUMENTOBSERVER_ENDLOAD + NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATECHANGED + + // nsIMutationObserver + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + + NS_DECL_NSIOBSERVER + + // Inline methods defined in PresShellInlines.h + inline void EnsureStyleFlush(); + inline void SetNeedStyleFlush(); + inline void SetNeedLayoutFlush(); + inline void SetNeedThrottledAnimationFlush(); + inline ServoStyleSet* StyleSet() const; + + /** + * Whether we might need a flush for the given flush type. If this + * function returns false, we definitely don't need to flush. + * + * @param aFlushType The flush type to check. This must be + * >= FlushType::Style. This also returns true if a throttled + * animation flush is required. + */ + bool NeedFlush(FlushType aType) const { + // We check mInFlush to handle re-entrant calls to FlushPendingNotifications + // by reporting that we always need a flush in that case. Otherwise, + // we could end up missing needed flushes, since we clear the mNeedXXXFlush + // flags at the top of FlushPendingNotifications. + MOZ_ASSERT(aType >= FlushType::Style); + return mNeedStyleFlush || + (mNeedLayoutFlush && aType >= FlushType::InterruptibleLayout) || + aType >= FlushType::Display || mNeedThrottledAnimationFlush || + mInFlush; + } + + /** + * Returns true if we might need to flush layout, even if we haven't scheduled + * one yet (as opposed to HasPendingReflow, which returns true if a flush is + * scheduled or will soon be scheduled). + */ + bool NeedLayoutFlush() const { return mNeedLayoutFlush; } + + bool NeedStyleFlush() const { return mNeedStyleFlush; } + + /** + * Flush pending notifications of the type specified. This method + * will not affect the content model; it'll just affect style and + * frames. Callers that actually want up-to-date presentation (other + * than the document itself) should probably be calling + * Document::FlushPendingNotifications. + * + * This method can execute script, which can destroy this presshell object + * unless someone is holding a reference to it on the stack. The presshell + * itself will ensure it lives up until the method returns, but callers who + * plan to use the presshell after this call should hold a strong ref + * themselves! + * + * @param aType the type of notifications to flush + */ + MOZ_CAN_RUN_SCRIPT + void FlushPendingNotifications(FlushType aType) { + if (!NeedFlush(aType)) { + return; + } + + DoFlushPendingNotifications(aType); + } + + MOZ_CAN_RUN_SCRIPT + void FlushPendingNotifications(ChangesToFlush aType) { + if (!NeedFlush(aType.mFlushType)) { + return; + } + + DoFlushPendingNotifications(aType); + } + + /** + * Tell the pres shell that a frame needs to be marked dirty and needs + * Reflow. It's OK if this is an ancestor of the frame needing reflow as + * long as the ancestor chain between them doesn't cross a reflow root. + * + * The bit to add should be NS_FRAME_IS_DIRTY, NS_FRAME_HAS_DIRTY_CHILDREN + * or nsFrameState(0); passing 0 means that dirty bits won't be set on the + * frame or its ancestors/descendants, but that intrinsic widths will still + * be marked dirty. Passing aIntrinsicDirty = eResize and aBitToAdd = 0 + * would result in no work being done, so don't do that. + */ + void FrameNeedsReflow( + nsIFrame* aFrame, IntrinsicDirty aIntrinsicDirty, nsFrameState aBitToAdd, + ReflowRootHandling aRootHandling = ReflowRootHandling::InferFromBitToAdd); + + /** + * Calls FrameNeedsReflow on all fixed position children of the root frame. + */ + void MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty); + + void MaybeReflowForInflationScreenSizeChange(); + + // This function handles all the work after VisualViewportSize is set + // or reset. + void CompleteChangeToVisualViewportSize(); + + /** + * The return value indicates whether the offset actually changed. + */ + bool SetVisualViewportOffset(const nsPoint& aScrollOffset, + const nsPoint& aPrevLayoutScrollPos); + + void ResetVisualViewportOffset(); + nsPoint GetVisualViewportOffset() const { + if (mVisualViewportOffset.isSome()) { + return *mVisualViewportOffset; + } + return GetLayoutViewportOffset(); + } + bool IsVisualViewportOffsetSet() const { + return mVisualViewportOffset.isSome(); + } + + void SetVisualViewportSize(nscoord aWidth, nscoord aHeight); + void ResetVisualViewportSize(); + bool IsVisualViewportSizeSet() { return mVisualViewportSizeSet; } + nsSize GetVisualViewportSize() { + NS_ASSERTION(mVisualViewportSizeSet, + "asking for visual viewport size when its not set?"); + return mVisualViewportSize; + } + + nsPoint GetVisualViewportOffsetRelativeToLayoutViewport() const; + + // Returns state of the dynamic toolbar. + DynamicToolbarState GetDynamicToolbarState() const { + if (!mPresContext) { + return DynamicToolbarState::None; + } + + return mPresContext->GetDynamicToolbarState(); + } + // Returns the visual viewport size during the dynamic toolbar is being + // shown/hidden. + nsSize GetVisualViewportSizeUpdatedByDynamicToolbar() const; + + /* Enable/disable author style level. Disabling author style disables the + * entire author level of the cascade, including the HTML preshint level. + */ + // XXX these could easily be inlined, but there is a circular #include + // problem with nsStyleSet. + void SetAuthorStyleDisabled(bool aDisabled); + bool GetAuthorStyleDisabled() const; + + /** + * Update the style set somehow to take into account changed prefs which + * affect document styling. + */ + void UpdatePreferenceStyles(); + + // aSheetType is one of the nsIStyleSheetService *_SHEET constants. + void NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet, + uint32_t aSheetType); + void NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet, + uint32_t aSheetType); + + // DoReflow returns whether the reflow finished without interruption + // If aFrame is not the root frame, the caller must pass a non-null + // aOverflowTracker. + bool DoReflow(nsIFrame* aFrame, bool aInterruptible, + OverflowChangedTracker* aOverflowTracker); + + /** + * Add a solid color item to the bottom of aList with frame aFrame and bounds + * aBounds. Checks first if this needs to be done by checking if aFrame is a + * canvas frame (if the AddCanvasBackgroundColorFlags::ForceDraw is passed + * then this check is skipped). aBackstopColor is composed behind the + * background color of the canvas, it is transparent by default. + * + * We attempt to make the background color part of the scrolled canvas (to + * reduce transparent layers), and if async scrolling is enabled (and the + * background is opaque) then we add a second, unscrolled item to handle the + * checkerboarding case. + * + * AddCanvasBackgroundColorFlags::AddSubDocument should be specified when + * calling this for a subdocument, and LayoutUseContainersForRootFrame might + * cause the whole list to be scrolled. In that case the second unscrolled + * item will be elided. + * + * AddCanvasBackgroundColorFlags::AppendUnscrolledOnly only attempts to add + * the unscrolled item, so that we can add it manually after + * LayoutUseContainersForRootFrame has built the scrolling ContainerLayer. + */ + void AddCanvasBackgroundColorItem( + nsDisplayListBuilder* aBuilder, nsDisplayList* aList, nsIFrame* aFrame, + const nsRect& aBounds, nscolor aBackstopColor = NS_RGBA(0, 0, 0, 0), + AddCanvasBackgroundColorFlags aFlags = + AddCanvasBackgroundColorFlags::None); + + size_t SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const; + + static PresShell* GetShellForEventTarget(nsIFrame* aFrame, + nsIContent* aContent); + static PresShell* GetShellForTouchEvent(WidgetGUIEvent* aEvent); + + /** + * Informs the pres shell that the document is now at the anchor with + * the given name. If |aScroll| is true, scrolls the view of the + * document so that the anchor with the specified name is displayed at + * the top of the window. If |aAnchorName| is empty, then this informs + * the pres shell that there is no current target, and |aScroll| must + * be false. If |aAdditionalScrollFlags| is ScrollFlags::ScrollSmoothAuto + * and |aScroll| is true, the scrolling may be performed with an animation. + */ + MOZ_CAN_RUN_SCRIPT + nsresult GoToAnchor(const nsAString& aAnchorName, bool aScroll, + ScrollFlags aAdditionalScrollFlags = ScrollFlags::None); + + /** + * Tells the presshell to scroll again to the last anchor scrolled to by + * GoToAnchor, if any. This scroll only happens if the scroll + * position has not changed since the last GoToAnchor (modulo scroll anchoring + * adjustments). This is called by nsDocumentViewer::LoadComplete. This clears + * the last anchor scrolled to by GoToAnchor (we don't want to keep it alive + * if it's removed from the DOM), so don't call this more than once. + */ + MOZ_CAN_RUN_SCRIPT nsresult ScrollToAnchor(); + + /** + * When scroll anchoring adjusts positions in the root frame during page load, + * it may move our scroll position in the root frame. + * + * While that's generally desirable, when scrolling to an anchor via an id-ref + * we have a more direct target. If the id-ref points to something that cannot + * be selected as a scroll anchor container (like an image or an inline), we + * may select a node following it as a scroll anchor, and if then stuff is + * inserted on top, we may end up moving the id-ref element offscreen to the + * top inadvertently. + * + * On page load, the document viewer will call ScrollToAnchor(), and will only + * scroll to the anchor again if the scroll position is not changed. We don't + * want scroll anchoring adjustments to prevent this, so account for them. + */ + void RootScrollFrameAdjusted(nscoord aYAdjustment) { + if (mLastAnchorScrolledTo) { + mLastAnchorScrollPositionY += aYAdjustment; + } + } + + /** + * Scrolls the view of the document so that the primary frame of the content + * is displayed in the window. Layout is flushed before scrolling. + * + * @param aContent The content object of which primary frame should be + * scrolled into view. + * @param aVertical How to align the frame vertically and when to do so. + * This is a ScrollAxis of Where and When. + * @param aHorizontal How to align the frame horizontally and when to do so. + * This is a ScrollAxis of Where and When. + * @param aScrollFlags If ScrollFlags::ScrollFirstAncestorOnly is set, + * only the nearest scrollable ancestor is scrolled, + * otherwise all scrollable ancestors may be scrolled + * if necessary. If ScrollFlags::ScrollOverflowHidden + * is set then we may scroll in a direction even if + * overflow:hidden is specified in that direction; + * otherwise we will not scroll in that direction when + * overflow:hidden is set for that direction. If + * ScrollFlags::ScrollNoParentFrames is set then we + * only scroll nodes in this document, not in any + * parent documents which contain this document in a + * iframe or the like. If ScrollFlags::ScrollSmooth + * is set and CSSOM-VIEW scroll-behavior is enabled, + * we will scroll smoothly using + * nsIScrollableFrame::ScrollMode::SMOOTH_MSD; + * otherwise, nsIScrollableFrame::ScrollMode::INSTANT + * will be used. If ScrollFlags::ScrollSmoothAuto is + * set, the CSSOM-View scroll-behavior attribute is + * set to 'smooth' on the scroll frame, and CSSOM-VIEW + * scroll-behavior is enabled, we will scroll smoothly + * using nsIScrollableFrame::ScrollMode::SMOOTH_MSD; + * otherwise, nsIScrollableFrame::ScrollMode::INSTANT + * will be used. + */ + MOZ_CAN_RUN_SCRIPT + nsresult ScrollContentIntoView(nsIContent* aContent, ScrollAxis aVertical, + ScrollAxis aHorizontal, + ScrollFlags aScrollFlags); + + /** + * When capturing content is set, it traps all mouse events and retargets + * them at this content node. If capturing is not allowed + * (gCaptureInfo.mAllowed is false), then capturing is not set. However, if + * the CaptureFlags::IgnoreAllowedState is set, the allowed state is ignored + * and capturing is set regardless. To disable capture, pass null for the + * value of aContent. + * + * If CaptureFlags::RetargetedToElement is set, all mouse events are + * targeted at aContent only. Otherwise, mouse events are targeted at + * aContent or its descendants. That is, descendants of aContent receive + * mouse events as they normally would, but mouse events outside of aContent + * are retargeted to aContent. + * + * If CaptureFlags::PreventDragStart is set then drags are prevented from + * starting while this capture is active. + * + * If CaptureFlags::PointerLock is set, similar to + * CaptureFlags::RetargetToElement, then events are targeted at aContent, + * but capturing is held more strongly (i.e., calls to SetCapturingContent() + * won't unlock unless CaptureFlags::PointerLock is set again). + */ + static void SetCapturingContent(nsIContent* aContent, CaptureFlags aFlags, + WidgetEvent* aEvent = nullptr); + + /** + * Alias for SetCapturingContent(nullptr, CaptureFlags::None) for making + * callers what they do clearer. + */ + static void ReleaseCapturingContent() { + PresShell::SetCapturingContent(nullptr, CaptureFlags::None); + } + + static void ReleaseCapturingRemoteTarget(dom::BrowserParent* aBrowserParent) { + MOZ_ASSERT(XRE_IsParentProcess()); + if (sCapturingContentInfo.mRemoteTarget == aBrowserParent) { + sCapturingContentInfo.mRemoteTarget = nullptr; + } + } + + // Called at the end of nsLayoutUtils::PaintFrame() if we were painting to + // the widget. + // This is used to clear any pending visual scroll updates that have been + // acknowledged, to make sure they don't stick around for the next paint. + void EndPaint(); + + /** + * Tell the presshell that the given frame's reflow was interrupted. This + * will mark as having dirty children a path from the given frame (inclusive) + * to the nearest ancestor with a dirty subtree, or to the reflow root + * currently being reflowed if no such ancestor exists (inclusive). This is + * to be done immediately after reflow of the current reflow root completes. + * This method must only be called during reflow, and the frame it's being + * called on must be in the process of being reflowed when it's called. This + * method doesn't mark any intrinsic widths dirty and doesn't add any bits + * other than NS_FRAME_HAS_DIRTY_CHILDREN. + */ + void FrameNeedsToContinueReflow(nsIFrame* aFrame); + + /** + * Notification sent by a frame informing the pres shell that it is about to + * be destroyed. + * This allows any outstanding references to the frame to be cleaned up + */ + void NotifyDestroyingFrame(nsIFrame* aFrame); + + bool GetZoomableByAPZ() const; + + /** + * If this frame has content hidden via `content-visibilty` that has a pending + * reflow, force the content to reflow immediately. + */ + void EnsureReflowIfFrameHasHiddenContent(nsIFrame*); + + /** + * Whether or not this presshell is is forcing a reflow of hidden content in + * this frame via EnsureReflowIfFrameHasHiddenContent(). + */ + bool IsForcingLayoutForHiddenContent(const nsIFrame*) const; + + void RegisterContentVisibilityAutoFrame(nsIFrame* aFrame) { + mContentVisibilityAutoFrames.Insert(aFrame); + } + + void UpdateRelevancyOfContentVisibilityAutoFrames(); + void ScheduleContentRelevancyUpdate(ContentRelevancyReason aReason); + + private: + ~PresShell(); + + void SetIsActive(bool aIsActive, bool aIsInActiveTab); + struct Activeness { + bool mShouldBeActive = false; + bool mIsInActiveTab = false; + }; + Activeness ComputeActiveness() const; + + MOZ_CAN_RUN_SCRIPT + void PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags); + + /** + * Refresh observer management. + */ + void DoObserveStyleFlushes(); + void DoObserveLayoutFlushes(); + + /** + * Does the actual work of figuring out the current state of font size + * inflation. + */ + bool DetermineFontSizeInflationState(); + + void RecordAlloc(void* aPtr) { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (!mAllocatedPointers) { + return; // Hash set was presumably freed to avert OOM. + } + MOZ_DIAGNOSTIC_ASSERT(!mAllocatedPointers->Contains(aPtr)); + if (!mAllocatedPointers->Insert(aPtr, fallible)) { + // Yikes! We're nearly out of memory, and this insertion would've pushed + // us over the ledge. At this point, we discard & stop using this set, + // since we don't have enough memory to keep it accurate from this point + // onwards. Hopefully this helps relieve the memory pressure a bit, too. + mAllocatedPointers = nullptr; + } +#endif + } + + void RecordFree(void* aPtr) { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (!mAllocatedPointers) { + return; // Hash set was presumably freed to avert OOM. + } + MOZ_DIAGNOSTIC_ASSERT(mAllocatedPointers->Contains(aPtr)); + mAllocatedPointers->Remove(aPtr); +#endif + } + + void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent); + void PopCurrentEventInfo(); + nsIContent* GetCurrentEventContent(); + + friend class ::nsRefreshDriver; + friend class ::nsAutoCauseReflowNotifier; + + void WillCauseReflow(); + MOZ_CAN_RUN_SCRIPT void DidCauseReflow(); + + void CancelPostedReflowCallbacks(); + void FlushPendingScrollAnchorAdjustments(); + + void SetPendingVisualScrollUpdate( + const nsPoint& aVisualViewportOffset, + FrameMetrics::ScrollOffsetUpdateType aUpdateType); + +#ifdef MOZ_REFLOW_PERF + UniquePtr<ReflowCountMgr> mReflowCountMgr; +#endif + + void WillDoReflow(); + + // This data is stored as a content property (nsGkAtoms::scrolling) on + // mContentToScrollTo when we have a pending ScrollIntoView. + struct ScrollIntoViewData { + ScrollAxis mContentScrollVAxis; + ScrollAxis mContentScrollHAxis; + ScrollFlags mContentToScrollToFlags; + }; + + static LazyLogModule gLog; + + DOMHighResTimeStamp GetPerformanceNowUnclamped(); + + // The callback for the mReflowContinueTimer timer. + static void sReflowContinueCallback(nsITimer* aTimer, void* aPresShell); + bool ScheduleReflowOffTimer(); + // MaybeScheduleReflow checks if posting a reflow is needed, then checks if + // the last reflow was interrupted. In the interrupted case ScheduleReflow is + // called off a timer, otherwise it is called directly. + void MaybeScheduleReflow(); + // Actually schedules a reflow. This should only be called by + // MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer + // sets up. + void ScheduleReflow(); + + friend class ::AutoPointerEventTargetUpdater; + + // ProcessReflowCommands returns whether we processed all our dirty roots + // without interruptions. + MOZ_CAN_RUN_SCRIPT bool ProcessReflowCommands(bool aInterruptible); + + /** + * Callback handler for whether reflow happened. + * + * @param aInterruptible Whether or not reflow interruption is allowed. + */ + MOZ_CAN_RUN_SCRIPT void DidDoReflow(bool aInterruptible); + + MOZ_CAN_RUN_SCRIPT void HandlePostedReflowCallbacks(bool aInterruptible); + + /** + * Helper for ScrollContentIntoView() + */ + MOZ_CAN_RUN_SCRIPT void DoScrollContentIntoView(); + + /** + * Methods to handle changes to user and UA sheet lists that we get + * notified about. + */ + void AddUserSheet(StyleSheet*); + void AddAgentSheet(StyleSheet*); + void AddAuthorSheet(StyleSheet*); + void RemovePreferenceStyles(); + + /** + * Initialize cached font inflation preference values and do an initial + * computation to determine if font inflation is enabled. + * + * @see nsLayoutUtils::sFontSizeInflationEmPerLine + * @see nsLayoutUtils::sFontSizeInflationMinTwips + * @see nsLayoutUtils::sFontSizeInflationLineThreshold + */ + void SetupFontInflation(); + + /** + * Implementation methods for FlushPendingNotifications. + */ + MOZ_CAN_RUN_SCRIPT void DoFlushPendingNotifications(FlushType aType); + MOZ_CAN_RUN_SCRIPT void DoFlushPendingNotifications(ChangesToFlush aType); + + struct RenderingState { + explicit RenderingState(PresShell* aPresShell) + : mResolution(aPresShell->mResolution), + mRenderingStateFlags(aPresShell->mRenderingStateFlags) {} + Maybe<float> mResolution; + RenderingStateFlags mRenderingStateFlags; + }; + + struct AutoSaveRestoreRenderingState { + explicit AutoSaveRestoreRenderingState(PresShell* aPresShell) + : mPresShell(aPresShell), mOldState(aPresShell) {} + + ~AutoSaveRestoreRenderingState() { + mPresShell->mRenderingStateFlags = mOldState.mRenderingStateFlags; + mPresShell->mResolution = mOldState.mResolution; +#ifdef ACCESSIBILITY + if (nsAccessibilityService* accService = GetAccService()) { + accService->NotifyOfResolutionChange(mPresShell, + mPresShell->GetResolution()); + } +#endif + } + + PresShell* mPresShell; + RenderingState mOldState; + }; + void SetRenderingState(const RenderingState& aState); + + friend class ::nsPresShellEventCB; + + // methods for painting a range to an offscreen buffer + + // given a display list, clip the items within the list to + // the range + nsRect ClipListToRange(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, + nsRange* aRange); + + // create a RangePaintInfo for the range aRange containing the + // display list needed to paint the range to a surface + UniquePtr<RangePaintInfo> CreateRangePaintInfo(nsRange* aRange, + nsRect& aSurfaceRect, + bool aForPrimarySelection); + + /* + * Paint the items to a new surface and return it. + * + * aSelection - selection being painted, if any + * aRegion - clip region, if any + * aArea - area that the surface occupies, relative to the root frame + * aPoint - reference point, typically the mouse position + * aScreenRect - [out] set to the area of the screen the painted area should + * be displayed at + * aFlags - set RenderImageFlags::AutoScale to scale down large images, but + * it must not be set if a custom image was specified + */ + already_AddRefed<SourceSurface> PaintRangePaintInfo( + const nsTArray<UniquePtr<RangePaintInfo>>& aItems, + dom::Selection* aSelection, const Maybe<CSSIntRegion>& aRegion, + nsRect aArea, const LayoutDeviceIntPoint aPoint, + LayoutDeviceIntRect* aScreenRect, RenderImageFlags aFlags); + + // Hide a view if it is a popup + void HideViewIfPopup(nsView* aView); + + // Utility method to restore the root scrollframe state + void RestoreRootScrollPosition(); + + MOZ_CAN_RUN_SCRIPT_BOUNDARY void MaybeReleaseCapturingContent(); + + class DelayedEvent { + public: + virtual ~DelayedEvent() = default; + virtual void Dispatch() {} + virtual bool IsKeyPressEvent() { return false; } + }; + + class DelayedInputEvent : public DelayedEvent { + public: + void Dispatch() override; + + protected: + DelayedInputEvent(); + ~DelayedInputEvent() override; + + WidgetInputEvent* mEvent; + }; + + class DelayedMouseEvent : public DelayedInputEvent { + public: + explicit DelayedMouseEvent(WidgetMouseEvent* aEvent); + }; + + class DelayedKeyEvent : public DelayedInputEvent { + public: + explicit DelayedKeyEvent(WidgetKeyboardEvent* aEvent); + bool IsKeyPressEvent() override; + }; + + /** + * return the nsPoint represents the location of the mouse event relative to + * the root document in visual coordinates + */ + nsPoint GetEventLocation(const WidgetMouseEvent& aEvent) const; + + // Check if aEvent is a mouse event and record the mouse location for later + // synth mouse moves. + void RecordPointerLocation(WidgetGUIEvent* aEvent); + inline bool MouseLocationWasSetBySynthesizedMouseEventForTests() const; + class nsSynthMouseMoveEvent final : public nsARefreshObserver { + public: + nsSynthMouseMoveEvent(PresShell* aPresShell, bool aFromScroll) + : mPresShell(aPresShell), mFromScroll(aFromScroll) { + NS_ASSERTION(mPresShell, "null parameter"); + } + + private: + // Private destructor, to discourage deletion outside of Release(): + ~nsSynthMouseMoveEvent() { Revoke(); } + + public: + NS_INLINE_DECL_REFCOUNTING(nsSynthMouseMoveEvent, override) + + void Revoke(); + + MOZ_CAN_RUN_SCRIPT + void WillRefresh(TimeStamp aTime) override { + if (mPresShell) { + RefPtr<PresShell> shell = mPresShell; + shell->ProcessSynthMouseMoveEvent(mFromScroll); + } + } + + private: + PresShell* mPresShell; + bool mFromScroll; + }; + MOZ_CAN_RUN_SCRIPT void ProcessSynthMouseMoveEvent(bool aFromScroll); + + void UpdateImageLockingState(); + + already_AddRefed<PresShell> GetParentPresShellForEventHandling(); + + /** + * EventHandler is implementation of PresShell::HandleEvent(). + */ + class MOZ_STACK_CLASS EventHandler final { + public: + EventHandler() = delete; + EventHandler(const EventHandler& aOther) = delete; + explicit EventHandler(PresShell& aPresShell) + : mPresShell(aPresShell), mCurrentEventInfoSetter(nullptr) {} + explicit EventHandler(RefPtr<PresShell>&& aPresShell) + : mPresShell(std::move(aPresShell)), mCurrentEventInfoSetter(nullptr) {} + + /** + * HandleEvent() may dispatch aGUIEvent. This may redirect the event to + * another PresShell, or the event may be handled by other classes like + * AccessibleCaretEventHub, or discarded. Otherwise, this sets current + * event info of mPresShell and calls HandleEventWithCurrentEventInfo() + * to dispatch the event into the DOM tree. + * + * @param aFrameForPresShell The frame for PresShell. If PresShell + * has root frame, it should be set. + * Otherwise, a frame which contains the + * PresShell should be set instead. I.e., + * in the latter case, the frame is in + * a parent document. + * @param aGUIEvent Event to be handled. Must be a trusted + * event. + * @param aDontRetargetEvents true if this shouldn't redirect the + * event to different PresShell. + * false if this can redirect the event to + * different PresShell. + * @param aEventStatus [in/out] EventStatus of aGUIEvent. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEvent(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, bool aDontRetargetEvents, + nsEventStatus* aEventStatus); + + /** + * HandleEventWithTarget() tries to dispatch aEvent on aContent after + * setting current event target content to aNewEventContent and current + * event frame to aNewEventFrame temporarily. Note that this supports + * WidgetEvent, not WidgetGUIEvent. So, you can dispatch a simple event + * with this. + * + * @param aEvent Event to be dispatched. Must be a + * trusted event. + * @param aNewEventFrame Temporal new event frame. + * @param aNewEventContent Temporal new event content. + * @param aEventStatus [in/out] EventStuatus of aEvent. + * @param aIsHandlingNativeEvent true if aEvent represents a native + * event. + * @param aTargetContent This is used only when aEvent is a + * pointer event. If + * PresShell::mPointerEventTarget is + * changed during dispatching aEvent, + * this is set to the new target. + * @param aOverrideClickTarget Override click event target. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventWithTarget(WidgetEvent* aEvent, + nsIFrame* aNewEventFrame, + nsIContent* aNewEventContent, + nsEventStatus* aEventStatus, + bool aIsHandlingNativeEvent, + nsIContent** aTargetContent, + nsIContent* aOverrideClickTarget); + + /** + * OnPresShellDestroy() is called when every PresShell instance is being + * destroyed. + */ + static inline void OnPresShellDestroy(Document* aDocument); + + private: + static bool InZombieDocument(nsIContent* aContent); + static nsIFrame* GetNearestFrameContainingPresShell(PresShell* aPresShell); + static nsIPrincipal* GetDocumentPrincipalToCompareWithBlacklist( + PresShell& aPresShell); + + /** + * HandleEventUsingCoordinates() handles aGUIEvent whose + * IsUsingCoordinates() returns true with the following helper methods. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. + * @param aGUIEvent The handling event. Make sure that + * its IsUsingCoordinates() returns true. + * @param aEventStatus The status of aGUIEvent. + * @param aDontRetargetEvents true if we've already retarget document. + * Otherwise, false. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventUsingCoordinates(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus, + bool aDontRetargetEvents); + + /** + * EventTargetData struct stores a set of a PresShell (event handler), + * a frame (to handle the event) and a content (event target for the frame). + */ + struct MOZ_STACK_CLASS EventTargetData final { + EventTargetData() = delete; + EventTargetData(const EventTargetData& aOther) = delete; + explicit EventTargetData(nsIFrame* aFrameToHandleEvent) { + SetFrameAndComputePresShell(aFrameToHandleEvent); + } + + void SetFrameAndComputePresShell(nsIFrame* aFrameToHandleEvent); + void SetFrameAndComputePresShellAndContent(nsIFrame* aFrameToHandleEvent, + WidgetGUIEvent* aGUIEvent); + void SetContentForEventFromFrame(WidgetGUIEvent* aGUIEvent); + + nsPresContext* GetPresContext() const { + return mPresShell ? mPresShell->GetPresContext() : nullptr; + }; + EventStateManager* GetEventStateManager() const { + nsPresContext* presContext = GetPresContext(); + return presContext ? presContext->EventStateManager() : nullptr; + } + Document* GetDocument() const { + return mPresShell ? mPresShell->GetDocument() : nullptr; + } + nsIContent* GetFrameContent() const; + + /** + * MaybeRetargetToActiveDocument() tries retarget aGUIEvent into + * active document if there is. Note that this does not support to + * retarget mContent. Make sure it is nullptr before calling this. + * + * @param aGUIEvent The handling event. + * @return true if retargetted. + */ + bool MaybeRetargetToActiveDocument(WidgetGUIEvent* aGUIEvent); + + /** + * ComputeElementFromFrame() computes mContent for aGUIEvent. If + * mContent is set by this method, mContent is always nullptr or an + * Element. + * + * @param aGUIEvent The handling event. + * @return true if caller can keep handling the event. + * Otherwise, false. + * Note that even if this returns true, mContent + * may be nullptr. + */ + bool ComputeElementFromFrame(WidgetGUIEvent* aGUIEvent); + + /** + * UpdateTouchEventTarget() updates mFrame, mPresShell and mContent if + * aGUIEvent is a touch event and there is new proper target. + * + * @param aGUIEvent The handled event. If it's not a touch event, + * this method does nothing. + */ + void UpdateTouchEventTarget(WidgetGUIEvent* aGUIEvent); + + RefPtr<PresShell> mPresShell; + nsIFrame* mFrame = nullptr; + nsCOMPtr<nsIContent> mContent; + nsCOMPtr<nsIContent> mOverrideClickTarget; + }; + + /** + * MaybeFlushPendingNotifications() maybe flush pending notifications if + * aGUIEvent should be handled with the latest layout. + * + * @param aGUIEvent The handling event. + * @return true if this actually flushes pending + * layout and that has caused changing the + * layout. + */ + MOZ_CAN_RUN_SCRIPT + bool MaybeFlushPendingNotifications(WidgetGUIEvent* aGUIEvent); + + /** + * GetFrameToHandleNonTouchEvent() returns a frame to handle the event. + * This may flush pending layout if the target is in child PresShell. + * + * @param aRootFrameToHandleEvent The root frame to handle the event. + * @param aGUIEvent The handling event. + * @return The frame which should handle the + * event. nullptr if the caller should + * stop handling the event. + */ + MOZ_CAN_RUN_SCRIPT + nsIFrame* GetFrameToHandleNonTouchEvent(nsIFrame* aRootFrameToHandleEvent, + WidgetGUIEvent* aGUIEvent); + + /** + * ComputeEventTargetFrameAndPresShellAtEventPoint() computes event + * target frame at the event point of aGUIEvent and set it to + * aEventTargetData. + * + * @param aRootFrameToHandleEvent The root frame to handle aGUIEvent. + * @param aGUIEvent The handling event. + * @param aEventTargetData [out] Its frame and PresShell will + * be set. + * @return true if the caller can handle the + * event. Otherwise, false. + */ + MOZ_CAN_RUN_SCRIPT + bool ComputeEventTargetFrameAndPresShellAtEventPoint( + nsIFrame* aRootFrameToHandleEvent, WidgetGUIEvent* aGUIEvent, + EventTargetData* aEventTargetData); + + /** + * DispatchPrecedingPointerEvent() dispatches preceding pointer event for + * aGUIEvent if Pointer Events is enabled. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. + * @param aGUIEvent The handled event. + * @param aPointerCapturingContent The content which is capturing pointer + * events if there is. Otherwise, nullptr. + * @param aDontRetargetEvents Set aDontRetargetEvents of + * HandleEvent() which called this method. + * @param aEventTargetData [in/out] Event target data of + * aGUIEvent. If pointer event listeners + * change the DOM tree or reframe the + * target, updated by this method. + * @param aEventStatus [in/out] The event status of aGUIEvent. + * @return true if the caller can handle the + * event. Otherwise, false. + */ + MOZ_CAN_RUN_SCRIPT + bool DispatchPrecedingPointerEvent(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsIContent* aPointerCapturingContent, + bool aDontRetargetEvents, + EventTargetData* aEventTargetData, + nsEventStatus* aEventStatus); + + /** + * MaybeDiscardEvent() checks whether it's safe to handle aGUIEvent right + * now. If it's not safe, this may notify somebody of discarding event if + * necessary. + * + * @param aGUIEvent Handling event. + * @return true if it's not safe to handle the event. + */ + bool MaybeDiscardEvent(WidgetGUIEvent* aGUIEvent); + + /** + * GetCapturingContentFor() returns capturing content for aGUIEvent. + * If aGUIEvent is not related to capturing, this returns nullptr. + */ + static nsIContent* GetCapturingContentFor(WidgetGUIEvent* aGUIEvent); + + /** + * GetRetargetEventDocument() returns a document if aGUIEvent should be + * handled in another document. + * + * @param aGUIEvent Handling event. + * @param aRetargetEventDocument Document which should handle aGUIEvent. + * @return true if caller can keep handling + * aGUIEvent. + */ + bool GetRetargetEventDocument(WidgetGUIEvent* aGUIEvent, + Document** aRetargetEventDocument); + + /** + * GetFrameForHandlingEventWith() returns a frame which should be used as + * aFrameForPresShell of HandleEvent(). See @return for the details. + * + * @param aGUIEvent Handling event. + * @param aRetargetDocument Document which aGUIEvent should be + * fired on. Typically, should be result + * of GetRetargetEventDocument(). + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. + * @return nullptr if caller should stop handling + * the event. + * aFrameForPresShell if caller should + * keep handling the event by itself. + * Otherwise, caller should handle it with + * another PresShell which is result of + * nsIFrame::PresContext()->GetPresShell(). + */ + nsIFrame* GetFrameForHandlingEventWith(WidgetGUIEvent* aGUIEvent, + Document* aRetargetDocument, + nsIFrame* aFrameForPresShell); + + /** + * MaybeHandleEventWithAnotherPresShell() may handle aGUIEvent with another + * PresShell. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. + * @param aGUIEvent Handling event. + * @param aEventStatus [in/out] EventStatus of aGUIEvent. + * @param aRv [out] Returns error if this gets an + * error handling the event. + * @return false if caller needs to keep handling + * the event by itself. + * true if caller shouldn't keep handling + * the event. Note that when no PresShell + * can handle the event, this returns true. + */ + MOZ_CAN_RUN_SCRIPT + bool MaybeHandleEventWithAnotherPresShell(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus, + nsresult* aRv); + + MOZ_CAN_RUN_SCRIPT + nsresult RetargetEventToParent(WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus); + + /** + * MaybeHandleEventWithAccessibleCaret() may handle aGUIEvent with + * AccessibleCaretEventHub if it's necessary. + * + * @param aFrameForPresShell The frame for PresShell. See explanation of + * HandleEvent() for the details. + * @param aGUIEvent Event may be handled by AccessibleCaretEventHub. + * @param aEventStatus [in/out] EventStatus of aGUIEvent. + * @return true if AccessibleCaretEventHub handled the + * event and caller shouldn't keep handling it. + */ + MOZ_CAN_RUN_SCRIPT + bool MaybeHandleEventWithAccessibleCaret(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus); + + /** + * MaybeDiscardOrDelayKeyboardEvent() may discared or put aGUIEvent into + * the delayed event queue if it's a keyboard event and if we should do so. + * If aGUIEvent is not a keyboard event, this does nothing. + * + * @param aGUIEvent The handling event. + * @return true if this method discard the event or + * put it into the delayed event queue. + */ + bool MaybeDiscardOrDelayKeyboardEvent(WidgetGUIEvent* aGUIEvent); + + /** + * MaybeDiscardOrDelayMouseEvent() may discard or put aGUIEvent into the + * delayed event queue if it's a mouse event and if we should do so. + * If aGUIEvent is not a mouse event, this does nothing. + * If there is suppressed event listener like debugger of devtools, this + * notifies it of the event after discard or put it into the delayed + * event queue. + * + * @param aFrameToHandleEvent The frame to handle aGUIEvent. + * @param aGUIEvent The handling event. + * @return true if this method discard the event + * or put it into the delayed event queue. + */ + bool MaybeDiscardOrDelayMouseEvent(nsIFrame* aFrameToHandleEvent, + WidgetGUIEvent* aGUIEvent); + + /** + * MaybeFlushThrottledStyles() tries to flush pending animation. If it's + * flushed and then aFrameForPresShell is destroyed, returns new frame + * which contains mPresShell. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. This can be nullptr. + * @return Maybe new frame for mPresShell. + * If aFrameForPresShell is not nullptr + * and hasn't been destroyed, returns + * aFrameForPresShell as-is. + */ + MOZ_CAN_RUN_SCRIPT + nsIFrame* MaybeFlushThrottledStyles(nsIFrame* aFrameForPresShell); + + /** + * ComputeRootFrameToHandleEvent() returns root frame to handle the event. + * For example, if there is a popup, this returns the popup frame. + * If there is capturing content and it's in a scrolled frame, returns + * the scrolled frame. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for + * the details. + * @param aGUIEvent The handling event. + * @param aCapturingContent Capturing content if there is. + * nullptr, otherwise. + * @param aIsCapturingContentIgnored [out] true if aCapturingContent + * is not nullptr but it should be + * ignored to handle the event. + * @param aIsCaptureRetargeted [out] true if aCapturingContent + * is not nullptr but it's + * retargeted. + * @return Root frame to handle the event. + */ + nsIFrame* ComputeRootFrameToHandleEvent(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsIContent* aCapturingContent, + bool* aIsCapturingContentIgnored, + bool* aIsCaptureRetargeted); + + /** + * ComputeRootFrameToHandleEventWithPopup() returns popup frame if there + * is a popup and we should handle the event in it. Otherwise, returns + * aRootFrameToHandleEvent. + * + * @param aRootFrameToHandleEvent Candidate root frame to handle + * the event. + * @param aGUIEvent The handling event. + * @param aCapturingContent Capturing content if there is. + * nullptr, otherwise. + * @param aIsCapturingContentIgnored [out] true if aCapturingContent + * is not nullptr but it should be + * ignored to handle the event. + * @return A popup frame if there is a + * popup and we should handle the + * event in it. Otherwise, + * aRootFrameToHandleEvent. + * I.e., never returns nullptr. + */ + nsIFrame* ComputeRootFrameToHandleEventWithPopup( + nsIFrame* aRootFrameToHandleEvent, WidgetGUIEvent* aGUIEvent, + nsIContent* aCapturingContent, bool* aIsCapturingContentIgnored); + + /** + * ComputeRootFrameToHandleEventWithCapturingContent() returns root frame + * to handle event for the capturing content, or aRootFrameToHandleEvent + * if it should be ignored. + * + * @param aRootFrameToHandleEvent Candidate root frame to handle + * the event. + * @param aCapturingContent Capturing content. nullptr is + * not allowed. + * @param aIsCapturingContentIgnored [out] true if aCapturingContent + * is not nullptr but it should be + * ignored to handle the event. + * @param aIsCaptureRetargeted [out] true if aCapturingContent + * is not nullptr but it's + * retargeted. + * @return A popup frame if there is a + * popup and we should handle the + * event in it. Otherwise, + * aRootFrameToHandleEvent. + * I.e., never returns nullptr. + */ + nsIFrame* ComputeRootFrameToHandleEventWithCapturingContent( + nsIFrame* aRootFrameToHandleEvent, nsIContent* aCapturingContent, + bool* aIsCapturingContentIgnored, bool* aIsCaptureRetargeted); + + /** + * HandleEventWithPointerCapturingContentWithoutItsFrame() handles + * aGUIEvent with aPointerCapturingContent when it does not have primary + * frame. + * + * @param aFrameForPresShell The frame for PresShell. See + * explanation of HandleEvent() for the + * details. + * @param aGUIEvent The handling event. + * @param aPointerCapturingContent Current pointer capturing content. + * Must not be nullptr. + * @param aEventStatus [in/out] The event status of aGUIEvent. + * @return Basically, result of + * HandeEventWithTraget(). + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventWithPointerCapturingContentWithoutItsFrame( + nsIFrame* aFrameForPresShell, WidgetGUIEvent* aGUIEvent, + nsIContent* aPointerCapturingContent, nsEventStatus* aEventStatus); + + /** + * HandleEventAtFocusedContent() handles aGUIEvent at focused content. + * + * @param aGUIEvent The handling event which should be handled at + * focused content. + * @param aEventStatus [in/out] The event status of aGUIEvent. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventAtFocusedContent(WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus); + + /** + * ComputeFocusedEventTargetElement() returns event target element for + * aGUIEvent which should be handled with focused content. + * This may set/unset sLastKeyDownEventTarget if necessary. + * + * @param aGUIEvent The handling event. + * @return The element which should be the event + * target of aGUIEvent. + */ + dom::Element* ComputeFocusedEventTargetElement(WidgetGUIEvent* aGUIEvent); + + /** + * MaybeHandleEventWithAnotherPresShell() may handle aGUIEvent with another + * PresShell. + * + * @param aEventTargetElement The event target element of aGUIEvent. + * @param aGUIEvent Handling event. + * @param aEventStatus [in/out] EventStatus of aGUIEvent. + * @param aRv [out] Returns error if this gets an + * error handling the event. + * @return false if caller needs to keep handling + * the event by itself. + * true if caller shouldn't keep handling + * the event. Note that when no PresShell + * can handle the event, this returns true. + */ + MOZ_CAN_RUN_SCRIPT + bool MaybeHandleEventWithAnotherPresShell(dom::Element* aEventTargetElement, + WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus, + nsresult* aRv); + + /** + * HandleRetargetedEvent() dispatches aGUIEvent on the PresShell without + * retargetting. This should be used only when caller computes final + * target of aGUIEvent. + * + * @param aGUIEvent Event to be dispatched. + * @param aEventStatus [in/out] EventStatus of aGUIEvent. + * @param aTarget The final target of aGUIEvent. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleRetargetedEvent(WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus, + nsIContent* aTarget) { + AutoCurrentEventInfoSetter eventInfoSetter(*this, nullptr, aTarget); + if (!mPresShell->GetCurrentEventFrame()) { + return NS_OK; + } + nsCOMPtr<nsIContent> overrideClickTarget; + return HandleEventWithCurrentEventInfo(aGUIEvent, aEventStatus, true, + overrideClickTarget); + } + + /** + * HandleEventWithFrameForPresShell() handles aGUIEvent with the frame + * for mPresShell. + * + * @param aFrameForPresShell The frame for mPresShell. + * @param aGUIEvent The handling event. It shouldn't be + * handled with using coordinates nor + * handled at focused content. + * @param aEventStatus [in/out] The status of aGUIEvent. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventWithFrameForPresShell(nsIFrame* aFrameForPresShell, + WidgetGUIEvent* aGUIEvent, + nsEventStatus* aEventStatus); + + /** + * HandleEventWithCurrentEventInfo() prepares to dispatch aEvent into the + * DOM, dispatches aEvent into the DOM with using current event info of + * mPresShell and notifies EventStateManager of that. + * + * @param aEvent Event to be dispatched. + * @param aEventStatus [in/out] EventStatus of aEvent. + * @param aIsHandlingNativeEvent true if aGUIEvent represents a native + * event. + * @param aOverrideClickTarget Override click event target. + */ + MOZ_CAN_RUN_SCRIPT + nsresult HandleEventWithCurrentEventInfo(WidgetEvent* aEvent, + nsEventStatus* aEventStatus, + bool aIsHandlingNativeEvent, + nsIContent* aOverrideClickTarget); + + /** + * HandlingTimeAccumulator() may accumulate handling time of telemetry + * for each type of events. + */ + class MOZ_STACK_CLASS HandlingTimeAccumulator final { + public: + HandlingTimeAccumulator() = delete; + HandlingTimeAccumulator(const HandlingTimeAccumulator& aOther) = delete; + HandlingTimeAccumulator(const EventHandler& aEventHandler, + const WidgetEvent* aEvent); + ~HandlingTimeAccumulator(); + + private: + const EventHandler& mEventHandler; + const WidgetEvent* mEvent; + TimeStamp mHandlingStartTime; + }; + + /** + * RecordEventPreparationPerformance() records event preparation performance + * with telemetry only when aEvent is a trusted event. + * + * @param aEvent The handling event which we've finished + * preparing something to dispatch. + */ + void RecordEventPreparationPerformance(const WidgetEvent* aEvent); + + /** + * RecordEventHandlingResponsePerformance() records event handling response + * performance with telemetry. + * + * @param aEvent The handled event. + */ + void RecordEventHandlingResponsePerformance(const WidgetEvent* aEvent); + + /** + * PrepareToDispatchEvent() prepares to dispatch aEvent. + * + * @param aEvent The handling event. + * @param aEventStatus [in/out] The status of aEvent. + * @param aTouchIsNew [out] Set to true if the event is an + * eTouchMove event and it represents new + * touch. Otherwise, set to false. + * @return true if the caller can dispatch the + * event into the DOM. + */ + MOZ_CAN_RUN_SCRIPT + bool PrepareToDispatchEvent(WidgetEvent* aEvent, + nsEventStatus* aEventStatus, bool* aTouchIsNew); + + /** + * MaybeHandleKeyboardEventBeforeDispatch() may handle aKeyboardEvent + * if it should do something before dispatched into the DOM. + * + * @param aKeyboardEvent The handling keyboard event. + */ + MOZ_CAN_RUN_SCRIPT + void MaybeHandleKeyboardEventBeforeDispatch( + WidgetKeyboardEvent* aKeyboardEvent); + + /** + * This and the next two helper methods are used to target and position the + * context menu when the keyboard shortcut is used to open it. + * + * If another menu is open, the context menu is opened relative to the + * active menuitem within the menu, or the menu itself if no item is active. + * Otherwise, if the caret is visible, the menu is opened near the caret. + * Otherwise, if a selectable list such as a listbox is focused, the + * current item within the menu is opened relative to this item. + * Otherwise, the context menu is opened at the topleft corner of the + * view. + * + * Returns true if the context menu event should fire and false if it should + * not. + */ + MOZ_CAN_RUN_SCRIPT + bool AdjustContextMenuKeyEvent(WidgetMouseEvent* aMouseEvent); + + MOZ_CAN_RUN_SCRIPT + bool PrepareToUseCaretPosition(nsIWidget* aEventWidget, + LayoutDeviceIntPoint& aTargetPt); + + /** + * Get the selected item and coordinates in device pixels relative to root + * document's root view for element, first ensuring the element is onscreen. + */ + MOZ_CAN_RUN_SCRIPT + void GetCurrentItemAndPositionForElement(dom::Element* aFocusedElement, + nsIContent** aTargetToUse, + LayoutDeviceIntPoint& aTargetPt, + nsIWidget* aRootWidget); + + nsIContent* GetOverrideClickTarget(WidgetGUIEvent* aGUIEvent, + nsIFrame* aFrame); + + /** + * DispatchEvent() tries to dispatch aEvent and notifies aEventStateManager + * of doing it. + * + * @param aEventStateManager EventStateManager which should handle + * the event before/after dispatching + * aEvent into the DOM. + * @param aEvent The handling event. + * @param aTouchIsNew Set this to true when the message is + * eTouchMove and it's newly touched. + * Then, the "touchmove" event becomes + * cancelable. + * @param aEventStatus [in/out] The status of aEvent. + * @param aOverrideClickTarget Override click event target. + */ + MOZ_CAN_RUN_SCRIPT nsresult + DispatchEvent(EventStateManager* aEventStateManager, WidgetEvent* aEvent, + bool aTouchIsNew, nsEventStatus* aEventStatus, + nsIContent* aOverrideClickTarget); + + /** + * DispatchEventToDOM() actually dispatches aEvent into the DOM tree. + * + * @param aEvent Event to be dispatched into the DOM tree. + * @param aEventStatus [in/out] EventStatus of aEvent. + * @param aEventCB The callback kicked when the event moves + * from the default group to the system group. + */ + MOZ_CAN_RUN_SCRIPT nsresult + DispatchEventToDOM(WidgetEvent* aEvent, nsEventStatus* aEventStatus, + nsPresShellEventCB* aEventCB); + + /** + * DispatchTouchEventToDOM() dispatches touch events into the DOM tree. + * + * @param aEvent The source of events to be dispatched into the + * DOM tree. + * @param aEventStatus [in/out] EventStatus of aEvent. + * @param aEventCB The callback kicked when the events move + * from the default group to the system group. + * @param aTouchIsNew Set this to true when the message is eTouchMove + * and it's newly touched. Then, the "touchmove" + * event becomes cancelable. + */ + MOZ_CAN_RUN_SCRIPT void DispatchTouchEventToDOM( + WidgetEvent* aEvent, nsEventStatus* aEventStatus, + nsPresShellEventCB* aEventCB, bool aTouchIsNew); + + /** + * FinalizeHandlingEvent() should be called after calling DispatchEvent() + * and then, this cleans up the state of mPresShell and aEvent. + * + * @param aEvent The handled event. + */ + void FinalizeHandlingEvent(WidgetEvent* aEvent); + + /** + * AutoCurrentEventInfoSetter() pushes and pops current event info of + * aEventHandler.mPresShell. + */ + struct MOZ_STACK_CLASS AutoCurrentEventInfoSetter final { + explicit AutoCurrentEventInfoSetter(EventHandler& aEventHandler) + : mEventHandler(aEventHandler) { + MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); + mEventHandler.mCurrentEventInfoSetter = this; + mEventHandler.mPresShell->PushCurrentEventInfo(nullptr, nullptr); + } + AutoCurrentEventInfoSetter(EventHandler& aEventHandler, nsIFrame* aFrame, + nsIContent* aContent) + : mEventHandler(aEventHandler) { + MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); + mEventHandler.mCurrentEventInfoSetter = this; + mEventHandler.mPresShell->PushCurrentEventInfo(aFrame, aContent); + } + AutoCurrentEventInfoSetter(EventHandler& aEventHandler, + EventTargetData& aEventTargetData) + : mEventHandler(aEventHandler) { + MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); + mEventHandler.mCurrentEventInfoSetter = this; + mEventHandler.mPresShell->PushCurrentEventInfo( + aEventTargetData.mFrame, aEventTargetData.mContent); + } + ~AutoCurrentEventInfoSetter() { + mEventHandler.mPresShell->PopCurrentEventInfo(); + mEventHandler.mCurrentEventInfoSetter = nullptr; + } + + private: + EventHandler& mEventHandler; + }; + + /** + * Wrapper methods to access methods of mPresShell. + */ + nsPresContext* GetPresContext() const { + return mPresShell->GetPresContext(); + } + Document* GetDocument() const { return mPresShell->GetDocument(); } + nsCSSFrameConstructor* FrameConstructor() const { + return mPresShell->FrameConstructor(); + } + already_AddRefed<nsPIDOMWindowOuter> GetFocusedDOMWindowInOurWindow() { + return mPresShell->GetFocusedDOMWindowInOurWindow(); + } + already_AddRefed<PresShell> GetParentPresShellForEventHandling() { + return mPresShell->GetParentPresShellForEventHandling(); + } + OwningNonNull<PresShell> mPresShell; + AutoCurrentEventInfoSetter* mCurrentEventInfoSetter; + static TimeStamp sLastInputCreated; + static TimeStamp sLastInputProcessed; + static StaticRefPtr<dom::Element> sLastKeyDownEventTargetElement; + }; + + PresShell* GetRootPresShell() const; + + bool IsTransparentContainerElement() const; + ColorScheme DefaultBackgroundColorScheme() const; + nscolor GetDefaultBackgroundColorToDraw() const; + + ////////////////////////////////////////////////////////////////////////////// + // Approximate frame visibility tracking implementation. + ////////////////////////////////////////////////////////////////////////////// + + void UpdateApproximateFrameVisibility(); + void DoUpdateApproximateFrameVisibility(bool aRemoveOnly); + + void ClearApproximatelyVisibleFramesList( + const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()); + static void ClearApproximateFrameVisibilityVisited(nsView* aView, + bool aClear); + static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList); + void MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame, + const nsRect& aRect, + bool aRemoveOnly = false); + + void DecApproximateVisibleCount( + VisibleFrames& aFrames, + const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()); + + nsRevocableEventPtr<nsRunnableMethod<PresShell>> + mUpdateApproximateFrameVisibilityEvent; + + // A set of frames that were visible or could be visible soon at the time + // that we last did an approximate frame visibility update. + VisibleFrames mApproximatelyVisibleFrames; + +#ifdef DEBUG + MOZ_CAN_RUN_SCRIPT_BOUNDARY bool VerifyIncrementalReflow(); + MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoVerifyReflow(); + void VerifyHasDirtyRootAncestor(nsIFrame* aFrame); + + bool mInVerifyReflow = false; + // The reflow root under which we're currently reflowing. Null when + // not in reflow. + nsIFrame* mCurrentReflowRoot = nullptr; +#endif // #ifdef DEBUG + + // Send, and reset, the current per tick telemetry. This includes: + // * non-zero number of style and layout flushes + // * non-zero ms duration spent in style and reflow since the last tick. + void PingPerTickTelemetry(FlushType aFlushType); + + private: + // IMPORTANT: The ownership implicit in the following member variables + // has been explicitly checked. If you add any members to this class, + // please make the ownership explicit (pinkerton, scc). + + // These are the same Document and PresContext owned by the DocViewer. + // we must share ownership. + // mDocument and mPresContext should've never been cleared nor swapped with + // another instance while PresShell instance is alive so that it's safe to + // call their can-run- script methods without local RefPtr variables. + MOZ_KNOWN_LIVE RefPtr<Document> const mDocument; + MOZ_KNOWN_LIVE RefPtr<nsPresContext> const mPresContext; + // The document's style set owns it but we maintain a ref, may be null. + RefPtr<StyleSheet> mPrefStyleSheet; + UniquePtr<nsCSSFrameConstructor> mFrameConstructor; + nsViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to + RefPtr<nsFrameSelection> mSelection; + // The frame selection that last took focus on this shell, which we need to + // hide if we focus another selection. May or may not be the same as + // `mSelection`. + RefPtr<nsFrameSelection> mFocusedFrameSelection; + RefPtr<nsCaret> mCaret; + RefPtr<nsCaret> mOriginalCaret; + RefPtr<AccessibleCaretEventHub> mAccessibleCaretEventHub; + // Pointer into mFrameConstructor - this is purely so that GetRootFrame() can + // be inlined: + nsFrameManager* mFrameManager; + WeakPtr<nsDocShell> mForwardingContainer; + + // The `performance.now()` value when we last started to process reflows. + DOMHighResTimeStamp mLastReflowStart{0.0}; + + // At least on Win32 and Mac after interupting a reflow we need to post + // the resume reflow event off a timer to avoid event starvation because + // posted messages are processed before other messages when the modal + // moving/sizing loop is running, see bug 491700 for details. + nsCOMPtr<nsITimer> mReflowContinueTimer; + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + // We track allocated pointers in a diagnostic hash set, to assert against + // missing/double frees. This set is allocated infallibly in the PresShell + // constructor's initialization list. The set can get quite large, so we use + // fallible allocation when inserting into it; and if these operations ever + // fail, then we just get rid of the set and stop using this diagnostic from + // that point on. (There's not much else we can do, when the set grows + // larger than the available memory.) + UniquePtr<nsTHashSet<void*>> mAllocatedPointers; +#endif + + // A list of stack weak frames. This is a pointer to the last item in the + // list. + AutoWeakFrame* mAutoWeakFrames; + + // A hash table of heap allocated weak frames. + nsTHashSet<WeakFrame*> mWeakFrames; + + // Reflow roots that need to be reflowed. + DepthOrderedFrameList mDirtyRoots; + + // These two fields capture call stacks of any changes that require a restyle + // or a reflow. Only the first change per restyle / reflow is recorded (the + // one that caused a call to SetNeedStyleFlush() / SetNeedLayoutFlush()). + UniquePtr<ProfileChunkedBuffer> mStyleCause; + UniquePtr<ProfileChunkedBuffer> mReflowCause; + + nsTArray<UniquePtr<DelayedEvent>> mDelayedEvents; + + nsRevocableEventPtr<nsSynthMouseMoveEvent> mSynthMouseMoveEvent; + + TouchManager mTouchManager; + + RefPtr<ZoomConstraintsClient> mZoomConstraintsClient; + RefPtr<GeckoMVMContext> mMVMContext; + RefPtr<MobileViewportManager> mMobileViewportManager; + + // This timer controls painting suppression. Until it fires + // or all frames are constructed, we won't paint anything but + // our <body> background and scrollbars. + nsCOMPtr<nsITimer> mPaintSuppressionTimer; + + // Information about live content (which still stay in DOM tree). + // Used in case we need re-dispatch event after sending pointer event, + // when target of pointer event was deleted during executing user handlers. + nsCOMPtr<nsIContent> mPointerEventTarget; + + nsCOMPtr<nsIContent> mLastAnchorScrolledTo; + + // Information needed to properly handle scrolling content into view if the + // pre-scroll reflow flush can be interrupted. mContentToScrollTo is non-null + // between the initial scroll attempt and the first time we finish processing + // all our dirty roots. mContentToScrollTo has a content property storing the + // details for the scroll operation, see ScrollIntoViewData above. + nsCOMPtr<nsIContent> mContentToScrollTo; + +#ifdef ACCESSIBILITY + a11y::DocAccessible* mDocAccessible; +#endif // #ifdef ACCESSIBILITY + + nsIFrame* mCurrentEventFrame; + nsCOMPtr<nsIContent> mCurrentEventContent; + nsTArray<nsIFrame*> mCurrentEventFrameStack; + nsCOMArray<nsIContent> mCurrentEventContentStack; + // Set of frames that we should mark with NS_FRAME_HAS_DIRTY_CHILDREN after + // we finish reflowing mCurrentReflowRoot. + nsTHashSet<nsIFrame*> mFramesToDirty; + nsTHashSet<nsIScrollableFrame*> mPendingScrollAnchorSelection; + nsTHashSet<nsIScrollableFrame*> mPendingScrollAnchorAdjustment; + nsTHashSet<nsIScrollableFrame*> mPendingScrollResnap; + + nsTHashSet<nsIContent*> mHiddenContentInForcedLayout; + + nsTHashSet<nsIFrame*> mContentVisibilityAutoFrames; + + // The type of content relevancy to update the next time content relevancy + // updates are triggered for `content-visibility: auto` frames. + ContentRelevancy mContentVisibilityRelevancyToUpdate; + + nsCallbackEventRequest* mFirstCallbackEventRequest = nullptr; + nsCallbackEventRequest* mLastCallbackEventRequest = nullptr; + + // This is used for synthetic mouse events that are sent when what is under + // the mouse pointer may have changed without the mouse moving (eg scrolling, + // change to the document contents). + // It is set only on a presshell for a root document, this value represents + // the last observed location of the mouse relative to that root document, + // in visual coordinates. It is set to (NS_UNCONSTRAINEDSIZE, + // NS_UNCONSTRAINEDSIZE) if the mouse isn't over our window or there is no + // last observed mouse location for some reason. + nsPoint mMouseLocation; + // The last observed pointer location relative to that root document in visual + // coordinates. + nsPoint mLastOverWindowPointerLocation; + // This is an APZ state variable that tracks the target guid for the last + // mouse event that was processed (corresponding to mMouseLocation). This is + // needed for the synthetic mouse events. + layers::ScrollableLayerGuid mMouseEventTargetGuid; + + // Only populated on root content documents. + nsSize mVisualViewportSize; + + // The focus information needed for async keyboard scrolling + FocusTarget mAPZFocusTarget; + + using Arena = nsPresArena<8192, ArenaObjectID, eArenaObjectID_COUNT>; + Arena mFrameArena; + + Maybe<nsPoint> mVisualViewportOffset; + + // A pending visual scroll offset that we will ask APZ to scroll to + // during the next transaction. Cleared when we send the transaction. + // Only applicable to the RCD pres shell. + Maybe<VisualScrollUpdate> mPendingVisualScrollUpdate; + + // Used to force allocation and rendering of proportionally more or + // less pixels in both dimensions. + Maybe<float> mResolution; + ResolutionChangeOrigin mLastResolutionChangeOrigin; + + TimeStamp mLoadBegin; // used to time loads + + TimeStamp mLastOSWake; + + // Count of the number of times this presshell has been painted to a window. + uint64_t mPaintCount; + + // The focus sequence number of the last processed input event + uint64_t mAPZFocusSequenceNumber; + + nscoord mLastAnchorScrollPositionY = 0; + + // Most recent canvas background color. + nscolor mCanvasBackgroundColor; + + int32_t mActiveSuppressDisplayport; + + uint32_t mPresShellId; + + // Cached font inflation values. This is done to prevent changing of font + // inflation until a page is reloaded. + uint32_t mFontSizeInflationEmPerLine; + uint32_t mFontSizeInflationMinTwips; + uint32_t mFontSizeInflationLineThreshold; + + // Can be multiple of nsISelectionDisplay::DISPLAY_*. + int16_t mSelectionFlags; + + // This is used to protect ourselves from triggering reflow while in the + // middle of frame construction and the like... it really shouldn't be + // needed, one hopes, but it is for now. + uint16_t mChangeNestCount; + + // Flags controlling how our document is rendered. These persist + // between paints and so are tied with retained layer pixels. + // PresShell flushes retained layers when the rendering state + // changes in a way that prevents us from being able to (usefully) + // re-use old pixels. + RenderingStateFlags mRenderingStateFlags; + + // Whether we're currently under a FlushPendingNotifications. + // This is used to handle flush reentry correctly. + // NOTE: This can't be a bitfield since AutoRestore has a reference to this + // variable. + bool mInFlush; + + bool mCaretEnabled : 1; + + // True if a layout flush might not be a no-op + bool mNeedLayoutFlush : 1; + + // True if a style flush might not be a no-op + bool mNeedStyleFlush : 1; + + // True if there are throttled animations that would be processed when + // performing a flush with mFlushAnimations == true. + bool mNeedThrottledAnimationFlush : 1; + + bool mVisualViewportSizeSet : 1; + + bool mDidInitialize : 1; + bool mIsDestroying : 1; + bool mIsReflowing : 1; + bool mIsObservingDocument : 1; + + // Whether we shouldn't ever get to FlushPendingNotifications. This flag is + // meant only to sanity-check / assert that FlushPendingNotifications doesn't + // happen during certain periods of time. It shouldn't be made public nor used + // for other purposes. + bool mForbiddenToFlush : 1; + + // We've been disconnected from the document. We will refuse to paint the + // document until either our timer fires or all frames are constructed. + bool mIsDocumentGone : 1; + bool mHaveShutDown : 1; + + // For all documents we initially lock down painting. + bool mPaintingSuppressed : 1; + + bool mLastRootReflowHadUnconstrainedBSize : 1; + + // Indicates that it is safe to unlock painting once all pending reflows + // have been processed. + bool mShouldUnsuppressPainting : 1; + + bool mIgnoreFrameDestruction : 1; + + bool mIsActive : 1; + bool mIsInActiveTab : 1; + bool mFrozen : 1; + bool mIsFirstPaint : 1; + bool mObservesMutationsForPrint : 1; + + // Whether the most recent interruptible reflow was actually interrupted: + bool mWasLastReflowInterrupted : 1; + + // True if we're observing the refresh driver for style flushes. + bool mObservingStyleFlushes : 1; + + // True if we're observing the refresh driver for layout flushes, that is, if + // we have a reflow scheduled. + // + // Guaranteed to be false if mReflowContinueTimer is non-null. + bool mObservingLayoutFlushes : 1; + + bool mResizeEventPending : 1; + + bool mFontSizeInflationForceEnabled : 1; + bool mFontSizeInflationDisabledInMasterProcess : 1; + bool mFontSizeInflationEnabled : 1; + + // If a document belongs to an invisible DocShell, this flag must be set + // to true, so we can avoid any paint calls for widget related to this + // presshell. + bool mIsNeverPainting : 1; + + // Whether the most recent change to the pres shell resolution was + // originated by the main thread. + bool mResolutionUpdated : 1; + + // True if the resolution has been ever changed by APZ. + bool mResolutionUpdatedByApz : 1; + + // Whether this presshell is hidden by 'vibility:hidden' on an ancestor + // nsSubDocumentFrame. + bool mUnderHiddenEmbedderElement : 1; + + bool mDocumentLoading : 1; + bool mNoDelayedMouseEvents : 1; + bool mNoDelayedKeyEvents : 1; + + bool mApproximateFrameVisibilityVisited : 1; + + bool mHasCSSBackgroundColor : 1; + + // Whether the last chrome-only escape key event is consumed. + bool mIsLastChromeOnlyEscapeKeyConsumed : 1; + + // Whether the widget has received a paint message yet. + bool mHasReceivedPaintMessage : 1; + + bool mIsLastKeyDownCanceled : 1; + + // Whether we have ever handled a user input event + bool mHasHandledUserInput : 1; + + // Whether we should dispatch keypress events even for non-printable keys + // for keeping backward compatibility. + bool mForceDispatchKeyPressEventsForNonPrintableKeys : 1; + // Whether we should set keyCode or charCode value of keypress events whose + // value is zero to the other value or not. When this is set to true, we + // should keep using legacy keyCode and charCode values (i.e., one of them + // is always 0). + bool mForceUseLegacyKeyCodeAndCharCodeValues : 1; + // Whether mForceDispatchKeyPressEventsForNonPrintableKeys and + // mForceUseLegacyKeyCodeAndCharCodeValues are initialized. + bool mInitializedWithKeyPressEventDispatchingBlacklist : 1; + + // Whether we should dispatch click events for non-primary mouse buttons. + bool mForceUseLegacyNonPrimaryDispatch : 1; + // Whether mForceUseLegacyNonPrimaryDispatch is initialised. + bool mInitializedWithClickEventDispatchingBlacklist : 1; + + // Set to true if mMouseLocation is set by a mouse event which is synthesized + // for tests. + bool mMouseLocationWasSetBySynthesizedMouseEventForTests : 1; + + bool mHasTriedFastUnsuppress : 1; + + bool mProcessingReflowCommands : 1; + bool mPendingDidDoReflow : 1; + + struct CapturingContentInfo final { + CapturingContentInfo() + : mRemoteTarget(nullptr), + mAllowed(false), + mPointerLock(false), + mRetargetToElement(false), + mPreventDrag(false) {} + + // capture should only be allowed during a mousedown event + StaticRefPtr<nsIContent> mContent; + dom::BrowserParent* mRemoteTarget; + bool mAllowed; + bool mPointerLock; + bool mRetargetToElement; + bool mPreventDrag; + }; + static CapturingContentInfo sCapturingContentInfo; + + static bool sDisableNonTestMouseEvents; + + static bool sProcessInteractable; + + layout_telemetry::Data mLayoutTelemetry; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(PresShell, NS_PRESSHELL_IID) + +} // namespace mozilla + +#endif // mozilla_PresShell_h |