Bug 1438026 - Part 3: Replace nsPresState with the new PresState type, r=baku
authorNika Layzell <nika@thelayzells.com>
Fri, 02 Mar 2018 13:18:35 -0500
changeset 412751 f394ca4f80af5fd29edab09afc6893112c808b15
parent 412750 7dadb3852649b5184bf5960b7565b0f15bee9b09
child 412752 e1fab4fd5afa8e38eeac19caab7c3b2be0872148
push id33818
push userapavel@mozilla.com
push dateWed, 11 Apr 2018 14:36:40 +0000
treeherdermozilla-central@cfe6399e142c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1438026
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1438026 - Part 3: Replace nsPresState with the new PresState type, r=baku
dom/html/HTMLButtonElement.cpp
dom/html/HTMLButtonElement.h
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/HTMLSelectElement.cpp
dom/html/HTMLSelectElement.h
dom/html/HTMLTextAreaElement.cpp
dom/html/HTMLTextAreaElement.h
dom/html/nsGenericHTMLElement.cpp
dom/html/nsGenericHTMLElement.h
dom/html/nsIFormControl.h
layout/base/nsFrameManager.cpp
layout/base/nsILayoutHistoryState.idl
layout/base/nsLayoutHistoryState.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsComboboxControlFrame.h
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIStatefulFrame.h
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -23,17 +23,17 @@
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
 #include "nsUnicharUtils.h"
 #include "nsLayoutUtils.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozAutoDocUpdate.h"
 
 #define NS_IN_SUBMIT_CLICK      (1 << 0)
 #define NS_OUTER_ACTIVATE_EVENT (1 << 1)
 
@@ -443,30 +443,31 @@ HTMLButtonElement::AfterSetAttr(int32_t 
 
 NS_IMETHODIMP
 HTMLButtonElement::SaveState()
 {
   if (!mDisabledChanged) {
     return NS_OK;
   }
 
-  nsPresState* state = GetPrimaryPresState();
+  PresState* state = GetPrimaryPresState();
   if (state) {
     // We do not want to save the real disabled state but the disabled
     // attribute.
-    state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+    state->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+    state->disabledSet() = true;
   }
 
   return NS_OK;
 }
 
 bool
-HTMLButtonElement::RestoreState(nsPresState* aState)
+HTMLButtonElement::RestoreState(PresState* aState)
 {
-  if (aState && aState->IsDisabledSet() && !aState->GetDisabled()) {
+  if (aState && aState->disabledSet() && !aState->disabled()) {
     SetDisabled(false, IgnoreErrors());
   }
 
   return false;
 }
 
 EventStates
 HTMLButtonElement::IntrinsicState() const
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -40,17 +40,17 @@ public:
   {
     return true;
   }
 
   // overriden nsIFormControl methods
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
   NS_IMETHOD SaveState() override;
-  bool RestoreState(nsPresState* aState) override;
+  bool RestoreState(PresState* aState) override;
   virtual bool IsDisabledForEvents(EventMessage aMessage) override;
 
   virtual void FieldSetDisabledChanged(bool aNotify) override;
 
   // EventTarget
   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -49,17 +49,17 @@
 #include "nsRangeFrame.h"
 #include "nsIServiceManager.h"
 #include "nsError.h"
 #include "nsIEditor.h"
 #include "nsDocument.h"
 #include "nsAttrValueOrString.h"
 #include "nsDateTimeControlFrame.h"
 
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMNodeList.h"
 #include "nsLinebreakConverter.h" //to strip out carriage returns
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsVariant.h"
 
@@ -269,139 +269,16 @@ public:
 
     return rv;
   }
 
 private:
   RefPtr<HTMLInputElement> mInputElement;
 };
 
-class HTMLInputElementState final : public nsISupports
-{
-  public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
-    NS_DECL_ISUPPORTS
-
-    bool IsCheckedSet()
-    {
-      return mCheckedSet;
-    }
-
-    bool GetChecked()
-    {
-      return mChecked;
-    }
-
-    void SetChecked(bool aChecked)
-    {
-      mChecked = aChecked;
-      mCheckedSet = true;
-    }
-
-    const nsString& GetValue()
-    {
-      return mValue;
-    }
-
-    void SetValue(const nsAString& aValue)
-    {
-      mValue = aValue;
-    }
-
-    void
-    GetFilesOrDirectories(nsPIDOMWindowInner* aWindow,
-                          nsTArray<OwningFileOrDirectory>& aResult) const
-    {
-      for (uint32_t i = 0; i < mBlobImplsOrDirectoryPaths.Length(); ++i) {
-        if (mBlobImplsOrDirectoryPaths[i].mType == BlobImplOrDirectoryPath::eBlobImpl) {
-          RefPtr<File> file =
-            File::Create(aWindow,
-                         mBlobImplsOrDirectoryPaths[i].mBlobImpl);
-          MOZ_ASSERT(file);
-
-          OwningFileOrDirectory* element = aResult.AppendElement();
-          element->SetAsFile() = file;
-        } else {
-          MOZ_ASSERT(mBlobImplsOrDirectoryPaths[i].mType == BlobImplOrDirectoryPath::eDirectoryPath);
-
-          nsCOMPtr<nsIFile> file;
-          nsresult rv =
-            NS_NewLocalFile(mBlobImplsOrDirectoryPaths[i].mDirectoryPath,
-                            true, getter_AddRefs(file));
-          if (NS_WARN_IF(NS_FAILED(rv))) {
-            continue;
-          }
-
-          RefPtr<Directory> directory = Directory::Create(aWindow, file);
-          MOZ_ASSERT(directory);
-
-          OwningFileOrDirectory* element = aResult.AppendElement();
-          element->SetAsDirectory() = directory;
-        }
-      }
-    }
-
-    void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
-    {
-      mBlobImplsOrDirectoryPaths.Clear();
-      for (uint32_t i = 0; i < aArray.Length(); ++i) {
-        if (aArray[i].IsFile()) {
-          BlobImplOrDirectoryPath* data = mBlobImplsOrDirectoryPaths.AppendElement();
-
-          data->mBlobImpl = aArray[i].GetAsFile()->Impl();
-          data->mType = BlobImplOrDirectoryPath::eBlobImpl;
-        } else {
-          MOZ_ASSERT(aArray[i].IsDirectory());
-          nsAutoString fullPath;
-          nsresult rv = aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);
-          if (NS_WARN_IF(NS_FAILED(rv))) {
-            continue;
-          }
-
-          BlobImplOrDirectoryPath* data =
-            mBlobImplsOrDirectoryPaths.AppendElement();
-
-          data->mDirectoryPath = fullPath;
-          data->mType = BlobImplOrDirectoryPath::eDirectoryPath;
-        }
-      }
-    }
-
-    HTMLInputElementState()
-      : mValue()
-      , mChecked(false)
-      , mCheckedSet(false)
-    {}
-
-  protected:
-    ~HTMLInputElementState() {}
-
-    nsString mValue;
-
-    struct BlobImplOrDirectoryPath
-    {
-      RefPtr<BlobImpl> mBlobImpl;
-      nsString mDirectoryPath;
-
-      enum {
-        eBlobImpl,
-        eDirectoryPath
-      } mType;
-    };
-
-    nsTArray<BlobImplOrDirectoryPath> mBlobImplsOrDirectoryPaths;
-
-    bool mChecked;
-    bool mCheckedSet;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
-
-NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
-
 struct HTMLInputElement::FileData
 {
   /**
    * The value of the input if it is a file input. This is the list of files or
    * directories DOM objects used when uploading a file. It is vital that this
    * is kept separate from mValue so that it won't be possible to 'leak' the
    * value from a text-input to a file-input. Additionally, the logic for this
    * value is kept as simple as possible to avoid accidental errors where the
@@ -6361,44 +6238,61 @@ HTMLInputElement::SubmitNamesValues(HTML
     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                        "Submit", defaultValue);
     value = defaultValue;
   }
 
   return aFormSubmission->AddNameValuePair(name, value);
 }
 
+static nsTArray<FileContentData>
+SaveFileContentData(const nsTArray<OwningFileOrDirectory>& aArray)
+{
+  nsTArray<FileContentData> res(aArray.Length());
+  for (auto& it : aArray) {
+    if (it.IsFile()) {
+      RefPtr<BlobImpl> impl = it.GetAsFile()->Impl();
+      res.AppendElement(Move(impl));
+    } else {
+      MOZ_ASSERT(it.IsDirectory());
+      nsString fullPath;
+      nsresult rv = it.GetAsDirectory()->GetFullRealPath(fullPath);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        continue;
+      }
+      res.AppendElement(Move(fullPath));
+    }
+  }
+  return res;
+}
 
 NS_IMETHODIMP
 HTMLInputElement::SaveState()
 {
-  nsPresState* state = nullptr;
+  PresState* state = nullptr;
   switch (GetValueMode()) {
     case VALUE_MODE_DEFAULT_ON:
       if (mCheckedChanged) {
         state = GetPrimaryPresState();
         if (!state) {
           return NS_OK;
         }
 
-        RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
-        inputState->SetChecked(mChecked);
-        state->SetStateProperty(inputState);
+        state->contentData() = CheckedContentData(mChecked);
       }
       break;
     case VALUE_MODE_FILENAME:
       if (!mFileData->mFilesOrDirectories.IsEmpty()) {
         state = GetPrimaryPresState();
         if (!state) {
           return NS_OK;
         }
 
-        RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
-        inputState->SetFilesOrDirectories(mFileData->mFilesOrDirectories);
-        state->SetStateProperty(inputState);
+        state->contentData() =
+          SaveFileContentData(mFileData->mFilesOrDirectories);
       }
       break;
     case VALUE_MODE_VALUE:
     case VALUE_MODE_DEFAULT:
       // VALUE_MODE_DEFAULT shouldn't have their value saved except 'hidden',
       // mType shouldn't be NS_FORM_INPUT_PASSWORD and value should have changed.
       if ((GetValueMode() == VALUE_MODE_DEFAULT &&
            mType != NS_FORM_INPUT_HIDDEN) ||
@@ -6406,45 +6300,44 @@ HTMLInputElement::SaveState()
         break;
       }
 
       state = GetPrimaryPresState();
       if (!state) {
         return NS_OK;
       }
 
-      RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
       nsAutoString value;
       GetValue(value, CallerType::System);
 
       if (!IsSingleLineTextControl(false)) {
         nsresult rv = nsLinebreakConverter::ConvertStringLineBreaks(
                value,
                nsLinebreakConverter::eLinebreakPlatform,
                nsLinebreakConverter::eLinebreakContent);
 
         if (NS_FAILED(rv)) {
           NS_ERROR("Converting linebreaks failed!");
           return rv;
         }
       }
 
-      inputState->SetValue(value);
-      state->SetStateProperty(inputState);
+      state->contentData() = Move(value);
       break;
   }
 
   if (mDisabledChanged) {
     if (!state) {
       state = GetPrimaryPresState();
     }
     if (state) {
       // We do not want to save the real disabled state but the disabled
       // attribute.
-      state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+      state->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+      state->disabledSet() = true;
     }
   }
 
   return NS_OK;
 }
 
 void
 HTMLInputElement::DoneCreatingElement()
@@ -6610,60 +6503,95 @@ HTMLInputElement::RemoveStates(EventStat
       if (ownerNumberControl) {
         ownerNumberControl->RemoveStates(focusStates);
       }
     }
   }
   nsGenericHTMLFormElementWithState::RemoveStates(aStates);
 }
 
+static nsTArray<OwningFileOrDirectory>
+RestoreFileContentData(nsPIDOMWindowInner* aWindow,
+                       const nsTArray<FileContentData>& aData)
+{
+  nsTArray<OwningFileOrDirectory> res(aData.Length());
+  for (auto& it : aData) {
+    if (it.type() == FileContentData::TBlobImplPtr) {
+      if (!it.get_BlobImplPtr()) {
+        // Serialization failed, skip this file.
+        continue;
+      }
+
+      RefPtr<File> file = File::Create(aWindow, it.get_BlobImplPtr());
+      MOZ_ASSERT(file);
+
+      OwningFileOrDirectory* element = res.AppendElement();
+      element->SetAsFile() = file;
+    } else {
+      MOZ_ASSERT(it.type() == FileContentData::TnsString);
+      nsCOMPtr<nsIFile> file;
+      nsresult rv = NS_NewLocalFile(it.get_nsString(), true,
+                                    getter_AddRefs(file));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        continue;
+      }
+
+      RefPtr<Directory> directory = Directory::Create(aWindow, file);
+      MOZ_ASSERT(directory);
+
+      OwningFileOrDirectory* element = res.AppendElement();
+      element->SetAsDirectory() = directory;
+    }
+  }
+  return res;
+}
+
 bool
-HTMLInputElement::RestoreState(nsPresState* aState)
+HTMLInputElement::RestoreState(PresState* aState)
 {
   bool restoredCheckedState = false;
 
-  nsCOMPtr<HTMLInputElementState> inputState
-    (do_QueryInterface(aState->GetStateProperty()));
-
-  if (inputState) {
-    switch (GetValueMode()) {
-      case VALUE_MODE_DEFAULT_ON:
-        if (inputState->IsCheckedSet()) {
-          restoredCheckedState = true;
-          DoSetChecked(inputState->GetChecked(), true, true);
+  const PresContentData& inputState = aState->contentData();
+
+  switch (GetValueMode()) {
+    case VALUE_MODE_DEFAULT_ON:
+      if (inputState.type() == PresContentData::TCheckedContentData) {
+        restoredCheckedState = true;
+        bool checked = inputState.get_CheckedContentData().checked();
+        DoSetChecked(checked, true, true);
+      }
+      break;
+    case VALUE_MODE_FILENAME:
+      if (inputState.type() == PresContentData::TArrayOfFileContentData) {
+        nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
+        if (window) {
+          nsTArray<OwningFileOrDirectory> array =
+            RestoreFileContentData(window, inputState);
+          SetFilesOrDirectories(array, true);
         }
+      }
+      break;
+    case VALUE_MODE_VALUE:
+    case VALUE_MODE_DEFAULT:
+      if (GetValueMode() == VALUE_MODE_DEFAULT &&
+          mType != NS_FORM_INPUT_HIDDEN) {
         break;
-      case VALUE_MODE_FILENAME:
-        {
-          nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
-          if (window) {
-            nsTArray<OwningFileOrDirectory> array;
-            inputState->GetFilesOrDirectories(window, array);
-
-            SetFilesOrDirectories(array, true);
-          }
-        }
-        break;
-      case VALUE_MODE_VALUE:
-      case VALUE_MODE_DEFAULT:
-        if (GetValueMode() == VALUE_MODE_DEFAULT &&
-            mType != NS_FORM_INPUT_HIDDEN) {
-          break;
-        }
-
+      }
+
+      if (inputState.type() == PresContentData::TnsString) {
         // TODO: What should we do if SetValueInternal fails?  (The allocation
         // may potentially be big, but most likely we've failed to allocate
         // before the type change.)
-        SetValueInternal(inputState->GetValue(),
+        SetValueInternal(inputState.get_nsString(),
                          nsTextEditorState::eSetValue_Notify);
-        break;
-    }
-  }
-
-  if (aState->IsDisabledSet() && !aState->GetDisabled()) {
+      }
+      break;
+  }
+
+  if (aState->disabledSet() && !aState->disabled()) {
     SetDisabled(false, IgnoreErrors());
   }
 
   return restoredCheckedState;
 }
 
 bool
 HTMLInputElement::AllowDrop()
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -178,17 +178,17 @@ public:
   }
 
   NS_IMETHOD SetUserInput(const nsAString& aInput) override;
 
   // Overriden nsIFormControl methods
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
   NS_IMETHOD SaveState() override;
-  virtual bool RestoreState(nsPresState* aState) override;
+  virtual bool RestoreState(PresState* aState) override;
   virtual bool AllowDrop() override;
   virtual bool IsDisabledForEvents(EventMessage aMessage) override;
 
   virtual void FieldSetDisabledChanged(bool aNotify) override;
 
   // nsIContent
   virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
 
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -27,28 +27,26 @@
 #include "nsIFormControlFrame.h"
 #include "nsIForm.h"
 #include "nsIFormProcessor.h"
 #include "nsIFrame.h"
 #include "nsIListControlFrame.h"
 #include "nsISelectControlFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsMappedAttributes.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleConsts.h"
 #include "nsTextNode.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Select)
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_ISUPPORTS(SelectState, SelectState)
-
 //----------------------------------------------------------------------
 //
 // SafeOptionListMutation
 //
 
 SafeOptionListMutation::SafeOptionListMutation(nsIContent* aSelect,
                                                nsIContent* aParent,
                                                nsIContent* aKid,
@@ -1240,17 +1238,17 @@ HTMLSelectElement::DoneAddingChildren(bo
 {
   mIsDoneAddingChildren = true;
 
   nsISelectControlFrame* selectFrame = GetSelectFrame();
 
   // If we foolishly tried to restore before we were done adding
   // content, restore the rest of the options proper-like
   if (mRestoreState) {
-    RestoreStateTo(mRestoreState);
+    RestoreStateTo(*mRestoreState);
     mRestoreState = nullptr;
   }
 
   // Notify the frame
   if (selectFrame) {
     selectFrame->DoneAddingChildren(true);
   }
 
@@ -1417,88 +1415,99 @@ HTMLSelectElement::IntrinsicState() cons
   return state;
 }
 
 // nsIFormControl
 
 NS_IMETHODIMP
 HTMLSelectElement::SaveState()
 {
-  nsPresState* presState = GetPrimaryPresState();
+  PresState* presState = GetPrimaryPresState();
   if (!presState) {
     return NS_OK;
   }
 
-  RefPtr<SelectState> state = new SelectState();
+  SelectContentData state;
 
   uint32_t len = Length();
 
   for (uint32_t optIndex = 0; optIndex < len; optIndex++) {
     HTMLOptionElement* option = Item(optIndex);
     if (option && option->Selected()) {
       nsAutoString value;
       option->GetValue(value);
-      state->PutOption(optIndex, value);
+      if (value.IsEmpty()) {
+        state.indices().AppendElement(optIndex);
+      } else {
+        state.values().AppendElement(Move(value));
+      }
     }
   }
 
-  presState->SetStateProperty(state);
+  presState->contentData() = Move(state);
 
   if (mDisabledChanged) {
     // We do not want to save the real disabled state but the disabled
     // attribute.
-    presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+    presState->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+    presState->disabledSet() = true;
   }
 
   return NS_OK;
 }
 
 bool
-HTMLSelectElement::RestoreState(nsPresState* aState)
+HTMLSelectElement::RestoreState(PresState* aState)
 {
   // Get the presentation state object to retrieve our stuff out of.
-  nsCOMPtr<SelectState> state(
-    do_QueryInterface(aState->GetStateProperty()));
-
-  if (state) {
-    RestoreStateTo(state);
+  const PresContentData& state = aState->contentData();
+  if (state.type() == PresContentData::TSelectContentData) {
+    RestoreStateTo(state.get_SelectContentData());
 
     // Don't flush, if the frame doesn't exist yet it doesn't care if
     // we're reset or not.
     DispatchContentReset();
   }
 
-  if (aState->IsDisabledSet() && !aState->GetDisabled()) {
+  if (aState->disabledSet() && !aState->disabled()) {
     SetDisabled(false, IgnoreErrors());
   }
 
   return false;
 }
 
 void
-HTMLSelectElement::RestoreStateTo(SelectState* aNewSelected)
+HTMLSelectElement::RestoreStateTo(const SelectContentData& aNewSelected)
 {
   if (!mIsDoneAddingChildren) {
-    mRestoreState = aNewSelected;
+    // Make a copy of the state for us to restore from in the future.
+    mRestoreState = MakeUnique<SelectContentData>(aNewSelected);
     return;
   }
 
   uint32_t len = Length();
   uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED | NOTIFY;
 
   // First clear all
   SetOptionsSelectedByIndex(-1, -1, mask);
 
-  // Next set the proper ones
-  for (uint32_t i = 0; i < len; i++) {
+  // Select by index.
+  for (uint32_t idx : aNewSelected.indices()) {
+    if (idx < len) {
+      SetOptionsSelectedByIndex(idx, idx, IS_SELECTED | SET_DISABLED | NOTIFY);
+    }
+  }
+
+  // Select by value.
+  for (uint32_t i = 0; i < len; ++i) {
     HTMLOptionElement* option = Item(i);
     if (option) {
       nsAutoString value;
       option->GetValue(value);
-      if (aNewSelected->ContainsOption(i, value)) {
+      if (aNewSelected.values().Contains(value)) {
         SetOptionsSelectedByIndex(i, i, IS_SELECTED | SET_DISABLED | NOTIFY);
       }
     }
   }
 }
 
 NS_IMETHODIMP
 HTMLSelectElement::Reset()
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -19,74 +19,29 @@
 #include "nsError.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "nsContentUtils.h"
 
 class nsContentList;
 class nsIDOMHTMLOptionElement;
 class nsIHTMLCollection;
 class nsISelectControlFrame;
-class nsPresState;
 
 namespace mozilla {
 
 class EventChainPostVisitor;
 class EventChainPreVisitor;
+class SelectContentData;
+class PresState;
 
 namespace dom {
 
 class HTMLFormSubmission;
 class HTMLSelectElement;
 
-#define NS_SELECT_STATE_IID                        \
-{ /* 4db54c7c-d159-455f-9d8e-f60ee466dbf3 */       \
-  0x4db54c7c,                                      \
-  0xd159,                                          \
-  0x455f,                                          \
-  {0x9d, 0x8e, 0xf6, 0x0e, 0xe4, 0x66, 0xdb, 0xf3} \
-}
-
-/**
- * The restore state used by select
- */
-class SelectState : public nsISupports
-{
-public:
-  SelectState()
-  {
-  }
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_SELECT_STATE_IID)
-  NS_DECL_ISUPPORTS
-
-  void PutOption(int32_t aIndex, const nsAString& aValue)
-  {
-    // If the option is empty, store the index.  If not, store the value.
-    if (aValue.IsEmpty()) {
-      mIndices.Put(aIndex);
-    } else {
-      mValues.Put(aValue);
-    }
-  }
-
-  bool ContainsOption(int32_t aIndex, const nsAString& aValue)
-  {
-    return mValues.Contains(aValue) || mIndices.Contains(aIndex);
-  }
-
-private:
-  virtual ~SelectState()
-  {
-  }
-
-  nsCheapSet<nsStringHashKey> mValues;
-  nsCheapSet<nsUint32HashKey> mIndices;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(SelectState, NS_SELECT_STATE_IID)
-
 class MOZ_STACK_CLASS SafeOptionListMutation
 {
 public:
   /**
    * @param aSelect The select element which option list is being mutated.
    *                Can be null.
    * @param aParent The content object which is being mutated.
    * @param aKid    If not null, a new child element is being inserted to
@@ -296,17 +251,17 @@ public:
                                             bool aNotify) override;
   virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
   virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
 
   // Overriden nsIFormControl methods
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
   NS_IMETHOD SaveState() override;
-  virtual bool RestoreState(nsPresState* aState) override;
+  virtual bool RestoreState(PresState* aState) override;
   virtual bool IsDisabledForEvents(EventMessage aMessage) override;
 
   virtual void FieldSetDisabledChanged(bool aNotify) override;
 
   EventStates IntrinsicState() const override;
 
   /**
    * To be called when stuff is added under a child of the select--but *before*
@@ -484,17 +439,17 @@ protected:
                         int32_t aIndex,
                         bool aSelected,
                         bool aChangeOptionState,
                         bool aNotify);
   /**
    * Restore state to a particular state string (representing the options)
    * @param aNewSelected the state string to restore to
    */
-  void RestoreStateTo(SelectState* aNewSelected);
+  void RestoreStateTo(const SelectContentData& aNewSelected);
 
   // Adding options
   /**
    * Insert option(s) into the options[] array and perform notifications
    * @param aOptions the option or optgroup being added
    * @param aListIndex the index to start adding options into the list at
    * @param aDepth the depth of aOptions (1=direct child of select ...)
    */
@@ -642,17 +597,17 @@ protected:
    * The current selected index for selectedIndex (will be the first selected
    * index if multiple are selected)
    */
   int32_t   mSelectedIndex;
   /**
    * The temporary restore state in case we try to restore before parser is
    * done adding options
    */
-  nsCOMPtr<SelectState> mRestoreState;
+  UniquePtr<SelectContentData> mRestoreState;
 
   /**
    * The live list of selected options.
   */
   RefPtr<nsContentList> mSelectedOptions;
 
   /**
    * The current displayed preview text.
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -30,17 +30,17 @@
 #include "nsIFrame.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITextControlFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsLinebreakConverter.h"
 #include "nsMappedAttributes.h"
 #include "nsPIDOMWindow.h"
 #include "nsPresContext.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsReadableUtils.h"
 #include "nsStyleConsts.h"
 #include "nsTextEditorState.h"
 #include "nsIController.h"
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
 
 #define NS_NO_CONTENT_DISPATCH (1 << 0)
@@ -826,72 +826,64 @@ HTMLTextAreaElement::SubmitNamesValues(H
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SaveState()
 {
   nsresult rv = NS_OK;
 
   // Only save if value != defaultValue (bug 62713)
-  nsPresState *state = nullptr;
+  PresState *state = nullptr;
   if (mValueChanged) {
     state = GetPrimaryPresState();
     if (state) {
       nsAutoString value;
       GetValueInternal(value, true);
 
       rv = nsLinebreakConverter::ConvertStringLineBreaks(
                value,
                nsLinebreakConverter::eLinebreakPlatform,
                nsLinebreakConverter::eLinebreakContent);
 
       if (NS_FAILED(rv)) {
         NS_ERROR("Converting linebreaks failed!");
         return rv;
       }
 
-      nsCOMPtr<nsISupportsString> pState =
-        do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-      if (!pState) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-      pState->SetData(value);
-      state->SetStateProperty(pState);
+      state->contentData() = Move(value);
     }
   }
 
   if (mDisabledChanged) {
     if (!state) {
       state = GetPrimaryPresState();
       rv = NS_OK;
     }
     if (state) {
       // We do not want to save the real disabled state but the disabled
       // attribute.
-      state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+      state->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+      state->disabledSet() = true;
     }
   }
   return rv;
 }
 
 bool
-HTMLTextAreaElement::RestoreState(nsPresState* aState)
+HTMLTextAreaElement::RestoreState(PresState* aState)
 {
-  nsCOMPtr<nsISupportsString> state
-    (do_QueryInterface(aState->GetStateProperty()));
+  const PresContentData& state = aState->contentData();
 
-  if (state) {
-    nsAutoString data;
-    state->GetData(data);
+  if (state.type() == PresContentData::TnsString) {
     ErrorResult rv;
-    SetValue(data, rv);
+    SetValue(state.get_nsString(), rv);
     ENSURE_SUCCESS(rv, false);
   }
 
-  if (aState->IsDisabledSet() && !aState->GetDisabled()) {
+  if (aState->disabledSet() && !aState->disabled()) {
     SetDisabled(false, IgnoreErrors());
   }
 
   return false;
 }
 
 EventStates
 HTMLTextAreaElement::IntrinsicState() const
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -20,23 +20,23 @@
 #include "nsGkAtoms.h"
 
 #include "mozilla/TextEditor.h"
 #include "nsTextEditorState.h"
 
 class nsIControllers;
 class nsIDocument;
 class nsPresContext;
-class nsPresState;
 
 namespace mozilla {
 
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 class EventStates;
+class PresState;
 
 namespace dom {
 
 class HTMLFormSubmission;
 
 class HTMLTextAreaElement final : public nsGenericHTMLFormElementWithState,
                                   public nsITextControlElement,
                                   public nsIDOMNSEditableElement,
@@ -70,17 +70,17 @@ public:
     return NS_OK;
   }
   NS_IMETHOD SetUserInput(const nsAString& aInput) override;
 
   // nsIFormControl
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
   NS_IMETHOD SaveState() override;
-  virtual bool RestoreState(nsPresState* aState) override;
+  virtual bool RestoreState(PresState* aState) override;
   virtual bool IsDisabledForEvents(EventMessage aMessage) override;
 
   virtual void FieldSetDisabledChanged(bool aNotify) override;
 
   virtual EventStates IntrinsicState() const override;
 
   // nsITextControlElemet
   NS_IMETHOD SetValueChanged(bool aValueChanged) override;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -44,17 +44,17 @@
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
 #include "nsNameSpaceManager.h"
 #include "nsError.h"
 #include "nsIPrincipal.h"
 #include "nsContainerFrame.h"
 #include "nsStyleUtil.h"
 
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsILayoutHistoryState.h"
 
 #include "nsHTMLParts.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsGkAtoms.h"
@@ -2751,34 +2751,35 @@ nsGenericHTMLFormElementWithState::Gener
   // reason we are not supposed to save/restore state: keep it as such.
   if (!mStateKey.IsEmpty()) {
     // Add something unique to content so layout doesn't muck us up.
     mStateKey += "-C";
   }
   return NS_OK;
 }
 
-nsPresState*
+PresState*
 nsGenericHTMLFormElementWithState::GetPrimaryPresState()
 {
   if (mStateKey.IsEmpty()) {
     return nullptr;
   }
 
   nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistory(false);
 
   if (!history) {
     return nullptr;
   }
 
   // Get the pres state for this key, if it doesn't exist, create one.
-  nsPresState* result = history->GetState(mStateKey);
+  PresState* result = history->GetState(mStateKey);
   if (!result) {
-    result = new nsPresState();
-    history->AddState(mStateKey, result);
+    UniquePtr<PresState> newState = NewPresState();
+    result = newState.get();
+    history->AddState(mStateKey, Move(newState));
   }
 
   return result;
 }
 
 already_AddRefed<nsILayoutHistoryState>
 nsGenericHTMLFormElementWithState::GetLayoutHistory(bool aRead)
 {
@@ -2810,19 +2811,18 @@ nsGenericHTMLFormElementWithState::Resto
   }
 
   nsCOMPtr<nsILayoutHistoryState> history =
     GetLayoutHistory(true);
   if (!history) {
     return false;
   }
 
-  nsPresState *state;
   // Get the pres state for this key
-  state = history->GetState(mStateKey);
+  PresState* state = history->GetState(mStateKey);
   if (state) {
     bool result = RestoreState(state);
     history->RemoveState(mStateKey);
     return result;
   }
 
   return false;
 }
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -20,26 +20,26 @@
 #include "mozilla/dom/ValidityState.h"
 #include "mozilla/dom/Element.h"
 
 class nsDOMTokenList;
 class nsIFormControlFrame;
 class nsIFrame;
 class nsILayoutHistoryState;
 class nsIURI;
-class nsPresState;
 struct nsSize;
 
 namespace mozilla {
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 class EventChainVisitor;
 class EventListenerManager;
 class EventStates;
 class TextEditor;
+class PresState;
 namespace dom {
 class HTMLFormElement;
 class HTMLMenuElement;
 } // namespace dom
 } // namespace mozilla
 
 typedef nsMappedAttributeElement nsGenericHTMLElementBase;
 
@@ -1013,17 +1013,17 @@ public:
   virtual void SetForm(mozilla::dom::HTMLFormElement* aForm) override;
   virtual void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) override;
 
   NS_IMETHOD SaveState() override
   {
     return NS_OK;
   }
 
-  virtual bool RestoreState(nsPresState* aState) override
+  virtual bool RestoreState(mozilla::PresState* aState) override
   {
     return false;
   }
   virtual bool AllowDrop() override
   {
     return true;
   }
 
@@ -1179,17 +1179,17 @@ class nsGenericHTMLFormElementWithState 
 public:
   nsGenericHTMLFormElementWithState(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                                     uint8_t aType);
 
   /**
    * Get the presentation state for a piece of content, or create it if it does
    * not exist.  Generally used by SaveState().
    */
-  nsPresState* GetPrimaryPresState();
+  mozilla::PresState* GetPrimaryPresState();
 
   /**
    * Get the layout history object for a particular piece of content.
    *
    * @param aRead if true, won't return a layout history state if the
    *              layout history state is empty.
    * @return the history state object
    */
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -4,19 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsIFormControl_h___
 #define nsIFormControl_h___
 
 #include "mozilla/EventForwards.h"
 #include "nsISupports.h"
 
-class nsPresState;
-
 namespace mozilla {
+class PresState;
 namespace dom {
 class Element;
 class HTMLFieldSetElement;
 class HTMLFormSubmission;
 class HTMLFormElement;
 } // namespace dom
 } // namespace mozilla
 
@@ -164,17 +163,17 @@ public:
    * Restore from presentation state.  You pass in the presentation state for
    * this form control (generated with GenerateStateKey() + "-C") and the form
    * control will grab its state from there.
    *
    * @param aState the pres state to use to restore the control
    * @return true if the form control was a checkbox and its
    *         checked state was restored, false otherwise.
    */
-  virtual bool RestoreState(nsPresState* aState) = 0;
+  virtual bool RestoreState(mozilla::PresState* aState) = 0;
 
   virtual bool AllowDrop() = 0;
 
   /**
    * Returns whether this is a control which submits the form when activated by
    * the user.
    * @return whether this is a submit control.
    */
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -10,17 +10,17 @@
 
 #include "nscore.h"
 #include "nsIPresShell.h"
 #include "nsCOMPtr.h"
 #include "plhash.h"
 #include "nsPlaceholderFrame.h"
 #include "nsGkAtoms.h"
 #include "nsILayoutHistoryState.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/UndisplayedNode.h"
 #include "nsIDocument.h"
 
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsAutoPtr.h"
@@ -147,34 +147,33 @@ nsFrameManager::CaptureFrameStateFor(nsI
 
   // Only capture state for stateful frames
   nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
   if (!statefulFrame) {
     return;
   }
 
   // Capture the state, exit early if we get null (nothing to save)
-  nsAutoPtr<nsPresState> frameState;
-  nsresult rv = statefulFrame->SaveState(getter_Transfers(frameState));
+  UniquePtr<PresState> frameState = statefulFrame->SaveState();
   if (!frameState) {
     return;
   }
 
   // Generate the hash key to store the state under
   // Exit early if we get empty key
   nsAutoCString stateKey;
   nsIContent* content = aFrame->GetContent();
   nsIDocument* doc = content ? content->GetUncomposedDoc() : nullptr;
-  rv = statefulFrame->GenerateStateKey(content, doc, stateKey);
+  nsresult rv = statefulFrame->GenerateStateKey(content, doc, stateKey);
   if(NS_FAILED(rv) || stateKey.IsEmpty()) {
     return;
   }
 
   // Store the state. aState owns frameState now.
-  aState->AddState(stateKey, frameState.forget());
+  aState->AddState(stateKey, Move(frameState));
 }
 
 void
 nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
                                   nsILayoutHistoryState* aState)
 {
   NS_PRECONDITION(nullptr != aFrame && nullptr != aState, "null parameters passed in");
 
@@ -227,17 +226,17 @@ nsFrameManager::RestoreFrameStateFor(nsI
   nsAutoCString stateKey;
   nsIDocument* doc = content->GetUncomposedDoc();
   nsresult rv = statefulFrame->GenerateStateKey(content, doc, stateKey);
   if (NS_FAILED(rv) || stateKey.IsEmpty()) {
     return;
   }
 
   // Get the state from the hash
-  nsPresState* frameState = aState->GetState(stateKey);
+  PresState* frameState = aState->GetState(stateKey);
   if (!frameState) {
     return;
   }
 
   // Restore it
   rv = statefulFrame->RestoreState(frameState);
   if (NS_FAILED(rv)) {
     return;
--- a/layout/base/nsILayoutHistoryState.idl
+++ b/layout/base/nsILayoutHistoryState.idl
@@ -5,19 +5,19 @@
 
 /*
  * interface for container for information saved in session history when
  * the document is not
  */
 
 #include "nsISupports.idl"
 
-interface nsPresState;
 
-[ptr] native nsPresStatePtr(nsPresState);
+[ptr] native PresStatePtr(mozilla::PresState);
+native PresStateUnique(mozilla::UniquePtr<mozilla::PresState>);
 [ref] native nsCString(const nsCString);
 native constBool(const bool);
 
 %{C++
 #include "nsStringFwd.h"
 #include "mozilla/UniquePtr.h"
 
 namespace mozilla {
@@ -47,38 +47,38 @@ interface nsILayoutHistoryState : nsISup
   * the passed key. Throws if no data could be found.
   */
   void getPresState(in ACString aKey,
                     out float aScrollX, out float aScrollY,
                     out boolean aAllowScrollOriginDowngrade,
                     out float aRes, out boolean aScaleToRes);
 
   /**
-   * Constructs a new nsPresState object based on the supplied data
+   * Constructs a new PresState object based on the supplied data
    * and adds it to the LayoutHistoryState.
    */
   void addNewPresState(in ACString aKey,
                    in float aScrollX, in float aScrollY,
                    in boolean aAllowScrollOriginDowngrade,
                    in float aRes, in boolean aScaleToRes);
 
   // Native only interface, converted from the original nsILayoutHistoryState.h
 
   /**
    * Set |aState| as the state object for |aKey|.
    * This _transfers_ownership_ of |aState| to the LayoutHistoryState.
    * It will be freed when RemoveState() is called or when the
    * LayoutHistoryState is destroyed.
    */
-  [noscript, notxpcom, nostdcall] void AddState(in nsCString aKey, in nsPresStatePtr aState);
+  [noscript, notxpcom, nostdcall] void AddState(in nsCString aKey, in PresStateUnique aState);
 
   /**
    * Look up the state object for |aKey|.
    */
-  [noscript, notxpcom, nostdcall] nsPresStatePtr GetState(in nsCString aKey);
+  [noscript, notxpcom, nostdcall] PresStatePtr GetState(in nsCString aKey);
 
   /**
    * Remove the state object for |aKey|.
    */
   [noscript, notxpcom, nostdcall] void RemoveState(in nsCString aKey);
 
   /**
    * Check whether this history has any states in it
@@ -87,17 +87,17 @@ interface nsILayoutHistoryState : nsISup
 
   /**
    * Sets whether this history can contain only scroll position history
    * or all possible history
    */
   [noscript, notxpcom, nostdcall] void SetScrollPositionOnly(in constBool aFlag);
 
   /**
-   * Resets nsPresState::GetScrollState of all nsPresState objects to 0,0.
+   * Resets PresState::GetScrollState of all PresState objects to 0,0.
    */
   [noscript, notxpcom, nostdcall] void ResetScrollState();
 };
 
 %{C++
 /* Defined in nsLayoutHistoryState.cpp */
 already_AddRefed<nsILayoutHistoryState>
 NS_NewLayoutHistoryState();
--- a/layout/base/nsLayoutHistoryState.cpp
+++ b/layout/base/nsLayoutHistoryState.cpp
@@ -7,18 +7,21 @@
 /*
  * container for information saved in session history when the document
  * is not
  */
 
 #include "nsILayoutHistoryState.h"
 #include "nsWeakReference.h"
 #include "nsClassHashtable.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
+
+using namespace mozilla;
 
 class nsLayoutHistoryState final : public nsILayoutHistoryState,
                                    public nsSupportsWeakReference
 {
 public:
   nsLayoutHistoryState()
     : mScrollPositionOnly(false)
   {
@@ -26,17 +29,17 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSILAYOUTHISTORYSTATE
 
 private:
   ~nsLayoutHistoryState() {}
   bool mScrollPositionOnly;
 
-  nsClassHashtable<nsCStringHashKey,nsPresState> mStates;
+  nsDataHashtable<nsCStringHashKey, UniquePtr<PresState>> mStates;
 };
 
 
 already_AddRefed<nsILayoutHistoryState>
 NS_NewLayoutHistoryState()
 {
   RefPtr<nsLayoutHistoryState> state = new nsLayoutHistoryState();
   return state.forget();
@@ -74,63 +77,67 @@ nsLayoutHistoryState::GetKeys(uint32_t* 
 }
 
 NS_IMETHODIMP
 nsLayoutHistoryState::GetPresState(const nsACString& aKey,
                                    float* aScrollX, float* aScrollY,
                                    bool* aAllowScrollOriginDowngrade,
                                    float* aRes, bool* aScaleToRes)
 {
-  nsPresState* state = GetState(nsCString(aKey));
+  PresState* state = GetState(nsCString(aKey));
 
   if (!state) {
     return NS_ERROR_FAILURE;
   }
 
-  *aScrollX = state->GetScrollPosition().x;
-  *aScrollY = state->GetScrollPosition().y;
-  *aAllowScrollOriginDowngrade = state->GetAllowScrollOriginDowngrade();
-  *aRes = state->GetResolution();
-  *aScaleToRes = state->GetScaleToResolution();
+  *aScrollX = state->scrollState().x;
+  *aScrollY = state->scrollState().y;
+  *aAllowScrollOriginDowngrade = state->allowScrollOriginDowngrade();
+  *aRes = state->resolution();
+  *aScaleToRes = state->scaleToResolution();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLayoutHistoryState::AddNewPresState(const nsACString& aKey,
                                       float aScrollX, float aScrollY,
                                       bool aAllowScrollOriginDowngrade,
                                       float aRes, bool aScaleToRes)
 {
-  nsPresState* newState = new nsPresState();
-  newState->SetScrollState(nsPoint(aScrollX, aScrollY));
-  newState->SetAllowScrollOriginDowngrade(aAllowScrollOriginDowngrade);
-  newState->SetResolution(aRes);
-  newState->SetScaleToResolution(aScaleToRes);
+  UniquePtr<PresState> newState = NewPresState();
+  newState->scrollState() = nsPoint(aScrollX, aScrollY);
+  newState->allowScrollOriginDowngrade() = aAllowScrollOriginDowngrade;
+  newState->resolution() = aRes;
+  newState->scaleToResolution() = aScaleToRes;
 
-  mStates.Put(nsCString(aKey), newState);
+  mStates.Put(nsCString(aKey), Move(newState));
 
   return NS_OK;
 }
 
 void
-nsLayoutHistoryState::AddState(const nsCString& aStateKey, nsPresState* aState)
+nsLayoutHistoryState::AddState(const nsCString& aStateKey, UniquePtr<PresState> aState)
 {
-  mStates.Put(aStateKey, aState);
+  mStates.Put(aStateKey, Move(aState));
 }
 
-nsPresState*
+PresState*
 nsLayoutHistoryState::GetState(const nsCString& aKey)
 {
-  nsPresState* state = nullptr;
-  bool entryExists = mStates.Get(aKey, &state);
+  UniquePtr<PresState>* statePtr = mStates.GetValue(aKey);
+  if (!statePtr) {
+    return nullptr;
+  }
+  PresState* state = statePtr->get();
 
-  if (entryExists && mScrollPositionOnly) {
+  if (mScrollPositionOnly) {
     // Ensure any state that shouldn't be restored is removed
-    state->ClearNonScrollState();
+    state->contentData() = void_t();
+    state->disabledSet() = false;
   }
 
   return state;
 }
 
 void
 nsLayoutHistoryState::RemoveState(const nsCString& aKey)
 {
@@ -148,19 +155,19 @@ nsLayoutHistoryState::SetScrollPositionO
 {
   mScrollPositionOnly = aFlag;
 }
 
 void
 nsLayoutHistoryState::ResetScrollState()
 {
   for (auto iter = mStates.Iter(); !iter.Done(); iter.Next()) {
-    nsPresState* state = iter.UserData();
+    PresState* state = iter.Data().get();
     if (state) {
-      state->SetScrollState(nsPoint(0, 0));
+      state->scrollState() = nsPoint(0, 0);
     }
   }
 }
 
 namespace mozilla {
 UniquePtr<PresState>
 NewPresState()
 {
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -16,17 +16,17 @@
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsHTMLParts.h"
 #include "nsIFormControl.h"
 #include "nsNameSpaceManager.h"
 #include "nsIListControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPresShell.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIContentInlines.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMNode.h"
 #include "nsISelectControlFrame.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/HTMLSelectElement.h"
@@ -45,16 +45,17 @@
 #include "nsTextNode.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Unused.h"
 #include "gfx2DGlue.h"
 #include "mozilla/widget/nsAutoRollup.h"
+#include "nsILayoutHistoryState.h"
 
 #ifdef XP_WIN
 #define COMBOBOX_ROLLUP_CONSUME_EVENT 0
 #else
 #define COMBOBOX_ROLLUP_CONSUME_EVENT 1
 #endif
 
 using namespace mozilla;
@@ -63,17 +64,16 @@ using namespace mozilla::gfx;
 NS_IMETHODIMP
 nsComboboxControlFrame::RedisplayTextEvent::Run()
 {
   if (mControlFrame)
     mControlFrame->HandleRedisplayTextEvent();
   return NS_OK;
 }
 
-class nsPresState;
 
 #define FIX_FOR_BUG_53259
 
 // Drop down list event management.
 // The combo box uses the following strategy for managing the drop-down list.
 // If the combo box or its arrow button is clicked on the drop-down list is displayed
 // If mouse exits the combo box with the drop-down list displayed the drop-down list
 // is asked to capture events
@@ -1689,32 +1689,31 @@ nsComboboxControlFrame::OnContentReset()
     mListControlFrame->OnContentReset();
   }
 }
 
 
 //--------------------------------------------------------
 // nsIStatefulFrame
 //--------------------------------------------------------
-NS_IMETHODIMP
-nsComboboxControlFrame::SaveState(nsPresState** aState)
+UniquePtr<PresState>
+nsComboboxControlFrame::SaveState()
 {
-  MOZ_ASSERT(!(*aState));
-  (*aState) = new nsPresState();
-  (*aState)->SetDroppedDown(mDroppedDown);
-  return NS_OK;
+  UniquePtr<PresState> state = NewPresState();
+  state->droppedDown() = mDroppedDown;
+  return state;
 }
 
 NS_IMETHODIMP
-nsComboboxControlFrame::RestoreState(nsPresState* aState)
+nsComboboxControlFrame::RestoreState(PresState* aState)
 {
   if (!aState) {
     return NS_ERROR_FAILURE;
   }
-  ShowList(aState->GetDroppedDown()); // might destroy us
+  ShowList(aState->droppedDown()); // might destroy us
   return NS_OK;
 }
 
 // Append a suffix so that the state key for the combobox is different
 // from the state key the list control uses to sometimes save the scroll
 // position for the same Element
 NS_IMETHODIMP
 nsComboboxControlFrame::GenerateStateKey(nsIContent* aContent,
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -208,18 +208,18 @@ public:
     { return false; }
 
   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override
     { return 0; }
 
   virtual nsIWidget* GetRollupWidget() override;
 
   //nsIStatefulFrame
-  NS_IMETHOD SaveState(nsPresState** aState) override;
-  NS_IMETHOD RestoreState(nsPresState* aState) override;
+  mozilla::UniquePtr<mozilla::PresState> SaveState() override;
+  NS_IMETHOD RestoreState(mozilla::PresState* aState) override;
   NS_IMETHOD GenerateStateKey(nsIContent* aContent,
                               nsIDocument* aDocument,
                               nsACString& aKey) override;
 
   static bool ToolkitHasNativePopup();
 
 protected:
   friend class RedisplayTextEvent;
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -27,19 +27,20 @@
 #include "nsIPresShell.h"
 
 #include <algorithm>
 #include "nsIDOMNodeList.h" //for selection setting helper func
 #include "nsRange.h" //for selection setting helper func
 #include "nsINode.h"
 #include "nsPIDOMWindow.h" //needed for notify selection changed to update the menus ect.
 #include "nsQueryObject.h"
+#include "nsILayoutHistoryState.h"
 
 #include "nsFocusManager.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/TextEditRules.h"
 #include "nsContentUtils.h"
 #include "nsTextNode.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/HTMLTextAreaElement.h"
 #include "mozilla/dom/ScriptSettings.h"
@@ -1228,19 +1229,19 @@ nsTextControlFrame::SetInitialChildList(
     txtCtrl->InitializeKeyboardEventListeners();
 
     nsPoint* contentScrollPos = GetProperty(ContentScrollPos());
     if (contentScrollPos) {
       // If we have a scroll pos stored to be passed to our anonymous
       // div, do it here!
       nsIStatefulFrame* statefulFrame = do_QueryFrame(first);
       NS_ASSERTION(statefulFrame, "unexpected type of frame for the anonymous div");
-      nsPresState fakePresState;
-      fakePresState.SetScrollState(*contentScrollPos);
-      statefulFrame->RestoreState(&fakePresState);
+      UniquePtr<PresState> fakePresState = NewPresState();
+      fakePresState->scrollState() = *contentScrollPos;
+      statefulFrame->RestoreState(fakePresState.get());
       RemoveProperty(ContentScrollPos());
       delete contentScrollPos;
     }
   }
 }
 
 void
 nsTextControlFrame::SetValueChanged(bool aValueChanged)
@@ -1343,40 +1344,36 @@ nsFrameSelection*
 nsTextControlFrame::GetOwnedFrameSelection()
 {
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
   return txtCtrl->GetConstFrameSelection();
 }
 
-NS_IMETHODIMP
-nsTextControlFrame::SaveState(nsPresState** aState)
+UniquePtr<PresState>
+nsTextControlFrame::SaveState()
 {
-  NS_ENSURE_ARG_POINTER(aState);
-
-  *aState = nullptr;
-
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
   if (rootNode) {
     // Query the nsIStatefulFrame from the HTMLScrollFrame
     nsIStatefulFrame* scrollStateFrame = do_QueryFrame(rootNode->GetPrimaryFrame());
     if (scrollStateFrame) {
-      return scrollStateFrame->SaveState(aState);
+      return scrollStateFrame->SaveState();
     }
   }
 
-  return NS_OK;
+  return nullptr;
 }
 
 NS_IMETHODIMP
-nsTextControlFrame::RestoreState(nsPresState* aState)
+nsTextControlFrame::RestoreState(PresState* aState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
   if (rootNode) {
@@ -1385,17 +1382,17 @@ nsTextControlFrame::RestoreState(nsPresS
     if (scrollStateFrame) {
       return scrollStateFrame->RestoreState(aState);
     }
   }
 
   // Most likely, we don't have our anonymous content constructed yet, which
   // would cause us to end up here.  In this case, we'll just store the scroll
   // pos ourselves, and forward it to the scroll frame later when it's created.
-  SetProperty(ContentScrollPos(), new nsPoint(aState->GetScrollPosition()));
+  SetProperty(ContentScrollPos(), new nsPoint(aState->scrollState()));
   return NS_OK;
 }
 
 nsresult
 nsTextControlFrame::PeekOffset(nsPeekOffsetStruct *aPos)
 {
   return NS_ERROR_FAILURE;
 }
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -153,18 +153,18 @@ public:
    * @throws various and sundry other things
    */
   virtual nsresult EnsureEditorInitialized() override;
 
 //==== END NSITEXTCONTROLFRAME
 
 //==== NSISTATEFULFRAME
 
-  NS_IMETHOD SaveState(nsPresState** aState) override;
-  NS_IMETHOD RestoreState(nsPresState* aState) override;
+  UniquePtr<PresState> SaveState() override;
+  NS_IMETHOD RestoreState(PresState* aState) override;
 
 //=== END NSISTATEFULFRAME
 
 //==== OVERLOAD of nsIFrame
 
   /** handler for attribute changes to mContent */
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsAtom*        aAttribute,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -24,17 +24,17 @@
 #include "nsBoxLayoutState.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsScrollbarFrame.h"
 #include "nsINode.h"
 #include "nsIScrollbarMediator.h"
 #include "nsITextControlFrame.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
-#include "nsPresState.h"
+#include "mozilla/PresState.h"
 #include "nsIHTMLDocument.h"
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsBidiPresUtils.h"
 #include "nsBidiUtils.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
@@ -53,16 +53,17 @@
 #include "mozilla/Attributes.h"
 #include "ScrollbarActivity.h"
 #include "nsRefreshDriver.h"
 #include "nsThemeConstants.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsIScrollPositionListener.h"
 #include "StickyScrollContainer.h"
 #include "nsIFrameInlines.h"
+#include "nsILayoutHistoryState.h"
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
 #include "ScrollAnimationPhysics.h"
 #include "ScrollAnimationBezierPhysics.h"
 #include "ScrollAnimationMSDPhysics.h"
 #include "ScrollSnap.h"
 #include "UnitTransforms.h"
 #include "nsPluginFrame.h"
@@ -6196,33 +6197,33 @@ ScrollFrameHelper::GetCoordAttribute(nsI
   }
 
   // Only this exact default value is allowed.
   *aRangeStart = aDefaultValue;
   *aRangeLength = 0;
   return aDefaultValue;
 }
 
-nsPresState*
+UniquePtr<PresState>
 ScrollFrameHelper::SaveState() const
 {
   nsIScrollbarMediator* mediator = do_QueryFrame(GetScrolledFrame());
   if (mediator) {
     // child handles its own scroll state, so don't bother saving state here
     return nullptr;
   }
 
   // Don't store a scroll state if we never have been scrolled or restored
   // a previous scroll state, and we're not in the middle of a smooth scroll.
   bool isInSmoothScroll = IsProcessingAsyncScroll() || mLastSmoothScrollOrigin;
   if (!mHasBeenScrolled && !mDidHistoryRestore && !isInSmoothScroll) {
     return nullptr;
   }
 
-  nsPresState* state = new nsPresState();
+  UniquePtr<PresState> state = NewPresState();
   bool allowScrollOriginDowngrade =
     !nsLayoutUtils::CanScrollOriginClobberApz(mLastScrollOrigin) ||
     mAllowScrollOriginDowngrade;
   // Save mRestorePos instead of our actual current scroll position, if it's
   // valid and we haven't moved since the last update of mLastPos (same check
   // that ScrollToRestoredPosition uses). This ensures if a reframe occurs
   // while we're in the process of loading content to scroll to a restored
   // position, we'll keep trying after the reframe. Similarly, if we're in the
@@ -6233,46 +6234,46 @@ ScrollFrameHelper::SaveState() const
   nsPoint pt = GetLogicalScrollPosition();
   if (isInSmoothScroll) {
     pt = mDestination;
     allowScrollOriginDowngrade = false;
   }
   if (mRestorePos.y != -1 && pt == mLastPos) {
     pt = mRestorePos;
   }
-  state->SetScrollState(pt);
-  state->SetAllowScrollOriginDowngrade(allowScrollOriginDowngrade);
+  state->scrollState() = pt;
+  state->allowScrollOriginDowngrade() = allowScrollOriginDowngrade;
   if (mIsRoot) {
     // Only save resolution properties for root scroll frames
     nsIPresShell* shell = mOuter->PresShell();
-    state->SetResolution(shell->GetResolution());
-    state->SetScaleToResolution(shell->ScaleToResolution());
+    state->resolution() = shell->GetResolution();
+    state->scaleToResolution() = shell->ScaleToResolution();
   }
   return state;
 }
 
 void
-ScrollFrameHelper::RestoreState(nsPresState* aState)
-{
-  mRestorePos = aState->GetScrollPosition();
+ScrollFrameHelper::RestoreState(PresState* aState)
+{
+  mRestorePos = aState->scrollState();
   MOZ_ASSERT(mLastScrollOrigin == nsGkAtoms::other);
-  mAllowScrollOriginDowngrade = aState->GetAllowScrollOriginDowngrade();
+  mAllowScrollOriginDowngrade = aState->allowScrollOriginDowngrade();
   mDidHistoryRestore = true;
   mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
 
   // Resolution properties should only exist on root scroll frames.
-  MOZ_ASSERT(mIsRoot || (!aState->GetScaleToResolution() &&
-                         aState->GetResolution() == 1.0));
+  MOZ_ASSERT(mIsRoot || (!aState->scaleToResolution() &&
+                         aState->resolution() == 1.0));
 
   if (mIsRoot) {
     nsIPresShell* presShell = mOuter->PresShell();
-    if (aState->GetScaleToResolution()) {
-      presShell->SetResolutionAndScaleTo(aState->GetResolution());
+    if (aState->scaleToResolution()) {
+      presShell->SetResolutionAndScaleTo(aState->resolution());
     } else {
-      presShell->SetResolution(aState->GetResolution());
+      presShell->SetResolution(aState->resolution());
     }
   }
 }
 
 void
 ScrollFrameHelper::PostScrolledAreaEvent()
 {
   if (mScrolledAreaEvent.IsPending()) {
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -19,22 +19,22 @@
 #include "nsThreadUtils.h"
 #include "nsIReflowCallback.h"
 #include "nsBoxLayoutState.h"
 #include "nsQueryFrame.h"
 #include "nsRefreshDriver.h"
 #include "nsExpirationTracker.h"
 #include "TextOverflow.h"
 #include "ScrollVelocityQueue.h"
+#include "mozilla/PresState.h"
 
 class nsPresContext;
 class nsIPresShell;
 class nsIContent;
 class nsAtom;
-class nsPresState;
 class nsIScrollPositionListener;
 
 namespace mozilla {
 struct ScrollReflowInput;
 namespace layers {
 class Layer;
 class LayerManager;
 } // namespace layers
@@ -292,18 +292,18 @@ public:
    */
   bool GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit,
                                   nsPoint aStartPos,
                                   nsPoint &aDestination);
 
   nsSize GetLineScrollAmount() const;
   nsSize GetPageScrollAmount() const;
 
-  nsPresState* SaveState() const;
-  void RestoreState(nsPresState* aState);
+  mozilla::UniquePtr<mozilla::PresState> SaveState() const;
+  void RestoreState(mozilla::PresState* aState);
 
   nsIFrame* GetScrolledFrame() const { return mScrolledFrame; }
   nsIFrame* GetScrollbarBox(bool aVertical) const {
     return aVertical ? mVScrollbarBox : mHScrollbarBox;
   }
 
   void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
     mListeners.AppendElement(aListener);
@@ -999,22 +999,20 @@ public:
   virtual bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(nsRect* aDisplayPort) override {
     return mHelper.GetDisplayPortAtLastApproximateFrameVisibilityUpdate(aDisplayPort);
   }
   void TriggerDisplayPortExpiration() override {
     mHelper.TriggerDisplayPortExpiration();
   }
 
   // nsIStatefulFrame
-  NS_IMETHOD SaveState(nsPresState** aState) override {
-    NS_ENSURE_ARG_POINTER(aState);
-    *aState = mHelper.SaveState();
-    return NS_OK;
+  mozilla::UniquePtr<mozilla::PresState> SaveState() override {
+    return mHelper.SaveState();
   }
-  NS_IMETHOD RestoreState(nsPresState* aState) override {
+  NS_IMETHOD RestoreState(mozilla::PresState* aState) override {
     NS_ENSURE_ARG_POINTER(aState);
     mHelper.RestoreState(aState);
     return NS_OK;
   }
 
   // nsIScrollbarMediator
   virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection,
                             nsIScrollbarMediator::ScrollSnapMode aSnap
@@ -1426,22 +1424,20 @@ public:
   virtual bool IsIgnoringViewportClipping() const override {
     return mHelper.IsIgnoringViewportClipping();
   }
   virtual void MarkScrollbarsDirtyForReflow() const override {
     mHelper.MarkScrollbarsDirtyForReflow();
   }
 
   // nsIStatefulFrame
-  NS_IMETHOD SaveState(nsPresState** aState) override {
-    NS_ENSURE_ARG_POINTER(aState);
-    *aState = mHelper.SaveState();
-    return NS_OK;
+  mozilla::UniquePtr<mozilla::PresState> SaveState() override {
+    return mHelper.SaveState();
   }
-  NS_IMETHOD RestoreState(nsPresState* aState) override {
+  NS_IMETHOD RestoreState(mozilla::PresState* aState) override {
     NS_ENSURE_ARG_POINTER(aState);
     mHelper.RestoreState(aState);
     return NS_OK;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     // Override bogus IsFrameOfType in nsBoxFrame.
--- a/layout/generic/nsIStatefulFrame.h
+++ b/layout/generic/nsIStatefulFrame.h
@@ -10,29 +10,30 @@
  */
 
 #ifndef _nsIStatefulFrame_h
 #define _nsIStatefulFrame_h
 
 #include "nsContentUtils.h"
 #include "nsQueryFrame.h"
 
-class nsPresState;
+namespace mozilla {
+class PresState;
+} // namespace mozilla
 
 class nsIStatefulFrame
 {
  public:
   NS_DECL_QUERYFRAME_TARGET(nsIStatefulFrame)
 
-  // Save the state for this frame.  If this method succeeds, the caller is
-  // responsible for deleting the resulting state when done with it.
-  NS_IMETHOD SaveState(nsPresState** aState) = 0;
+  // Save the state for this frame.
+  virtual mozilla::UniquePtr<mozilla::PresState> SaveState() = 0;
 
   // Restore the state for this frame from aState
-  NS_IMETHOD RestoreState(nsPresState* aState) = 0;
+  NS_IMETHOD RestoreState(mozilla::PresState* aState) = 0;
 
   // Generate a key for this stateful frame
   NS_IMETHOD GenerateStateKey(nsIContent* aContent,
                               nsIDocument* aDocument,
                               nsACString& aKey)
   {
     return nsContentUtils::GenerateStateKey(aContent, aDocument, aKey);
   };