Changeset 21430 in webkit


Ignore:
Timestamp:
May 12, 2007, 2:22:08 PM (18 years ago)
Author:
beidson
Message:

Reviewed by Darin and Geoff

Fix for http://bugs.webkit.org/show_bug.cgi?id=13630
and
<rdar://problem/4873628>

Back/Forward cache should work with pages with login fields.

First change is to relocate the "useSecureKeyboardEntry" flag to the document. This lets
it persist through page cache transitions and it is truly a per-document concept more than
per-frame anyways since its the document that has a password field, not the frame.

Second change is to introduce the concept of an Element getting a "didRestoreFromCache()" callback.
The idea is for elements to register with the document if they need work to be done when the
page comes out of the back/forward cache. Currently the only client of this service is
HTMLInputElements that are input type == PASSWORD. Such an element's implementation for this
method is to call reset()

Finally, after a page is restored from the cache we have the document send the didRestoreFromCache()
callback to its registered Elements. The whole design is to clear the password fields after
restoring the page instead of when caching the page because we want to defer work for the common
case - there shouldn't be extra work here just to navigate away from a page when the common case
is that you'll never go back!

No layout tests possible until http://bugs.webkit.org/show_bug.cgi?id=13672 is resolved

  • dom/Document.cpp: (WebCore::Document::Document): (WebCore::Document::registerForDidRestoreFromCacheCallback): Add an Element to the special page-restoration callback list (WebCore::Document::unregisterForDidRestoreFromCacheCallback): Remove such an element (WebCore::Document::didRestoreFromCache): Called by FrameLoader - dispatch to all the registered elements (WebCore::Document::setUseSecureKeyboardEntryWhenActive): Set the local flag and call updateSecureKeyboardEntryIfActive on the Frame (WebCore::Document::useSecureKeyboardEntryWhenActive): Return the flag
  • dom/Document.h: (WebCore::Document::unregisterFormElementWithState): Renamed
  • dom/Element.h: (WebCore::Element::didRestoreFromCache): Added virtual base method
  • html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::~HTMLInputElement): Deregister from the document if inputType == PASSWORD (WebCore::HTMLInputElement::dispatchFocusEvent): Set the flag on the document, not the frame (WebCore::HTMLInputElement::dispatchBlurEvent): Ditto (WebCore::HTMLInputElement::setInputType): If changing to/from PASSWORD, register/deregister in the document accordingly (WebCore::HTMLInputElement::attach): Call registerForDidRestoreFromCacheCallback(this) instead of passwordFieldAdded() (WebCore::HTMLInputElement::didRestoreFromCache): Call reset();
  • html/HTMLInputElement.h:
  • html/HTMLSelectElement.cpp: (WebCore::HTMLSelectElement::~HTMLSelectElement): Renamed deregisterFormElementWithState to unregisterFormElementWithState
  • html/HTMLTextAreaElement.cpp: (WebCore::HTMLTextAreaElement::~HTMLTextAreaElement): Ditto
  • loader/FrameLoader.cpp: (WebCore::FrameLoader::canCachePage): Remove the check for password fields - they're allowed now! (WebCore::FrameLoader::opened): Tell the document to dispatch to the registered elements (WebCore::FrameLoader::saveDocumentState): Remove the check for password fields. Turns out that when we grab a copy a the form state we're only copying the state of form elements that are registered with the Document - and that set explicitly excludes Password elements
  • page/Frame.cpp: (WebCore::Frame::setDocument): If the frame is active, set the setUseSecureKeyboardEntry based on the setting contained in the new document (WebCore::Frame::updateSecureKeyboardEntryIfActive): Notification for the secure entry flag changing - if the Frame is active, then update to the new setting from the document (WebCore::Frame::setIsActive): Grab the useSecureKeyboardEntry flag from the document instead of FramePrivate (WebCore::FramePrivate::FramePrivate):
  • page/Frame.h:
  • page/FramePrivate.h:
Location:
trunk/WebCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r21428 r21430  
     12007-05-11  Brady Eidson  <beidson@apple.com>
     2
     3        Reviewed by Darin and Geoff
     4
     5        Fix for http://bugs.webkit.org/show_bug.cgi?id=13630
     6        and
     7        <rdar://problem/4873628>
     8
     9        Back/Forward cache should work with pages with login fields.
     10
     11        First change is to relocate the "useSecureKeyboardEntry" flag to the document.  This lets
     12        it persist through page cache transitions and it is truly a per-document concept more than
     13        per-frame anyways since its the document that has a password field, not the frame.
     14
     15        Second change is to introduce the concept of an Element getting a "didRestoreFromCache()" callback.
     16        The idea is for elements to register with the document if they need work to be done when the
     17        page comes out of the back/forward cache.  Currently the only client of this service is
     18        HTMLInputElements that are input type == PASSWORD.  Such an element's implementation for this
     19        method is to call reset()
     20
     21        Finally, after a page is restored from the cache we have the document send the didRestoreFromCache()
     22        callback to its registered Elements.  The whole design is to clear the password fields after
     23        restoring the page instead of when caching the page because we want to defer work for the common
     24        case - there shouldn't be extra work here just to navigate away from a page when the common case
     25        is that you'll never go back!
     26
     27        No layout tests possible until http://bugs.webkit.org/show_bug.cgi?id=13672 is resolved
     28
     29        * dom/Document.cpp:
     30        (WebCore::Document::Document):
     31        (WebCore::Document::registerForDidRestoreFromCacheCallback): Add an Element to the special page-restoration callback list
     32        (WebCore::Document::unregisterForDidRestoreFromCacheCallback): Remove such an element
     33        (WebCore::Document::didRestoreFromCache): Called by FrameLoader - dispatch to all the registered elements
     34        (WebCore::Document::setUseSecureKeyboardEntryWhenActive): Set the local flag and call updateSecureKeyboardEntryIfActive
     35          on the Frame
     36        (WebCore::Document::useSecureKeyboardEntryWhenActive): Return the flag
     37
     38        * dom/Document.h:
     39        (WebCore::Document::unregisterFormElementWithState): Renamed
     40
     41        * dom/Element.h:
     42        (WebCore::Element::didRestoreFromCache): Added virtual base method
     43
     44        * html/HTMLInputElement.cpp:
     45        (WebCore::HTMLInputElement::~HTMLInputElement): Deregister from the document if inputType == PASSWORD
     46        (WebCore::HTMLInputElement::dispatchFocusEvent): Set the flag on the document, not the frame
     47        (WebCore::HTMLInputElement::dispatchBlurEvent): Ditto
     48        (WebCore::HTMLInputElement::setInputType): If changing to/from PASSWORD, register/deregister in the document accordingly
     49        (WebCore::HTMLInputElement::attach): Call registerForDidRestoreFromCacheCallback(this) instead of passwordFieldAdded()
     50        (WebCore::HTMLInputElement::didRestoreFromCache): Call reset();
     51        * html/HTMLInputElement.h:
     52
     53        * html/HTMLSelectElement.cpp:
     54        (WebCore::HTMLSelectElement::~HTMLSelectElement): Renamed deregisterFormElementWithState to unregisterFormElementWithState
     55        * html/HTMLTextAreaElement.cpp:
     56        (WebCore::HTMLTextAreaElement::~HTMLTextAreaElement): Ditto
     57
     58        * loader/FrameLoader.cpp:
     59        (WebCore::FrameLoader::canCachePage): Remove the check for password fields - they're allowed now!
     60        (WebCore::FrameLoader::opened): Tell the document to dispatch to the registered elements
     61        (WebCore::FrameLoader::saveDocumentState): Remove the check for password fields.  Turns out that when we grab a copy a the
     62          form state we're only copying the state of form elements that are registered with the Document - and that set
     63          explicitly excludes Password elements
     64
     65        * page/Frame.cpp:
     66        (WebCore::Frame::setDocument): If the frame is active, set the setUseSecureKeyboardEntry based on the setting contained
     67          in the new document
     68        (WebCore::Frame::updateSecureKeyboardEntryIfActive): Notification for the secure entry flag changing - if the Frame is
     69          active, then update to the new setting from the document
     70        (WebCore::Frame::setIsActive): Grab the useSecureKeyboardEntry flag from the document instead of FramePrivate
     71        (WebCore::FramePrivate::FramePrivate):
     72        * page/Frame.h:
     73        * page/FramePrivate.h:
     74
    1752007-05-12  David Hyatt  <hyatt@apple.com>
    276
  • trunk/WebCore/dom/Document.cpp

    r21420 r21430  
    287287#endif
    288288    , m_savedRenderer(0)
    289     , m_passwordFields(0)
    290289    , m_secureForms(0)
    291290    , m_designMode(inherit)
     
    300299    , m_inPageCache(false)
    301300    , m_isAllowedToLoadLocalResources(false)
     301    , m_useSecureKeyboardEntryWhenActive(false)
    302302#if USE(LOW_BANDWIDTH_DISPLAY)
    303303    , m_inLowBandwidthDisplay(false)
     
    26842684}
    26852685
    2686 void Document::passwordFieldAdded()
    2687 {
    2688     m_passwordFields++;
    2689 }
    2690 
    2691 void Document::passwordFieldRemoved()
    2692 {
    2693     ASSERT(m_passwordFields > 0);
    2694     m_passwordFields--;
    2695 }
    2696 
    2697 bool Document::hasPasswordField() const
    2698 {
    2699     return m_passwordFields > 0;
     2686void Document::registerForDidRestoreFromCacheCallback(Element* e)
     2687{
     2688    m_didRestorePageCallbackSet.add(e);
     2689}
     2690
     2691void Document::unregisterForDidRestoreFromCacheCallback(Element* e)
     2692{
     2693    m_didRestorePageCallbackSet.remove(e);
     2694}
     2695
     2696void Document::didRestoreFromCache()
     2697{
     2698    HashSet<Element*>::iterator it = m_didRestorePageCallbackSet.begin();
     2699    for (; it != m_didRestorePageCallbackSet.end(); ++it)
     2700        (*it)->didRestoreFromCache();
    27002701}
    27012702
     
    36053606}
    36063607
    3607 }
     3608void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
     3609{
     3610    if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
     3611        return;
     3612       
     3613    m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
     3614    m_frame->updateSecureKeyboardEntryIfActive();
     3615}
     3616
     3617bool Document::useSecureKeyboardEntryWhenActive() const
     3618{
     3619    return m_useSecureKeyboardEntryWhenActive;
     3620}
     3621
     3622}
  • trunk/WebCore/dom/Document.h

    r21179 r21430  
    291291    // Machinery for saving and restoring state when you leave and then go back to a page.
    292292    void registerFormElementWithState(HTMLGenericFormElement* e) { m_formElementsWithState.add(e); }
    293     void deregisterFormElementWithState(HTMLGenericFormElement* e) { m_formElementsWithState.remove(e); }
     293    void unregisterFormElementWithState(HTMLGenericFormElement* e) { m_formElementsWithState.remove(e); }
    294294    Vector<String> formElementsState() const;
    295295    void setStateForNewFormElements(const Vector<String>&);
     
    635635    bool isAllowedToLoadLocalResources() const { return m_isAllowedToLoadLocalResources; }
    636636
     637    void setUseSecureKeyboardEntryWhenActive(bool);
     638    bool useSecureKeyboardEntryWhenActive() const;
     639   
    637640#if USE(LOW_BANDWIDTH_DISPLAY)
    638641    void setDocLoader(DocLoader* loader) { m_docLoader = loader; }
     
    702705    FormElementStateMap m_stateForNewFormElements;
    703706
     707    HashSet<Element*> m_didRestorePageCallbackSet;
     708   
    704709    Color m_linkColor;
    705710    Color m_visitedLinkColor;
     
    767772    void setInPageCache(bool flag);
    768773
    769     void passwordFieldAdded();
    770     void passwordFieldRemoved();
    771     bool hasPasswordField() const;
     774    // Elements can register themselves for the "didRestoreFromCache()" callback which will be
     775    // called if the document is restored from the Page Cache
     776    void registerForDidRestoreFromCacheCallback(Element*);
     777    void unregisterForDidRestoreFromCacheCallback(Element*);
     778   
     779    void didRestoreFromCache();
    772780
    773781    void secureFormAdded();
     
    816824    mutable String m_domain;
    817825    RenderObject* m_savedRenderer;
    818     int m_passwordFields;
    819826    int m_secureForms;
    820827   
     
    854861
    855862    bool m_isAllowedToLoadLocalResources;
     863   
     864    bool m_useSecureKeyboardEntryWhenActive;
    856865
    857866#if USE(LOW_BANDWIDTH_DISPLAY)
  • trunk/WebCore/dom/Element.h

    r21184 r21430  
    183183    void setMinimumSizeForResizing(const IntSize&);
    184184
     185    // The following method is called when a Document is restored from the page cache
     186    // and the element has registered itself with the Document via registerForDidRestorePageCallback()
     187    virtual void didRestoreFromCache() { }
     188   
    185189private:
    186190    ElementRareData* rareData();
  • trunk/WebCore/html/HTMLInputElement.cpp

    r21055 r21430  
    137137HTMLInputElement::~HTMLInputElement()
    138138{
    139     document()->deregisterFormElementWithState(this);
     139    document()->unregisterFormElementWithState(this);
     140    document()->unregisterForDidRestoreFromCacheCallback(this);
    140141    delete m_imageLoader;
    141142}
     
    233234        setAutofilled(false);
    234235        if (inputType() == PASSWORD && document()->frame())
    235             document()->frame()->setUseSecureKeyboardEntryWhenActive(true);
     236            document()->setUseSecureKeyboardEntryWhenActive(true);
    236237    }
    237238    HTMLGenericFormElement::dispatchFocusEvent();
     
    242243    if (isTextField() && document()->frame()) {
    243244        if (inputType() == PASSWORD)
    244             document()->frame()->setUseSecureKeyboardEntryWhenActive(false);
     245            document()->setUseSecureKeyboardEntryWhenActive(false);
    245246        document()->frame()->textFieldDidEndEditing(this);
    246247    }
     
    306307
    307308            bool didStoreValue = storesValueSeparateFromAttribute();
    308             bool didMaintainState = inputType() != PASSWORD;
     309            bool wasPasswordField = inputType() == PASSWORD;
    309310            bool didRespectHeightAndWidth = respectHeightAndWidthAttrs();
    310311            m_type = newType;
    311312            bool willStoreValue = storesValueSeparateFromAttribute();
    312             bool willMaintainState = inputType() != PASSWORD;
     313            bool isPasswordField = inputType() == PASSWORD;
    313314            bool willRespectHeightAndWidth = respectHeightAndWidthAttrs();
    314315
     
    322323                recheckValue();
    323324
    324             if (willMaintainState && !didMaintainState)
     325            if (wasPasswordField && !isPasswordField) {
    325326                document()->registerFormElementWithState(this);
    326             else if (!willMaintainState && didMaintainState)
    327                 document()->deregisterFormElementWithState(this);
     327                document()->unregisterForDidRestoreFromCacheCallback(this);
     328            } else if (!wasPasswordField && isPasswordField) {
     329                document()->unregisterFormElementWithState(this);
     330                document()->registerForDidRestoreFromCacheCallback(this);
     331            }
    328332
    329333            if (didRespectHeightAndWidth != willRespectHeightAndWidth) {
     
    759763    }
    760764
    761     // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
    762     // was such that it cleared our state too early
    763765    if (inputType() == PASSWORD)
    764         document()->passwordFieldAdded();
     766        document()->unregisterForDidRestoreFromCacheCallback(this);
    765767}
    766768
     
    14711473   return static_cast<RenderTextControl*>(renderer())->selection(cachedSelStart, cachedSelEnd);
    14721474}
     1475
     1476void HTMLInputElement::didRestoreFromCache()
     1477{
     1478    ASSERT(inputType() == PASSWORD);
     1479    reset();
     1480}
    14731481   
    14741482} // namespace
  • trunk/WebCore/html/HTMLInputElement.h

    r20440 r21430  
    184184    String constrainValue(const String& proposedValue) const;
    185185
     186    virtual void didRestoreFromCache();
     187   
    186188protected:
    187189    AtomicString m_name;
  • trunk/WebCore/html/HTMLSelectElement.cpp

    r21269 r21430  
    9797HTMLSelectElement::~HTMLSelectElement()
    9898{
    99     document()->deregisterFormElementWithState(this);
     99    document()->unregisterFormElementWithState(this);
    100100}
    101101
  • trunk/WebCore/html/HTMLTextAreaElement.cpp

    r21224 r21430  
    6161HTMLTextAreaElement::~HTMLTextAreaElement()
    6262{
    63     document()->deregisterFormElementWithState(this);
     63    document()->unregisterFormElementWithState(this);
    6464}
    6565
  • trunk/WebCore/loader/FrameLoader.cpp

    r21421 r21430  
    16171617        && !m_frame->document()->applets()->length()
    16181618        && !m_frame->document()->hasWindowEventListener(unloadEvent)
    1619         // If you change the following to allow caching of documents with password fields,
    1620         // you also need to make sure that Frame::setDocument turns on secure keyboard
    1621         // entry mode if the document's focused node requires it.
    1622         && !m_frame->document()->hasPasswordField()
    16231619        && m_frame->page()
    16241620        && m_frame->page()->backForwardList()->pageCacheSize() != 0
     
    32453241
    32463242    if (m_documentLoader->isLoadingFromCachedPage()) {
     3243        m_frame->document()->didRestoreFromCache();
     3244       
    32473245        // Force a layout to update view size and thereby update scrollbars.
    32483246        m_client->forceLayout();
     
    37433741        return;
    37443742
    3745     // Do not save doc state if the page has a password field and a form that would be submitted via https.
     3743    // Do not save doc state if the page has a form that would be submitted via https.
    37463744    Document* document = m_frame->document();
    37473745    ASSERT(document);
    3748     if (document->hasPasswordField() && document->hasSecureForm())
    3749         return;
    37503746       
     3747    if (document->hasSecureForm())
     3748         return;
     3749         
    37513750    // For a standard page load, we will have a previous item set, which will be used to
    37523751    // store the form state.  However, in some cases we will have no previous item, and
  • trunk/WebCore/page/Frame.cpp

    r21387 r21430  
    308308void Frame::setDocument(PassRefPtr<Document> newDoc)
    309309{
    310     if (d) {
    311         if (d->m_doc) {
    312             if (d->m_doc->attached())
    313                 d->m_doc->detach();
    314             // The old document's focused node may have turned on secure keyboard entry.
    315             // Now that it's going away, turn it off. Documents containing a password
    316             // field cannot enter the page cache, therefore |newDoc| cannot contain a
    317             // focused password field, and hence we can always set to false.
    318             setUseSecureKeyboardEntryWhenActive(false);
    319         }
    320         d->m_doc = newDoc;
    321         if (d->m_doc && !d->m_doc->attached())
    322             d->m_doc->attach();
    323     }
     310    if (d->m_doc && d->m_doc->attached())
     311        d->m_doc->detach();
     312
     313    d->m_doc = newDoc;
     314    if (d->m_doc && d->m_isActive)
     315        setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
     316       
     317    if (d->m_doc && !d->m_doc->attached())
     318        d->m_doc->attach();
    324319}
    325320
     
    790785#endif
    791786
    792 void Frame::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
    793 {
    794     if (d->m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
    795         return;
    796     d->m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
    797 
     787void Frame::updateSecureKeyboardEntryIfActive()
     788{
    798789    if (d->m_isActive)
    799         setUseSecureKeyboardEntry(usesSecureKeyboard);
     790        setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
    800791}
    801792
     
    15181509
    15191510    // Secure keyboard entry is set by the active frame.
    1520     if (d->m_useSecureKeyboardEntryWhenActive)
     1511    if (d->m_doc->useSecureKeyboardEntryWhenActive())
    15211512        setUseSecureKeyboardEntry(flag);
    15221513}
     
    18711862    , m_caretPaint(true)
    18721863    , m_isActive(false)
    1873     , m_useSecureKeyboardEntryWhenActive(false)
    18741864    , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
    18751865    , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
  • trunk/WebCore/page/Frame.h

    r21387 r21430  
    317317    bool isContentEditable() const; // if true, everything in frame is editable
    318318
    319     void setUseSecureKeyboardEntryWhenActive(bool);
     319    void updateSecureKeyboardEntryIfActive();
    320320
    321321    CSSMutableStyleDeclaration* typingStyle() const;
  • trunk/WebCore/page/FramePrivate.h

    r20901 r21430  
    9898        bool m_caretPaint : 1;
    9999        bool m_isActive : 1;
    100         bool m_useSecureKeyboardEntryWhenActive : 1;
    101100
    102101        RefPtr<CSSMutableStyleDeclaration> m_typingStyle;
Note: See TracChangeset for help on using the changeset viewer.