Title: [280718] trunk/Source
Revision
280718
Author
[email protected]
Date
2021-08-05 20:10:40 -0700 (Thu, 05 Aug 2021)

Log Message

Stop tracking form elements with FormController
https://bugs.webkit.org/show_bug.cgi?id=228724
<rdar://problem/81435095>

Reviewed by Darin Adler.

Source/WebCore:

FormController currently tracks the insertion order of
HTMLFormElementWithState objects in the document.  But we don't need
to know this list of form controls until the time we need to save
form state for the document (e.g. on pagehide).  So we instead
traverse the document to find those elements at the point we need
them, rather than maintain FormController::m_formElementsWithState.

This is a small speedup (1-2%) on a few of the Speedometer subtests
that insert and remove many input elements.

A future optimization could record on the Document whether there are
any input elements that have had their value changed, since it's
probably common for pages with form controls to never be changed.

* dom/Document.cpp:
(WebCore::Document::formElementsState const): Traverse the document to
find all the HTMLFormElementWithState objects.
* dom/Element.h:
(WebCore::Element::isFormControlElementWithState const):
* html/FormController.cpp:
(WebCore::FormController::createSavedFormStateMap):
(WebCore::FormController::formElementsState const):
* html/FormController.h:
* html/HTMLFormControlElementWithState.cpp:
(WebCore::HTMLFormControlElementWithState::insertedIntoAncestor):
Track the order that HTMLFormControlElementWithState objects are
inserted into the document.
(WebCore::HTMLFormControlElementWithState::removedFromAncestor):
* html/HTMLFormControlElementWithState.h:
(WebCore::HTMLFormControlElementWithState::insertionIndex const):
(isType):
* page/Frame.h: Remove unused formElementsCharacterCount.
* page/ios/FrameIOS.mm:

Source/WebKitLegacy/mac:

formElementsCharacterCount is unused and can be removed.

* WebView/WebFrame.mm:
* WebView/WebFramePrivate.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (280717 => 280718)


--- trunk/Source/WebCore/ChangeLog	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/ChangeLog	2021-08-06 03:10:40 UTC (rev 280718)
@@ -1,3 +1,45 @@
+2021-08-05  Cameron McCormack  <[email protected]>
+
+        Stop tracking form elements with FormController
+        https://bugs.webkit.org/show_bug.cgi?id=228724
+        <rdar://problem/81435095>
+
+        Reviewed by Darin Adler.
+
+        FormController currently tracks the insertion order of
+        HTMLFormElementWithState objects in the document.  But we don't need
+        to know this list of form controls until the time we need to save
+        form state for the document (e.g. on pagehide).  So we instead
+        traverse the document to find those elements at the point we need
+        them, rather than maintain FormController::m_formElementsWithState.
+
+        This is a small speedup (1-2%) on a few of the Speedometer subtests
+        that insert and remove many input elements.
+
+        A future optimization could record on the Document whether there are
+        any input elements that have had their value changed, since it's
+        probably common for pages with form controls to never be changed.
+
+        * dom/Document.cpp:
+        (WebCore::Document::formElementsState const): Traverse the document to
+        find all the HTMLFormElementWithState objects.
+        * dom/Element.h:
+        (WebCore::Element::isFormControlElementWithState const):
+        * html/FormController.cpp:
+        (WebCore::FormController::createSavedFormStateMap):
+        (WebCore::FormController::formElementsState const):
+        * html/FormController.h:
+        * html/HTMLFormControlElementWithState.cpp:
+        (WebCore::HTMLFormControlElementWithState::insertedIntoAncestor):
+        Track the order that HTMLFormControlElementWithState objects are
+        inserted into the document.
+        (WebCore::HTMLFormControlElementWithState::removedFromAncestor):
+        * html/HTMLFormControlElementWithState.h:
+        (WebCore::HTMLFormControlElementWithState::insertionIndex const):
+        (isType):
+        * page/Frame.h: Remove unused formElementsCharacterCount.
+        * page/ios/FrameIOS.mm:
+
 2021-08-05  Tim Horton  <[email protected]>
 
         fast/canvas/canvas-crash.html doesn't test what it intends to on iOS

Modified: trunk/Source/WebCore/dom/Document.cpp (280717 => 280718)


--- trunk/Source/WebCore/dom/Document.cpp	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/dom/Document.cpp	2021-08-06 03:10:40 UTC (rev 280718)
@@ -1909,7 +1909,7 @@
 {
     if (!m_formController)
         return Vector<String>();
-    return m_formController->formElementsState();
+    return m_formController->formElementsState(*this);
 }
 
 void Document::setStateForNewFormElements(const Vector<String>& stateVector)

Modified: trunk/Source/WebCore/dom/Element.h (280717 => 280718)


--- trunk/Source/WebCore/dom/Element.h	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/dom/Element.h	2021-08-06 03:10:40 UTC (rev 280718)
@@ -468,6 +468,7 @@
 #endif
 
     virtual bool isFormControlElement() const { return false; }
+    virtual bool isFormControlElementWithState() const { return false; }
     virtual bool isSpinButtonElement() const { return false; }
     virtual bool isTextFormControlElement() const { return false; }
     virtual bool isTextField() const { return false; }

Modified: trunk/Source/WebCore/html/FormController.cpp (280717 => 280718)


--- trunk/Source/WebCore/html/FormController.cpp	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/html/FormController.cpp	2021-08-06 03:10:40 UTC (rev 280718)
@@ -342,16 +342,6 @@
 
 FormController::~FormController() = default;
 
-unsigned FormController::formElementsCharacterCount() const
-{
-    unsigned count = 0;
-    for (auto& element : m_formElementsWithState) {
-        if (element->isTextField())
-            count += element->saveFormControlState()[0].length();
-    }
-    return count;
-}
-
 static String formStateSignature()
 {
     // In the legacy version of serialized state, the first item was a name
@@ -361,26 +351,37 @@
     return signature;
 }
 
-std::unique_ptr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList)
+std::unique_ptr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormControlVector& controlList)
 {
     FormKeyGenerator keyGenerator;
     auto stateMap = makeUnique<SavedFormStateMap>();
-    for (auto& control : controlList) {
-        if (!control->shouldSaveAndRestoreFormControlState())
+    for (const HTMLFormControlElementWithState& control : controlList) {
+        if (!control.shouldSaveAndRestoreFormControlState())
             continue;
-        auto& formState = stateMap->add(keyGenerator.formKey(*control).impl(), nullptr).iterator->value;
+        auto& formState = stateMap->add(keyGenerator.formKey(control).impl(), nullptr).iterator->value;
         if (!formState)
             formState = makeUnique<SavedFormState>();
-        formState->appendControlState(control->name(), control->type(), control->saveFormControlState());
+        formState->appendControlState(control.name(), control.type(), control.saveFormControlState());
     }
     return stateMap;
 }
 
-Vector<String> FormController::formElementsState() const
+Vector<String> FormController::formElementsState(const Document& document) const
 {
-    std::unique_ptr<SavedFormStateMap> stateMap = createSavedFormStateMap(m_formElementsWithState);
+    // FIXME: We should be saving the state of form controls in shadow trees, too.
+    FormControlVector controls;
+    for (auto& control : descendantsOfType<HTMLFormControlElementWithState>(document)) {
+        ASSERT(control.insertionIndex());
+        controls.append(control);
+    }
+
+    std::sort(controls.begin(), controls.end(), [](auto a, auto b) {
+        return a.get().insertionIndex() < b.get().insertionIndex();
+    });
+
+    auto stateMap = createSavedFormStateMap(controls);
     Vector<String> stateVector;
-    stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4);
+    stateVector.reserveInitialCapacity(controls.size() * 4);
     stateVector.append(formStateSignature());
     for (auto& state : *stateMap) {
         stateVector.append(state.key.get());
@@ -484,16 +485,4 @@
     return paths;
 }
 
-void FormController::registerFormElementWithState(HTMLFormControlElementWithState& control)
-{
-    ASSERT(!m_formElementsWithState.contains(&control));
-    m_formElementsWithState.add(&control);
-}
-
-void FormController::unregisterFormElementWithState(HTMLFormControlElementWithState& control)
-{
-    ASSERT(m_formElementsWithState.contains(&control));
-    m_formElementsWithState.remove(&control);
-}
-
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/FormController.h (280717 => 280718)


--- trunk/Source/WebCore/html/FormController.h	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/html/FormController.h	2021-08-06 03:10:40 UTC (rev 280718)
@@ -42,12 +42,7 @@
     FormController();
     ~FormController();
 
-    void registerFormElementWithState(HTMLFormControlElementWithState&);
-    void unregisterFormElementWithState(HTMLFormControlElementWithState&);
-
-    unsigned formElementsCharacterCount() const;
-
-    Vector<String> formElementsState() const;
+    Vector<String> formElementsState(const Document&) const;
     void setStateForNewFormElements(const Vector<String>&);
 
     void willDeleteForm(HTMLFormElement&);
@@ -58,14 +53,13 @@
     WEBCORE_EXPORT static Vector<String> referencedFilePaths(const Vector<String>& stateVector);
 
 private:
-    typedef ListHashSet<RefPtr<HTMLFormControlElementWithState>> FormElementListHashSet;
-    typedef HashMap<RefPtr<AtomStringImpl>, std::unique_ptr<SavedFormState>> SavedFormStateMap;
+    using FormControlVector = Vector<std::reference_wrapper<const HTMLFormControlElementWithState>>;
+    using SavedFormStateMap = HashMap<RefPtr<AtomStringImpl>, std::unique_ptr<SavedFormState>>;
 
-    static std::unique_ptr<SavedFormStateMap> createSavedFormStateMap(const FormElementListHashSet&);
+    static std::unique_ptr<SavedFormStateMap> createSavedFormStateMap(const FormControlVector&);
     FormControlState takeStateForFormElement(const HTMLFormControlElementWithState&);
     static void formStatesFromStateVector(const Vector<String>&, SavedFormStateMap&);
 
-    FormElementListHashSet m_formElementsWithState;
     SavedFormStateMap m_savedFormStateMap;
     std::unique_ptr<FormKeyGenerator> m_formKeyGenerator;
 };

Modified: trunk/Source/WebCore/html/HTMLFormControlElementWithState.cpp (280717 => 280718)


--- trunk/Source/WebCore/html/HTMLFormControlElementWithState.cpp	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/html/HTMLFormControlElementWithState.cpp	2021-08-06 03:10:40 UTC (rev 280718)
@@ -43,15 +43,13 @@
 
 Node::InsertedIntoAncestorResult HTMLFormControlElementWithState::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
 {
-    if (insertionType.connectedToDocument && !containingShadowRoot())
-        document().formController().registerFormElementWithState(*this);
+    m_insertionIndex = ++lastInsertionIndex;
     return HTMLFormControlElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
 }
 
 void HTMLFormControlElementWithState::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
 {
-    if (removalType.disconnectedFromDocument && !containingShadowRoot() && !oldParentOfRemovedTree.containingShadowRoot())
-        document().formController().unregisterFormElementWithState(*this);
+    m_insertionIndex = 0;
     HTMLFormControlElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
 }
 
@@ -84,4 +82,6 @@
     return true;
 }
 
+uint64_t HTMLFormControlElementWithState::lastInsertionIndex { 0 };
+
 } // namespace Webcore

Modified: trunk/Source/WebCore/html/HTMLFormControlElementWithState.h (280717 => 280718)


--- trunk/Source/WebCore/html/HTMLFormControlElementWithState.h	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/html/HTMLFormControlElementWithState.h	2021-08-06 03:10:40 UTC (rev 280718)
@@ -38,6 +38,8 @@
     virtual FormControlState saveFormControlState() const;
     virtual void restoreFormControlState(const FormControlState&) { } // Called only if state is not empty.
 
+    uint64_t insertionIndex() const { return m_insertionIndex; }
+
 protected:
     HTMLFormControlElementWithState(const QualifiedName& tagName, Document&, HTMLFormElement*);
 
@@ -50,10 +52,15 @@
 
 private:
     bool isFormControlElementWithState() const final;
+
+    uint64_t m_insertionIndex { 0 };
+    static uint64_t lastInsertionIndex;
 };
 
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::HTMLFormControlElementWithState)
+    static bool isType(const WebCore::Element& element) { return element.isFormControlElementWithState(); }
+    static bool isType(const WebCore::Node& node) { return is<WebCore::Element>(node) && isType(downcast<WebCore::Element>(node)); }
     static bool isType(const WebCore::FormAssociatedElement& element) { return element.isFormControlElementWithState(); }
 SPECIALIZE_TYPE_TRAITS_END()

Modified: trunk/Source/WebCore/page/Frame.h (280717 => 280718)


--- trunk/Source/WebCore/page/Frame.h	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/page/Frame.h	2021-08-06 03:10:40 UTC (rev 280718)
@@ -282,7 +282,6 @@
     WEBCORE_EXPORT void updateLayout() const;
     WEBCORE_EXPORT NSRect caretRect();
     WEBCORE_EXPORT NSRect rectForScrollToVisible();
-    WEBCORE_EXPORT unsigned formElementsCharacterCount() const;
 
     // This function is used by Legacy WebKit.
     WEBCORE_EXPORT void setTimersPaused(bool);

Modified: trunk/Source/WebCore/page/ios/FrameIOS.mm (280717 => 280718)


--- trunk/Source/WebCore/page/ios/FrameIOS.mm	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebCore/page/ios/FrameIOS.mm	2021-08-06 03:10:40 UTC (rev 280718)
@@ -627,14 +627,6 @@
     return unionRect(selection.visibleStart().absoluteCaretBounds(), selection.visibleEnd().absoluteCaretBounds());
 }
 
-unsigned Frame::formElementsCharacterCount() const
-{
-    Document* document = this->document();
-    if (!document)
-        return 0;
-    return document->formController().formElementsCharacterCount();
-}
-
 void Frame::setTimersPaused(bool paused)
 {
     if (!m_page)

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (280717 => 280718)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2021-08-06 03:10:40 UTC (rev 280718)
@@ -1,3 +1,16 @@
+2021-08-05  Cameron McCormack  <[email protected]>
+
+        Stop tracking form elements with FormController
+        https://bugs.webkit.org/show_bug.cgi?id=228724
+        <rdar://problem/81435095>
+
+        Reviewed by Darin Adler.
+
+        formElementsCharacterCount is unused and can be removed.
+
+        * WebView/WebFrame.mm:
+        * WebView/WebFramePrivate.h:
+
 2021-07-29  Myles C. Maxfield  <[email protected]>
 
         Stop building WebGPU and the WHLSL compiler to decrease binary size

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm (280717 => 280718)


--- trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm	2021-08-06 03:10:40 UTC (rev 280718)
@@ -1163,11 +1163,6 @@
 
 #if PLATFORM(IOS_FAMILY)
 
-- (unsigned)formElementsCharacterCount
-{
-    return core(self)->formElementsCharacterCount();
-}
-
 - (void)setTimeoutsPaused:(BOOL)flag
 {
     if ([self _webHTMLDocumentView]) {

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebFramePrivate.h (280717 => 280718)


--- trunk/Source/WebKitLegacy/mac/WebView/WebFramePrivate.h	2021-08-06 02:39:49 UTC (rev 280717)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebFramePrivate.h	2021-08-06 03:10:40 UTC (rev 280718)
@@ -95,7 +95,6 @@
 - (BOOL)needsLayout; // Needed for Mail <rdar://problem/6228038>
 - (void)_setLoadsSynchronously:(BOOL)flag;
 - (BOOL)_loadsSynchronously;
-- (unsigned)formElementsCharacterCount;
 - (void)setTimeoutsPaused:(BOOL)flag;
 
 /*!
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to