Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/layout/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 432 kB image not shown  

Quelle  PresShell.cpp   Sprache: C

 
/* -*- 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 */

#include "mozilla/PresShell.h"

#include <algorithm>

#include "AutoProfilerStyleMarker.h"
#include "ChildIterator.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxUserFontSet.h"
#include "gfxUtils.h"
#include "MobileViewportManager.h"
#include "mozilla/AccessibleCaretEventHub.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/CaretAssociationHint.h"
#include "mozilla/ContentIterator.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/DisplayPortUtils.h"
#include "mozilla/dom/AncestorIterator.h"
#include "mozilla/dom/BrowserBridgeChild.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/DOMIntersectionObserver.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/FragmentDirective.h"
#include "mozilla/dom/HTMLAreaElement.h"
#include "mozilla/dom/ImageTracker.h"
#include "mozilla/dom/LargestContentfulPaint.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceMainThread.h"
#include "mozilla/dom/PointerEventBinding.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/ShadowIncludingTreeIterator.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventForwards.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/GeckoMVMContext.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/GlobalStyleSheetCache.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/InputTaskManager.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/layers/APZPublicUtils.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/FocusTarget.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/layers/ScrollingInteractionContext.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/layout/ScrollAnchorContainer.h"
#include "mozilla/Likely.h"
#include "mozilla/Logging.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PerfStats.h"
#include "mozilla/PointerLockManager.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/RangeUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RestyleManager.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/ScrollTimelineAnimationTracker.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/SMILAnimationController.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/StaticPrefs_apz.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_font.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StaticPrefs_test.h"
#include "mozilla/StaticPrefs_toolkit.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/SVGFragmentIdentifier.h"
#include "mozilla/SVGObserverUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/Try.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/ViewportFrame.h"
#include "mozilla/ViewportUtils.h"
#include "nsAnimationManager.h"
#include "nsAutoLayoutPhase.h"
#include "nsCanvasFrame.h"
#include "nsCaret.h"
#include "nsClassHashtable.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsContainerFrame.h"
#include "nsContentList.h"
#include "nsCRTGlue.h"
#include "nsCSSFrameConstructor.h"
#include "nsCSSRendering.h"
#include "nsDisplayList.h"
#include "nsDocShell.h"  // for reflow observation
#include "nsDOMNavigationTiming.h"
#include "nsError.h"
#include "nsFlexContainerFrame.h"
#include "nsFocusManager.h"
#include "nsFrameSelection.h"
#include "nsGkAtoms.h"
#include "nsGlobalWindowOuter.h"
#include "nsHashKeys.h"
#include "nsIBaseWindow.h"
#include "nsIContent.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDragSession.h"
#include "nsIFrame.h"
#include "nsIFrameInlines.h"
#include "nsILayoutHistoryState.h"
#include "nsILineIterator.h"  // for ScrollContentIntoView
#include "nsImageFrame.h"
#include "nsIObserverService.h"
#include "nsIReflowCallback.h"
#include "nsIScreen.h"
#include "nsIScreenManager.h"
#include "nsITimer.h"
#include "nsIURI.h"
#include "nsLayoutUtils.h"
#include "nsMenuPopupFrame.h"
#include "nsNameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
#include "nsNetUtil.h"
#include "nsNetUtil.h"
#include "nsPageSequenceFrame.h"
#include "nsPIDOMWindow.h"
#include "nsPlaceholderFrame.h"
#include "nsPresContext.h"
#include "nsQueryObject.h"
#include "nsRange.h"
#include "nsReadableUtils.h"
#include "nsRefreshDriver.h"
#include "nsRegion.h"
#include "nsStyleChangeList.h"
#include "nsStyleSheetService.h"
#include "nsSubDocumentFrame.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsTransitionManager.h"
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
#include "nsView.h"
#include "nsViewManager.h"
#include "nsViewportInfo.h"
#include "nsWindowSizes.h"
#include "nsXPCOM.h"
#include "nsXULElement.h"
#include "OverflowChangedTracker.h"
#include "PLDHashTable.h"
#include "PositionedEventTargeting.h"
#include "prenv.h"
#include "prinrval.h"
#include "ScrollSnap.h"
#include "StickyScrollContainer.h"
#include "Units.h"
#include "VisualViewport.h"
#include "XULTreeElement.h"
#include "ZoomConstraintsClient.h"

#ifdef XP_WIN
#  include "winuser.h"
#endif

#ifdef MOZ_REFLOW_PERF
#  include "nsFontMetrics.h"
#endif

#ifdef ACCESSIBILITY
#  include "mozilla/a11y/DocAccessible.h"
#  ifdef DEBUG
#    include "mozilla/a11y/Logging.h"
#  endif
#endif

// define the scalfactor of drag and drop images
// relative to the max screen height/width
#define RELATIVE_SCALEFACTOR 0.0925f

using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::gfx;
using namespace mozilla::layout;
using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
typedef ScrollableLayerGuid::ViewID ViewID;

MOZ_RUNINIT PresShell::CapturingContentInfo PresShell::sCapturingContentInfo;

// RangePaintInfo is used to paint ranges to offscreen buffers
struct RangePaintInfo {
  nsDisplayListBuilder mBuilder;
  nsDisplayList mList;

  // offset of builder's reference frame to the root frame
  nsPoint mRootOffset;

  // Resolution at which the items are normally painted. So if we're painting
  // these items in a range separately from the "full display list", we may want
  // to paint them at this resolution.
  float mResolution = 1.0;

  explicit RangePaintInfo(nsIFrame* aFrame)
      : mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false),
        mList(&mBuilder) {
    MOZ_COUNT_CTOR(RangePaintInfo);
    mBuilder.BeginFrame();
  }

  ~RangePaintInfo() {
    mList.DeleteAll(&mBuilder);
    mBuilder.EndFrame();
    MOZ_COUNT_DTOR(RangePaintInfo);
  }
};

#undef NOISY

// ----------------------------------------------------------------------

#ifdef DEBUG
// Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
// more of the following flags (comma separated) for handy debug
// output.
static VerifyReflowFlags gVerifyReflowFlags;

struct VerifyReflowFlagData {
  const char* name;
  VerifyReflowFlags bit;
};

static const VerifyReflowFlagData gFlags[] = {
    // clang-format off
  { "verify",                VerifyReflowFlags::On },
  { "reflow",                VerifyReflowFlags::Noisy },
  { "all",                   VerifyReflowFlags::All },
  { "list-commands",         VerifyReflowFlags::DumpCommands },
  { "noisy-commands",        VerifyReflowFlags::NoisyCommands },
  { "really-noisy-commands", VerifyReflowFlags::ReallyNoisyCommands },
  { "resize",                VerifyReflowFlags::DuringResizeReflow },
    // clang-format on
};

#  define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))

static void ShowVerifyReflowFlags() {
  printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
  const VerifyReflowFlagData* flag = gFlags;
  const VerifyReflowFlagData* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
  while (flag < limit) {
    printf(" %s\n", flag->name);
    ++flag;
  }
  printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
  printf("names (no whitespace)\n");
}
#endif

//========================================================================
//========================================================================
//========================================================================
#ifdef MOZ_REFLOW_PERF
class ReflowCountMgr;

static const char kGrandTotalsStr[] = "Grand Totals";

// Counting Class
class ReflowCounter {
 public:
  explicit ReflowCounter(ReflowCountMgr* aMgr = nullptr);
  ~ReflowCounter();

  void ClearTotals();
  void DisplayTotals(const char* aStr);
  void DisplayDiffTotals(const char* aStr);
  void DisplayHTMLTotals(const char* aStr);

  void Add() { mTotal++; }
  void Add(uint32_t aTotal) { mTotal += aTotal; }

  void CalcDiffInTotals();
  void SetTotalsCache();

  void SetMgr(ReflowCountMgr* aMgr) { mMgr = aMgr; }

  uint32_t GetTotal() { return mTotal; }

 protected:
  void DisplayTotals(uint32_t aTotal, const char* aTitle);
  void DisplayHTMLTotals(uint32_t aTotal, const char* aTitle);

  uint32_t mTotal;
  uint32_t mCacheTotal;

  ReflowCountMgr* mMgr;  // weak reference (don't delete)
};

// Counting Class
class IndiReflowCounter {
 public:
  explicit IndiReflowCounter(ReflowCountMgr* aMgr = nullptr)
      : mFrame(nullptr),
        mCount(0),
        mMgr(aMgr),
        mCounter(aMgr),
        mHasBeenOutput(false) {}
  virtual ~IndiReflowCounter() = default;

  nsAutoString mName;
  nsIFrame* mFrame;  // weak reference (don't delete)
  int32_t mCount;

  ReflowCountMgr* mMgr;  // weak reference (don't delete)

  ReflowCounter mCounter;
  bool mHasBeenOutput;
};

//--------------------
// Manager Class
//--------------------
class ReflowCountMgr {
 public:
  ReflowCountMgr();
  virtual ~ReflowCountMgr();

  void ClearTotals();
  void ClearGrandTotals();
  void DisplayTotals(const char* aStr);
  void DisplayHTMLTotals(const char* aStr);
  void DisplayDiffsInTotals();

  void Add(const char* aName, nsIFrame* aFrame);
  ReflowCounter* LookUp(const char* aName);

  void PaintCount(const char* aName, gfxContext* aRenderingContext,
                  nsPresContext* aPresContext, nsIFrame* aFrame,
                  const nsPoint& aOffset, uint32_t aColor);

  FILE* GetOutFile() { return mFD; }

  void SetPresContext(nsPresContext* aPresContext) {
    mPresContext = aPresContext;  // weak reference
  }
  void SetPresShell(PresShell* aPresShell) {
    mPresShell = aPresShell;  // weak reference
  }

  void SetDumpFrameCounts(bool aVal) { mDumpFrameCounts = aVal; }
  void SetDumpFrameByFrameCounts(bool aVal) { mDumpFrameByFrameCounts = aVal; }
  void SetPaintFrameCounts(bool aVal) { mPaintFrameByFrameCounts = aVal; }

  bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }

 protected:
  void DisplayTotals(uint32_t aTotal, uint32_t* aDupArray, char* aTitle);
  void DisplayHTMLTotals(uint32_t aTotal, uint32_t* aDupArray, char* aTitle);

  void DoGrandTotals();
  void DoIndiTotalsTree();

  // HTML Output Methods
  void DoGrandHTMLTotals();

  nsClassHashtable<nsCharPtrHashKey, ReflowCounter> mCounts;
  nsClassHashtable<nsCharPtrHashKey, IndiReflowCounter> mIndiFrameCounts;
  FILE* mFD;

  bool mDumpFrameCounts;
  bool mDumpFrameByFrameCounts;
  bool mPaintFrameByFrameCounts;

  bool mCycledOnce;

  // Root Frame for Individual Tracking
  nsPresContext* mPresContext;
  PresShell* mPresShell;

  // ReflowCountMgr gReflowCountMgr;
};
#endif
//========================================================================

// comment out to hide caret
#define SHOW_CARET

// The upper bound on the amount of time to spend reflowing, in
// microseconds.  When this bound is exceeded and reflow commands are
// still queued up, a reflow event is posted.  The idea is for reflow
// to not hog the processor beyond the time specifed in
// gMaxRCProcessingTime.  This data member is initialized from the
// layout.reflow.timeslice pref.
#define NS_MAX_REFLOW_TIME 1000000
static int32_t gMaxRCProcessingTime = -1;

struct nsCallbackEventRequest {
  nsIReflowCallback* callback;
  nsCallbackEventRequest* next;
};

// ----------------------------------------------------------------------------
//
// NOTE(emilio): It'd be nice for this to assert that our document isn't in the
// bfcache, but font pref changes don't care about that, and maybe / probably
// shouldn't.
#ifdef DEBUG
#  define ASSERT_REFLOW_SCHEDULED_STATE()                                      \
    {                                                                          \
      if (ObservingStyleFlushes()) {                                           \
        MOZ_ASSERT(                                                            \
            mDocument->GetBFCacheEntry() ||                                    \
                mPresContext->RefreshDriver()->IsStyleFlushObserver(this),     \
            "Unexpected state");                                               \
      } else {                                                                 \
        MOZ_ASSERT(!mPresContext->RefreshDriver()->IsStyleFlushObserver(this), \
                   "Unexpected state");                                        \
      }                                                                        \
    }
#else
#  define ASSERT_REFLOW_SCHEDULED_STATE() /* nothing */
#endif

class nsAutoCauseReflowNotifier {
 public:
  MOZ_CAN_RUN_SCRIPT explicit nsAutoCauseReflowNotifier(PresShell* aPresShell)
      : mPresShell(aPresShell) {
    mPresShell->WillCauseReflow();
  }
  MOZ_CAN_RUN_SCRIPT ~nsAutoCauseReflowNotifier() {
    // This check should not be needed. Currently the only place that seem
    // to need it is the code that deals with bug 337586.
    if (!mPresShell->mHaveShutDown) {
      RefPtr<PresShell> presShell(mPresShell);
      presShell->DidCauseReflow();
    } else {
      nsContentUtils::RemoveScriptBlocker();
    }
  }

  PresShell* mPresShell;
};

class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback {
 public:
  explicit nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}

  MOZ_CAN_RUN_SCRIPT
  virtual void HandleEvent(EventChainPostVisitor& aVisitor) override {
    if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
      if (aVisitor.mEvent->mMessage == eMouseDown ||
          aVisitor.mEvent->mMessage == eMouseUp) {
        // Mouse-up and mouse-down events call nsIFrame::HandlePress/Release
        // which call GetContentOffsetsFromPoint which requires up-to-date
        // layout. Bring layout up-to-date now so that GetCurrentEventFrame()
        // below will return a real frame and we don't have to worry about
        // destroying it by flushing later.
        MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Layout);
      } else if (aVisitor.mEvent->mMessage == eWheel &&
                 aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
        nsIFrame* frame = mPresShell->GetCurrentEventFrame();
        if (frame) {
          // chrome (including addons) should be able to know if content
          // handles both D3E "wheel" event and legacy mouse scroll events.
          // We should dispatch legacy mouse events before dispatching the
          // "wheel" event into system group.
          RefPtr<EventStateManager> esm =
              aVisitor.mPresContext->EventStateManager();
          esm->DispatchLegacyMouseScrollEvents(
              frame, aVisitor.mEvent->AsWheelEvent(), &aVisitor.mEventStatus);
        }
      }
      nsIFrame* frame = mPresShell->GetCurrentEventFrame();
      if (!frame && (aVisitor.mEvent->mMessage == eMouseUp ||
                     aVisitor.mEvent->mMessage == eTouchEnd)) {
        // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
        // that capturing is released.
        frame = mPresShell->GetRootFrame();
      }
      if (frame) {
        frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
                           &aVisitor.mEventStatus);
      }
    }
  }

  RefPtr<PresShell> mPresShell;
};

class nsBeforeFirstPaintDispatcher : public Runnable {
 public:
  explicit nsBeforeFirstPaintDispatcher(Document* aDocument)
      : mozilla::Runnable("nsBeforeFirstPaintDispatcher"),
        mDocument(aDocument) {}

  // Fires the "before-first-paint" event so that interested parties (right now,
  // the mobile browser) are aware of it.
  NS_IMETHOD Run() override {
    nsCOMPtr<nsIObserverService> observerService =
        mozilla::services::GetObserverService();
    if (observerService) {
      observerService->NotifyObservers(ToSupports(mDocument),
                                       "before-first-paint", nullptr);
    }
    return NS_OK;
  }

 private:
  RefPtr<Document> mDocument;
};

// This is a helper class to track whether the targeted frame is destroyed after
// dispatching pointer events. In that case, we need the original targeted
// content so that we can dispatch the mouse events to it.
class MOZ_RAII AutoPointerEventTargetUpdater final {
 public:
  AutoPointerEventTargetUpdater(PresShell* aShell, WidgetEvent* aEvent,
                                nsIFrame* aFrame, nsIContent* aTargetContent,
                                nsIContent** aOutTargetContent) {
    MOZ_ASSERT(aEvent);
    if (!aOutTargetContent || aEvent->mClass != ePointerEventClass) {
      // Make the destructor happy.
      mOutTargetContent = nullptr;
      return;
    }
    MOZ_ASSERT(aShell);
    MOZ_ASSERT_IF(aFrame && aFrame->GetContent(),
                  aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());

    mShell = aShell;
    mWeakFrame = aFrame;
    mOutTargetContent = aOutTargetContent;
    mFromTouch = aEvent->AsPointerEvent()->mFromTouchEvent;
    // Touch event target may have no frame, e.g., removed from the DOM
    MOZ_ASSERT_IF(!mFromTouch, aFrame);
    // The frame may be a text frame, but the event target should be an element
    // node.  Therefore, refer aTargetContent first, then, if we have only a
    // frame, we should use inclusive ancestor of the content.
    mOriginalPointerEventTarget =
        aShell->mPointerEventTarget = [&]() -> nsIContent* {
      nsIContent* const target =
          aTargetContent ? aTargetContent
                         : (aFrame ? aFrame->GetContent() : nullptr);
      if (MOZ_UNLIKELY(!target)) {
        return nullptr;
      }
      if (target->IsElement() ||
          !IsForbiddenDispatchingToNonElementContent(aEvent->mMessage)) {
        return target;
      }
      return target->GetInclusiveFlattenedTreeAncestorElement();
    }();
  }

  ~AutoPointerEventTargetUpdater() {
    if (!mOutTargetContent || !mShell || mWeakFrame.IsAlive()) {
      return;
    }
    if (mFromTouch) {
      // If the source event is a touch event, the touch event target should
      // always be same target as preceding ePointerDown.  Therefore, we should
      // always set it back to the original event target.
      mOriginalPointerEventTarget.swap(*mOutTargetContent);
    } else {
      // If the source event is not a touch event (must be a mouse event in
      // this case), the event should be fired on the closest inclusive ancestor
      // of the pointer event target which is still connected.  The mutations
      // are tracked by PresShell::ContentRemoved.  Therefore, we should set it.
      mShell->mPointerEventTarget.swap(*mOutTargetContent);
    }
  }

 private:
  RefPtr<PresShell> mShell;
  nsCOMPtr<nsIContent> mOriginalPointerEventTarget;
  AutoWeakFrame mWeakFrame;
  nsIContent** mOutTargetContent;
  bool mFromTouch = false;
};

bool PresShell::sDisableNonTestMouseEvents = false;
int16_t PresShell::sMouseButtons = MouseButtonsFlag::eNoButtons;

LazyLogModule PresShell::gLog("PresShell");

#ifdef DEBUG
// MouseLocation logs the mouse location and when/where enqueued synthesized
// mouse move is flushed.  If you don't need all mouse location recording at
// eMouseMove, you can use MouseLocation:3,sync.  Then, it's logged once per
// 50 times.  Otherwise, if you need to log all eMouseMove locations, you can
// use MouseLocation:5,sync.
LazyLogModule gLogMouseLocation("MouseLocation");
#endif

TimeStamp PresShell::EventHandler::sLastInputCreated;
TimeStamp PresShell::EventHandler::sLastInputProcessed;
StaticRefPtr<Element> PresShell::EventHandler::sLastKeyDownEventTargetElement;

bool PresShell::sProcessInteractable = false;

static bool gVerifyReflowEnabled;

bool PresShell::GetVerifyReflowEnable() {
#ifdef DEBUG
  static bool firstTime = true;
  if (firstTime) {
    firstTime = false;
    char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
    if (flags) {
      bool error = false;

      for (;;) {
        char* comma = strchr(flags, ',');
        if (comma) *comma = '\0';

        bool found = false;
        const VerifyReflowFlagData* flag = gFlags;
        const VerifyReflowFlagData* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
        while (flag < limit) {
          if (nsCRT::strcasecmp(flag->name, flags) == 0) {
            gVerifyReflowFlags |= flag->bit;
            found = true;
            break;
          }
          ++flag;
        }

        if (!found) error = true;

        if (!comma) break;

        *comma = ',';
        flags = comma + 1;
      }

      if (error) ShowVerifyReflowFlags();
    }

    if (VerifyReflowFlags::On & gVerifyReflowFlags) {
      gVerifyReflowEnabled = true;

      printf("Note: verifyreflow is enabled");
      if (VerifyReflowFlags::Noisy & gVerifyReflowFlags) {
        printf(" (noisy)");
      }
      if (VerifyReflowFlags::All & gVerifyReflowFlags) {
        printf(" (all)");
      }
      if (VerifyReflowFlags::DumpCommands & gVerifyReflowFlags) {
        printf(" (show reflow commands)");
      }
      if (VerifyReflowFlags::NoisyCommands & gVerifyReflowFlags) {
        printf(" (noisy reflow commands)");
        if (VerifyReflowFlags::ReallyNoisyCommands & gVerifyReflowFlags) {
          printf(" (REALLY noisy reflow commands)");
        }
      }
      printf("\n");
    }
  }
#endif
  return gVerifyReflowEnabled;
}

void PresShell::SetVerifyReflowEnable(bool aEnabled) {
  gVerifyReflowEnabled = aEnabled;
}

void PresShell::AddAutoWeakFrame(AutoWeakFrame* aWeakFrame) {
  if (aWeakFrame->GetFrame()) {
    aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
  }
  aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
  mAutoWeakFrames = aWeakFrame;
}

void PresShell::AddWeakFrame(WeakFrame* aWeakFrame) {
  if (aWeakFrame->GetFrame()) {
    aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
  }
  MOZ_ASSERT(!mWeakFrames.Contains(aWeakFrame));
  mWeakFrames.Insert(aWeakFrame);
}

void PresShell::RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame) {
  if (mAutoWeakFrames == aWeakFrame) {
    mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
    return;
  }
  AutoWeakFrame* nextWeak = mAutoWeakFrames;
  while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
    nextWeak = nextWeak->GetPreviousWeakFrame();
  }
  if (nextWeak) {
    nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
  }
}

void PresShell::RemoveWeakFrame(WeakFrame* aWeakFrame) {
  MOZ_ASSERT(mWeakFrames.Contains(aWeakFrame));
  mWeakFrames.Remove(aWeakFrame);
}

already_AddRefed<nsFrameSelection> PresShell::FrameSelection() {
  RefPtr<nsFrameSelection> ret = mSelection;
  return ret.forget();
}

//----------------------------------------------------------------------

static uint32_t sNextPresShellId = 0;

/* static */
bool PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell) {
  // If the pref forces it on, then enable it.
  if (StaticPrefs::layout_accessiblecaret_enabled()) {
    return true;
  }
  // If the touch pref is on, and touch events are enabled (this depends
  // on the specific device running), then enable it.
  if (StaticPrefs::layout_accessiblecaret_enabled_on_touch() &&
      dom::TouchEvent::PrefEnabled(aDocShell)) {
    return true;
  }
  // Otherwise, disabled.
  return false;
}

PresShell::PresShell(Document* aDocument)
    : mDocument(aDocument),
      mViewManager(nullptr),
      mAutoWeakFrames(nullptr),
#ifdef ACCESSIBILITY
      mDocAccessible(nullptr),
#endif  // ACCESSIBILITY
      mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
      mLastResolutionChangeOrigin(ResolutionChangeOrigin::Apz),
      mPaintCount(0),
      mAPZFocusSequenceNumber(0),
      mActiveSuppressDisplayport(0),
      mPresShellId(++sNextPresShellId),
      mFontSizeInflationEmPerLine(0),
      mFontSizeInflationMinTwips(0),
      mFontSizeInflationLineThreshold(0),
      mSelectionFlags(nsISelectionDisplay::DISPLAY_TEXT |
                      nsISelectionDisplay::DISPLAY_IMAGES),
      mChangeNestCount(0),
      mRenderingStateFlags(RenderingStateFlags::None),
      mCaretEnabled(false),
      mNeedLayoutFlush(true),
      mNeedStyleFlush(true),
      mNeedThrottledAnimationFlush(true),
      mVisualViewportSizeSet(false),
      mDidInitialize(false),
      mIsDestroying(false),
      mIsReflowing(false),
      mIsObservingDocument(false),
      mForbiddenToFlush(false),
      mIsDocumentGone(false),
      mHaveShutDown(false),
      mPaintingSuppressed(false),
      mShouldUnsuppressPainting(false),
      mIgnoreFrameDestruction(false),
      mIsActive(true),
      mFrozen(false),
      mIsFirstPaint(true),
      mObservesMutationsForPrint(false),
      mWasLastReflowInterrupted(false),
      mObservingStyleFlushes(false),
      mResizeEventPending(false),
      mFontSizeInflationForceEnabled(false),
      mFontSizeInflationDisabledInMasterProcess(false),
      mFontSizeInflationEnabled(false),
      mIsNeverPainting(false),
      mResolutionUpdated(false),
      mResolutionUpdatedByApz(false),
      mUnderHiddenEmbedderElement(false),
      mDocumentLoading(false),
      mNoDelayedMouseEvents(false),
      mNoDelayedKeyEvents(false),
      mApproximateFrameVisibilityVisited(false),
      mIsLastChromeOnlyEscapeKeyConsumed(false),
      mHasReceivedPaintMessage(false),
      mIsLastKeyDownCanceled(false),
      mHasHandledUserInput(false),
      mForceDispatchKeyPressEventsForNonPrintableKeys(false),
      mForceUseLegacyKeyCodeAndCharCodeValues(false),
      mInitializedWithKeyPressEventDispatchingBlacklist(false),
      mMouseLocationWasSetBySynthesizedMouseEventForTests(false),
      mHasTriedFastUnsuppress(false),
      mProcessingReflowCommands(false),
      mPendingDidDoReflow(false) {
  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p"this));
  MOZ_ASSERT(aDocument);

#ifdef MOZ_REFLOW_PERF
  mReflowCountMgr = MakeUnique<ReflowCountMgr>();
  mReflowCountMgr->SetPresContext(mPresContext);
  mReflowCountMgr->SetPresShell(this);
#endif
  mLastOSWake = mLoadBegin = TimeStamp::Now();
}

NS_INTERFACE_TABLE_HEAD(PresShell)
  NS_INTERFACE_TABLE_BEGIN
    // In most cases, PresShell should be treated as concrete class, but need to
    // QI for weak reference.  Therefore, the case needed by do_QueryReferent()
    // should be tested first.
    NS_INTERFACE_TABLE_ENTRY(PresShell, PresShell)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIDocumentObserver)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionController)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionDisplay)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIObserver)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISupportsWeakReference)
    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIMutationObserver)
    NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(PresShell, nsISupports, nsIObserver)
  NS_INTERFACE_TABLE_END
  NS_INTERFACE_TABLE_TO_MAP_SEGUE
NS_INTERFACE_MAP_END

NS_IMPL_ADDREF(PresShell)
NS_IMPL_RELEASE(PresShell)

PresShell::~PresShell() {
  MOZ_RELEASE_ASSERT(!mForbiddenToFlush,
                     "Flag should only be set temporarily, while doing things "
                     "that shouldn't cause destruction");
  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::~PresShell this=%p"this));

  if (!mHaveShutDown) {
    MOZ_ASSERT_UNREACHABLE("Someone did not call PresShell::Destroy()");
    Destroy();
  }

  NS_ASSERTION(mCurrentEventTargetStack.IsEmpty(),
               "Huh, event content left on the stack in pres shell dtor!");
  NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
                   mLastCallbackEventRequest == nullptr,
               "post-reflow queues not empty. This means we're leaking");

  MOZ_ASSERT(!mAllocatedPointers || mAllocatedPointers->IsEmpty(),
             "Some pres arena objects were not freed");

  mFrameConstructor = nullptr;
}

/**
 * Initialize the presentation shell. Create view manager and style
 * manager.
 * Note this can't be merged into our constructor because caret initialization
 * calls AddRef() on us.
 */

void PresShell::Init(nsPresContext* aPresContext, nsViewManager* aViewManager) {
  MOZ_ASSERT(mDocument);
  MOZ_ASSERT(aPresContext);
  MOZ_ASSERT(aViewManager);
  MOZ_ASSERT(!mViewManager, "already initialized");

  mViewManager = aViewManager;

  // mDocument is now set.  It might have a display document whose "need layout/
  // style" flush flags are not set, but ours will be set.  To keep these
  // consistent, call the flag setting functions to propagate those flags up
  // to the display document.
  SetNeedLayoutFlush();
  SetNeedStyleFlush();

  // Create our frame constructor.
  mFrameConstructor = MakeUnique<nsCSSFrameConstructor>(mDocument, this);

  // The document viewer owns both view manager and pres shell.
  mViewManager->SetPresShell(this);

  // Bind the context to the presentation shell.
  // FYI: We cannot initialize mPresContext in the constructor because we
  //      cannot call AttachPresShell() in it and once we initialize
  //      mPresContext, other objects may refer refresh driver or restyle
  //      manager via mPresContext and that causes hitting MOZ_ASSERT in some
  //      places.  Therefore, we should initialize mPresContext here with
  //      const_cast hack since we want to guarantee that mPresContext lives
  //      as long as the PresShell.
  const_cast<RefPtr<nsPresContext>&>(mPresContext) = aPresContext;
  mPresContext->AttachPresShell(this);

  mPresContext->InitFontCache();

  // FIXME(emilio, bug 1544185): Some Android code somehow depends on the shell
  // being eagerly registered as a style flush observer. This shouldn't be
  // needed otherwise.
  EnsureStyleFlush();

  const bool accessibleCaretEnabled =
      AccessibleCaretEnabled(mDocument->GetDocShell());
  if (accessibleCaretEnabled) {
    // Need to happen before nsFrameSelection has been set up.
    mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
    mAccessibleCaretEventHub->Init();
  }

  mSelection = new nsFrameSelection(this, accessibleCaretEnabled);

  // Important: this has to happen after the selection has been set up
#ifdef SHOW_CARET
  // make the caret
  mCaret = new nsCaret();
  mCaret->Init(this);
  mOriginalCaret = mCaret;

  // SetCaretEnabled(true);       // make it show in browser windows
#endif
  // set up selection to be displayed in document
  // Don't enable selection for print media
  nsPresContext::nsPresContextType type = mPresContext->Type();
  if (type != nsPresContext::eContext_PrintPreview &&
      type != nsPresContext::eContext_Print) {
    SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
  }

  if (gMaxRCProcessingTime == -1) {
    gMaxRCProcessingTime =
        Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
  }

  if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
    ss->RegisterPresShell(this);
  }

  {
    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    if (os) {
      os->AddObserver(this"memory-pressure"false);
      os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false);
      if (XRE_IsParentProcess() && !sProcessInteractable) {
        os->AddObserver(this"sessionstore-one-or-no-tab-restored"false);
      }
      os->AddObserver(this"font-info-updated"false);
      os->AddObserver(this"internal-look-and-feel-changed"false);
    }
  }

#ifdef MOZ_REFLOW_PERF
  if (mReflowCountMgr) {
    bool paintFrameCounts =
        Preferences::GetBool("layout.reflow.showframecounts");

    bool dumpFrameCounts =
        Preferences::GetBool("layout.reflow.dumpframecounts");

    bool dumpFrameByFrameCounts =
        Preferences::GetBool("layout.reflow.dumpframebyframecounts");

    mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
    mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
    mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
  }
#endif

  if (mDocument->HasAnimationController()) {
    SMILAnimationController* animCtrl = mDocument->GetAnimationController();
    animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
  }

  for (DocumentTimeline* timelines : mDocument->Timelines()) {
    timelines->UpdateLastRefreshDriverTime();
  }

  // Get our activeness from the docShell.
  ActivenessMaybeChanged();

  // Setup our font inflation preferences.
  mFontSizeInflationEmPerLine = StaticPrefs::font_size_inflation_emPerLine();
  mFontSizeInflationMinTwips = StaticPrefs::font_size_inflation_minTwips();
  mFontSizeInflationLineThreshold =
      StaticPrefs::font_size_inflation_lineThreshold();
  mFontSizeInflationForceEnabled =
      StaticPrefs::font_size_inflation_forceEnabled();
  mFontSizeInflationDisabledInMasterProcess =
      StaticPrefs::font_size_inflation_disabledInMasterProcess();
  // We'll compute the font size inflation state in Initialize(), when we know
  // the document type.

  mTouchManager.Init(this, mDocument);

  if (mPresContext->IsRootContentDocumentCrossProcess()) {
    mZoomConstraintsClient = new ZoomConstraintsClient();
    mZoomConstraintsClient->Init(this, mDocument);

    // We call this to create mMobileViewportManager, if it is needed.
    MaybeRecreateMobileViewportManager(false);
  }

  if (nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell()) {
    if (BrowsingContext* bc = docShell->GetBrowsingContext()) {
      mUnderHiddenEmbedderElement = bc->IsUnderHiddenEmbedderElement();
    }
  }
}

enum TextPerfLogType { eLog_reflow, eLog_loaddone, eLog_totals };

static void LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
                             PresShell* aPresShell,
                             const gfxTextPerfMetrics::TextCounts& aCounts,
                             float aTime, TextPerfLogType aLogType,
                             const char* aURL) {
  LogModule* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);

  // ignore XUL contexts unless at debug level
  mozilla::LogLevel logLevel = LogLevel::Warning;
  if (aCounts.numContentTextRuns == 0) {
    logLevel = LogLevel::Debug;
  }

  if (!MOZ_LOG_TEST(tpLog, logLevel)) {
    return;
  }

  char prefix[256];

  switch (aLogType) {
    case eLog_reflow:
      SprintfLiteral(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell,
                     aTime);
      break;
    case eLog_loaddone:
      SprintfLiteral(prefix, "(textperf-loaddone) %p time-ms: %7.0f",
                     aPresShell, aTime);
      break;
    default:
      MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
      SprintfLiteral(prefix, "(textperf-totals) %p", aPresShell);
  }

  double hitRatio = 0.0;
  uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
  if (lookups) {
    hitRatio = double(aCounts.wordCacheHit) / double(lookups);
  }

  if (aLogType == eLog_loaddone) {
    MOZ_LOG(
        tpLog, logLevel,
        ("%s reflow: %d chars: %d "
         "[%s] "
         "content-textruns: %d chrome-textruns: %d "
         "max-textrun-len: %d "
         "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
         "word-cache-space: %d word-cache-long: %d "
         "pref-fallbacks: %d system-fallbacks: %d "
         "textruns-const: %d textruns-destr: %d "
         "generic-lookups: %d "
         "cumulative-textruns-destr: %d\n",
         prefix, aTextPerf->reflowCount, aCounts.numChars, (aURL ? aURL : ""),
         aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
         aCounts.maxTextRunLen, lookups, hitRatio, aCounts.wordCacheSpaceRules,
         aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem,
         aCounts.textrunConst, aCounts.textrunDestr, aCounts.genericLookups,
         aTextPerf->cumulative.textrunDestr));
  } else {
    MOZ_LOG(
        tpLog, logLevel,
        ("%s reflow: %d chars: %d "
         "content-textruns: %d chrome-textruns: %d "
         "max-textrun-len: %d "
         "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
         "word-cache-space: %d word-cache-long: %d "
         "pref-fallbacks: %d system-fallbacks: %d "
         "textruns-const: %d textruns-destr: %d "
         "generic-lookups: %d "
         "cumulative-textruns-destr: %d\n",
         prefix, aTextPerf->reflowCount, aCounts.numChars,
         aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
         aCounts.maxTextRunLen, lookups, hitRatio, aCounts.wordCacheSpaceRules,
         aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem,
         aCounts.textrunConst, aCounts.textrunDestr, aCounts.genericLookups,
         aTextPerf->cumulative.textrunDestr));
  }
}

bool PresShell::InRDMPane() {
  if (Document* doc = GetDocument()) {
    if (BrowsingContext* bc = doc->GetBrowsingContext()) {
      return bc->InRDMPane();
    }
  }
  return false;
}

#if defined(MOZ_WIDGET_ANDROID)
void PresShell::MaybeNotifyShowDynamicToolbar() {
  const DynamicToolbarState dynToolbarState = GetDynamicToolbarState();
  if ((dynToolbarState == DynamicToolbarState::Collapsed ||
       dynToolbarState == DynamicToolbarState::InTransition)) {
    MOZ_ASSERT(mPresContext &&
               mPresContext->IsRootContentDocumentCrossProcess());
    if (BrowserChild* browserChild = BrowserChild::GetFrom(this)) {
      browserChild->SendShowDynamicToolbar();
    }
  }
}
#endif  // defined(MOZ_WIDGET_ANDROID)

void PresShell::Destroy() {
  // Do not add code before this line please!
  if (mHaveShutDown) {
    return;
  }

  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
               "destroy called on presshell while scripts not blocked");

  [[maybe_unused]] nsIURI* uri = mDocument->GetDocumentURI();
  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_RELEVANT_FOR_JS(
      "Layout tree destruction", LAYOUT_Destroy,
      uri ? uri->GetSpecOrDefault() : "N/A"_ns);

  // Try to determine if the page is the user had a meaningful opportunity to
  // zoom this page. This is not 100% accurate but should be "good enough" for
  // telemetry purposes.
  auto isUserZoomablePage = [&]() -> bool {
    if (mIsFirstPaint) {
      // Page was never painted, so it wasn't zoomable by the user. We get a
      // handful of these "transient" presShells.
      return false;
    }
    if (!mPresContext->IsRootContentDocumentCrossProcess()) {
      // Not a root content document, so APZ doesn't support zooming it.
      return false;
    }
    if (InRDMPane()) {
      // Responsive design mode is a special case that we want to ignore here.
      return false;
    }
    if (mDocument && mDocument->IsInitialDocument()) {
      // Ignore initial about:blank page loads
      return false;
    }
    if (XRE_IsContentProcess() &&
        IsExtensionRemoteType(ContentChild::GetSingleton()->GetRemoteType())) {
      // Also omit presShells from the extension process because they sometimes
      // can't be zoomed by the user.
      return false;
    }
    // Otherwise assume the page is user-zoomable.
    return true;
  };
  if (isUserZoomablePage()) {
    Telemetry::Accumulate(Telemetry::APZ_ZOOM_ACTIVITY,
                          IsResolutionUpdatedByApz());
  }

  // dump out cumulative text perf metrics
  gfxTextPerfMetrics* tp;
  if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
    tp->Accumulate();
    if (tp->cumulative.numChars > 0) {
      LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
    }
  }
  if (mPresContext) {
    if (gfxUserFontSet* fs = mPresContext->GetUserFontSet()) {
      uint32_t fontCount;
      uint64_t fontSize;
      fs->GetLoadStatistics(fontCount, fontSize);
      Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, fontCount);
      Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE,
                            uint32_t(fontSize / 1024));
    } else {
      Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, 0);
      Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE, 0);
    }
  }

#ifdef MOZ_REFLOW_PERF
  DumpReflows();
  mReflowCountMgr = nullptr;
#endif

  if (mZoomConstraintsClient) {
    mZoomConstraintsClient->Destroy();
    mZoomConstraintsClient = nullptr;
  }
  if (mMobileViewportManager) {
    mMobileViewportManager->Destroy();
    mMobileViewportManager = nullptr;
    mMVMContext = nullptr;
  }

#ifdef ACCESSIBILITY
  if (mDocAccessible) {
#  ifdef DEBUG
    if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy))
      a11y::logging::DocDestroy("presshell destroyed", mDocument);
#  endif

    mDocAccessible->Shutdown();
    mDocAccessible = nullptr;
  }
#endif  // ACCESSIBILITY

  MaybeReleaseCapturingContent();

  EventHandler::OnPresShellDestroy(mDocument);

  if (mContentToScrollTo) {
    mContentToScrollTo->RemoveProperty(nsGkAtoms::scrolling);
    mContentToScrollTo = nullptr;
  }

  if (mPresContext) {
    // We need to notify the destroying the nsPresContext to ESM for
    // suppressing to use from ESM.
    mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
  }

  if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
    ss->UnregisterPresShell(this);
  }

  {
    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    if (os) {
      os->RemoveObserver(this"memory-pressure");
      os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
      if (XRE_IsParentProcess()) {
        os->RemoveObserver(this"sessionstore-one-or-no-tab-restored");
      }
      os->RemoveObserver(this"font-info-updated");
      os->RemoveObserver(this"internal-look-and-feel-changed");
    }
  }

  // If our paint suppression timer is still active, kill it.
  CancelPaintSuppressionTimer();

  mSynthMouseMoveEvent.Revoke();

  mUpdateApproximateFrameVisibilityEvent.Revoke();

  ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DiscardImages));

  if (mOriginalCaret) {
    mOriginalCaret->Terminate();
  }
  if (mCaret && mCaret != mOriginalCaret) {
    mCaret->Terminate();
  }
  mCaret = mOriginalCaret = nullptr;

  mFocusedFrameSelection = nullptr;

  if (mSelection) {
    RefPtr<nsFrameSelection> frameSelection = mSelection;
    frameSelection->DisconnectFromPresShell();
  }

  mIsDestroying = true;

  // We can't release all the event content in
  // mCurrentEventContentStack here since there might be code on the
  // stack that will release the event content too. Double release
  // bad!

  // The frames will be torn down, so remove them from the current
  // event frame stack (since they'd be dangling references if we'd
  // leave them in) and null out the mCurrentEventFrame pointer as
  // well.

  mCurrentEventTarget.ClearFrame();

  for (EventTargetInfo& eventTargetInfo : mCurrentEventTargetStack) {
    eventTargetInfo.ClearFrame();
  }

  mFramesToDirty.Clear();
  mPendingScrollAnchorSelection.Clear();
  mPendingScrollAnchorAdjustment.Clear();
  mPendingScrollResnap.Clear();

  if (mViewManager) {
    // Clear the view manager's weak pointer back to |this| in case it
    // was leaked.
    mViewManager->SetPresShell(nullptr);
    mViewManager = nullptr;
  }

  nsRefreshDriver* rd = GetPresContext()->RefreshDriver();

  // This shell must be removed from the document before the frame
  // hierarchy is torn down to avoid finding deleted frames through
  // this presshell while the frames are being torn down
  if (mDocument) {
    NS_ASSERTION(mDocument->GetPresShell() == this"Wrong shell?");
    mDocument->ClearServoRestyleRoot();
    mDocument->DeletePresShell();

    if (mDocument->HasAnimationController()) {
      mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
    }
  }

  if (mPresContext) {
    rd->CancelPendingAnimationEvents(mPresContext->AnimationEventDispatcher());
  }

  // Revoke any pending events.  We need to do this and cancel pending reflows
  // before we destroy the frame constructor, since apparently frame destruction
  // sometimes spins the event queue when plug-ins are involved(!).
  // XXXmats is this still needed now that plugins are gone?
  StopObservingRefreshDriver();
  mObservingStyleFlushes = false;

  if (rd->GetPresContext() == GetPresContext()) {
    rd->RevokeViewManagerFlush();
    rd->ClearHasScheduleFlush();
  }

  CancelAllPendingReflows();
  CancelPostedReflowCallbacks();

  // Destroy the frame constructor. This will destroy the frame hierarchy
  mFrameConstructor->WillDestroyFrameTree();

  NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
                       "Weak frames alive after destroying FrameManager");
  while (mAutoWeakFrames) {
    mAutoWeakFrames->Clear(this);
  }
  const nsTArray<WeakFrame*> weakFrames = ToArray(mWeakFrames);
  for (WeakFrame* weakFrame : weakFrames) {
    weakFrame->Clear(this);
  }

  // Terminate AccessibleCaretEventHub after tearing down the frame tree so that
  // we don't need to remove caret element's frame in
  // AccessibleCaret::RemoveCaretElement().
  if (mAccessibleCaretEventHub) {
    mAccessibleCaretEventHub->Terminate();
    mAccessibleCaretEventHub = nullptr;
  }

  if (mPresContext) {
    // We hold a reference to the pres context, and it holds a weak link back
    // to us. To avoid the pres context having a dangling reference, set its
    // pres shell to nullptr
    mPresContext->DetachPresShell();
  }

  mHaveShutDown = true;

  mTouchManager.Destroy();
}

void PresShell::StopObservingRefreshDriver() {
  nsRefreshDriver* rd = mPresContext->RefreshDriver();
  if (mResizeEventPending) {
    rd->RemoveResizeEventFlushObserver(this);
  }
  if (mObservingStyleFlushes) {
    rd->RemoveStyleFlushObserver(this);
  }
}

void PresShell::StartObservingRefreshDriver() {
  nsRefreshDriver* rd = mPresContext->RefreshDriver();
  if (mResizeEventPending) {
    rd->AddResizeEventFlushObserver(this);
  }
  if (mObservingStyleFlushes) {
    rd->AddStyleFlushObserver(this);
  }
}

nsRefreshDriver* PresShell::GetRefreshDriver() const {
  return mPresContext ? mPresContext->RefreshDriver() : nullptr;
}

void PresShell::SetAuthorStyleDisabled(bool aStyleDisabled) {
  if (aStyleDisabled != StyleSet()->GetAuthorStyleDisabled()) {
    StyleSet()->SetAuthorStyleDisabled(aStyleDisabled);
    mDocument->ApplicableStylesChanged();

    nsCOMPtr<nsIObserverService> observerService =
        mozilla::services::GetObserverService();
    if (observerService) {
      observerService->NotifyObservers(
          ToSupports(mDocument), "author-style-disabled-changed", nullptr);
    }
  }
}

bool PresShell::GetAuthorStyleDisabled() const {
  return StyleSet()->GetAuthorStyleDisabled();
}

void PresShell::AddUserSheet(StyleSheet* aSheet) {
  // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
  // ordering. We want this new sheet to come after all the existing stylesheet
  // service sheets (which are at the start), but before other user sheets; see
  // nsIStyleSheetService.idl for the ordering.

  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
  nsTArray<RefPtr<StyleSheet>>& userSheets = *sheetService->UserStyleSheets();

  // Search for the place to insert the new user sheet. Since all of the
  // stylesheet service provided user sheets should be at the start of the style
  // set's list, and aSheet should be at the end of userSheets. Given that, we
  // can find the right place to insert the new sheet based on the length of
  // userSheets.
  MOZ_ASSERT(aSheet);
  MOZ_ASSERT(userSheets.LastElement() == aSheet);

  size_t index = userSheets.Length() - 1;

  // Assert that all of userSheets (except for the last, new element) matches up
  // with what's in the style set.
  for (size_t i = 0; i < index; ++i) {
    MOZ_ASSERT(StyleSet()->SheetAt(StyleOrigin::User, i) == userSheets[i]);
  }

  if (index == static_cast<size_t>(StyleSet()->SheetCount(StyleOrigin::User))) {
    StyleSet()->AppendStyleSheet(*aSheet);
  } else {
    StyleSheet* ref = StyleSet()->SheetAt(StyleOrigin::User, index);
    StyleSet()->InsertStyleSheetBefore(*aSheet, *ref);
  }

  mDocument->ApplicableStylesChanged();
}

void PresShell::AddAgentSheet(StyleSheet* aSheet) {
  // Make sure this does what nsDocumentViewer::CreateStyleSet does
  // wrt ordering.
  StyleSet()->AppendStyleSheet(*aSheet);
  mDocument->ApplicableStylesChanged();
}

void PresShell::AddAuthorSheet(StyleSheet* aSheet) {
  // Document specific "additional" Author sheets should be stronger than the
  // ones added with the StyleSheetService.
  StyleSheet* firstAuthorSheet = mDocument->GetFirstAdditionalAuthorSheet();
  if (firstAuthorSheet) {
    StyleSet()->InsertStyleSheetBefore(*aSheet, *firstAuthorSheet);
  } else {
    StyleSet()->AppendStyleSheet(*aSheet);
  }

  mDocument->ApplicableStylesChanged();
}

bool PresShell::NeedsFocusFixUp() const {
  if (NS_WARN_IF(!mDocument)) {
    return false;
  }

  nsIContent* currentFocus = mDocument->GetUnretargetedFocusedContent(
      Document::IncludeChromeOnly::Yes);
  if (!currentFocus) {
    return false;
  }

  // If focus target is an area element with one or more shapes that are
  // focusable areas.
  if (auto* area = HTMLAreaElement::FromNode(currentFocus)) {
    if (nsFocusManager::IsAreaElementFocusable(*area)) {
      return false;
    }
  }

  nsIFrame* f = currentFocus->GetPrimaryFrame();
  if (f && f->IsFocusable()) {
    return false;
  }

  if (currentFocus == mDocument->GetBody() ||
      currentFocus == mDocument->GetRootElement()) {
    return false;
  }

  return true;
}

bool PresShell::FixUpFocus() {
  if (!NeedsFocusFixUp()) {
    return false;
  }
  RefPtr fm = nsFocusManager::GetFocusManager();
  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
  if (NS_WARN_IF(!window)) {
    return false;
  }
  fm->ClearFocus(window);
  return true;
}

void PresShell::SelectionWillTakeFocus() {
  if (mSelection) {
    FrameSelectionWillTakeFocus(*mSelection);
  }
}

void PresShell::SelectionWillLoseFocus() {
  // Do nothing, the main selection is the default focused selection.
}

// Selection repainting code relies on selection offsets being properly
// adjusted (see bug 1626291), so we need to wait until the DOM is finished
// notifying.
static void RepaintNormalSelectionWhenSafe(nsFrameSelection& aFrameSelection) {
  if (nsContentUtils::IsSafeToRunScript()) {
    aFrameSelection.RepaintSelection(SelectionType::eNormal);
    return;
  }

  // Note that importantly we don't defer changing the DisplaySelection. That'd
  // be potentially racy with other code that may change it.
  nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
      "RepaintNormalSelectionWhenSafe",
      [sel = RefPtr<nsFrameSelection>(&aFrameSelection)] {
        sel->RepaintSelection(SelectionType::eNormal);
      }));
}

void PresShell::FrameSelectionWillLoseFocus(nsFrameSelection& aFrameSelection) {
  if (mFocusedFrameSelection != &aFrameSelection) {
    return;
  }

  // Do nothing, the main selection is the default focused selection.
  if (&aFrameSelection == mSelection) {
    return;
  }

  RefPtr<nsFrameSelection> old = std::move(mFocusedFrameSelection);
  MOZ_ASSERT(!mFocusedFrameSelection);

  if (old->GetDisplaySelection() != nsISelectionController::SELECTION_HIDDEN) {
    old->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
    RepaintNormalSelectionWhenSafe(*old);
  }

  if (mSelection) {
    FrameSelectionWillTakeFocus(*mSelection);
  }
}

void PresShell::FrameSelectionWillTakeFocus(nsFrameSelection& aFrameSelection) {
  if (mFocusedFrameSelection == &aFrameSelection) {
#ifdef XP_MACOSX
    // FIXME: Mac needs to update the global selection cache, even if the
    // document's focused selection doesn't change, and this is currently done
    // from RepaintSelection. Maybe we should move part of the global selection
    // handling here, or something of that sort, unclear.
    RepaintNormalSelectionWhenSafe(aFrameSelection);
#endif
    return;
  }

  RefPtr<nsFrameSelection> old = std::move(mFocusedFrameSelection);
  mFocusedFrameSelection = &aFrameSelection;

  if (old &&
      old->GetDisplaySelection() != nsISelectionController::SELECTION_HIDDEN) {
    old->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
    RepaintNormalSelectionWhenSafe(*old);
  }

  if (aFrameSelection.GetDisplaySelection() !=
      nsISelectionController::SELECTION_ON) {
    aFrameSelection.SetDisplaySelection(nsISelectionController::SELECTION_ON);
    RepaintNormalSelectionWhenSafe(aFrameSelection);
  }
}

NS_IMETHODIMP
PresShell::SetDisplaySelection(int16_t aToggle) {
  mSelection->SetDisplaySelection(aToggle);
  return NS_OK;
}

NS_IMETHODIMP
PresShell::GetDisplaySelection(int16_t* aToggle) {
  *aToggle = mSelection->GetDisplaySelection();
  return NS_OK;
}

NS_IMETHODIMP
PresShell::GetSelectionFromScript(RawSelectionType aRawSelectionType,
                                  Selection** aSelection) {
  if (!aSelection || !mSelection) {
    return NS_ERROR_NULL_POINTER;
  }

  RefPtr<Selection> selection =
      mSelection->GetSelection(ToSelectionType(aRawSelectionType));

  if (!selection) {
    return NS_ERROR_INVALID_ARG;
  }

  selection.forget(aSelection);
  return NS_OK;
}

Selection* PresShell::GetSelection(RawSelectionType aRawSelectionType) {
  if (!mSelection) {
    return nullptr;
  }

  return mSelection->GetSelection(ToSelectionType(aRawSelectionType));
}

Selection* PresShell::GetCurrentSelection(SelectionType aSelectionType) {
  if (!mSelection) {
    return nullptr;
  }

  return mSelection->GetSelection(aSelectionType);
}

nsFrameSelection* PresShell::GetLastFocusedFrameSelection() {
  return mFocusedFrameSelection ? mFocusedFrameSelection : mSelection;
}

NS_IMETHODIMP
PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
                                   SelectionRegion aRegion,
                                   ControllerScrollFlags aFlags) {
  if (!mSelection) {
    return NS_ERROR_NULL_POINTER;
  }

  RefPtr<nsFrameSelection> frameSelection = mSelection;
  return frameSelection->ScrollSelectionIntoView(
      ToSelectionType(aRawSelectionType), aRegion, aFlags);
}

NS_IMETHODIMP
PresShell::RepaintSelection(RawSelectionType aRawSelectionType) {
  if (!mSelection) {
    return NS_ERROR_NULL_POINTER;
  }

  if (MOZ_UNLIKELY(mIsDestroying)) {
    return NS_OK;
  }

  RefPtr<nsFrameSelection> frameSelection = mSelection;
  return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
}

// Make shell be a document observer
void PresShell::BeginObservingDocument() {
  if (mDocument && !mIsDestroying) {
    mIsObservingDocument = true;
    if (mIsDocumentGone) {
      NS_WARNING(
          "Adding a presshell that was disconnected from the document "
          "as a document observer? Sounds wrong...");
      mIsDocumentGone = false;
    }
  }
}

// Make shell stop being a document observer
void PresShell::EndObservingDocument() {
  // XXXbz do we need to tell the frame constructor that the document
  // is gone, perhaps?  Except for printing it's NOT gone, sometimes.
  mIsDocumentGone = true;
  mIsObservingDocument = false;
}

void PresShell::InitPaintSuppressionTimer() {
  // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
  Document* doc = mDocument->GetDisplayDocument()
                      ? mDocument->GetDisplayDocument()
                      : mDocument.get();
  const bool inProcess = !doc->GetBrowsingContext() ||
                         doc->GetBrowsingContext()->Top()->IsInProcess();
  int32_t delay = inProcess
                      ? StaticPrefs::nglayout_initialpaint_delay()
                      : StaticPrefs::nglayout_initialpaint_delay_in_oopif();
  mPaintSuppressionTimer->InitWithNamedFuncCallback(
      [](nsITimer* aTimer, void* aPresShell) {
        RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
        self->UnsuppressPainting();
      },
      this, delay, nsITimer::TYPE_ONE_SHOT,
      "PresShell::sPaintSuppressionCallback");
}

nsresult PresShell::Initialize() {
  if (mIsDestroying) {
    return NS_OK;
  }

  if (!mDocument) {
    // Nothing to do
    return NS_OK;
  }

  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::Initialize this=%p"this));

  NS_ASSERTION(!mDidInitialize, "Why are we being called?");

  RefPtr<PresShell> kungFuDeathGrip(this);

  RecomputeFontSizeInflationEnabled();
  MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);

  // Ensure the pres context doesn't think it has changed, since we haven't even
  // started layout. This avoids spurious restyles / reflows afterwards.
  //
  // Note that this is very intentionally before setting mDidInitialize so it
  // doesn't notify the document, or run media query change events.
  mPresContext->FlushPendingMediaFeatureValuesChanged();
  MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);

  mDidInitialize = true;

#ifdef DEBUG
  if (VerifyReflowFlags::NoisyCommands & gVerifyReflowFlags) {
    if (mDocument) {
      nsIURI* uri = mDocument->GetDocumentURI();
      if (uri) {
        printf("*** PresShell::Initialize (this=%p, url='%s')\n", (void*)this,
               uri->GetSpecOrDefault().get());
      }
    }
  }
#endif

  // Get the root frame from the frame constructor.
  // XXXbz it would be nice to move this somewhere else... like frame manager
  // Init(), say.  But we need to make sure our views are all set up by the
  // time we do this!
  MOZ_ASSERT(!mFrameConstructor->GetRootFrame(),
             "How did that happen, exactly?");
  ViewportFrame* rootFrame;
  {
    nsAutoScriptBlocker scriptBlocker;
    rootFrame = mFrameConstructor->ConstructRootFrame();
    mFrameConstructor->SetRootFrame(rootFrame);
  }

  NS_ENSURE_STATE(!mHaveShutDown);

  if (!rootFrame) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  if (Element* root = mDocument->GetRootElement()) {
    {
      nsAutoCauseReflowNotifier reflowNotifier(this);
      // Have the style sheet processor construct frame for the root
      // content object down
      mFrameConstructor->ContentInserted(
          root, nsCSSFrameConstructor::InsertionKind::Sync);
    }
    // Something in mFrameConstructor->ContentInserted may have caused
    // Destroy() to get called, bug 337586.  Or, nsAutoCauseReflowNotifier
    // (which sets up a script blocker) going out of scope may have killed us
    // too
    NS_ENSURE_STATE(!mHaveShutDown);
  }

  if (mDocument->HasAutoFocusCandidates()) {
    mDocument->ScheduleFlushAutoFocusCandidates();
  }

  NS_ASSERTION(rootFrame, "How did that happen?");

  // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
  // set, but XBL processing could have caused a reflow which clears it.
  if (MOZ_LIKELY(rootFrame->HasAnyStateBits(NS_FRAME_IS_DIRTY))) {
    // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
    rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
    NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
                 "Why is the root in mDirtyRoots already?");
    FrameNeedsReflow(rootFrame, IntrinsicDirty::None, NS_FRAME_IS_DIRTY);
    NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
                 "Should be in mDirtyRoots now");
    NS_ASSERTION(mObservingStyleFlushes, "Why no reflow scheduled?");
  }

  // Restore our root scroll position now if we're getting here after EndLoad
  // got called, since this is our one chance to do it.  Note that we need not
  // have reflowed for this to work; when the scrollframe is finally reflowed
  // it'll pick up the position we store in it here.
  if (!mDocumentLoading) {
    RestoreRootScrollPosition();
  }

  // For printing, we just immediately unsuppress.
  if (!mPresContext->IsPaginated()) {
    // Kick off a one-shot timer based off our pref value.  When this timer
    // fires, if painting is still locked down, then we will go ahead and
    // trigger a full invalidate and allow painting to proceed normally.
    mPaintingSuppressed = true;
    // Don't suppress painting if the document isn't loading.
    Document::ReadyState readyState = mDocument->GetReadyStateEnum();
    if (readyState != Document::READYSTATE_COMPLETE) {
      mPaintSuppressionTimer = NS_NewTimer();
    }
    if (!mPaintSuppressionTimer) {
      mPaintingSuppressed = false;
    } else {
      // Initialize the timer.
      mPaintSuppressionTimer->SetTarget(GetMainThreadSerialEventTarget());
      InitPaintSuppressionTimer();
      if (mHasTriedFastUnsuppress) {
        // Someone tried to unsuppress painting before Initialize was called so
        // unsuppress painting rather soon.
        mHasTriedFastUnsuppress = false;
        TryUnsuppressPaintingSoon();
        MOZ_ASSERT(mHasTriedFastUnsuppress);
      }
    }
  }

  // If we get here and painting is not suppressed, we still want to run the
  // unsuppression logic, so set mShouldUnsuppressPainting to true.
  if (!mPaintingSuppressed) {
    mShouldUnsuppressPainting = true;
  }

  return NS_OK;  // XXX this needs to be real. MMP
}

void PresShell::TryUnsuppressPaintingSoon() {
  if (mHasTriedFastUnsuppress) {
    return;
  }
  mHasTriedFastUnsuppress = true;

  if (!mDidInitialize || !IsPaintingSuppressed() || !XRE_IsContentProcess()) {
    return;
  }

  if (!mDocument->IsInitialDocument() &&
      mDocument->DidHitCompleteSheetCache() &&
      mPresContext->IsRootContentDocumentCrossProcess()) {
    // Try to unsuppress faster on a top level page if it uses stylesheet
    // cache, since that hints that many resources can be painted sooner than
    // in a cold page load case.
    NS_DispatchToCurrentThreadQueue(
        NS_NewRunnableFunction("PresShell::TryUnsuppressPaintingSoon",
                               [self = RefPtr{this}]() -> void {
                                 if (self->IsPaintingSuppressed()) {
                                   PROFILER_MARKER_UNTYPED(
                                       "Fast paint unsuppression", GRAPHICS);
                                   self->UnsuppressPainting();
                                 }
                               }),
        EventQueuePriority::Control);
  }
}

void PresShell::RefreshZoomConstraintsForScreenSizeChange() {
  if (mZoomConstraintsClient) {
    mZoomConstraintsClient->ScreenSizeChanged();
  }
}

void PresShell::ForceResizeReflowWithCurrentDimensions() {
  nscoord currentWidth = 0;
  nscoord currentHeight = 0;
  mViewManager->GetWindowDimensions(¤tWidth, ¤tHeight);
  ResizeReflow(currentWidth, currentHeight);
}

void PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight,
                             ResizeReflowOptions aOptions) {
  if (mZoomConstraintsClient) {
    // If we have a ZoomConstraintsClient and the available screen area
    // changed, then we might need to disable double-tap-to-zoom, so notify
    // the ZCC to update itself.
    mZoomConstraintsClient->ScreenSizeChanged();
  }
  if (UsesMobileViewportSizing()) {
    // If we are using mobile viewport sizing, request a reflow from the MVM.
    // It can recompute the final CSS viewport and trigger a call to
    // ResizeReflowIgnoreOverride if it changed. We don't force adjusting
--> --------------------

--> maximum size reached

--> --------------------

97%


¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.