[webkit-changes] cvs commit: WebCore/khtml/xml dom_nodeimpl.cpp dom_nodeimpl.h

David hyatt at opensource.apple.com
Thu Aug 4 15:45:56 PDT 2005


hyatt       05/08/04 15:45:56

  Modified:    .        ChangeLog
               khtml/html html_elementimpl.cpp html_elementimpl.h
                        html_formimpl.cpp html_formimpl.h
               khtml/xml dom_nodeimpl.cpp dom_nodeimpl.h
  Log:
  	This patch significantly improves the performance of radio button groups and enables consistent tabbing
  	behavior in radio groups with both OS X and Internet Explorer for Windows.  It also adds support for
  	arrow key navigation between the radio buttons in a group.
  
  	In addition elements can now be shifted between forms using DOM operations and they will properly be
  	adopted by the form into which they are inserted.  This movement works even when the forms themselves
  	are not currently in the document by introducing a new set of notifications when an object is connected
  	and removed from a tree of nodes (where that tree may or may not be the main document's tree).
  
          Test cases added: formmove.html, formmove2.html in fast/forms
  
          * khtml/html/html_formimpl.cpp:
          (DOM::HTMLFormElementImpl::HTMLFormElementImpl):
          (DOM::HTMLFormElementImpl::~HTMLFormElementImpl):
  	Updated to init/delete a new selectedRadioButtons member variable that is a hash tracking the current
  	checked button in each radio group owned by the form.
  
          (DOM::HTMLFormElementImpl::radioButtonChecked):
          A notification that is called when a radio button becomes checked.
  
  	(DOM::HTMLFormElementImpl::checkedRadioButtonForGroup):
          Returns the current checked radio button for a given named group.
  
  	(DOM::HTMLFormElementImpl::removeRadioButtonForGroup):
          Clears out the checked radio button for a given named group.
  
  	(DOM::HTMLFormElementImpl::registerFormElement):
          (DOM::HTMLFormElementImpl::removeFormElement):
          The registration and removal functions have been patched to deal with radio buttons and to remove
  	the "dormant form control" concept, which is no longer needed now that controls can actually move
  	between forms.
  
  	(DOM::HTMLGenericFormElementImpl::HTMLGenericFormElementImpl):
          Remove the dormant bit from form controls.
  
  	(DOM::HTMLGenericFormElementImpl::attach):
  	Remove the code that attempted to register a form element in attached.  We use new notifications now
  	for dynamically inserted controls via JS.
  
          (DOM::HTMLGenericFormElementImpl::insertedIntoTree):
          (DOM::HTMLGenericFormElementImpl::removedFromTree):
          These are the new notifications that are called whenever a form control is connected to or removed from
  	a tree.  This tree may or may not be the document tree.  The form control can then "seek out" a form
  	to latch on to, thus keeping its current status regarding what form it belongs to current across DOM
  	operations.
  
  	(DOM::HTMLInputElementImpl::isKeyboardFocusable):
          Overridden to deal with radio buttons.  Unnamed radio buttons can't be focused.  Radio buttons can't be
  	focused if another member of their group is already currently focused.  Unchecked radio buttons can
  	only be focused if no button within the group is checked.
  
  	(DOM::HTMLInputElementImpl::setInputType):
  	Make sure to remove a checked radio button from the form's radio button hash if the type is changed
  	to something else, e.g., checkbox.
  
          (DOM::HTMLInputElementImpl::setChecked):
          Revised to update the form's hash when a radio button gets checked and to also prevent unnamed radio
  	buttons from changing state (matches WinIE).
  
  	(DOM::HTMLInputElementImpl::defaultEventHandler):
          Add support for arrow key navigation through radio button groups.  Fix space behavior so that an unselected
  	radio can become checked but not unchecked on space.  Fix enter behavior so that the form is not submitted
  	on enter.  (Matches WinIE.)
  
  	* khtml/html/html_formimpl.h:
          Adds the new member variable to track the current radio buttons in the various groups and the notifications
  	for updating form controls when they switch forms.
  
  	* khtml/xml/dom_nodeimpl.cpp:
          (DOM::NodeImpl::insertedIntoDocument):
          (DOM::NodeImpl::removedFromDocument):
          Patch insertedIntoDocument and removedFromDocument to also send the insertedIntoTree and removedFromTree
  	notifications.
  
  	(DOM::ContainerNodeImpl::removeChild):
          Call removedFromTree in the case where the removal of a child happens on a tree that is not in the
  	document.
  
  	(DOM::ContainerNodeImpl::insertedIntoTree):
          (DOM::ContainerNodeImpl::removedFromTree):
          The new notifications.  The container node can optionally crawl into children invoking their notifications.
  
  	(DOM::ContainerNodeImpl::dispatchChildInsertedEvents):
          Patched to call insertedIntoTree in the case where the insertion happened on a tree that is not in the
  	document.
  
  	* khtml/xml/dom_nodeimpl.h:
          (DOM::NodeImpl::insertedIntoTree):
          (DOM::NodeImpl::removedFromTree):
  	Added the new notifications to NodeImpl for use by the form controls.
  
  Revision  Changes    Path
  1.4524    +93 -0     WebCore/ChangeLog
  
  Index: ChangeLog
  ===================================================================
  RCS file: /cvs/root/WebCore/ChangeLog,v
  retrieving revision 1.4523
  retrieving revision 1.4524
  diff -u -r1.4523 -r1.4524
  --- ChangeLog	4 Aug 2005 22:23:00 -0000	1.4523
  +++ ChangeLog	4 Aug 2005 22:45:50 -0000	1.4524
  @@ -1,3 +1,96 @@
  +2005-08-03  David Hyatt  <hyatt at apple.com>
  +
  +	This patch significantly improves the performance of radio button groups and enables consistent tabbing
  +	behavior in radio groups with both OS X and Internet Explorer for Windows.  It also adds support for
  +	arrow key navigation between the radio buttons in a group.
  +
  +	In addition elements can now be shifted between forms using DOM operations and they will properly be
  +	adopted by the form into which they are inserted.  This movement works even when the forms themselves
  +	are not currently in the document by introducing a new set of notifications when an object is connected
  +	and removed from a tree of nodes (where that tree may or may not be the main document's tree).
  +	
  +        Test cases added: formmove.html, formmove2.html in fast/forms
  +
  +        * khtml/html/html_formimpl.cpp:
  +        (DOM::HTMLFormElementImpl::HTMLFormElementImpl):
  +        (DOM::HTMLFormElementImpl::~HTMLFormElementImpl):
  +	Updated to init/delete a new selectedRadioButtons member variable that is a hash tracking the current
  +	checked button in each radio group owned by the form.
  +	
  +        (DOM::HTMLFormElementImpl::radioButtonChecked):
  +        A notification that is called when a radio button becomes checked.
  +	
  +	(DOM::HTMLFormElementImpl::checkedRadioButtonForGroup):
  +        Returns the current checked radio button for a given named group.
  +	
  +	(DOM::HTMLFormElementImpl::removeRadioButtonForGroup):
  +        Clears out the checked radio button for a given named group.
  +	
  +	(DOM::HTMLFormElementImpl::registerFormElement):
  +        (DOM::HTMLFormElementImpl::removeFormElement):
  +        The registration and removal functions have been patched to deal with radio buttons and to remove
  +	the "dormant form control" concept, which is no longer needed now that controls can actually move
  +	between forms.
  +	
  +	(DOM::HTMLGenericFormElementImpl::HTMLGenericFormElementImpl):
  +        Remove the dormant bit from form controls.
  +	
  +	(DOM::HTMLGenericFormElementImpl::attach):
  +	Remove the code that attempted to register a form element in attached.  We use new notifications now
  +	for dynamically inserted controls via JS.
  +	
  +        (DOM::HTMLGenericFormElementImpl::insertedIntoTree):
  +        (DOM::HTMLGenericFormElementImpl::removedFromTree):
  +        These are the new notifications that are called whenever a form control is connected to or removed from
  +	a tree.  This tree may or may not be the document tree.  The form control can then "seek out" a form
  +	to latch on to, thus keeping its current status regarding what form it belongs to current across DOM
  +	operations.
  +
  +	(DOM::HTMLInputElementImpl::isKeyboardFocusable):
  +        Overridden to deal with radio buttons.  Unnamed radio buttons can't be focused.  Radio buttons can't be
  +	focused if another member of their group is already currently focused.  Unchecked radio buttons can
  +	only be focused if no button within the group is checked.
  +	
  +	(DOM::HTMLInputElementImpl::setInputType):
  +	Make sure to remove a checked radio button from the form's radio button hash if the type is changed
  +	to something else, e.g., checkbox.
  +	
  +        (DOM::HTMLInputElementImpl::setChecked):
  +        Revised to update the form's hash when a radio button gets checked and to also prevent unnamed radio
  +	buttons from changing state (matches WinIE).
  +	
  +	(DOM::HTMLInputElementImpl::defaultEventHandler):
  +        Add support for arrow key navigation through radio button groups.  Fix space behavior so that an unselected
  +	radio can become checked but not unchecked on space.  Fix enter behavior so that the form is not submitted
  +	on enter.  (Matches WinIE.)
  +	
  +	* khtml/html/html_formimpl.h:
  +        Adds the new member variable to track the current radio buttons in the various groups and the notifications
  +	for updating form controls when they switch forms.
  +	
  +	* khtml/xml/dom_nodeimpl.cpp:
  +        (DOM::NodeImpl::insertedIntoDocument):
  +        (DOM::NodeImpl::removedFromDocument):
  +        Patch insertedIntoDocument and removedFromDocument to also send the insertedIntoTree and removedFromTree
  +	notifications.
  +	
  +	(DOM::ContainerNodeImpl::removeChild):
  +        Call removedFromTree in the case where the removal of a child happens on a tree that is not in the 
  +	document.
  +	
  +	(DOM::ContainerNodeImpl::insertedIntoTree):
  +        (DOM::ContainerNodeImpl::removedFromTree):
  +        The new notifications.  The container node can optionally crawl into children invoking their notifications.
  +	
  +	(DOM::ContainerNodeImpl::dispatchChildInsertedEvents):
  +        Patched to call insertedIntoTree in the case where the insertion happened on a tree that is not in the
  +	document.
  +	
  +	* khtml/xml/dom_nodeimpl.h:
  +        (DOM::NodeImpl::insertedIntoTree):
  +        (DOM::NodeImpl::removedFromTree):
  +	Added the new notifications to NodeImpl for use by the form controls.
  +
   2005-08-04  Darin Adler  <darin at apple.com>
   
           Reviewed by John Sullivan.
  
  
  
  1.94      +3 -3      WebCore/khtml/html/html_elementimpl.cpp
  
  Index: html_elementimpl.cpp
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/html/html_elementimpl.cpp,v
  retrieving revision 1.93
  retrieving revision 1.94
  diff -u -r1.93 -r1.94
  --- html_elementimpl.cpp	31 Jul 2005 01:08:12 -0000	1.93
  +++ html_elementimpl.cpp	4 Aug 2005 22:45:54 -0000	1.94
  @@ -547,7 +547,7 @@
           setAttribute(contenteditableAttr, enabled.isEmpty() ? "true" : enabled);
   }
   
  -void HTMLElementImpl::click(bool sendMouseEvents)
  +void HTMLElementImpl::click(bool sendMouseEvents, bool showPressedLook)
   {
       int x = 0;
       int y = 0;
  @@ -560,13 +560,13 @@
           QMouseEvent pressEvt(QEvent::MouseButtonPress, QPoint(x,y), Qt::LeftButton, 0);
           dispatchMouseEvent(&pressEvt, EventImpl::MOUSEDOWN_EVENT);
           if (r)
  -            setActive(true, true);
  +            setActive(true, showPressedLook);
           QMouseEvent upEvent(QEvent::MouseButtonRelease, QPoint(x,y), Qt::LeftButton, 0);
           dispatchMouseEvent(&upEvent, EventImpl::MOUSEUP_EVENT);
           if (r)
               setActive(false);
       } else if (r) {
  -        setActive(true, true);
  +        setActive(true, showPressedLook);
           setActive(false);
       }
   
  
  
  
  1.38      +1 -1      WebCore/khtml/html/html_elementimpl.h
  
  Index: html_elementimpl.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/html/html_elementimpl.h,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- html_elementimpl.h	18 Jul 2005 21:44:20 -0000	1.37
  +++ html_elementimpl.h	4 Aug 2005 22:45:54 -0000	1.38
  @@ -79,7 +79,7 @@
       virtual void setContentEditable(MappedAttributeImpl* attr);
       virtual void setContentEditable(const DOMString &enabled);
   
  -    virtual void click(bool sendMouseEvents);
  +    virtual void click(bool sendMouseEvents = false, bool showPressedLook = true);
       virtual void accessKeyAction(bool sendToAnyElement);
   
       virtual bool isGenericFormElement() const { return false; }
  
  
  
  1.183     +166 -58   WebCore/khtml/html/html_formimpl.cpp
  
  Index: html_formimpl.cpp
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/html/html_formimpl.cpp,v
  retrieving revision 1.182
  retrieving revision 1.183
  diff -u -r1.182 -r1.183
  --- html_formimpl.cpp	2 Aug 2005 20:28:39 -0000	1.182
  +++ html_formimpl.cpp	4 Aug 2005 22:45:54 -0000	1.183
  @@ -117,6 +117,7 @@
       m_boundary = "----------0xKhTmLbOuNdArY";
       m_acceptcharset = "UNKNOWN";
       m_malformed = false;
  +    m_selectedRadioButtons = 0;
   }
   
   HTMLFormElementImpl::~HTMLFormElementImpl()
  @@ -125,10 +126,10 @@
       
       for (unsigned i = 0; i < formElements.count(); ++i)
           formElements[i]->m_form = 0;
  -    for (unsigned i = 0; i < dormantFormElements.count(); ++i)
  -        dormantFormElements[i]->m_form = 0;
       for (unsigned i = 0; i < imgElements.count(); ++i)
           imgElements[i]->m_form = 0;
  +        
  +    delete m_selectedRadioButtons;
   }
   
   #if APPLE_CHANGES
  @@ -678,16 +679,33 @@
           HTMLElementImpl::parseMappedAttribute(attr);
   }
   
  -void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
  +void HTMLFormElementImpl::radioButtonChecked(HTMLInputElementImpl *caller)
   {
  -    for (unsigned i = 0; i < formElements.count(); ++i) {
  -        HTMLGenericFormElementImpl *current = formElements[i];
  -        if (current->hasLocalName(inputTag) &&
  -            static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
  -            current != caller && current->form() == caller->form() && current->name() == caller->name()) {
  -            static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
  -        }
  -    }
  +    // Uncheck the currently selected item
  +    if (!m_selectedRadioButtons)
  +        m_selectedRadioButtons = new HashMap<DOMStringImpl*, HTMLInputElementImpl*, PointerHash<DOMStringImpl*> >;
  +
  +    HTMLInputElementImpl* currentCheckedRadio = m_selectedRadioButtons->get(caller->name().implementation());
  +    if (currentCheckedRadio && currentCheckedRadio != caller)
  +        currentCheckedRadio->setChecked(false);
  +        
  +    // Now insert ourselves into the hash. There should really be a replace method
  +    // in HashMap...
  +    m_selectedRadioButtons->remove(caller->name().implementation());
  +    m_selectedRadioButtons->insert(caller->name().implementation(), caller);
  +}
  +
  +HTMLInputElementImpl* HTMLFormElementImpl::checkedRadioButtonForGroup(DOMStringImpl* name)
  +{
  +    if (!m_selectedRadioButtons)
  +        return 0;
  +    return m_selectedRadioButtons->get(name);
  +}
  +
  +void HTMLFormElementImpl::removeRadioButtonGroup(DOMStringImpl* name)
  +{
  +    if (m_selectedRadioButtons)
  +        m_selectedRadioButtons->remove(name);
   }
   
   template<class T> static void insertIntoVector(QPtrVector<T> &vec, unsigned pos, T* item)
  @@ -745,18 +763,16 @@
   void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
   {
       insertIntoVector(formElements, formElementIndex(e), e);
  -    removeFromVector(dormantFormElements, e);
   }
   
   void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
   {
  -    removeFromVector(formElements, e);
  -    removeFromVector(dormantFormElements, e);
  -}
  -
  -void HTMLFormElementImpl::makeFormElementDormant(HTMLGenericFormElementImpl *e)
  -{
  -    appendToVector(dormantFormElements, e);
  +    if (m_selectedRadioButtons && !e->name().isEmpty()) {
  +        HTMLGenericFormElementImpl* currentCheckedRadio = m_selectedRadioButtons->get(e->name().implementation());
  +        if (currentCheckedRadio == e)
  +            m_selectedRadioButtons->remove(e->name().implementation());
  +    }
  +            
       removeFromVector(formElements, e);
   }
   
  @@ -841,7 +857,6 @@
       : HTMLElementImpl(tagName, doc)
   {
       m_disabled = m_readOnly = false;
  -    m_dormant = false;
   
       if (f)
   	m_form = f;
  @@ -881,19 +896,6 @@
   {
       assert(!attached());
   
  -    // FIXME: This handles the case of a new form element being created by
  -    // JavaScript and inserted inside a form. What it does not handle is
  -    // a form element being moved from inside a form to outside, or from one
  -    // inside one form to another. The reason this other case is hard to fix
  -    // is that during parsing, we may have been passed a form that we are not
  -    // inside, DOM-tree-wise. If so, it's hard for us to know when we should
  -    // be removed from that form's element list.
  -    if (!m_form) {
  -	m_form = getForm();
  -	if (m_form)
  -	    m_form->registerFormElement(this);
  -    }
  -
       HTMLElementImpl::attach();
   
       // The call to updateFromElement() needs to go after the call through
  @@ -913,24 +915,55 @@
       }
   }
   
  -void HTMLGenericFormElementImpl::insertedIntoDocument()
  +void HTMLGenericFormElementImpl::insertedIntoTree(bool deep)
   {
  -    if (m_form && m_dormant)
  -        m_form->registerFormElement(this);
  -
  -    m_dormant = false;
  +    if (!m_form) {
  +        // This handles the case of a new form element being created by
  +        // JavaScript and inserted inside a form.  In the case of the parser
  +        // setting a form, we will already have a non-null value for m_form, 
  +        // and so we don't need to do anything.
  +        m_form = getForm();
  +	if (m_form)
  +	    m_form->registerFormElement(this);
  +    }
   
  -    HTMLElementImpl::insertedIntoDocument();
  +    HTMLElementImpl::insertedIntoTree(deep);
   }
   
  -void HTMLGenericFormElementImpl::removedFromDocument()
  +void HTMLGenericFormElementImpl::removedFromTree(bool deep)
   {
  -    if (m_form)
  -        m_form->makeFormElementDormant(this);
  -
  -    m_dormant = true;
  +    // When being removed we have to possibly null out our form and remove ourselves from
  +    // the form's list of elements.
  +    if (m_form) {
  +        // Attempt to re-acquire the form.  If we can't re-acquire, then
  +        // remove ourselves from the form.
  +        NodeImpl* form = parentNode();
  +        NodeImpl* root = this;
  +        while (form) {
  +            if (form->hasTagName(formTag))
  +                break;
  +            root = form;
  +            form = form->parentNode();
  +        }
  +        
  +        // If the form has been demoted to a leaf, then we won't find it as an ancestor.
  +        // Check to see if the root node of our current form and our root node
  +        // match.  If so, preserve the connection to the form.
  +        if (!form) {
  +            NodeImpl* formRoot = m_form;
  +            while (formRoot->parent()) formRoot = formRoot->parent();
  +            if (formRoot == root)
  +                form = m_form;
  +        } 
  +        
  +        if (!form) {
  +            m_form->removeFormElement(this);
  +            m_form = 0;
  +        } else
  +            assert(form == m_form); // The re-acquired form should be the same. If not, something really strange happened.
  +    }
      
  -    HTMLElementImpl::removedFromDocument();
  +    HTMLElementImpl::removedFromTree(deep);
   }
   
   HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
  @@ -1294,7 +1327,7 @@
   
   bool HTMLFieldSetElementImpl::checkDTD(const NodeImpl* newChild)
   {
  -	return newChild->hasTagName(legendTag) || HTMLElementImpl::checkDTD(newChild);
  +    return newChild->hasTagName(legendTag) || HTMLElementImpl::checkDTD(newChild);
   }
   
   bool HTMLFieldSetElementImpl::isFocusable() const
  @@ -1357,6 +1390,34 @@
       delete m_imageLoader;
   }
   
  +bool HTMLInputElementImpl::isKeyboardFocusable() const
  +{
  +    // If the base class says we can't be focused, then we can stop now.
  +    if (!HTMLGenericFormElementImpl::isKeyboardFocusable())
  +        return false;
  +
  +    if (m_type == RADIO) {
  +        // Unnamed radio buttons are never focusable (matches WinIE).
  +        if (name().isEmpty())
  +            return false;
  +
  +        // Never allow keyboard tabbing to leave you in the same radio group.  Always
  +        // skip any other elements in the group.
  +        NodeImpl* currentFocusNode = getDocument()->focusNode();
  +        if (currentFocusNode && currentFocusNode->hasTagName(inputTag)) {
  +            HTMLInputElementImpl* focusedInput = static_cast<HTMLInputElementImpl*>(currentFocusNode);
  +            if (focusedInput->inputType() == RADIO && focusedInput->form() == m_form &&
  +                focusedInput->name() == name())
  +                return false;
  +        }
  +        
  +        // Allow keyboard focus if we're checked or if nothing in the group is checked.
  +        return checked() || !m_form->checkedRadioButtonForGroup(name().implementation());
  +    }
  +    
  +    return true;
  +}
  +
   void HTMLInputElementImpl::setType(const DOMString& t)
   {
       if (t.isEmpty()) {
  @@ -1409,6 +1470,10 @@
               // Useful in case we were called from inside parseMappedAttribute.
               setAttribute(typeAttr, type());
           } else {
  +            if (m_form && m_type == RADIO && !name().isEmpty()) {
  +                if (m_form->checkedRadioButtonForGroup(name().implementation()) == this)
  +                    m_form->removeRadioButtonGroup(name().implementation());
  +            }
               bool wasAttached = m_attached;
               if (wasAttached)
                   detach();
  @@ -1619,7 +1684,7 @@
       }
   }
   
  -void HTMLInputElementImpl::click(bool sendMouseEvents)
  +void HTMLInputElementImpl::click(bool sendMouseEvents, bool showPressedLook)
   {
       switch (inputType()) {
           case HIDDEN:
  @@ -1632,14 +1697,14 @@
   #if APPLE_CHANGES
           {
               QWidget *widget;
  -            if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
  +            if (showPressedLook && renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
                   // using this method gives us nice Cocoa user interface feedback
                   static_cast<QButton *>(widget)->click(sendMouseEvents);
                   break;
               }
           }
   #endif
  -            HTMLGenericFormElementImpl::click(sendMouseEvents);
  +            HTMLGenericFormElementImpl::click(sendMouseEvents, showPressedLook);
               break;
           case FILE:
   #if APPLE_CHANGES
  @@ -1648,7 +1713,7 @@
                   break;
               }
   #endif
  -            HTMLGenericFormElementImpl::click(sendMouseEvents);
  +            HTMLGenericFormElementImpl::click(sendMouseEvents, showPressedLook);
               break;
           case CHECKBOX:
           case IMAGE:
  @@ -1659,7 +1724,7 @@
           case RANGE:
   #endif
           case TEXT:
  -            HTMLGenericFormElementImpl::click(sendMouseEvents);
  +            HTMLGenericFormElementImpl::click(sendMouseEvents, showPressedLook);
               break;
       }
   }
  @@ -2075,10 +2140,12 @@
   
   void HTMLInputElementImpl::setChecked(bool _checked)
   {
  -    if (checked() == _checked) return;
  +    // WinIE does not allow unnamed radio buttons to even be checked.
  +    if (checked() == _checked || name().isEmpty())
  +        return;
   
  -    if (m_form && m_type == RADIO && _checked && !name().isEmpty())
  -        m_form->radioClicked(this);
  +    if (m_form && m_type == RADIO && _checked)
  +        m_form->radioButtonChecked(this);
   
       m_useDefaultChecked = false;
       m_checked = _checked;
  @@ -2263,13 +2330,18 @@
                   case CHECKBOX:
                   case FILE:
                   case IMAGE:
  -                case RADIO:
                   case RESET:
                   case SUBMIT:
                       // Simulate mouse click for spacebar for these types of elements.
                       // The AppKit already does this for some, but not all, of them.
                       clickElement = true;
                       break;
  +                case RADIO:
  +                    // If an unselected radio is tabbed into (because the entire group has nothing
  +                    // checked, or because of some explicit .focus() call), then allow space to check it.
  +                    if (!checked())
  +                        clickElement = true;
  +                    break;
                   case HIDDEN:
                   case ISINDEX:
                   case PASSWORD:
  @@ -2295,12 +2367,48 @@
                       break;
                   case FILE:
                   case IMAGE:
  -                case RADIO:
                   case RESET:
                   case SUBMIT:
                       // Simulate mouse click for enter for these types of elements.
                       clickElement = true;
                       break;
  +                case RADIO:
  +                    break; // Don't do anything for enter on a radio button.
  +            }
  +        }
  +
  +        if (m_type == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
  +            // Left and up mean "previous radio button".
  +            // Right and down mean "next radio button".
  +            // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
  +            // to the right).  Seems strange, but we'll match it.
  +            bool forward = (key == "Down" || key == "Right");
  +            
  +            // We can only stay within the form's children if the form hasn't been demoted to a leaf because
  +            // of malformed HTML.
  +            NodeImpl* n = this;
  +            while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) {
  +                // Once we encounter a form element, we know we're through.
  +                if (n->hasTagName(formTag))
  +                    break;
  +                    
  +                // Look for more radio buttons.
  +                if (n->hasTagName(inputTag)) {
  +                    HTMLInputElementImpl* elt = static_cast<HTMLInputElementImpl*>(n);
  +                    if (elt->form() != m_form)
  +                        break;
  +                    if (n->hasTagName(inputTag)) {
  +                        HTMLInputElementImpl* inputElt = static_cast<HTMLInputElementImpl*>(n);
  +                        if (inputElt->inputType() == RADIO && inputElt->name() == name() &&
  +                            inputElt->isFocusable()) {
  +                            inputElt->setChecked(true);
  +                            getDocument()->setFocusNode(inputElt);
  +                            inputElt->click(false, false);
  +                            evt->setDefaultHandled();
  +                            break;
  +                        }
  +                    }
  +                }
               }
           }
   
  @@ -2625,8 +2733,8 @@
   
   bool HTMLSelectElementImpl::checkDTD(const NodeImpl* newChild)
   {
  -	return newChild->isTextNode() || newChild->hasTagName(optionTag) || newChild->hasTagName(optgroupTag) ||
  -		   newChild->hasTagName(scriptTag);
  +    return newChild->isTextNode() || newChild->hasTagName(optionTag) || newChild->hasTagName(optgroupTag) ||
  +           newChild->hasTagName(scriptTag);
   }
   
   void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
  
  
  
  1.84      +15 -10    WebCore/khtml/html/html_formimpl.h
  
  Index: html_formimpl.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/html/html_formimpl.h,v
  retrieving revision 1.83
  retrieving revision 1.84
  diff -u -r1.83 -r1.84
  --- html_formimpl.h	2 Aug 2005 20:28:39 -0000	1.83
  +++ html_formimpl.h	4 Aug 2005 22:45:54 -0000	1.84
  @@ -30,6 +30,8 @@
   
   #include <qptrvector.h>
   #include <qmemarray.h>
  +#include "hashtable.h"
  +#include "pointerhash.h"
   
   class KHTMLView;
   class QTextCodec;
  @@ -54,6 +56,7 @@
   class FormDataList;
   class HTMLFormElement;
   class HTMLGenericFormElementImpl;
  +class HTMLInputElementImpl;
   class HTMLImageElementImpl;
   class HTMLImageLoader;
   class HTMLOptionElementImpl;
  @@ -87,11 +90,12 @@
   
       virtual void parseMappedAttribute(MappedAttributeImpl *attr);
   
  -    void radioClicked( HTMLGenericFormElementImpl *caller );
  +    void radioButtonChecked(HTMLInputElementImpl *caller);
  +    HTMLInputElementImpl* checkedRadioButtonForGroup(DOMStringImpl* name);
  +    void removeRadioButtonGroup(DOMStringImpl* name);
   
       void registerFormElement(HTMLGenericFormElementImpl *);
       void removeFormElement(HTMLGenericFormElementImpl *);
  -    void makeFormElementDormant(HTMLGenericFormElementImpl *);
       void registerImgElement(HTMLImageElementImpl *);
       void removeImgElement(HTMLImageElementImpl *);
   
  @@ -130,7 +134,6 @@
       HTMLCollectionImpl::CollectionInfo *collectionInfo;
   
       QPtrVector<HTMLGenericFormElementImpl> formElements;
  -    QPtrVector<HTMLGenericFormElementImpl> dormantFormElements;
       QPtrVector<HTMLImageElementImpl> imgElements;
       DOMString m_url;
       DOMString m_target;
  @@ -145,7 +148,9 @@
       bool m_inreset : 1;
       bool m_malformed : 1;
   
  - private:
  +    khtml::HashMap<DOMStringImpl*, HTMLInputElementImpl*, khtml::PointerHash<DOMStringImpl*> >* m_selectedRadioButtons;
  +    
  +private:
       void parseEnctype(const DOMString &);
       bool formData(khtml::FormData &) const;
   
  @@ -177,8 +182,8 @@
   
       virtual void parseMappedAttribute(MappedAttributeImpl *attr);
       virtual void attach();
  -    virtual void insertedIntoDocument();
  -    virtual void removedFromDocument();
  +    virtual void insertedIntoTree(bool deep);
  +    virtual void removedFromTree(bool deep);
   
       virtual void reset() {}
   
  @@ -230,10 +235,9 @@
   
       DOMString m_overrideName;
       HTMLFormElementImpl *m_form;
  -    bool m_disabled, m_readOnly;
  -
  +    bool m_disabled : 1;
  +    bool m_readOnly: 1;
       bool m_inited : 1;
  -    bool m_dormant : 1;
   };
   
   // -------------------------------------------------------------------------
  @@ -338,6 +342,7 @@
       virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; }
       virtual int tagPriority() const { return 0; }
   
  +    virtual bool isKeyboardFocusable() const;
       virtual bool isEnumeratable() const { return inputType() != IMAGE; }
   
       bool autoComplete() const { return m_autocomplete; }
  @@ -377,7 +382,7 @@
       void select();
       void setSelectionRange(long, long);
       
  -    virtual void click(bool sendMouseEvents = false);
  +    virtual void click(bool sendMouseEvents = false, bool showPressedLook = true);
       virtual void accessKeyAction(bool sendToAnyElement);
   
       virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const;
  
  
  
  1.168     +29 -10    WebCore/khtml/xml/dom_nodeimpl.cpp
  
  Index: dom_nodeimpl.cpp
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/xml/dom_nodeimpl.cpp,v
  retrieving revision 1.167
  retrieving revision 1.168
  diff -u -r1.167 -r1.168
  --- dom_nodeimpl.cpp	1 Aug 2005 03:25:29 -0000	1.167
  +++ dom_nodeimpl.cpp	4 Aug 2005 22:45:55 -0000	1.168
  @@ -1246,6 +1246,8 @@
           getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
   
       setInDocument(true);
  +    
  +    insertedIntoTree(false);
   }
   
   void NodeImpl::removedFromDocument()
  @@ -1254,6 +1256,8 @@
           getDocument()->registerDisconnectedNodeWithEventListeners(this);
   
       setInDocument(false);
  +    
  +    removedFromTree(false);
   }
   
   void NodeImpl::childrenChanged()
  @@ -1969,6 +1973,8 @@
   
       if (oldChild->inDocument())
           oldChild->removedFromDocument();
  +    else
  +        oldChild->removedFromTree(true);
   
       return oldChild;
   }
  @@ -2185,6 +2191,24 @@
           child->removedFromDocument();
   }
   
  +void ContainerNodeImpl::insertedIntoTree(bool deep)
  +{
  +    NodeImpl::insertedIntoTree(deep);
  +    if (deep) {
  +        for (NodeImpl *child = _first; child; child = child->nextSibling())
  +            child->insertedIntoTree(deep);
  +    }
  +}
  +
  +void ContainerNodeImpl::removedFromTree(bool deep)
  +{
  +    NodeImpl::removedFromTree(deep);
  +    if (deep) {
  +        for (NodeImpl *child = _first; child; child = child->nextSibling())
  +            child->removedFromTree(deep);
  +    }
  +}
  +
   void ContainerNodeImpl::cloneChildNodes(NodeImpl *clone)
   {
       int exceptioncode = 0;
  @@ -2394,15 +2418,10 @@
   
   void ContainerNodeImpl::dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode )
   {
  -    NodeImpl *p = this;
  -    while (p->parentNode())
  -        p = p->parentNode();
  -
  -    if (p->nodeType() == Node::DOCUMENT_NODE) {
  -        for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
  -            c->insertedIntoDocument();
  -        }
  -    }
  +    if (inDocument())
  +        child->insertedIntoDocument();
  +    else
  +        child->insertedIntoTree(true);
   
       if (getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER)) {
           child->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTED_EVENT,
  @@ -2414,7 +2433,7 @@
       // dispatch the DOMNodeInsertedIntoDocument event to all descendants
       bool hasInsertedListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
   
  -    if (hasInsertedListeners && p->nodeType() == Node::DOCUMENT_NODE) {
  +    if (hasInsertedListeners && inDocument()) {
           for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
               c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT,
                                                      false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
  
  
  
  1.95      +10 -2     WebCore/khtml/xml/dom_nodeimpl.h
  
  Index: dom_nodeimpl.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/xml/dom_nodeimpl.h,v
  retrieving revision 1.94
  retrieving revision 1.95
  diff -u -r1.94 -r1.95
  --- dom_nodeimpl.h	1 Aug 2005 03:25:29 -0000	1.94
  +++ dom_nodeimpl.h	4 Aug 2005 22:45:55 -0000	1.95
  @@ -251,7 +251,7 @@
       virtual bool isControl() const { return false; } // Eventually the notion of what is a control will be extensible.
       virtual bool isEnabled() const { return true; }
       virtual bool isChecked() const { return false; }
  -    
  +
       virtual bool isContentEditable() const;
       virtual QRect getRect() const;
   
  @@ -435,6 +435,12 @@
        */
       virtual void removedFromDocument();
   
  +    // These functions are called whenever you are connected or disconnected from a tree.  That tree may be the main
  +    // document tree, or it could be another disconnected tree.  Override these functions to do any work that depends
  +    // on connectedness to some ancestor (e.g., an ancestor <form> for example).
  +    virtual void insertedIntoTree(bool deep) {};
  +    virtual void removedFromTree(bool deep) {};
  +
       /**
        * Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
        * node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
  @@ -531,7 +537,9 @@
   
       virtual void insertedIntoDocument();
       virtual void removedFromDocument();
  -    
  +    virtual void insertedIntoTree(bool deep);
  +    virtual void removedFromTree(bool deep);
  +
   //protected:
       NodeImpl *_first;
       NodeImpl *_last;
  
  
  



More information about the webkit-changes mailing list