Follow up the recent HTMLSelectElement improvements with a little bit more
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Oct 2011 00:30:43 +0000 (00:30 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Oct 2011 00:30:43 +0000 (00:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=70139

Reviewed by Ryosuke Niwa.

Refactoring, covered by existing tests.

Mostly, this adds a toHTMLSelectElement and uses it wherever possible.

* accessibility/AccessibilityListBox.cpp:
(WebCore::AccessibilityListBox::canSetSelectedChildrenAttribute): Use toHTMLSelectElement.
(WebCore::AccessibilityListBox::addChildren): Ditto. Also removed unneeded toHTMLElement.
* accessibility/AccessibilityMenuListPopup.cpp:
(WebCore::AccessibilityMenuListPopup::addChildren): Ditto.
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::isMultiSelectable): Ditto.
(WebCore::AccessibilityRenderObject::stringValue): Removed checks on the type of the
underlying node, since other code already assumes that a menu list renderer is only
created for a select element. Streamlined the code a bit and removed some unneeded
local variables.
* bindings/js/JSHTMLOptionsCollectionCustom.cpp:
(WebCore::JSHTMLOptionsCollection::indexSetter): Use toHTMLSelectElement.
* bindings/js/JSHTMLSelectElementCustom.cpp:
(WebCore::JSHTMLSelectElement::remove): Ditto.
(WebCore::JSHTMLSelectElement::indexSetter): Ditto.
* editing/FrameSelection.cpp:
(WebCore::FrameSelection::selectAll): Ditto.
* html/HTMLKeygenElement.cpp:
(WebCore::HTMLKeygenElement::shadowSelect): Ditto.
* html/HTMLOptGroupElement.cpp:
(WebCore::HTMLOptGroupElement::recalcSelectOptions): Ditto.
(WebCore::HTMLOptGroupElement::ownerSelectElement): Ditto.
* html/HTMLOptionElement.cpp:
(WebCore::HTMLOptionElement::selected): Changed code to call renamed
updateListItemSelectedStates rather than the confusing old name
recalcListItemsIfNeeded.
(WebCore::HTMLOptionElement::childrenChanged): Changed to call
optionElementChildrenChanged rather than calling childrenChanged,
because the children of the select element did not change!
(WebCore::HTMLOptionElement::ownerSelectElement): Use toHTMLSelectElement.
* html/HTMLOptionsCollection.cpp:
(WebCore::HTMLOptionsCollection::add): Use toHTMLSelectElement.
(WebCore::HTMLOptionsCollection::remove): Use toHTMLSelectElement.
(WebCore::HTMLOptionsCollection::selectedIndex): Use toHTMLSelectElement.
(WebCore::HTMLOptionsCollection::setSelectedIndex): Use toHTMLSelectElement.
(WebCore::HTMLOptionsCollection::setLength): Use toHTMLSelectElement.
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::setSelectedIndexByUser): Call setSelectedIndex
without the now-unneeded internal suffix.
(WebCore::HTMLSelectElement::parseMappedAttribute): When the code says that
we should "determine selectedness of the items", call updateListItemSelectedStates
rather than the confusingly named recalcListItemsIfNeeded.
(WebCore::HTMLSelectElement::updateListItemSelectedStates): Renamed
recalcListItemsIfNeeded to this, since that's what this function is for.
(WebCore::HTMLSelectElement::optionElementChildrenChanged): Added. Does
the same work as childrenChanged, although it does not call up to the
base class childrenChanged function. Later we might find we can remove
some of the work here, for example it's not clear we should call the
accessibility childrenChanged function.
(WebCore::HTMLSelectElement::nextValidIndex): Changed this to a member function
and made it get the list items itself rather than requiring they be passed in.
(WebCore::HTMLSelectElement::nextSelectableListIndex): Updated for change to
nextValidIndex.
(WebCore::HTMLSelectElement::previousSelectableListIndex): Ditto.
(WebCore::HTMLSelectElement::firstSelectableListIndex): Ditto.
(WebCore::HTMLSelectElement::lastSelectableListIndex): Ditto.
(WebCore::HTMLSelectElement::nextSelectableListIndexPageAway): Ditto.
(WebCore::HTMLSelectElement::listItems): Removed unneeded const_cast, since
recalcListItems is now a const member function. Call recalcListItems by that
name instead of recalcListItemsInternal.
(WebCore::HTMLSelectElement::recalcListItems): Renamed from recalcListItemsInternal
and made this a const member function. The data members that this needs to modify
are now mutable.
(WebCore::HTMLSelectElement::setSelectedIndex): Renamed from setSelectedIndexInternal.
Changed call to updateValidity to instead call setNeedsValidityCheck, since both
do the same thing.
(WebCore::HTMLSelectElement::parseMultipleAttribute): Ditto.
(WebCore::HTMLSelectElement::menuListDefaultEventHandler): Updated for change to
nextValidIndex, removed unneeded comparison with zero that's already handled by
casting to an unsigned type, and use setSelectedIndex instead of using
setSelectedIndexInternal since they are both the same thing.
(WebCore::HTMLSelectElement::listBoxDefaultEventHandler): Removed another unneeded
comparision with zero that's handled by casting to an unsigned type.
(WebCore::HTMLSelectElement::lastSelectedListIndex): Use size_t instead of unsigned
for a vector index.
(WebCore::HTMLSelectElement::typeAheadFind): Use setSelectedIndex instead of
setSelectedIndexInternal.
(WebCore::HTMLSelectElement::insertedIntoTree): Removed unneeded explicit boolean
when calling a function that already has a default value of true.
(WebCore::HTMLSelectElement::accessKeySetSelectedIndex): Use setSelectedIndex
instead of setSelectedIndexInternal.

* html/HTMLSelectElement.h: Made childrenChanged private. Added
optionElementChildrenChanged. Renamed recalcListItemsIfNeeded to the clearer
updateListItemSelectedStates. Removed unused listBoxSelectItem. Removed
updateValidity after changing all callers to instead call setNeedsValidityCheck.
Made canSelectAll and selectAll non-virtual. Removed recalcListItemsInternal
since it's the same thing as recalcListItems now. Renamed setSelectedIndexInternal
to setSelectedIndex since it's the same function, just with a few arguments we
don't want to allow outside callers to pass. Changed nextValidIndex into a
non-static member function. Made m_listItems and m_shouldRecalcListItems mutable.
Added a toHTMLSelectElement function, modeled on the toElement function.

* html/ValidityState.cpp:
(WebCore::ValidityState::valueMissing): Use toHTMLSelectElement.
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::updateFromElement): Ditto.
(WebCore::RenderListBox::scrollToRevealSelection): Ditto.
(WebCore::RenderListBox::size): Ditto.
(WebCore::RenderListBox::numItems): Ditto.
(WebCore::RenderListBox::addFocusRingRects): Ditto.
(WebCore::RenderListBox::paintItemForeground): Ditto.
(WebCore::RenderListBox::paintItemBackground): Ditto.
(WebCore::RenderListBox::panScroll): Ditto.
(WebCore::RenderListBox::autoscroll): Ditto.
(WebCore::RenderListBox::stopAutoscroll): Ditto.
(WebCore::RenderListBox::valueChanged): Ditto.
(WebCore::RenderListBox::nodeAtPoint): Ditto.
* rendering/RenderMenuList.cpp:
(WebCore::RenderMenuList::updateOptionsWidth): Ditto.
(WebCore::RenderMenuList::updateFromElement): Ditto.
(WebCore::RenderMenuList::setTextFromOption): Ditto.
(WebCore::RenderMenuList::showPopup): Ditto.
(WebCore::RenderMenuList::valueChanged): Ditto.
(WebCore::RenderMenuList::listBoxSelectItem): Ditto.
(WebCore::RenderMenuList::multiple): Ditto.
(WebCore::RenderMenuList::didSetSelectedIndex): Ditto.
(WebCore::RenderMenuList::didUpdateActiveOption): Ditto.
(WebCore::RenderMenuList::itemText): Ditto.
(WebCore::RenderMenuList::itemAccessibilityText): Ditto.
(WebCore::RenderMenuList::itemToolTip): Ditto.
(WebCore::RenderMenuList::itemIsEnabled): Ditto. Also use the
disabled function instead of the virtual isEnabledFormControl
function to check if the optgroup is enabled.
(WebCore::RenderMenuList::itemStyle): Ditto.
(WebCore::RenderMenuList::itemBackgroundColor): Ditto.
(WebCore::RenderMenuList::listSize): Ditto.
(WebCore::RenderMenuList::selectedIndex): Ditto.
(WebCore::RenderMenuList::itemIsSeparator): Ditto.
(WebCore::RenderMenuList::itemIsLabel): Ditto.
(WebCore::RenderMenuList::itemIsSelected): Ditto.
(WebCore::RenderMenuList::setTextFromItem): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@97533 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityListBox.cpp
Source/WebCore/accessibility/AccessibilityMenuListPopup.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/bindings/js/JSHTMLOptionsCollectionCustom.cpp
Source/WebCore/bindings/js/JSHTMLSelectElementCustom.cpp
Source/WebCore/editing/FrameSelection.cpp
Source/WebCore/html/HTMLKeygenElement.cpp
Source/WebCore/html/HTMLOptGroupElement.cpp
Source/WebCore/html/HTMLOptionElement.cpp
Source/WebCore/html/HTMLOptionsCollection.cpp
Source/WebCore/html/HTMLSelectElement.cpp
Source/WebCore/html/HTMLSelectElement.h
Source/WebCore/html/ValidityState.cpp
Source/WebCore/rendering/RenderListBox.cpp
Source/WebCore/rendering/RenderMenuList.cpp

index 6c53cb7..8d12357 100644 (file)
@@ -1,3 +1,148 @@
+2011-10-14  Darin Adler  <darin@apple.com>
+
+        Follow up the recent HTMLSelectElement improvements with a little bit more
+        https://bugs.webkit.org/show_bug.cgi?id=70139
+
+        Reviewed by Ryosuke Niwa.
+
+        Refactoring, covered by existing tests.
+
+        Mostly, this adds a toHTMLSelectElement and uses it wherever possible.
+
+        * accessibility/AccessibilityListBox.cpp:
+        (WebCore::AccessibilityListBox::canSetSelectedChildrenAttribute): Use toHTMLSelectElement.
+        (WebCore::AccessibilityListBox::addChildren): Ditto. Also removed unneeded toHTMLElement.
+        * accessibility/AccessibilityMenuListPopup.cpp:
+        (WebCore::AccessibilityMenuListPopup::addChildren): Ditto.
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::isMultiSelectable): Ditto.
+        (WebCore::AccessibilityRenderObject::stringValue): Removed checks on the type of the
+        underlying node, since other code already assumes that a menu list renderer is only
+        created for a select element. Streamlined the code a bit and removed some unneeded
+        local variables.
+        * bindings/js/JSHTMLOptionsCollectionCustom.cpp:
+        (WebCore::JSHTMLOptionsCollection::indexSetter): Use toHTMLSelectElement.
+        * bindings/js/JSHTMLSelectElementCustom.cpp:
+        (WebCore::JSHTMLSelectElement::remove): Ditto.
+        (WebCore::JSHTMLSelectElement::indexSetter): Ditto.
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::selectAll): Ditto.
+        * html/HTMLKeygenElement.cpp:
+        (WebCore::HTMLKeygenElement::shadowSelect): Ditto.
+        * html/HTMLOptGroupElement.cpp:
+        (WebCore::HTMLOptGroupElement::recalcSelectOptions): Ditto.
+        (WebCore::HTMLOptGroupElement::ownerSelectElement): Ditto.
+        * html/HTMLOptionElement.cpp:
+        (WebCore::HTMLOptionElement::selected): Changed code to call renamed
+        updateListItemSelectedStates rather than the confusing old name
+        recalcListItemsIfNeeded.
+        (WebCore::HTMLOptionElement::childrenChanged): Changed to call
+        optionElementChildrenChanged rather than calling childrenChanged,
+        because the children of the select element did not change!
+        (WebCore::HTMLOptionElement::ownerSelectElement): Use toHTMLSelectElement.
+        * html/HTMLOptionsCollection.cpp:
+        (WebCore::HTMLOptionsCollection::add): Use toHTMLSelectElement.
+        (WebCore::HTMLOptionsCollection::remove): Use toHTMLSelectElement.
+        (WebCore::HTMLOptionsCollection::selectedIndex): Use toHTMLSelectElement.
+        (WebCore::HTMLOptionsCollection::setSelectedIndex): Use toHTMLSelectElement.
+        (WebCore::HTMLOptionsCollection::setLength): Use toHTMLSelectElement.
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::setSelectedIndexByUser): Call setSelectedIndex
+        without the now-unneeded internal suffix.
+        (WebCore::HTMLSelectElement::parseMappedAttribute): When the code says that
+        we should "determine selectedness of the items", call updateListItemSelectedStates
+        rather than the confusingly named recalcListItemsIfNeeded.
+        (WebCore::HTMLSelectElement::updateListItemSelectedStates): Renamed
+        recalcListItemsIfNeeded to this, since that's what this function is for.
+        (WebCore::HTMLSelectElement::optionElementChildrenChanged): Added. Does
+        the same work as childrenChanged, although it does not call up to the
+        base class childrenChanged function. Later we might find we can remove
+        some of the work here, for example it's not clear we should call the
+        accessibility childrenChanged function.
+        (WebCore::HTMLSelectElement::nextValidIndex): Changed this to a member function
+        and made it get the list items itself rather than requiring they be passed in.
+        (WebCore::HTMLSelectElement::nextSelectableListIndex): Updated for change to
+        nextValidIndex.
+        (WebCore::HTMLSelectElement::previousSelectableListIndex): Ditto.
+        (WebCore::HTMLSelectElement::firstSelectableListIndex): Ditto.
+        (WebCore::HTMLSelectElement::lastSelectableListIndex): Ditto.
+        (WebCore::HTMLSelectElement::nextSelectableListIndexPageAway): Ditto.
+        (WebCore::HTMLSelectElement::listItems): Removed unneeded const_cast, since
+        recalcListItems is now a const member function. Call recalcListItems by that
+        name instead of recalcListItemsInternal.
+        (WebCore::HTMLSelectElement::recalcListItems): Renamed from recalcListItemsInternal
+        and made this a const member function. The data members that this needs to modify
+        are now mutable.
+        (WebCore::HTMLSelectElement::setSelectedIndex): Renamed from setSelectedIndexInternal.
+        Changed call to updateValidity to instead call setNeedsValidityCheck, since both
+        do the same thing.
+        (WebCore::HTMLSelectElement::parseMultipleAttribute): Ditto.
+        (WebCore::HTMLSelectElement::menuListDefaultEventHandler): Updated for change to
+        nextValidIndex, removed unneeded comparison with zero that's already handled by
+        casting to an unsigned type, and use setSelectedIndex instead of using
+        setSelectedIndexInternal since they are both the same thing.
+        (WebCore::HTMLSelectElement::listBoxDefaultEventHandler): Removed another unneeded
+        comparision with zero that's handled by casting to an unsigned type.
+        (WebCore::HTMLSelectElement::lastSelectedListIndex): Use size_t instead of unsigned
+        for a vector index.
+        (WebCore::HTMLSelectElement::typeAheadFind): Use setSelectedIndex instead of
+        setSelectedIndexInternal.
+        (WebCore::HTMLSelectElement::insertedIntoTree): Removed unneeded explicit boolean
+        when calling a function that already has a default value of true.
+        (WebCore::HTMLSelectElement::accessKeySetSelectedIndex): Use setSelectedIndex
+        instead of setSelectedIndexInternal.
+
+        * html/HTMLSelectElement.h: Made childrenChanged private. Added
+        optionElementChildrenChanged. Renamed recalcListItemsIfNeeded to the clearer
+        updateListItemSelectedStates. Removed unused listBoxSelectItem. Removed
+        updateValidity after changing all callers to instead call setNeedsValidityCheck.
+        Made canSelectAll and selectAll non-virtual. Removed recalcListItemsInternal
+        since it's the same thing as recalcListItems now. Renamed setSelectedIndexInternal
+        to setSelectedIndex since it's the same function, just with a few arguments we
+        don't want to allow outside callers to pass. Changed nextValidIndex into a
+        non-static member function. Made m_listItems and m_shouldRecalcListItems mutable.
+        Added a toHTMLSelectElement function, modeled on the toElement function.
+
+        * html/ValidityState.cpp:
+        (WebCore::ValidityState::valueMissing): Use toHTMLSelectElement.
+        * rendering/RenderListBox.cpp:
+        (WebCore::RenderListBox::updateFromElement): Ditto.
+        (WebCore::RenderListBox::scrollToRevealSelection): Ditto.
+        (WebCore::RenderListBox::size): Ditto.
+        (WebCore::RenderListBox::numItems): Ditto.
+        (WebCore::RenderListBox::addFocusRingRects): Ditto.
+        (WebCore::RenderListBox::paintItemForeground): Ditto.
+        (WebCore::RenderListBox::paintItemBackground): Ditto.
+        (WebCore::RenderListBox::panScroll): Ditto.
+        (WebCore::RenderListBox::autoscroll): Ditto.
+        (WebCore::RenderListBox::stopAutoscroll): Ditto.
+        (WebCore::RenderListBox::valueChanged): Ditto.
+        (WebCore::RenderListBox::nodeAtPoint): Ditto.
+        * rendering/RenderMenuList.cpp:
+        (WebCore::RenderMenuList::updateOptionsWidth): Ditto.
+        (WebCore::RenderMenuList::updateFromElement): Ditto.
+        (WebCore::RenderMenuList::setTextFromOption): Ditto.
+        (WebCore::RenderMenuList::showPopup): Ditto.
+        (WebCore::RenderMenuList::valueChanged): Ditto.
+        (WebCore::RenderMenuList::listBoxSelectItem): Ditto.
+        (WebCore::RenderMenuList::multiple): Ditto.
+        (WebCore::RenderMenuList::didSetSelectedIndex): Ditto.
+        (WebCore::RenderMenuList::didUpdateActiveOption): Ditto.
+        (WebCore::RenderMenuList::itemText): Ditto.
+        (WebCore::RenderMenuList::itemAccessibilityText): Ditto.
+        (WebCore::RenderMenuList::itemToolTip): Ditto.
+        (WebCore::RenderMenuList::itemIsEnabled): Ditto. Also use the
+        disabled function instead of the virtual isEnabledFormControl
+        function to check if the optgroup is enabled.
+        (WebCore::RenderMenuList::itemStyle): Ditto.
+        (WebCore::RenderMenuList::itemBackgroundColor): Ditto.
+        (WebCore::RenderMenuList::listSize): Ditto.
+        (WebCore::RenderMenuList::selectedIndex): Ditto.
+        (WebCore::RenderMenuList::itemIsSeparator): Ditto.
+        (WebCore::RenderMenuList::itemIsLabel): Ditto.
+        (WebCore::RenderMenuList::itemIsSelected): Ditto.
+        (WebCore::RenderMenuList::setTextFromItem): Ditto.
+
 2011-10-14  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Rename virtual put to putVirtual
index ae711e2..db11ac0 100644 (file)
@@ -63,7 +63,7 @@ bool AccessibilityListBox::canSetSelectedChildrenAttribute() const
     if (!selectNode)
         return false;
     
-    return !static_cast<HTMLSelectElement*>(selectNode)->disabled();
+    return !toHTMLSelectElement(selectNode)->disabled();
 }
 
 void AccessibilityListBox::addChildren()
@@ -74,12 +74,12 @@ void AccessibilityListBox::addChildren()
     
     m_haveChildren = true;
     
-    const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(selectNode)->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(selectNode)->listItems();
     unsigned length = listItems.size();
     for (unsigned i = 0; i < length; i++) {
         // The cast to HTMLElement below is safe because the only other possible listItem type
         // would be a WMLElement, but WML builds don't use accessibility features at all.
-        AccessibilityObject* listOption = listBoxOptionAccessibilityObject(toHTMLElement(listItems[i]));
+        AccessibilityObject* listOption = listBoxOptionAccessibilityObject(listItems[i]);
         if (listOption && !listOption->accessibilityIsIgnored())
             m_children.append(listOption);
     }
index 7d28683..d379dfa 100644 (file)
@@ -96,12 +96,10 @@ void AccessibilityMenuListPopup::addChildren()
 
     m_haveChildren = true;
 
-    ASSERT(selectNode->hasTagName(selectTag));
-
-    const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(selectNode)->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(selectNode)->listItems();
     unsigned length = listItems.size();
     for (unsigned i = 0; i < length; i++) {
-        AccessibilityMenuListOption* option = menuListOptionAccessibilityObject(toHTMLElement(listItems[i]));
+        AccessibilityMenuListOption* option = menuListOptionAccessibilityObject(listItems[i]);
         if (option) {
             option->setParent(this);
             m_children.append(option);
index 8409836..a49966b 100644 (file)
@@ -663,7 +663,7 @@ bool AccessibilityRenderObject::isMultiSelectable() const
     
     if (!m_renderer->isBoxModelObject() || !toRenderBoxModelObject(m_renderer)->isListBox())
         return false;
-    return m_renderer->node() && static_cast<HTMLSelectElement*>(m_renderer->node())->multiple();
+    return m_renderer->node() && toHTMLSelectElement(m_renderer->node())->multiple();
 }
 
 bool AccessibilityRenderObject::isReadOnly() const
@@ -1145,21 +1145,14 @@ String AccessibilityRenderObject::stringValue() const
     
     if (cssBox && cssBox->isMenuList()) {
         // RenderMenuList will go straight to the text() of its selected item.
-        // This has to be overriden in the case where the selected item has an aria label
-        Node* node = m_renderer->node();
-        if (node && node->isHTMLElement() && node->hasTagName(selectTag)) {
-            HTMLSelectElement* selectNode = static_cast<HTMLSelectElement*>(node);
-            int selectedIndex = selectNode->selectedIndex();
-            const Vector<HTMLElement*> listItems = selectNode->listItems();
-        
-            Element* selectedOption = 0;
-            if (selectedIndex >= 0 && selectedIndex < (int)listItems.size()) 
-                selectedOption = listItems[selectedIndex];
-            if (selectedOption) {
-                String overridenDescription = selectedOption->getAttribute(aria_labelAttr);
-                if (!overridenDescription.isNull())
-                    return overridenDescription;
-            }
+        // This has to be overridden in the case where the selected item has an ARIA label.
+        HTMLSelectElement* selectElement = toHTMLSelectElement(m_renderer->node());
+        int selectedIndex = selectElement->selectedIndex();
+        const Vector<HTMLElement*> listItems = selectElement->listItems();
+        if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems.size()) {
+            const AtomicString& overriddenDescription = listItems[selectedIndex]->fastGetAttribute(aria_labelAttr);
+            if (!overriddenDescription.isNull())
+                return overriddenDescription;
         }
         return toRenderMenuList(m_renderer)->text();
     }
index d169bc4..d98602a 100644 (file)
@@ -63,7 +63,7 @@ void JSHTMLOptionsCollection::setLength(ExecState* exec, JSValue value)
 void JSHTMLOptionsCollection::indexSetter(ExecState* exec, unsigned index, JSValue value)
 {
     HTMLOptionsCollection* imp = static_cast<HTMLOptionsCollection*>(impl());
-    HTMLSelectElement* base = static_cast<HTMLSelectElement*>(imp->base());
+    HTMLSelectElement* base = toHTMLSelectElement(imp->base());
     selectIndexSetter(base, exec, index, value);
 }
 
index 2495c1e..13ea8f3 100644 (file)
@@ -34,7 +34,7 @@ using namespace HTMLNames;
 
 JSValue JSHTMLSelectElement::remove(ExecState* exec)
 {
-    HTMLSelectElement& select = *static_cast<HTMLSelectElement*>(impl());
+    HTMLSelectElement& select = *toHTMLSelectElement(impl());
 
     // The remove function can take either an option object or the index of an option.
     if (HTMLOptionElement* option = toHTMLOptionElement(exec->argument(0)))
@@ -62,7 +62,7 @@ void selectIndexSetter(HTMLSelectElement* select, JSC::ExecState* exec, unsigned
 
 void JSHTMLSelectElement::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value)
 {
-    selectIndexSetter(static_cast<HTMLSelectElement*>(impl()), exec, index, value);
+    selectIndexSetter(toHTMLSelectElement(impl()), exec, index, value);
 }
 
 }
index e333d3b..bcf7df3 100644 (file)
@@ -1520,7 +1520,7 @@ void FrameSelection::selectAll()
     Document* document = m_frame->document();
 
     if (document->focusedNode() && document->focusedNode()->hasTagName(selectTag)) {
-        HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>(document->focusedNode());
+        HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedNode());
         if (selectElement->canSelectAll()) {
             selectElement->selectAll();
             return;
index d60b105..db1bd2f 100644 (file)
@@ -134,7 +134,7 @@ HTMLSelectElement* HTMLKeygenElement::shadowSelect() const
 {
     ShadowRoot* shadow = shadowRoot();
     ASSERT(shadow);
-    return shadow ? static_cast<HTMLSelectElement*>(shadow->firstChild()) : 0;
+    return shadow ? toHTMLSelectElement(shadow->firstChild()) : 0;
 }
 
 } // namespace
index 2ec196e..b1e6ab2 100644 (file)
@@ -84,7 +84,7 @@ void HTMLOptGroupElement::recalcSelectOptions()
     while (select && !select->hasTagName(selectTag))
         select = select->parentNode();
     if (select)
-        static_cast<HTMLSelectElement*>(select)->setRecalcListItems();
+        toHTMLSelectElement(select)->setRecalcListItems();
 }
 
 void HTMLOptGroupElement::attach()
@@ -131,7 +131,7 @@ HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
     if (!select)
        return 0;
     
-    return static_cast<HTMLSelectElement*>(select);
+    return toHTMLSelectElement(select);
 }
 
 void HTMLOptGroupElement::accessKeyAction(bool)
index a1855b0..89adf6a 100644 (file)
@@ -166,7 +166,7 @@ void HTMLOptionElement::setValue(const String& value)
 bool HTMLOptionElement::selected()
 {
     if (HTMLSelectElement* select = ownerSelectElement())
-        select->recalcListItemsIfNeeded();
+        select->updateListItemSelectedStates();
     return m_data.selected();
 }
 
@@ -188,9 +188,8 @@ void HTMLOptionElement::setSelectedState(bool selected)
 
 void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
 {
-    HTMLSelectElement* select = ownerSelectElement();
-    if (select)
-        select->childrenChanged(changedByParser);
+    if (HTMLSelectElement* select = ownerSelectElement())
+        select->optionElementChildrenChanged();
     HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
 }
 
@@ -203,7 +202,7 @@ HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const
     if (!select)
         return 0;
 
-    return static_cast<HTMLSelectElement*>(select);
+    return toHTMLSelectElement(select);
 }
 
 bool HTMLOptionElement::defaultSelected() const
index db9a457..83f3b09 100644 (file)
@@ -57,7 +57,7 @@ void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index
     }
 
     ec = 0;
-    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(base());
+    HTMLSelectElement* select = toHTMLSelectElement(base());
 
     if (index == -1 || unsigned(index) >= length())
         select->add(newOption, 0, ec);
@@ -69,22 +69,22 @@ void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index
 
 void HTMLOptionsCollection::remove(int index)
 {
-    static_cast<HTMLSelectElement*>(base())->remove(index);
+    toHTMLSelectElement(base())->remove(index);
 }
 
 int HTMLOptionsCollection::selectedIndex() const
 {
-    return static_cast<HTMLSelectElement*>(base())->selectedIndex();
+    return toHTMLSelectElement(base())->selectedIndex();
 }
 
 void HTMLOptionsCollection::setSelectedIndex(int index)
 {
-    static_cast<HTMLSelectElement*>(base())->setSelectedIndex(index);
+    toHTMLSelectElement(base())->setSelectedIndex(index);
 }
 
 void HTMLOptionsCollection::setLength(unsigned length, ExceptionCode& ec)
 {
-    static_cast<HTMLSelectElement*>(base())->setLength(length, ec);
+    toHTMLSelectElement(base())->setLength(length, ec);
 }
 
 } //namespace
index 5a34251..f734a36 100644 (file)
@@ -110,11 +110,6 @@ void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
     setNeedsValidityCheck();
 }
 
-void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect)
-{
-    setSelectedIndexInternal(optionIndex, deselect, false, false);
-}
-
 void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow, bool allowMultipleSelection)
 {
     // List box selects can fire onchange events through user interaction, such as
@@ -134,7 +129,7 @@ void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, b
     if (optionIndex == selectedIndex())
         return;
     
-    setSelectedIndexInternal(optionIndex, deselect, fireOnChangeNow, true);
+    setSelectedIndex(optionIndex, deselect, fireOnChangeNow, true);
 }
 
 bool HTMLSelectElement::hasPlaceholderLabelOption() const
@@ -172,18 +167,6 @@ bool HTMLSelectElement::valueMissing() const
     return firstSelectionIndex < 0 || (!firstSelectionIndex && hasPlaceholderLabelOption());
 }
 
-void HTMLSelectElement::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow)
-{
-    if (!multiple())
-        setSelectedIndexByUser(listToOptionIndex(listIndex), true, fireOnChangeNow);
-    else {
-        updateSelectedState(listIndex, allowMultiplySelections, shift);
-        setNeedsValidityCheck();
-        if (fireOnChangeNow)
-            listBoxOnChange();
-    }
-}
-
 int HTMLSelectElement::activeSelectionStartListIndex() const
 {
     if (m_activeSelectionAnchorIndex >= 0)
@@ -272,7 +255,7 @@ void HTMLSelectElement::parseMappedAttribute(Attribute* attr)
 
         // Ensure that we've determined selectedness of the items at least once prior to changing the size.
         if (oldSize != size)
-            recalcListItemsIfNeeded();
+            updateListItemSelectedStates();
 
         m_size = size;
         setNeedsValidityCheck();
@@ -324,12 +307,7 @@ PassRefPtr<HTMLOptionsCollection> HTMLSelectElement::options()
     return HTMLOptionsCollection::create(this);
 }
 
-void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
-{
-    const_cast<HTMLSelectElement*>(this)->recalcListItemsInternal(updateSelectedStates);
-}
-
-void HTMLSelectElement::recalcListItemsIfNeeded()
+void HTMLSelectElement::updateListItemSelectedStates()
 {
     if (m_shouldRecalcListItems)
         recalcListItems();
@@ -339,12 +317,22 @@ void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange
 {
     setRecalcListItems();
     setNeedsValidityCheck();
+
     HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     
     if (AXObjectCache::accessibilityEnabled() && renderer())
         renderer()->document()->axObjectCache()->childrenChanged(renderer());
 }
 
+void HTMLSelectElement::optionElementChildrenChanged()
+{
+    setRecalcListItems();
+    setNeedsValidityCheck();
+
+    if (AXObjectCache::accessibilityEnabled() && renderer())
+        renderer()->document()->axObjectCache()->childrenChanged(renderer());
+}
+
 void HTMLSelectElement::accessKeyAction(bool sendToAnyElement)
 {
     focus();
@@ -449,9 +437,10 @@ bool HTMLSelectElement::isRequiredFormControl() const
 // Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one.
 // Otherwise, it returns |listIndex|.
 // Valid means that it is enabled and an option element.
-int HTMLSelectElement::nextValidIndex(const Vector<HTMLElement*>& listItems, int listIndex, SkipDirection direction, int skip)
+int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, int skip) const
 {
     ASSERT(direction == -1 || direction == 1);
+    const Vector<HTMLElement*>& listItems = this->listItems();
     int lastGoodIndex = listIndex;
     int size = listItems.size();
     for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
@@ -467,28 +456,28 @@ int HTMLSelectElement::nextValidIndex(const Vector<HTMLElement*>& listItems, int
 
 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const
 {
-    return nextValidIndex(listItems(), startIndex, SkipForwards, 1);
+    return nextValidIndex(startIndex, SkipForwards, 1);
 }
 
 int HTMLSelectElement::previousSelectableListIndex(int startIndex) const
 {
     if (startIndex == -1)
         startIndex = listItems().size();
-    return nextValidIndex(listItems(), startIndex, SkipBackwards, 1);
+    return nextValidIndex(startIndex, SkipBackwards, 1);
 }
 
 int HTMLSelectElement::firstSelectableListIndex() const
 {
     const Vector<HTMLElement*>& items = listItems();
-    int index = nextValidIndex(items, items.size(), SkipBackwards, INT_MAX);
-    if (static_cast<unsigned>(index) == items.size())
+    int index = nextValidIndex(items.size(), SkipBackwards, INT_MAX);
+    if (static_cast<size_t>(index) == items.size())
         return -1;
     return index;
 }
 
 int HTMLSelectElement::lastSelectableListIndex() const
 {
-    return nextValidIndex(listItems(), -1, SkipForwards, INT_MAX);
+    return nextValidIndex(-1, SkipForwards, INT_MAX);
 }
 
 // Returns the index of the next valid item one page away from |startIndex| in direction |direction|.
@@ -505,7 +494,7 @@ int HTMLSelectElement::nextSelectableListIndexPageAway(int startIndex, SkipDirec
     // If there is no exact one page away valid option, returns startIndex or the most far index.
     int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1);
     int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex));
-    return nextValidIndex(items, edgeIndex, direction, skipAmount);
+    return nextValidIndex(edgeIndex, direction, skipAmount);
 }
 
 void HTMLSelectElement::selectAll()
@@ -601,7 +590,7 @@ void HTMLSelectElement::listBoxOnChange()
         return;
     }
 
-    // Update lastOnChangeSelection and fire dispatchFormControlChangeEvent.
+    // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent.
     bool fireOnChange = false;
     for (unsigned i = 0; i < items.size(); ++i) {
         OptionElement* optionElement = toOptionElement(items[i]);
@@ -649,14 +638,15 @@ void HTMLSelectElement::setOptionsChangedOnRenderer()
 const Vector<HTMLElement*>& HTMLSelectElement::listItems() const
 {
     if (m_shouldRecalcListItems)
-        const_cast<HTMLSelectElement*>(this)->recalcListItemsInternal();
+        recalcListItems();
     else {
 #if !ASSERT_DISABLED
         Vector<HTMLElement*> items = m_listItems;
-        const_cast<HTMLSelectElement*>(this)->recalcListItemsInternal(false);
+        recalcListItems(false);
         ASSERT(items == m_listItems);
 #endif
     }
+
     return m_listItems;
 }
 
@@ -671,7 +661,7 @@ void HTMLSelectElement::setRecalcListItems()
         m_collectionInfo.reset();
 }
 
-void HTMLSelectElement::recalcListItemsInternal(bool updateSelectedStates)
+void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
 {
     m_listItems.clear();
 
@@ -741,7 +731,7 @@ int HTMLSelectElement::selectedIndex() const
     return -1;
 }
 
-void HTMLSelectElement::setSelectedIndexInternal(int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange)
+void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange)
 {
     if (optionIndex == -1 && !deselect && !m_multiple)
         optionIndex = nextSelectableListIndex(-1);
@@ -784,7 +774,7 @@ void HTMLSelectElement::setSelectedIndexInternal(int optionIndex, bool deselect,
         }
     }
 
-    updateValidity();
+    setNeedsValidityCheck();
     if (Frame* frame = document()->frame())
         frame->page()->chrome()->client()->formStateDidChange(this);
 }
@@ -827,7 +817,7 @@ int HTMLSelectElement::listToOptionIndex(int listIndex) const
 void HTMLSelectElement::dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode)
 {
     // Save the selection so it can be compared to the new selection when
-    // dispatching change events during blur event dispatchal.
+    // dispatching change events during blur event dispatch.
     if (usesMenuList())
         saveLastSelection();
     HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedNode);
@@ -890,7 +880,7 @@ void HTMLSelectElement::parseMultipleAttribute(const Attribute* attribute)
 {
     bool oldUsesMenuList = usesMenuList();
     m_multiple = !attribute->isNull();
-    updateValidity();
+    setNeedsValidityCheck();
     if (oldUsesMenuList != usesMenuList())
         reattachIfAttached();
 }
@@ -1001,22 +991,22 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* event)
         int listIndex = optionToListIndex(selectedIndex());
 
         if (keyIdentifier == "Down" || keyIdentifier == "Right")
-            listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 1);
+            listIndex = nextValidIndex(listIndex, SkipForwards, 1);
         else if (keyIdentifier == "Up" || keyIdentifier == "Left")
-            listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 1);
+            listIndex = nextValidIndex(listIndex, SkipBackwards, 1);
         else if (keyIdentifier == "PageDown")
-            listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 3);
+            listIndex = nextValidIndex(listIndex, SkipForwards, 3);
         else if (keyIdentifier == "PageUp")
-            listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 3);
+            listIndex = nextValidIndex(listIndex, SkipBackwards, 3);
         else if (keyIdentifier == "Home")
-            listIndex = nextValidIndex(listItems, -1, SkipForwards, 1);
+            listIndex = nextValidIndex(-1, SkipForwards, 1);
         else if (keyIdentifier == "End")
-            listIndex = nextValidIndex(listItems, listItems.size(), SkipBackwards, 1);
+            listIndex = nextValidIndex(listItems.size(), SkipBackwards, 1);
         else
             handled = false;
 
-        if (handled && listIndex >= 0 && static_cast<unsigned>(listIndex) < listItems.size())
-            setSelectedIndexInternal(listToOptionIndex(listIndex));
+        if (handled && static_cast<size_t>(listIndex) < listItems.size())
+            setSelectedIndex(listToOptionIndex(listIndex));
 
         if (handled)
             event->setDefaultHandled();
@@ -1083,7 +1073,7 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* event)
         int listIndex = optionToListIndex(selectedIndex());
         if (keyCode == '\r') {
             // listIndex should already be selected, but this will fire the onchange handler.
-            setSelectedIndexInternal(listToOptionIndex(listIndex), true, true);
+            setSelectedIndex(listToOptionIndex(listIndex), true, true);
             handled = true;
         }
 #endif
@@ -1252,7 +1242,7 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
             // selection.
             saveLastSelection();
 
-            ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && static_cast<unsigned>(endIndex) < listItems.size()));
+            ASSERT_UNUSED(listItems, !listItems.size() || static_cast<size_t>(endIndex) < listItems.size());
             setActiveSelectionEndIndex(endIndex);
 
             bool selectNewItem = !m_multiple || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(document()->frame());
@@ -1321,7 +1311,7 @@ void HTMLSelectElement::defaultEventHandler(Event* event)
 int HTMLSelectElement::lastSelectedListIndex() const
 {
     const Vector<HTMLElement*>& items = listItems();
-    for (unsigned i = items.size(); i;) {
+    for (size_t i = items.size(); i;) {
         if (OptionElement* optionElement = toOptionElement(items[--i])) {
             if (optionElement->selected())
                 return i;
@@ -1395,7 +1385,7 @@ void HTMLSelectElement::typeAheadFind(KeyboardEvent* event)
         // Fold the option string and check if its prefix is equal to the folded prefix.
         String text = optionElement->textIndentedToRespectGroupLabel();
         if (stripLeadingWhiteSpace(text).foldCase().startsWith(prefixWithCaseFolded)) {
-            setSelectedIndexInternal(listToOptionIndex(index));
+            setSelectedIndex(listToOptionIndex(index));
             if (!usesMenuList())
                 listBoxOnChange();
 
@@ -1411,7 +1401,7 @@ void HTMLSelectElement::insertedIntoTree(bool deep)
     // When the element is created during document parsing, it won't have any
     // items yet - but for innerHTML and related methods, this method is called
     // after the whole subtree is constructed.
-    recalcListItems(true);
+    recalcListItems();
     HTMLFormControlElementWithState::insertedIntoTree(deep);
 }
 
@@ -1428,7 +1418,7 @@ void HTMLSelectElement::accessKeySetSelectedIndex(int index)
         if (optionElement->selected())
             optionElement->setSelectedState(false);
         else
-            setSelectedIndexInternal(index, false, true);
+            setSelectedIndex(index, false, true);
     }
 
     if (usesMenuList())
@@ -1452,12 +1442,20 @@ unsigned HTMLSelectElement::length() const
     return options;
 }
 
-HTMLSelectElement* toSelectElement(Element* element)
+#ifndef NDEBUG
+
+HTMLSelectElement* toHTMLSelectElement(Node* node)
 {
-    if (element->isHTMLElement() && element->hasTagName(selectTag))
-        return static_cast<HTMLSelectElement*>(element);
-    // FIXME: toFooClass() function should not return 0.
-    return 0;
+    ASSERT(!node || node->hasTagName(selectTag));
+    return static_cast<HTMLSelectElement*>(node);
 }
 
+const HTMLSelectElement* toHTMLSelectElement(const Node* node)
+{
+    ASSERT(!node || node->hasTagName(selectTag));
+    return static_cast<const HTMLSelectElement*>(node);
+}
+
+#endif
+
 } // namespace
index f9de431..7919910 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Google Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -61,10 +61,10 @@ public:
 
     PassRefPtr<HTMLOptionsCollection> options();
 
-    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+    void optionElementChildrenChanged();
 
     void setRecalcListItems();
-    void recalcListItemsIfNeeded();
+    void updateListItemSelectedStates();
 
     const Vector<HTMLElement*>& listItems() const;
 
@@ -85,12 +85,8 @@ public:
 
     void scrollToSelection();
 
-    void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true);
-
-    void updateValidity() { setNeedsValidityCheck(); }
-
-    virtual bool canSelectAll() const;
-    virtual void selectAll();
+    bool canSelectAll() const;
+    void selectAll();
     int listToOptionIndex(int listIndex) const;
     void listBoxOnChange();
     int optionToListIndex(int optionIndex) const;
@@ -143,8 +139,7 @@ private:
 
     bool hasPlaceholderLabelOption() const;
 
-    void recalcListItemsInternal(bool updateSelectedStates = true);
-    void setSelectedIndexInternal(int optionIndex, bool deselect = true, bool fireOnChangeNow = false, bool userDrivenChange = true);
+    void setSelectedIndex(int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange = true);
     void deselectItemsWithoutValidation(Element* excludeElement = 0);
     void parseMultipleAttribute(const Attribute*);
     int lastSelectedListIndex() const;
@@ -159,16 +154,18 @@ private:
         SkipBackwards = -1,
         SkipForwards = 1
     };
-    static int nextValidIndex(const Vector<HTMLElement*>& listItems, int listIndex, SkipDirection, int skip);
+    int nextValidIndex(int listIndex, SkipDirection, int skip) const;
     int nextSelectableListIndex(int startIndex) const;
     int previousSelectableListIndex(int startIndex) const;
     int firstSelectableListIndex() const;
     int lastSelectableListIndex() const;
     int nextSelectableListIndexPageAway(int startIndex, SkipDirection) const;
 
+    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
     CollectionCache m_collectionInfo;
-    // m_listItems contains HTMLOptionElement, HTMLOptGroupElement, or HTMLHRElement.
-    Vector<HTMLElement*> m_listItems;
+    // m_listItems contains HTMLOptionElement, HTMLOptGroupElement, and HTMLHRElement objects.
+    mutable Vector<HTMLElement*> m_listItems;
     Vector<bool> m_lastOnChangeSelection;
     Vector<bool> m_cachedStateForActiveSelection;
     DOMTimeStamp m_lastCharTime;
@@ -181,10 +178,13 @@ private:
     bool m_userDrivenChange;
     bool m_multiple;
     bool m_activeSelectionState;
-    bool m_shouldRecalcListItems;
+    mutable bool m_shouldRecalcListItems;
 };
 
-HTMLSelectElement* toSelectElement(Element*);
+inline void HTMLSelectElement::setSelectedIndex(int index, bool deselect)
+{
+    setSelectedIndex(index, deselect, false);
+}
 
 inline bool HTMLSelectElement::usesMenuList() const
 {
@@ -195,6 +195,26 @@ inline bool HTMLSelectElement::usesMenuList() const
 #endif
 }
 
+HTMLSelectElement* toHTMLSelectElement(Node*);
+const HTMLSelectElement* toHTMLSelectElement(const Node*);
+void toHTMLSelectElement(const HTMLSelectElement*); // This overload will catch anyone doing an unnecessary cast.
+
+#ifdef NDEBUG
+
+// The debug versions of these, with assertions, are not inlined.
+
+inline HTMLSelectElement* toHTMLSelectElement(Node* node)
+{
+    return static_cast<HTMLSelectElement*>(node);
+}
+
+inline const HTMLSelectElement* toHTMLSelectElement(const Node* node)
+{
+    return static_cast<const HTMLSelectElement*>(node);
+}
+
+#endif
+
 } // namespace
 
 #endif
index 2e65327..fe7312c 100644 (file)
@@ -117,10 +117,8 @@ bool ValidityState::valueMissing() const
         HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(element);
         return textArea->valueMissing(textArea->value());
     }
-    if (element->hasTagName(selectTag)) {
-        HTMLSelectElement* select = static_cast<HTMLSelectElement*>(element);
-        return select->valueMissing();
-    }
+    if (element->hasTagName(selectTag))
+        return toHTMLSelectElement(element)->valueMissing();
     return false;
 }
 
index 9545c6c..a0ddcb2 100644 (file)
@@ -106,7 +106,7 @@ void RenderListBox::updateFromElement()
     FontCachePurgePreventer fontCachePurgePreventer;
 
     if (m_optionsChanged) {
-        const Vector<HTMLElement*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems();
+        const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
         int size = numItems();
         
         float width = 0;
@@ -167,7 +167,7 @@ void RenderListBox::layout()
 
 void RenderListBox::scrollToRevealSelection()
 {    
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
 
     m_scrollToRevealSelectionAfterLayout = false;
 
@@ -213,7 +213,7 @@ void RenderListBox::computePreferredLogicalWidths()
 
 int RenderListBox::size() const
 {
-    int specifiedSize = toSelectElement(static_cast<Element*>(node()))->size();
+    int specifiedSize = toHTMLSelectElement(node())->size();
     if (specifiedSize > 1)
         return max(minSize, specifiedSize);
     return min(max(minSize, numItems()), maxDefaultSize);
@@ -227,7 +227,7 @@ int RenderListBox::numVisibleItems() const
 
 int RenderListBox::numItems() const
 {
-    return toSelectElement(static_cast<Element*>(node()))->listItems().size();
+    return toHTMLSelectElement(node())->listItems().size();
 }
 
 LayoutUnit RenderListBox::listHeight() const
@@ -314,7 +314,7 @@ void RenderListBox::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoi
     if (!isSpatialNavigationEnabled(frame()))
         return RenderBlock::addFocusRingRects(rects, additionalOffset);
 
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
 
     // Focus the last selected item.
     int selectedItem = select->activeSelectionEndListIndex();
@@ -370,8 +370,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint&
 {
     FontCachePurgePreventer fontCachePurgePreventer;
 
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     Element* element = listItems[listIndex];
     OptionElement* optionElement = toOptionElement(element);
 
@@ -422,8 +421,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint&
 
 void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex)
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     Element* element = listItems[listIndex];
     OptionElement* optionElement = toOptionElement(element);
 
@@ -519,7 +517,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition)
         return;
 
     m_inAutoscroll = true;
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     select->updateListBoxSelection(!select->multiple());
     m_inAutoscroll = false;
 }
@@ -548,7 +546,7 @@ void RenderListBox::autoscroll()
 
     int endIndex = scrollToward(pos);
     if (endIndex >= 0) {
-        HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+        HTMLSelectElement* select = toHTMLSelectElement(node());
         m_inAutoscroll = true;
 
         if (!select->multiple())
@@ -562,7 +560,7 @@ void RenderListBox::autoscroll()
 
 void RenderListBox::stopAutoscroll()
 {
-    toSelectElement(static_cast<Element*>(node()))->listBoxOnChange();
+    toHTMLSelectElement(node())->listBoxOnChange();
 }
 
 bool RenderListBox::scrollToRevealElementAtListIndex(int index)
@@ -598,9 +596,8 @@ bool RenderListBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranul
 
 void RenderListBox::valueChanged(unsigned listIndex)
 {
-    Element* element = static_cast<Element*>(node());
-    HTMLSelectElement* select = toSelectElement(element);
-    select->setSelectedIndex(select->listToOptionIndex(listIndex));
+    HTMLSelectElement* element = toHTMLSelectElement(node());
+    element->setSelectedIndex(element->listToOptionIndex(listIndex));
     element->dispatchFormControlChangeEvent();
 }
 
@@ -680,7 +677,7 @@ bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
 {
     if (!RenderBlock::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction))
         return false;
-    const Vector<HTMLElement*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     int size = numItems();
     LayoutPoint adjustedLocation = accumulatedOffset + location();
 
index 3f356a6..368199c 100644 (file)
 #include "Frame.h"
 #include "FrameView.h"
 #include "HTMLNames.h"
+#include "HTMLOptGroupElement.h"
 #include "HTMLSelectElement.h"
 #include "NodeRenderStyle.h"
 #include "OptionElement.h"
-#include "OptionGroupElement.h"
 #include "Page.h"
 #include "PopupMenu.h"
 #include "RenderBR.h"
@@ -146,7 +146,7 @@ void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* old
 void RenderMenuList::updateOptionsWidth()
 {
     float maxOptionWidth = 0;
-    const Vector<HTMLElement*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     int size = listItems.size();    
     FontCachePurgePreventer fontCachePurgePreventer;
 
@@ -189,12 +189,12 @@ void RenderMenuList::updateFromElement()
     if (m_popupIsVisible)
         m_popup->updateFromElement();
     else
-        setTextFromOption(toSelectElement(static_cast<Element*>(node()))->selectedIndex());
+        setTextFromOption(toHTMLSelectElement(node())->selectedIndex());
 }
 
 void RenderMenuList::setTextFromOption(int optionIndex)
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     const Vector<HTMLElement*>& listItems = select->listItems();
     int size = listItems.size();
 
@@ -300,7 +300,6 @@ void RenderMenuList::showPopup()
     createInnerBlock();
     if (!m_popup)
         m_popup = document()->page()->chrome()->createPopupMenu(this);
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
     m_popupIsVisible = true;
 
     // Compute the top left taking transforms into account, but use
@@ -308,8 +307,8 @@ void RenderMenuList::showPopup()
     FloatPoint absTopLeft = localToAbsolute(FloatPoint(), false, true);
     LayoutRect absBounds = absoluteBoundingBoxRectIgnoringTransforms();
     absBounds.setLocation(roundedIntPoint(absTopLeft));
-    m_popup->show(absBounds, document()->view(),
-        select->optionToListIndex(select->selectedIndex()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
+    m_popup->show(absBounds, document()->view(), select->optionToListIndex(select->selectedIndex()));
 }
 
 void RenderMenuList::hidePopup()
@@ -326,28 +325,25 @@ void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
     if (!doc || doc != doc->frame()->document())
         return;
     
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange);
 }
 
 #if ENABLE(NO_LISTBOX_RENDERING)
 void RenderMenuList::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow)
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    select->listBoxSelectItem(listIndex, allowMultiplySelections, shift, fireOnChangeNow);
+    toHTMLSelectElement(node())->listBoxSelectItem(listIndex, allowMultiplySelections, shift, fireOnChangeNow);
 }
 
 bool RenderMenuList::multiple()
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    return select->multiple();
+    return toHTMLSelectElement(node())->multiple();
 }
 #endif
 
 void RenderMenuList::didSetSelectedIndex(int listIndex)
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    didUpdateActiveOption(select->listToOptionIndex(listIndex));
+    didUpdateActiveOption(toHTMLSelectElement(node())->listToOptionIndex(listIndex));
 }
 
 void RenderMenuList::didUpdateActiveOption(int optionIndex)
@@ -359,12 +355,12 @@ void RenderMenuList::didUpdateActiveOption(int optionIndex)
         return;
     m_lastActiveIndex = optionIndex;
 
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     int listIndex = select->optionToListIndex(optionIndex);
     if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size()))
         return;
 
-    ASSERT(toOptionElement(select->listItems()[listIndex]));
+    ASSERT(select->listItems()[listIndex]);
 
     if (AccessibilityMenuList* menuList = static_cast<AccessibilityMenuList*>(document()->axObjectCache()->get(this)))
         menuList->didUpdateActiveOption(optionIndex);
@@ -372,7 +368,7 @@ void RenderMenuList::didUpdateActiveOption(int optionIndex)
 
 String RenderMenuList::itemText(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     const Vector<HTMLElement*>& listItems = select->listItems();
     if (listIndex >= listItems.size())
         return String();
@@ -401,38 +397,31 @@ String RenderMenuList::itemIcon(unsigned) const
 String RenderMenuList::itemAccessibilityText(unsigned listIndex) const
 {
     // Allow the accessible name be changed if necessary.
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size())
         return String();
-
-    return listItems[listIndex]->getAttribute(aria_labelAttr);
+    return listItems[listIndex]->fastGetAttribute(aria_labelAttr);
 }
     
 String RenderMenuList::itemToolTip(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size())
         return String();
-    Element* element = listItems[listIndex];
-    return element->title();
+    return listItems[listIndex]->title();
 }
 
 bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size())
         return false;
-    Element* element = listItems[listIndex];
-    if (!isOptionElement(element))
-        return false;
+    HTMLElement* element = listItems[listIndex];
 
     bool groupEnabled = true;
     if (Element* parentElement = element->parentElement()) {
         if (isOptionGroupElement(parentElement))
-            groupEnabled = parentElement->isEnabledFormControl();
+            groupEnabled = !static_cast<HTMLOptGroupElement*>(parentElement)->disabled();
     }
     if (!groupEnabled)
         return false;
@@ -442,8 +431,7 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
 
 PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size()) {
         // If we are making an out of bounds access, then we want to use the style
         // of a different option element (index 0). However, if there isn't an option element
@@ -454,7 +442,7 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
         // Try to retrieve the style of an option element we know exists (index 0).
         listIndex = 0;
     }
-    Element* element = listItems[listIndex];
+    HTMLElement* element = listItems[listIndex];
     
     RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
     return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->display() == NONE, style->textIndent(), style->direction(), style->unicodeBidi() == Override) : menuStyle();
@@ -462,11 +450,10 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
 
 Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size())
         return style()->visitedDependentColor(CSSPropertyBackgroundColor);
-    Element* element = listItems[listIndex];
+    HTMLElement* element = listItems[listIndex];
 
     Color backgroundColor;
     if (element->renderStyle())
@@ -539,13 +526,12 @@ int RenderMenuList::clientPaddingRight() const
 
 int RenderMenuList::listSize() const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    return select->listItems().size();
+    return toHTMLSelectElement(node())->listItems().size();
 }
 
 int RenderMenuList::selectedIndex() const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
+    HTMLSelectElement* select = toHTMLSelectElement(node());
     return select->optionToListIndex(select->selectedIndex());
 }
 
@@ -556,40 +542,29 @@ void RenderMenuList::popupDidHide()
 
 bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
-    if (listIndex >= listItems.size())
-        return false;
-    Element* element = listItems[listIndex];
-    return element->hasTagName(hrTag);
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
+    return listIndex < listItems.size() && listItems[listIndex]->hasTagName(hrTag);
 }
 
 bool RenderMenuList::itemIsLabel(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
-    if (listIndex >= listItems.size())
-        return false;
-    Element* element = listItems[listIndex];
-    return isOptionGroupElement(element);
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
+    return listIndex < listItems.size() && isOptionGroupElement(listItems[listIndex]);
 }
 
 bool RenderMenuList::itemIsSelected(unsigned listIndex) const
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    const Vector<HTMLElement*>& listItems = select->listItems();
+    const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems();
     if (listIndex >= listItems.size())
         return false;
-    Element* element = listItems[listIndex];
-    if (OptionElement* optionElement = toOptionElement(element))
+    if (OptionElement* optionElement = toOptionElement(listItems[listIndex]))
         return optionElement->selected();
     return false;
 }
 
 void RenderMenuList::setTextFromItem(unsigned listIndex)
 {
-    HTMLSelectElement* select = toSelectElement(static_cast<Element*>(node()));
-    setTextFromOption(select->listToOptionIndex(listIndex));
+    setTextFromOption(toHTMLSelectElement(node())->listToOptionIndex(listIndex));
 }
 
 FontSelector* RenderMenuList::fontSelector() const