Reviewed by Adam.
authoradele <adele@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 29 Sep 2006 23:13:49 +0000 (23:13 +0000)
committeradele <adele@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 29 Sep 2006 23:13:49 +0000 (23:13 +0000)
        Initial implementation of engine-based list box control.

        * WebCore.xcodeproj/project.pbxproj: Added RenderListBox.h and RenderListBox.cpp

        * bridge/mac/FrameMac.h: Added _mouseDownMayStartAutoscroll.
        * bridge/mac/FrameMac.mm: Updated autoscroll code to use renderers instead of layers, so any renderer that implements autoscroll will work.
        (WebCore::FrameMac::FrameMac):
        (WebCore::FrameMac::handleMousePressEvent):
        (WebCore::FrameMac::handleMouseMoveEvent):
        (WebCore::FrameMac::mouseDown):

        * page/Frame.cpp:
        (WebCore::Frame::handleMouseMoveEvent):
        (WebCore::Frame::scrollOverflow): Don't scroll list box here- this would cause arrow keys to scroll instead of select.
        (WebCore::Frame::handleAutoscroll): Updated to use a renderer instead of a layer when setting up autoscroll.
        (WebCore::Frame::autoscrollTimerFired): ditto.
        (WebCore::Frame::stopAutoscrollTimer): ditto.
        (WebCore::Frame::passWidgetMouseDownEventToWidget): Updated to check for list box's scroll bar.
        * page/Frame.h:
        * page/FramePrivate.h: (WebCore::FramePrivate::FramePrivate): Updated to use renderer unstead of layer for autoscroll.

        * page/FrameView.cpp: Keep track of current mouse position so this can be used for list box autoscroll.
        (WebCore::FrameViewPrivate::reset):
        (WebCore::FrameView::currentMousePosition):
        (WebCore::FrameView::handleMousePressEvent):
        (WebCore::FrameView::handleMouseDoubleClickEvent):
        (WebCore::selectCursor):
        (WebCore::FrameView::handleMouseMoveEvent):
        (WebCore::FrameView::handleMouseReleaseEvent):
        * page/FrameView.h:

        * platform/ScrollBar.cpp: (WebCore::ScrollBar::ScrollBar): Added controlSize argument.  The list box will use a smaller scroll bar size.
        * platform/ScrollBar.h:
        (WebCore::):
        (WebCore::ScrollBar::controlSize):
        * platform/mac/PlatformScrollBar.h:
        * platform/mac/PlatformScrollBarMac.mm:
        (NSControlSizeForScrollBarControlSize):
        (-[WebCoreScrollBar initWithPlatformScrollBar:]):
        (WebCore::PlatformScrollBar::PlatformScrollBar):

        * rendering/RenderBlock.h:
        * rendering/RenderLayer.cpp: (WebCore::RenderLayer::createScrollbar): Updated to pass regular control size to scrollbar constructor.
        * rendering/RenderLayer.h:
        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::shouldAutoscroll):
        (WebCore::RenderObject::autoscroll):
        * rendering/RenderObject.h: (WebCore::RenderObject::isListBox):

        * css/html4.css: Added properties for new list boxes.

        * html/HTMLOptionElement.cpp:
        (WebCore::HTMLOptionElement::setSelected): Doesn't allow selection to be changed here if the option is disabled.
        (WebCore::HTMLOptionElement::disabled): Added. Checks the parent's disabled status.
        * html/HTMLOptionElement.h: Added disabled method.

        * html/HTMLSelectElement.cpp: Added appearance switch for new list box implementation.
        (WebCore::HTMLSelectElement::recalcStyle):
        (WebCore::HTMLSelectElement::lastSelectedListIndex):
        (WebCore::HTMLSelectElement::deselectItems):
        (WebCore::HTMLSelectElement::setSelectedIndex):
        (WebCore::HTMLSelectElement::isKeyboardFocusable):
        (WebCore::HTMLSelectElement::isMouseFocusable):
        (WebCore::HTMLSelectElement::createRenderer):
        (WebCore::HTMLSelectElement::recalcListItems):
        (WebCore::HTMLSelectElement::setRecalcListItems):
        (WebCore::HTMLSelectElement::reset):
        (WebCore::HTMLSelectElement::notifyOptionSelected):
        (WebCore::HTMLSelectElement::defaultEventHandler): Added code to select options for list box when clicking and using arrow keys.
        (WebCore::HTMLSelectElement::nextSelectableListIndex):
        (WebCore::HTMLSelectElement::previousSelectableListIndex):
        * html/HTMLSelectElement.h:

        * rendering/RenderTheme.cpp: Added support for ListBoxAppearance
        (WebCore::RenderTheme::paint):
        (WebCore::RenderTheme::paintBorderOnly):
        (WebCore::RenderTheme::paintDecorations):
        (WebCore::RenderTheme::activeListBoxSelectionBackgroundColor):
        (WebCore::RenderTheme::activeListBoxSelectionForegroundColor):
        (WebCore::RenderTheme::inactiveListBoxSelectionBackgroundColor):
        (WebCore::RenderTheme::inactiveListBoxSelectionForegroundColor):
        (WebCore::RenderTheme::isControlStyled):
        (WebCore::RenderTheme::supportsFocusRing):
        * rendering/RenderTheme.h:
        * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::isControlStyled):

        * rendering/RenderListBox.cpp: Added.
        (WebCore::RenderListBox::RenderListBox):
        (WebCore::RenderListBox::~RenderListBox):
        (WebCore::RenderListBox::setStyle):
        (WebCore::RenderListBox::updateFromElement):
        (WebCore::RenderListBox::calcMinMaxWidth):
        (WebCore::RenderListBox::size):
        (WebCore::RenderListBox::numItems):
        (WebCore::RenderListBox::calcHeight):
        (WebCore::RenderListBox::baselinePosition):
        (WebCore::RenderListBox::itemBoundingBoxRect):
        (WebCore::RenderListBox::paintObject):
        (WebCore::RenderListBox::paintScrollbar):
        (WebCore::RenderListBox::paintItemForeground):
        (WebCore::RenderListBox::paintItemBackground):
        (WebCore::RenderListBox::scrollBarTarget):
        (WebCore::RenderListBox::isPointInScrollbar):
        (WebCore::RenderListBox::optionAtPoint):
        (WebCore::RenderListBox::autoscroll):
        (WebCore::RenderListBox::scrollToRevealElementAtListIndex):
        (WebCore::RenderListBox::scroll):
        (WebCore::RenderListBox::valueChanged):
        * rendering/RenderListBox.h: Added.
        (WebCore::RenderListBox::isListBox):
        (WebCore::RenderListBox::selectionChanged):
        (WebCore::RenderListBox::setSelectionChanged):
        (WebCore::RenderListBox::canHaveChildren):
        (WebCore::RenderListBox::renderName):
        (WebCore::RenderListBox::setOptionsChanged):
        (WebCore::RenderListBox::shouldAutoscroll):
        (WebCore::RenderListBox::listIndexIsVisible):

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

28 files changed:
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bridge/mac/FrameMac.h
WebCore/bridge/mac/FrameMac.mm
WebCore/css/html4.css
WebCore/html/HTMLOptionElement.cpp
WebCore/html/HTMLOptionElement.h
WebCore/html/HTMLSelectElement.cpp
WebCore/html/HTMLSelectElement.h
WebCore/page/Frame.cpp
WebCore/page/Frame.h
WebCore/page/FramePrivate.h
WebCore/page/FrameView.cpp
WebCore/page/FrameView.h
WebCore/platform/ScrollBar.cpp
WebCore/platform/ScrollBar.h
WebCore/platform/mac/PlatformScrollBar.h
WebCore/platform/mac/PlatformScrollBarMac.mm
WebCore/rendering/RenderBlock.h
WebCore/rendering/RenderLayer.cpp
WebCore/rendering/RenderLayer.h
WebCore/rendering/RenderListBox.cpp [new file with mode: 0644]
WebCore/rendering/RenderListBox.h [new file with mode: 0644]
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RenderTheme.cpp
WebCore/rendering/RenderTheme.h
WebCore/rendering/RenderThemeMac.mm

index cde1f94c994128a54d4fd03808818a3aa82528fc..fa47a11aad3d615f7cb9b188d595d8e86b2e86f4 100644 (file)
@@ -1,3 +1,125 @@
+2006-09-29  Adele Peterson  <adele@apple.com>
+
+        Reviewed by Adam.
+
+        Initial implementation of engine-based list box control.
+
+        * WebCore.xcodeproj/project.pbxproj: Added RenderListBox.h and RenderListBox.cpp
+
+        * bridge/mac/FrameMac.h: Added _mouseDownMayStartAutoscroll.
+        * bridge/mac/FrameMac.mm: Updated autoscroll code to use renderers instead of layers, so any renderer that implements autoscroll will work.
+        (WebCore::FrameMac::FrameMac):
+        (WebCore::FrameMac::handleMousePressEvent):
+        (WebCore::FrameMac::handleMouseMoveEvent):
+        (WebCore::FrameMac::mouseDown):
+
+        * page/Frame.cpp:
+        (WebCore::Frame::handleMouseMoveEvent):
+        (WebCore::Frame::scrollOverflow): Don't scroll list box here- this would cause arrow keys to scroll instead of select.
+        (WebCore::Frame::handleAutoscroll): Updated to use a renderer instead of a layer when setting up autoscroll.
+        (WebCore::Frame::autoscrollTimerFired): ditto.
+        (WebCore::Frame::stopAutoscrollTimer): ditto.
+        (WebCore::Frame::passWidgetMouseDownEventToWidget): Updated to check for list box's scroll bar.
+        * page/Frame.h:
+        * page/FramePrivate.h: (WebCore::FramePrivate::FramePrivate): Updated to use renderer unstead of layer for autoscroll.
+
+        * page/FrameView.cpp: Keep track of current mouse position so this can be used for list box autoscroll.
+        (WebCore::FrameViewPrivate::reset):
+        (WebCore::FrameView::currentMousePosition):
+        (WebCore::FrameView::handleMousePressEvent):
+        (WebCore::FrameView::handleMouseDoubleClickEvent):
+        (WebCore::selectCursor):
+        (WebCore::FrameView::handleMouseMoveEvent):
+        (WebCore::FrameView::handleMouseReleaseEvent):
+        * page/FrameView.h:
+
+        * platform/ScrollBar.cpp: (WebCore::ScrollBar::ScrollBar): Added controlSize argument.  The list box will use a smaller scroll bar size.
+        * platform/ScrollBar.h:
+        (WebCore::):
+        (WebCore::ScrollBar::controlSize):
+        * platform/mac/PlatformScrollBar.h:
+        * platform/mac/PlatformScrollBarMac.mm:
+        (NSControlSizeForScrollBarControlSize):
+        (-[WebCoreScrollBar initWithPlatformScrollBar:]):
+        (WebCore::PlatformScrollBar::PlatformScrollBar):
+
+        * rendering/RenderBlock.h:
+        * rendering/RenderLayer.cpp: (WebCore::RenderLayer::createScrollbar): Updated to pass regular control size to scrollbar constructor.
+        * rendering/RenderLayer.h:
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::shouldAutoscroll):
+        (WebCore::RenderObject::autoscroll):
+        * rendering/RenderObject.h: (WebCore::RenderObject::isListBox):
+
+        * css/html4.css: Added properties for new list boxes.
+
+        * html/HTMLOptionElement.cpp:
+        (WebCore::HTMLOptionElement::setSelected): Doesn't allow selection to be changed here if the option is disabled.
+        (WebCore::HTMLOptionElement::disabled): Added. Checks the parent's disabled status.
+        * html/HTMLOptionElement.h: Added disabled method.
+
+        * html/HTMLSelectElement.cpp: Added appearance switch for new list box implementation.
+        (WebCore::HTMLSelectElement::recalcStyle):
+        (WebCore::HTMLSelectElement::lastSelectedListIndex):
+        (WebCore::HTMLSelectElement::deselectItems):
+        (WebCore::HTMLSelectElement::setSelectedIndex):
+        (WebCore::HTMLSelectElement::isKeyboardFocusable):
+        (WebCore::HTMLSelectElement::isMouseFocusable):
+        (WebCore::HTMLSelectElement::createRenderer):
+        (WebCore::HTMLSelectElement::recalcListItems):
+        (WebCore::HTMLSelectElement::setRecalcListItems):
+        (WebCore::HTMLSelectElement::reset):
+        (WebCore::HTMLSelectElement::notifyOptionSelected):
+        (WebCore::HTMLSelectElement::defaultEventHandler): Added code to select options for list box when clicking and using arrow keys.
+        (WebCore::HTMLSelectElement::nextSelectableListIndex):
+        (WebCore::HTMLSelectElement::previousSelectableListIndex):
+        * html/HTMLSelectElement.h:
+
+        * rendering/RenderTheme.cpp: Added support for ListBoxAppearance
+        (WebCore::RenderTheme::paint):
+        (WebCore::RenderTheme::paintBorderOnly):
+        (WebCore::RenderTheme::paintDecorations):
+        (WebCore::RenderTheme::activeListBoxSelectionBackgroundColor):
+        (WebCore::RenderTheme::activeListBoxSelectionForegroundColor):
+        (WebCore::RenderTheme::inactiveListBoxSelectionBackgroundColor):
+        (WebCore::RenderTheme::inactiveListBoxSelectionForegroundColor):
+        (WebCore::RenderTheme::isControlStyled):
+        (WebCore::RenderTheme::supportsFocusRing):
+        * rendering/RenderTheme.h:
+        * rendering/RenderThemeMac.mm: (WebCore::RenderThemeMac::isControlStyled):
+
+        * rendering/RenderListBox.cpp: Added.
+        (WebCore::RenderListBox::RenderListBox):
+        (WebCore::RenderListBox::~RenderListBox):
+        (WebCore::RenderListBox::setStyle):
+        (WebCore::RenderListBox::updateFromElement):
+        (WebCore::RenderListBox::calcMinMaxWidth):
+        (WebCore::RenderListBox::size):
+        (WebCore::RenderListBox::numItems):
+        (WebCore::RenderListBox::calcHeight):
+        (WebCore::RenderListBox::baselinePosition):
+        (WebCore::RenderListBox::itemBoundingBoxRect):
+        (WebCore::RenderListBox::paintObject):
+        (WebCore::RenderListBox::paintScrollbar):
+        (WebCore::RenderListBox::paintItemForeground):
+        (WebCore::RenderListBox::paintItemBackground):
+        (WebCore::RenderListBox::scrollBarTarget):
+        (WebCore::RenderListBox::isPointInScrollbar):
+        (WebCore::RenderListBox::optionAtPoint):
+        (WebCore::RenderListBox::autoscroll):
+        (WebCore::RenderListBox::scrollToRevealElementAtListIndex):
+        (WebCore::RenderListBox::scroll):
+        (WebCore::RenderListBox::valueChanged):
+        * rendering/RenderListBox.h: Added.
+        (WebCore::RenderListBox::isListBox):
+        (WebCore::RenderListBox::selectionChanged):
+        (WebCore::RenderListBox::setSelectionChanged):
+        (WebCore::RenderListBox::canHaveChildren):
+        (WebCore::RenderListBox::renderName):
+        (WebCore::RenderListBox::setOptionsChanged):
+        (WebCore::RenderListBox::shouldAutoscroll):
+        (WebCore::RenderListBox::listIndexIsVisible):
+
 2006-09-29  Beth Dakin  <bdakin@apple.com>
 
         Reviewed by Darin.
index 578c610bd8b968c171b92a291c3ce9fb8779b3ad..712bdb6001246e83e7c3eb5cf7db877dded0b401 100644 (file)
                AB4261D80A2F6C9700BDD17D /* missingImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = AB4261D70A2F6C9700BDD17D /* missingImage.tiff */; };
                AB67D1A8097F3AE300F9392E /* RenderTextControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB67D1A6097F3AE300F9392E /* RenderTextControl.cpp */; };
                AB67D1A9097F3AE300F9392E /* RenderTextControl.h in Headers */ = {isa = PBXBuildFile; fileRef = AB67D1A7097F3AE300F9392E /* RenderTextControl.h */; };
+               ABB5419E0ACDDFE4002820EB /* RenderListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */; };
+               ABB5419F0ACDDFE4002820EB /* RenderListBox.h in Headers */ = {isa = PBXBuildFile; fileRef = ABB5419D0ACDDFE4002820EB /* RenderListBox.h */; };
                ABDDFE790A5C6E7000A3E11D /* RenderMenuList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */; };
                ABDDFE7A0A5C6E7000A3E11D /* RenderMenuList.h in Headers */ = {isa = PBXBuildFile; fileRef = ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */; };
                ABDDFE7B0A5C6E7000A3E11D /* RenderPopupMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABDDFE750A5C6E7000A3E11D /* RenderPopupMenu.cpp */; };
                AB4261D70A2F6C9700BDD17D /* missingImage.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = missingImage.tiff; sourceTree = "<group>"; };
                AB67D1A6097F3AE300F9392E /* RenderTextControl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTextControl.cpp; sourceTree = "<group>"; };
                AB67D1A7097F3AE300F9392E /* RenderTextControl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderTextControl.h; sourceTree = "<group>"; };
+               ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderListBox.cpp; sourceTree = "<group>"; };
+               ABB5419D0ACDDFE4002820EB /* RenderListBox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderListBox.h; sourceTree = "<group>"; };
                ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMenuList.cpp; sourceTree = "<group>"; };
                ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderMenuList.h; sourceTree = "<group>"; };
                ABDDFE750A5C6E7000A3E11D /* RenderPopupMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderPopupMenu.cpp; sourceTree = "<group>"; };
                F523D2F302DE443B018635CA /* rendering */ = {
                        isa = PBXGroup;
                        children = (
+                               ABB5419C0ACDDFE4002820EB /* RenderListBox.cpp */,
+                               ABB5419D0ACDDFE4002820EB /* RenderListBox.h */,
                                A8CFF04B0A154F09000A4234 /* AutoTableLayout.cpp */,
                                A8CFF0490A154F09000A4234 /* AutoTableLayout.h */,
                                BCEA4813097D93020094C9E4 /* bidi.cpp */,
                                85989DD00ACC8BBD00A0BC51 /* DOMUIEventInternal.h in Headers */,
                                85989DD10ACC8BBD00A0BC51 /* DOMWheelEventInternal.h in Headers */,
                                4BBDBF7E0ACC9290005F6E97 /* CommandByName.h in Headers */,
+                               ABB5419F0ACDDFE4002820EB /* RenderListBox.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        mainGroup = 0867D691FE84028FC02AAC07 /* WebKit */;
                        productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
                        projectDirPath = "";
-                       projectRoot = "";
                        targets = (
                                93F198A508245E59001E9ABC /* WebCore */,
                                DD041FBE09D9DDBE0010AF2A /* Derived Sources */,
                                85D79ADB0ACA17EB00F02FC5 /* DOMSVGStringList.mm in Sources */,
                                859C9C400ACACCCC00791611 /* DOMSVGRectElement.mm in Sources */,
                                4BBDBF7D0ACC9290005F6E97 /* CommandByName.cpp in Sources */,
+                               ABB5419E0ACDDFE4002820EB /* RenderListBox.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index b675b9faa3eddb01686eafa579d814e83552a0c8..c73e36ee5a4d2cf739721a69571ba76862fa8fee 100644 (file)
@@ -351,6 +351,7 @@ private:
     bool _sendingEventToSubview;
     bool _mouseDownMayStartDrag;
     bool _mouseDownMayStartSelect;
+    bool _mouseDownMayStartAutoscroll;
     PlatformMouseEvent m_mouseDown;
     // in our view's coords
     IntPoint m_mouseDownPos;
index 6782bfad8fd2dc1af89981817b92130bd5cb2222..bc0d3d15f08eca780640b9693b848e213ed892d4 100644 (file)
@@ -153,6 +153,7 @@ FrameMac::FrameMac(Page* page, Element* ownerElement)
     , _sendingEventToSubview(false)
     , _mouseDownMayStartDrag(false)
     , _mouseDownMayStartSelect(false)
+    , _mouseDownMayStartAutoscroll(false)
     , _activationEventNumber(0)
     , _bindingRoot(0)
     , _windowScriptObject(0)
@@ -1380,6 +1381,8 @@ void FrameMac::handleMousePressEvent(const MouseEventWithHitTestResults& event)
     _mouseDownMayStartDrag = singleClick;
 
     d->m_mousePressNode = event.targetNode();
+
+    _mouseDownMayStartAutoscroll = d->m_mousePressNode && d->m_mousePressNode->renderer() && d->m_mousePressNode->renderer()->shouldAutoscroll();
     
     if (!passWidgetMouseDownEventToWidget(event, false)) {
         // We don't do this at the start of mouse down handling (before calling into WebCore),
@@ -1714,7 +1717,7 @@ void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
             // No more default handling (like selection), whether we're past the hysteresis bounds or not
             return;
         }
-        if (!_mouseDownMayStartSelect) {
+        if (!_mouseDownMayStartSelect && !_mouseDownMayStartAutoscroll) {
             return;
         }
 
@@ -1723,16 +1726,16 @@ void FrameMac::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
         d->m_view->invalidateClick();
 
         Node* node = event.targetNode();
-        RenderLayer* layer = 0;
-        if (node && node->renderer())
-            layer = node->renderer()->enclosingLayer();
+        RenderObject* renderer = 0;
+        if (node)
+            renderer = node->renderer();
             
         // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
         // Otherwise, let the bridge handle it so the view can scroll itself.
-        while (layer && !layer->shouldAutoscroll())
-            layer = layer->parent();
-        if (layer)
-            handleAutoscroll(layer);
+        while (renderer && !renderer->shouldAutoscroll())
+            renderer = renderer->parent();
+        if (renderer)
+            handleAutoscroll(renderer);
         else {
             if (!d->m_autoscrollTimer.isActive())
                 startAutoscrollTimer();
@@ -1965,6 +1968,7 @@ void FrameMac::mouseDown(NSEvent *event)
 
     _mouseDownMayStartDrag = false;
     _mouseDownMayStartSelect = false;
+    _mouseDownMayStartAutoscroll = false;
 
     v->handleMousePressEvent(event);
     
index ff00f025945585817599500f257f658eecaafb5f..e5a2fb5dafe9003e7fe1fc0ec1fb5d9b23a34cd2 100644 (file)
@@ -379,7 +379,7 @@ input[type="button"], input[type="submit"], input[type="reset"], input[type="fil
     box-sizing: border-box
 }
 
-input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled, input[type="file"]::-webkit-file-upload-button:disabled, button:disabled, select:disabled {
+input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled, input[type="file"]::-webkit-file-upload-button:disabled, button:disabled, select:disabled, optgroup:disabled, option:disabled {
     color: GrayText
 }
 
@@ -431,6 +431,14 @@ select[size][multiple] {
     color: initial;
     border: initial;
     background-color: initial;
+    /*
+    -webkit-appearance: listbox;
+    -webkit-box-align: start;
+    box-sizing: initial;
+    border: 1px inset gray;
+    -webkit-border-radius: initial;
+    white-space: initial;
+    */
 }
  
 select[size="0"],
@@ -521,7 +529,7 @@ html:focus, body:focus {
     outline: none
 }
   
-input:focus, textarea:focus, isindex:focus {
+input:focus, textarea:focus, isindex:focus, select:focus {
     outline-offset: -2px
 }
 
index 30f0ac38fcef107f7da348c5c64a3b06fe90ab59..f95794af938e3e843be947b2a3d495a153aa93c0 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Document.h"
 #include "ExceptionCode.h"
+#include "EventNames.h"
 #include "HTMLNames.h"
 #include "HTMLSelectElement.h"
 #include "RenderMenuList.h"
@@ -39,6 +40,7 @@
 namespace WebCore {
 
 using namespace HTMLNames;
+using namespace EventNames;
 
 HTMLOptionElement::HTMLOptionElement(Document* doc, HTMLFormElement* f)
     : HTMLGenericFormElement(optionTag, doc, f)
@@ -169,7 +171,7 @@ void HTMLOptionElement::setValue(const String& value)
 
 void HTMLOptionElement::setSelected(bool selected)
 {
-    if (m_selected == selected)
+    if (m_selected == selected || disabled())
         return;
     m_selected = selected;
     if (HTMLSelectElement* select = getSelect())
@@ -238,4 +240,9 @@ String HTMLOptionElement::optionText()
     return itemText;
 }
 
+bool HTMLOptionElement::disabled() const
+{ 
+    return HTMLGenericFormElement::disabled() || (parentNode() && static_cast<HTMLGenericFormElement*>(parentNode())->disabled()); 
+}
+
 } // namespace
index 50657522eb3c33c6280f317c29ed7a9b2ba2d06d..aee5951bc1c8304247672b3d2d22a26b4e751fc5 100644 (file)
@@ -79,6 +79,8 @@ public:
     void setLabel(const String&);
     
     String optionText();
+    
+    virtual bool disabled() const;
 
 private:
     String m_value;
index 60297998b631de7cfd7cd4428ae137decf2c3d9f..89375d14b9588692bc4e8a68de5f156c80d2ef5a 100644 (file)
 #include "Event.h"
 #include "EventNames.h"
 #include "FormDataList.h"
+#include "Frame.h"
 #include "HTMLFormElement.h"
 #include "HTMLNames.h"
 #include "HTMLOptionElement.h"
 #include "HTMLOptionsCollection.h"
 #include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "RenderListBox.h"
 #include "RenderMenuList.h"
 #include "RenderPopupMenu.h"
 #include "cssstyleselector.h"
 #include <wtf/Vector.h>
+#include <math.h>
 
 #if PLATFORM(MAC)
 #define ARROW_KEYS_POP_MENU 1
@@ -49,6 +53,8 @@
 #define ARROW_KEYS_POP_MENU 0
 #endif
 
+using namespace std;
+
 namespace WebCore {
 
 using namespace EventNames;
@@ -84,8 +90,10 @@ bool HTMLSelectElement::checkDTD(const Node* newChild)
 void HTMLSelectElement::recalcStyle( StyleChange ch )
 {
     if (hasChangedChild() && renderer()) {
-        if (shouldUseMenuList())
+        if (usesMenuList())
             static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
+        else if (renderer() && renderer()->style()->appearance() == ListboxAppearance)
+            static_cast<RenderListBox*>(renderer())->setOptionsChanged(true);
         else
             static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
     }
@@ -93,7 +101,6 @@ void HTMLSelectElement::recalcStyle( StyleChange ch )
     HTMLGenericFormElement::recalcStyle( ch );
 }
 
-
 const AtomicString& HTMLSelectElement::type() const
 {
     static const AtomicString selectMultiple("select-multiple");
@@ -104,34 +111,59 @@ const AtomicString& HTMLSelectElement::type() const
 int HTMLSelectElement::selectedIndex() const
 {
     // return the number of the first option selected
-    unsigned o = 0;
+    unsigned index = 0;
     const Vector<HTMLElement*>& items = listItems();
     for (unsigned int i = 0; i < items.size(); i++) {
         if (items[i]->hasLocalName(optionTag)) {
             if (static_cast<HTMLOptionElement*>(items[i])->selected())
-                return o;
-            o++;
+                return index;
+            index++;
         }
     }
     return -1;
 }
 
-void HTMLSelectElement::setSelectedIndex(int index, bool deselect)
+int HTMLSelectElement::lastSelectedListIndex() const
 {
-    // deselect all other options and select only the new one
+    // return the number of the last option selected
+    unsigned index = 0;
+    bool found = false;
     const Vector<HTMLElement*>& items = listItems();
-    int listIndex;
-    if (deselect) {
-        for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
-            if (items[listIndex]->hasLocalName(optionTag))
-                static_cast<HTMLOptionElement*>(items[listIndex])->setSelected(false);
+    for (unsigned int i = 0; i < items.size(); i++) {
+        if (items[i]->hasLocalName(optionTag)) {
+            if (static_cast<HTMLOptionElement*>(items[i])->selected()) {
+                index = i;
+                found = true;
+            }
         }
     }
-    listIndex = optionToListIndex(index);
-    if (listIndex >= 0)
-        static_cast<HTMLOptionElement*>(items[listIndex])->setSelected(true);
+    return found ? index : -1;
+}
 
-    setChanged(true);
+void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
+{
+    const Vector<HTMLElement*>& items = listItems();
+    unsigned i;
+    for (i = 0; i < items.size(); i++) {
+        if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) {
+            HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]);
+            element->m_selected = false;
+            element->setChanged();
+        }
+    }
+}
+
+void HTMLSelectElement::setSelectedIndex(int index, bool deselect)
+{
+    const Vector<HTMLElement*>& items = listItems();
+    int listIndex = optionToListIndex(index);
+    HTMLOptionElement* element = 0;
+    if (listIndex >= 0) {
+        element = static_cast<HTMLOptionElement*>(items[listIndex]);
+        element->setSelected(true);
+    }
+    if (deselect)
+        deselectItems(element);
 }
 
 int HTMLSelectElement::length() const
@@ -264,10 +296,10 @@ ContainerNode* HTMLSelectElement::addChild(PassRefPtr<Node> newChild)
 
 void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
 {
-    bool oldShouldUseMenuList = shouldUseMenuList();
+    bool oldUsesMenuList = usesMenuList();
     if (attr->name() == sizeAttr) {
         m_size = max(attr->value().toInt(), 1);
-        if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
+        if (oldUsesMenuList != usesMenuList() && attached()) {
             detach();
             attach();
         }
@@ -275,7 +307,7 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
         m_minwidth = max(attr->value().toInt(), 0);
     } else if (attr->name() == multipleAttr) {
         m_multiple = (!attr->isNull());
-        if (oldShouldUseMenuList != shouldUseMenuList() && attached()) {
+        if (oldUsesMenuList != usesMenuList() && attached()) {
             detach();
             attach();
         }
@@ -293,22 +325,24 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr)
 
 bool HTMLSelectElement::isKeyboardFocusable() const
 {
-    if (renderer() && shouldUseMenuList())
+    if (renderer() && (usesMenuList() || renderer()->style()->appearance() == ListboxAppearance))
         return isFocusable();
     return HTMLGenericFormElement::isKeyboardFocusable();
 }
 
 bool HTMLSelectElement::isMouseFocusable() const
 {
-    if (renderer() && shouldUseMenuList())
+    if (renderer() && (usesMenuList() || renderer()->style()->appearance() == ListboxAppearance))
         return isFocusable();
     return HTMLGenericFormElement::isMouseFocusable();
 }
 
 RenderObject *HTMLSelectElement::createRenderer(RenderArena *arena, RenderStyle *style)
 {
-    if (shouldUseMenuList())
+    if (usesMenuList())
         return new (arena) RenderMenuList(this);
+    if (style->appearance() == ListboxAppearance)
+        return new (arena) RenderListBox(this);
     return new (arena) DeprecatedRenderSelect(this);
 }
 
@@ -394,7 +428,7 @@ void HTMLSelectElement::recalcListItems() const
         }
         if (current->hasTagName(optionTag)) {
             m_listItems.append(static_cast<HTMLElement*>(current));
-            if (!foundSelected && !m_multiple && m_size <= 1) {
+            if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) {
                 foundSelected = static_cast<HTMLOptionElement*>(current);
                 foundSelected->m_selected = true;
             } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) {
@@ -426,8 +460,10 @@ void HTMLSelectElement::setRecalcListItems()
 {
     m_recalcListItems = true;
     if (renderer()) {
-        if (shouldUseMenuList())
+        if (usesMenuList())
             static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true);
+        else if (renderer() && renderer()->style()->appearance() == ListboxAppearance)
+            static_cast<RenderListBox*>(renderer())->setOptionsChanged(true);
         else
             static_cast<DeprecatedRenderSelect*>(renderer())->setOptionsChanged(true);
     }
@@ -454,29 +490,34 @@ void HTMLSelectElement::reset()
     }
     if (!optionSelected && firstOption)
         firstOption->setSelected(true);
-    if (renderer() && !shouldUseMenuList())
-        static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
     setChanged(true);
 }
 
 void HTMLSelectElement::notifyOptionSelected(HTMLOptionElement *selectedOption, bool selected)
-{
-    if (selected && !m_multiple) {
-        // deselect all other options
-        const Vector<HTMLElement*>& items = listItems();
-        unsigned i;
-        for (i = 0; i < items.size(); i++) {
-            if (items[i]->hasLocalName(optionTag))
-                static_cast<HTMLOptionElement*>(items[i])->m_selected = (items[i] == selectedOption);
-        }
-    }
-    if (renderer() && !shouldUseMenuList())
-        static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
+ {
+    if (selected && !m_multiple)
+        deselectItems(selectedOption);
 
+    if (renderer() && !usesMenuList()) {
+        if (renderer()->style()->appearance() == ListboxAppearance)
+            static_cast<RenderListBox*>(renderer())->setSelectionChanged(true);
+        else
+            static_cast<DeprecatedRenderSelect*>(renderer())->setSelectionChanged(true);
+    }
     setChanged(true);
 }
 
-void HTMLSelectElement::defaultEventHandler(Event *evt)
+void HTMLSelectElement::defaultEventHandler(Event* evt)
+{
+    if (usesMenuList())
+        menuListDefaultEventHandler(evt);
+    else if (renderer() && renderer()->isListBox() && renderer()->style()->appearance() == ListboxAppearance) 
+        listBoxDefaultEventHandler(evt);
+    HTMLGenericFormElement::defaultEventHandler(evt);
+}
+
+void HTMLSelectElement::menuListDefaultEventHandler(Event* evt)
 {
     RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer());
 
@@ -495,7 +536,7 @@ void HTMLSelectElement::defaultEventHandler(Event *evt)
                 form()->submitClick();
             handled = true;
         }
-        if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && shouldUseMenuList()) {
+        if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && usesMenuList()) {
             focus();
             menuList->showPopup();
             handled = true;
@@ -516,16 +557,94 @@ void HTMLSelectElement::defaultEventHandler(Event *evt)
             evt->setDefaultHandled();
 
     }
-    if (evt->type() == mousedownEvent && renderer() && shouldUseMenuList()) {
-        focus();
+    if (evt->type() == mousedownEvent) {
+         focus();
         if (menuList->popupIsVisible())
             menuList->hidePopup();
         else
             menuList->showPopup();
         evt->setDefaultHandled();
     }
+}
 
-    HTMLGenericFormElement::defaultEventHandler(evt);
+void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
+{
+    if (evt->type() == mousedownEvent) {
+        MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
+        if (HTMLOptionElement* element = static_cast<RenderListBox*>(renderer())->optionAtPoint(mEvt->x(), mEvt->y())) {
+            bool deselectOtherOptions = true;
+            bool shouldSelect = true;
+            
+            bool multiSelectKeyPressed = false;
+#if PLATFORM(MAC)
+            multiSelectKeyPressed = mEvt->metaKey();
+#else
+            multiSelectKeyPressed = mEvt->ctrlKey();
+#endif
+            if (multiple() && multiSelectKeyPressed)
+                deselectOtherOptions = false;
+            if (element->selected() && multiSelectKeyPressed)
+                shouldSelect = false;
+            
+            int optionIndex = element->index();
+            if (!shouldSelect) {
+                optionIndex = -1;
+                element->m_selected = false;
+            }
+            setSelectedIndex(optionIndex, deselectOtherOptions);
+        }
+    }
+    
+    if (evt->type() == keypressEvent) {
+        if (!evt->isKeyboardEvent())
+            return;
+        String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
+        
+        int index;
+        const Vector<HTMLElement*>& items = listItems();
+
+        if (keyIdentifier == "Down") {
+            index = nextSelectableListIndex(lastSelectedListIndex());
+            
+        } else if (keyIdentifier == "Up") {
+            index = previousSelectableListIndex(optionToListIndex(selectedIndex()));
+        }
+        if (keyIdentifier == "Down" || keyIdentifier == "Up") {
+            ASSERT(index >= 0 && (unsigned)index < items.size()); 
+            HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[index]);
+            
+            setSelectedIndex(element->index(), !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey());
+            static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(index);
+            
+            evt->setDefaultHandled();
+            setChanged();
+            renderer()->repaint();
+        }
+    }
+}
+
+int HTMLSelectElement::nextSelectableListIndex(int startIndex)
+{
+    const Vector<HTMLElement*>& items = listItems();
+    int index = startIndex + 1;
+    while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled()))
+        index++;
+    if ((unsigned) index == items.size())
+        return startIndex;
+    return index;
+}
+
+int HTMLSelectElement::previousSelectableListIndex(int startIndex)
+{
+    const Vector<HTMLElement*>& items = listItems();
+    if (startIndex == -1)
+        startIndex = items.size();
+    int index = startIndex - 1;
+    while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled()))
+        index--;
+    if (index == -1)
+        return startIndex;
+    return index;
 }
 
 void HTMLSelectElement::accessKeyAction(bool sendToAnyElement)
index 375ba11660393cff74d00be54e5e80ed6458f0ec..c7e782912a904452f0ed7f44179c7bd339a06f62 100644 (file)
@@ -55,8 +55,9 @@ public:
     virtual void recalcStyle(StyleChange);
 
     int selectedIndex() const;
-    void setSelectedIndex(int index, bool = true);
-
+    void setSelectedIndex(int index, bool deselect = true);
+    void notifyOptionSelected(HTMLOptionElement* selectedOption, bool selected);
+    
     virtual bool isEnumeratable() const { return true; }
 
     int length() const;
@@ -105,7 +106,6 @@ public:
         return m_listItems;
     }
     virtual void reset();
-    void notifyOptionSelected(HTMLOptionElement* selectedOption, bool selected);
 
     virtual void defaultEventHandler(Event*);
     virtual void accessKeyAction(bool sendToAnyElement);
@@ -120,10 +120,16 @@ public:
     virtual Node* namedItem(const String& name, bool caseSensitive = true);
 
     HTMLCollection::CollectionInfo* collectionInfo() { return &m_collectionInfo; }
-
+    
 private:
     void recalcListItems() const;
-    bool shouldUseMenuList() const { return !m_multiple && m_size <= 1; }
+    void deselectItems(HTMLOptionElement* excludeElement);
+    bool usesMenuList() const { return !m_multiple && m_size <= 1; }
+    int lastSelectedListIndex() const;
+    int nextSelectableListIndex(int startIndex);
+    int previousSelectableListIndex(int startIndex);
+    void menuListDefaultEventHandler(Event*);
+    void listBoxDefaultEventHandler(Event*);
 
     mutable Vector<HTMLElement*> m_listItems;
     int m_minwidth;
index 4ab09fc1129f16efdbec33044a8e1d2eb33b09eb..10bcb6bd99d874605ebe0061b13ed3cf59e1cd41 100644 (file)
@@ -64,6 +64,7 @@
 #include "PlugInInfoStore.h"
 #include "Plugin.h"
 #include "PluginDocument.h"
+#include "RenderListBox.h"
 #include "RenderPart.h"
 #include "RenderTextControl.h"
 #include "RenderTheme.h"
@@ -1954,6 +1955,7 @@ void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
         return;
 
     // handle making selection
+
     IntPoint vPoint = view()->convertFromContainingWindow(event.event().pos());
     VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
 
@@ -2841,7 +2843,7 @@ bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granular
     
     if (node != 0) {
         RenderObject *r = node->renderer();
-        if (r != 0) {
+        if (r != 0 && !r->isListBox()) {
             return r->scroll(direction, granularity);
         }
     }
@@ -2849,11 +2851,11 @@ bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granular
     return false;
 }
 
-void Frame::handleAutoscroll(RenderLayer* layer)
+void Frame::handleAutoscroll(RenderObject* renderer)
 {
     if (d->m_autoscrollTimer.isActive())
         return;
-    d->m_autoscrollLayer = layer;
+    d->m_autoscrollRenderer = renderer;
     startAutoscrollTimer();
 }
 
@@ -2863,8 +2865,8 @@ void Frame::autoscrollTimerFired(Timer<Frame>*)
         stopAutoscrollTimer();
         return;
     }
-    if (d->m_autoscrollLayer) {
-        d->m_autoscrollLayer->autoscroll();
+    if (d->m_autoscrollRenderer) {
+        d->m_autoscrollRenderer->autoscroll();
     } 
 }
 
@@ -2929,7 +2931,7 @@ void Frame::startAutoscrollTimer()
 
 void Frame::stopAutoscrollTimer()
 {
-    d->m_autoscrollLayer = 0;
+    d->m_autoscrollRenderer = 0;
     d->m_autoscrollTimer.stop();
 }
 
@@ -3260,7 +3262,12 @@ bool Frame::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&
     if (!target)
         return false;
     
-    Widget* widget = RenderLayer::gScrollBar;
+    Widget* widget;
+    if (target->isListBox())
+        widget = static_cast<RenderListBox*>(target)->scrollBarTarget();
+    else
+        widget = RenderLayer::gScrollBar;
+
     if (!widget) {
         if (!target->isWidget())
             return false;
index 5f39b520424c4a8333df7df11815606b5284d97b..12e716b017e8144d9bd10c42f099d6d184f99f99 100644 (file)
@@ -760,7 +760,7 @@ protected:
     virtual void cleanupPluginObjects() { }
     void cancelAndClear();
     
-    void handleAutoscroll(RenderLayer*);
+    void handleAutoscroll(RenderObject*);
     void startAutoscrollTimer();
     void stopAutoscrollTimer();
 
index 219fd2b215c9f47c10c67e1eb1c500483511bdaa..d9c2ebf674b290b4ece340714b49427b0f852c73 100644 (file)
@@ -102,7 +102,7 @@ namespace WebCore {
             , m_userStyleSheetLoader(0)
             , m_iconLoader(0)
             , m_autoscrollTimer(thisFrame, &Frame::autoscrollTimerFired)
-            , m_autoscrollLayer(0)
+            , m_autoscrollRenderer(0)
             , m_paintRestriction(PaintRestrictionNone)
             , m_markedTextUsesUnderlines(false)
             , m_highlightTextMatches(false)
@@ -223,7 +223,7 @@ namespace WebCore {
         IconLoader* m_iconLoader;
         
         Timer<Frame> m_autoscrollTimer;
-        RenderLayer* m_autoscrollLayer;
+        RenderObject* m_autoscrollRenderer;
         
         RefPtr<Node> m_elementToDraw;
         PaintRestriction m_paintRestriction;
index 45e9510d420604a418978f30181e3f38af2b279b..9de0cafb14521430f1384d07fa99bf6ed172ca97 100644 (file)
@@ -125,6 +125,7 @@ public:
             repaintRects->clear();
         resizingFrameSet = 0;
         m_resizeLayer = 0;
+        m_currentMousePosition = IntPoint();
     }
 
     RefPtr<Node> underMouse;
@@ -183,6 +184,8 @@ public:
     bool horizontalOverflow;
     bool m_verticalOverflow;    
     RenderObject* m_viewportRenderer;
+    
+    IntPoint m_currentMousePosition;
 };
 
 FrameView::FrameView(Frame *frame)
@@ -564,6 +567,11 @@ static Frame* subframeForEvent(const MouseEventWithHitTestResults& mev)
     return static_cast<FrameView*>(widget)->frame();
 }
 
+IntPoint FrameView::currentMousePosition() const
+{
+    return d->m_currentMousePosition;
+}
+
 void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
 {
     if (!m_frame->document())
@@ -572,7 +580,8 @@ void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
     RefPtr<FrameView> protector(this);
 
     d->mousePressed = true;
-
+    d->m_currentMousePosition = convertFromContainingWindow(mouseEvent.pos());
+    
     MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
 
     if (m_frame->passSubframeEventToSubframe(mev)) {
@@ -623,6 +632,7 @@ void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent
 
     // We get this instead of a second mouse-up 
     d->mousePressed = false;
+    d->m_currentMousePosition = convertFromContainingWindow(mouseEvent.pos());
 
     MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
 
@@ -755,7 +765,8 @@ void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
         return;
 
     RefPtr<FrameView> protector(this);
-    
+    d->m_currentMousePosition = convertFromContainingWindow(mouseEvent.pos());
+   
     if (d->hoverTimer.isActive())
         d->hoverTimer.stop();
 
@@ -814,6 +825,7 @@ void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
     RefPtr<FrameView> protector(this);
 
     d->mousePressed = false;
+    d->m_currentMousePosition = convertFromContainingWindow(mouseEvent.pos());
 
     if (d->resizingFrameSet) {
         dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
index 29a4178c887a624979164f9b6c68e9492c6f7437..08cff47fed929f01aaff4200dec71bed4ec19411 100644 (file)
@@ -53,6 +53,7 @@ class HTMLFrameSetElement;
 class HTMLGenericFormElement;
 class HTMLTitleElement;
 class InlineBox;
+class IntPoint;
 class IntRect;
 class PlatformKeyboardEvent;
 class FrameMac;
@@ -183,10 +184,12 @@ public:
 
     void scheduleEvent(PassRefPtr<Event>, PassRefPtr<EventTargetNode>, bool tempEvent);
 
+    IntPoint currentMousePosition() const;
+
     void ref() { ++m_refCount; }
     void deref() { if (!--m_refCount) delete this; }
     bool hasOneRef() { return m_refCount == 1; }
-    
+
 private:
     void cleared();
     void scrollBarMoved();
index 6a5d51af3501d31c5dfd61f02c2c8fcf5d8589fd..f24dcc828258c02c40d13e5d801ff8d918119fd2 100644 (file)
 
 namespace WebCore {
 
-ScrollBar::ScrollBar(ScrollBarClient* client, ScrollBarOrientation orientation)
+ScrollBar::ScrollBar(ScrollBarClient* client, ScrollBarOrientation orientation, ScrollBarControlSize controlSize)
     : m_client(client)
     , m_orientation(orientation)
+    , m_controlSize(controlSize)
     , m_visibleSize(0)
     , m_totalSize(0)
     , m_currentPos(0)
index fc042c273505bb58659513742e58fa1b652eda07..851fbf99f3ff8fe1bd19b3e1b76dbc1c88463dcb 100644 (file)
@@ -55,6 +55,8 @@ enum ScrollGranularity {
 
 enum ScrollBarOrientation { HorizontalScrollBar, VerticalScrollBar };
 
+enum ScrollBarControlSize { RegularScrollBar, SmallScrollBar, MiniScrollBar };
+
 class ScrollBarClient {
 public:
     virtual ~ScrollBarClient() {}
@@ -63,7 +65,7 @@ public:
 
 class ScrollBar : public Shared<ScrollBar> {
 protected:
-    ScrollBar(ScrollBarClient*, ScrollBarOrientation);
+    ScrollBar(ScrollBarClient*, ScrollBarOrientation, ScrollBarControlSize);
 
 public:
     virtual ~ScrollBar() {}
@@ -72,6 +74,8 @@ public:
 
     ScrollBarOrientation orientation() const { return m_orientation; }
     int value() const { return m_currentPos; } 
+    
+    ScrollBarControlSize controlSize() const { return m_controlSize; }
 
     void setSteps(int lineStep, int pageStep);
     
@@ -107,6 +111,7 @@ protected:
 
     ScrollBarClient* m_client;
     ScrollBarOrientation m_orientation;
+    ScrollBarControlSize m_controlSize;
     int m_visibleSize;
     int m_totalSize;
     int m_currentPos;
index 43ac05ba70b63aee353befd470e26a5bc87f1bf2..1f5975612ffe3204e1f0c65b6d98f11ec5554b37 100644 (file)
@@ -40,7 +40,7 @@ namespace WebCore {
 
 class PlatformScrollBar : public Widget, public ScrollBar {
 public:
-    PlatformScrollBar(ScrollBarClient*, ScrollBarOrientation);
+    PlatformScrollBar(ScrollBarClient*, ScrollBarOrientation, ScrollBarControlSize);
     virtual ~PlatformScrollBar();
 
     virtual bool isWidget() const { return true; }
index 5d969dfe1fd8ad3ca431cd21754227eeb0ba2f83..17a8e964bc11fd167b01d6acd58d6c37845110fe 100644 (file)
@@ -44,6 +44,15 @@ using namespace WebCore;
 
 @implementation WebCoreScrollBar
 
+static NSControlSize NSControlSizeForScrollBarControlSize(ScrollBarControlSize size)
+{
+    if (size == SmallScrollBar)
+        return NSSmallControlSize;
+    if (size == MiniScrollBar)
+        return NSMiniControlSize;
+    return NSRegularControlSize;
+}
+
 - (id)initWithPlatformScrollBar:(PlatformScrollBar*)s
 {
     // Cocoa scrollbars just set their orientation by examining their own
@@ -64,6 +73,7 @@ using namespace WebCore;
     [self setEnabled:YES];
     [self setTarget:self];
     [self setAction:@selector(scroll:)];
+    [self setControlSize:NSControlSizeForScrollBarControlSize(s->controlSize())];
 
     return self;
 }
@@ -97,8 +107,8 @@ using namespace WebCore;
 namespace WebCore
 {
 
-PlatformScrollBar::PlatformScrollBar(ScrollBarClient* client, ScrollBarOrientation orientation)
-    : ScrollBar(client, orientation)
+PlatformScrollBar::PlatformScrollBar(ScrollBarClient* client, ScrollBarOrientation orientation, ScrollBarControlSize controlSize)
+    : ScrollBar(client, orientation, controlSize)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
index 5ccb35875e159676a30cd4a4e444b2723a600123..ee8bd13f030abc46cf48e64665cab298a2bc9425 100644 (file)
@@ -201,7 +201,7 @@ public:
     virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
                              HitTestAction hitTestAction);
 
-    bool isPointInScrollbar(int x, int y, int tx, int ty);
+    virtual bool isPointInScrollbar(int x, int y, int tx, int ty);
 
     virtual VisiblePosition positionForCoordinates(int x, int y);
     
index cf5e5b63dbe2710d0b18510080ac43e55e0f30f6..ea2b2847fbeb7938155faefac59a3cb139d80ac7 100644 (file)
@@ -792,13 +792,6 @@ void RenderLayer::autoscroll()
     scrollToOffset(xOffset + diffX, yOffset + diffY);
 }
 
-bool RenderLayer::shouldAutoscroll()
-{
-    if (renderer()->hasOverflowClip() && (m_object->scrollsOverflow() || renderer()->node()->isContentEditable()))
-        return true;
-    return false;
-}
-
 void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& offsetFromResizeCorner)
 {
     if (!inResizeMode() || !renderer()->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE)
@@ -897,7 +890,7 @@ void RenderLayer::valueChanged(ScrollBar*)
 ScrollBar* RenderLayer::createScrollbar(ScrollBarOrientation orientation)
 {
     if (ScrollBar::hasPlatformScrollBars()) {
-        PlatformScrollBar* widget = new PlatformScrollBar(this, orientation);
+        PlatformScrollBar* widget = new PlatformScrollBar(this, orientation, RegularScrollBar);
         widget->ref();
         m_object->element()->document()->view()->addChild(widget);
         return widget;
index 16a4b2e49d7246aa1e4ece227872c4731f1be424..cd7189ef5c0d98f2047bc7b9e5fb44262f9b7654 100644 (file)
@@ -251,7 +251,6 @@ public:
     void updateScrollInfoAfterLayout();
     bool scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier=1.0);
     void autoscroll();
-    bool shouldAutoscroll();
     IntRect resizeControlRect() { return m_resizeControlRect; }
     void setResizeControlRect(const IntRect& r) { m_resizeControlRect = r; }
     void resize(const PlatformMouseEvent&, const IntSize&);
diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp
new file mode 100644 (file)
index 0000000..c3a357e
--- /dev/null
@@ -0,0 +1,434 @@
+/**
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderListBox.h"
+
+#include "Document.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLSelectElement.h"
+#include "PlatformScrollBar.h" 
+#include "RenderBR.h"
+#include "RenderListBoxItem.h"
+#include "RenderText.h"
+#include "RenderTheme.h"
+#include "TextStyle.h"
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace EventNames;
+const int optionsSpacingMiddle = 1;
+const int optionsSpacingLeft = 2;
+
+RenderListBox::RenderListBox(HTMLSelectElement* element)
+    : RenderBlock(element)
+    , m_optionsChanged(true)
+    , m_optionsWidth(0)
+    , m_indexOffset(0)
+    , m_selectionChanged(true)
+    , m_scrollBarHit(false)
+    , m_vBar(0)
+{
+}
+
+RenderListBox::~RenderListBox()
+{
+    if (m_vBar && m_vBar->isWidget()) {
+        element()->document()->view()->removeChild(static_cast<PlatformScrollBar*>(m_vBar));
+        m_vBar->deref();
+        delete m_vBar;
+    }
+}
+
+
+void RenderListBox::setStyle(RenderStyle* style)
+{
+    RenderBlock::setStyle(style);
+    setReplaced(isInline());
+}
+
+void RenderListBox::updateFromElement()
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& listItems = select->listItems();
+    int size = listItems.size();
+    if (m_optionsChanged) {  
+        float width = 0;
+        TextStyle textStyle(0, 0, 0, false, false, false, false);
+        for (int i = 0; i < size; ++i) {
+            HTMLElement* element = listItems[i];
+            String text;
+            Font itemFont = style()->font();
+            if (element->hasTagName(optionTag))
+                text = static_cast<HTMLOptionElement*>(element)->optionText();
+            else if (element->hasTagName(optgroupTag)) {
+                text = static_cast<HTMLOptGroupElement*>(element)->groupLabelText();
+                FontDescription d = itemFont.fontDescription();
+                d.setBold(true);
+                itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+                itemFont.update();
+            }
+                
+            if (!text.isEmpty()) {
+                float textWidth = itemFont.floatWidth(TextRun(text.impl()), textStyle);
+                width = max(width, textWidth);
+            }
+        }
+        m_optionsWidth = static_cast<int>(ceilf(width));
+        m_optionsChanged = false;
+    }
+}
+
+void RenderListBox::calcMinMaxWidth()
+{
+    if (!m_vBar) {
+        if (ScrollBar::hasPlatformScrollBars()) {
+            PlatformScrollBar* widget = new PlatformScrollBar(this, VerticalScrollBar, SmallScrollBar);
+            widget->ref();
+            node()->document()->view()->addChild(widget);
+            m_vBar = widget;
+        }
+    }
+    if (m_optionsChanged)
+        updateFromElement();
+
+    m_minWidth = 0;
+    m_maxWidth = 0;
+
+    if (style()->width().isFixed() && style()->width().value() > 0)
+        m_minWidth = m_maxWidth = calcContentBoxWidth(style()->width().value());
+    else {
+        m_maxWidth = m_optionsWidth;
+        if (m_vBar)
+           m_maxWidth += m_vBar->width();
+    }
+
+    if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+        m_maxWidth = max(m_maxWidth, calcContentBoxWidth(style()->minWidth().value()));
+        m_minWidth = max(m_minWidth, calcContentBoxWidth(style()->minWidth().value()));
+    } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+        m_minWidth = 0;
+    else
+        m_minWidth = m_maxWidth;
+
+    if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+        m_maxWidth = min(m_maxWidth, calcContentBoxWidth(style()->maxWidth().value()));
+        m_minWidth = min(m_minWidth, calcContentBoxWidth(style()->maxWidth().value()));
+    }
+
+    int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+    m_minWidth += toAdd;
+    m_maxWidth += toAdd;
+                                
+    setMinMaxKnown();
+}
+
+const int minSize = 4;
+const int minDefaultSize = 10;
+int RenderListBox::size() const
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    int specifiedSize = select->size();
+    if (specifiedSize > 1)
+        return max(minSize, specifiedSize);
+
+    return min(max(numItems(), minSize), minDefaultSize);
+}
+
+int RenderListBox::numItems() const
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    return select->listItems().size();
+}
+
+void RenderListBox::calcHeight()
+{
+    int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom();
+
+    int itemHeight = style()->font().height() + optionsSpacingMiddle;
+    m_height = itemHeight * size() + toAdd;
+    
+    RenderBlock::calcHeight();
+    
+    if (m_vBar) {
+        m_vBar->setEnabled(size() < numItems());
+        m_vBar->setSteps(itemHeight, itemHeight);
+        m_vBar->setProportion(m_height - toAdd, itemHeight * numItems());
+    }
+}
+
+const int baselineAdjustment = 7;
+short RenderListBox::baselinePosition(bool b, bool isRootLineBox) const
+{
+    // FIXME: This hardcoded baselineAdjustment is what we used to do for the old widget, but I'm not sure this is right for the new control.
+    return height() + marginTop() + marginBottom() - baselineAdjustment;
+}
+
+IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index)
+{
+    return IntRect (tx + borderLeft() + paddingLeft(),
+                   ty + borderTop() + paddingTop() + ((style()->font().height() + optionsSpacingMiddle) * (index - m_indexOffset)),
+                   absoluteBoundingBoxRect().width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(),
+                   style()->font().height() + optionsSpacingMiddle);
+}
+    
+void RenderListBox::paintObject(PaintInfo& i, int tx, int ty)
+{
+    // Push a clip.
+    IntRect clipRect(tx + borderLeft(), ty + borderTop(),
+         width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop());
+    if (i.phase == PaintPhaseForeground || i.phase == PaintPhaseChildBlockBackgrounds) {
+        if (clipRect.width() == 0 || clipRect.height() == 0)
+            return;
+        i.p->save();
+        i.p->addClip(clipRect);
+    }
+    
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    int listItemsSize = select->listItems().size();
+
+    if (i.phase == PaintPhaseForeground) {
+        int index = m_indexOffset;
+        while (index < listItemsSize && index < m_indexOffset + size()) {
+            paintItemForeground(i, tx, ty, index);
+            index++;
+        }
+    }
+    
+    // Paint the children.
+    RenderBlock::paintObject(i, tx, ty);
+    
+    if (i.phase == PaintPhaseBlockBackground) {
+        int index = m_indexOffset;
+        while (index < listItemsSize && index < m_indexOffset + size()) {
+            paintItemBackground(i, tx, ty, index);
+            index++;
+        }
+        paintScrollbar(i);
+    }
+    // Pop the clip.
+    if (i.phase == PaintPhaseForeground || i.phase == PaintPhaseChildBlockBackgrounds)
+        i.p->restore();
+}
+
+void RenderListBox::paintScrollbar(PaintInfo& i)
+{
+    if (m_vBar) {
+        IntRect absBounds = absoluteBoundingBoxRect();
+        IntRect scrollRect(absBounds.right() - borderRight() - m_vBar->width(),
+                absBounds.y() + borderTop(),
+                m_vBar->width(),
+                absBounds.height() - (borderTop() + borderBottom()));
+        m_vBar->setRect(scrollRect);
+        m_vBar->paint(i.p, scrollRect);
+    }
+}
+
+void RenderListBox::paintItemForeground(PaintInfo& i, int tx, int ty, int listIndex)
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& listItems = select->listItems();
+    HTMLElement* element = listItems[listIndex];
+            
+    String itemText;
+    if (element->hasTagName(optionTag))
+        itemText = static_cast<HTMLOptionElement*>(element)->optionText();
+    else if (element->hasTagName(optgroupTag))
+        itemText = static_cast<HTMLOptGroupElement*>(element)->groupLabelText();
+   
+    TextRun textRun(itemText.characters(), itemText.length());
+    
+    // Determine where the item text should be placed
+    IntRect r = itemBoundingBoxRect(tx, ty, listIndex);
+    r.move(optionsSpacingLeft, style()->font().ascent());
+
+    RenderStyle* itemStyle = element->renderStyle();
+    if (!itemStyle)
+        itemStyle = style();
+    
+    Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color();
+    if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) {
+        if (document()->frame()->isActive() && document()->focusNode() == node())
+            textColor = theme()->activeListBoxSelectionForegroundColor();
+ /*
+    FIXME: Decide what the desired behavior is for inactive foreground color.  
+    For example, disabled items have a dark grey foreground color defined in CSS.  
+    If we don't honor that, the selected disabled items will have a weird black-on-grey look.
+        else
+            textColor = theme()->inactiveListBoxSelectionForegroundColor();
+ */
+          
+    }
+        
+    i.p->setPen(textColor);
+    
+    Font itemFont = style()->font();
+    if (element->hasTagName(optgroupTag)) {
+        FontDescription d = itemFont.fontDescription();
+        d.setBold(true);
+        itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+        itemFont.update();
+    }
+    i.p->setFont(itemFont);
+    
+    // Draw the item text
+    if (itemStyle->visibility() != HIDDEN)
+        i.p->drawText(textRun, r.location());
+}
+
+void RenderListBox::paintItemBackground(PaintInfo& i, int tx, int ty, int listIndex)
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& listItems = select->listItems();
+    HTMLElement* element = listItems[listIndex];
+
+    Color backColor;
+    if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) {
+        if (document()->frame()->isActive() && document()->focusNode() == node())
+            backColor = theme()->activeListBoxSelectionBackgroundColor();
+        else
+            backColor = theme()->inactiveListBoxSelectionBackgroundColor();
+    } else
+        backColor = element->renderStyle() ? element->renderStyle()->backgroundColor() : style()->backgroundColor();
+
+    // Draw the background for this list box item
+    if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN)
+        i.p->fillRect(itemBoundingBoxRect(tx, ty, listIndex), backColor);
+}
+
+PlatformScrollBar* RenderListBox::scrollBarTarget()
+{
+    return m_scrollBarHit ? static_cast<PlatformScrollBar*>(m_vBar) : 0; 
+}
+
+bool RenderListBox::isPointInScrollbar(int _x, int _y, int _tx, int _ty)
+{
+    if (!m_vBar)
+        return false;
+
+    IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(),
+                   _ty + borderTop() - borderTopExtra(),
+                   m_vBar->width(),
+                   height() + borderTopExtra() + borderBottomExtra() - borderTop() - borderBottom());
+
+    m_scrollBarHit = vertRect.contains(_x, _y);
+    return m_scrollBarHit;
+}
+
+HTMLOptionElement* RenderListBox::optionAtPoint(int x, int y)
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& listItems = select->listItems();
+    int yOffset = y - absoluteBoundingBoxRect().y();
+    int newOffset = max(0, yOffset / (style()->font().height() + optionsSpacingMiddle)) + m_indexOffset;
+    newOffset = max(0, min((int)listItems.size() - 1, newOffset));
+    int scrollBarWidth = m_vBar ? m_vBar->width() : 0;
+    if (x >= absoluteBoundingBoxRect().x() + borderLeft() + paddingLeft() && x < absoluteBoundingBoxRect().right() - borderRight() - paddingRight() - scrollBarWidth)
+        return static_cast<HTMLOptionElement*>(listItems[newOffset]);
+    return 0;
+}
+
+void RenderListBox::autoscroll()
+{
+    int mouseX = document()->frame()->view()->currentMousePosition().x();
+    int mouseY = document()->frame()->view()->currentMousePosition().y();
+    IntRect bounds = absoluteBoundingBoxRect();
+
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& items = select->listItems();
+    HTMLOptionElement* element = 0;
+    int rows = size();
+    int offset = m_indexOffset;
+    if (mouseY < bounds.y() && scrollToRevealElementAtListIndex(offset - 1) && items[offset - 1]->hasTagName(optionTag))
+        element = static_cast<HTMLOptionElement*>(items[offset - 1]);
+    else if (mouseY > bounds.bottom() && scrollToRevealElementAtListIndex(offset + rows) && items[offset + rows - 1]->hasTagName(optionTag))
+        element = static_cast<HTMLOptionElement*>(items[offset + rows - 1]);
+    else
+        element = optionAtPoint(mouseX, mouseY);
+        
+    if (element) {
+        select->setSelectedIndex(element->index(), !select->multiple());
+        repaint();
+    }
+}
+
+bool RenderListBox::scrollToRevealElementAtListIndex(int index)
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    const Vector<HTMLElement*>& listItems = select->listItems();
+    
+    if (index < 0 || index > (int)listItems.size() - 1 || (index >= m_indexOffset && index < m_indexOffset + size()))
+        return false;
+
+    int newOffset;
+    if (index < m_indexOffset)
+        newOffset = index;
+    else
+        newOffset = index - size() + 1;
+
+    if (m_vBar) {
+        IntRect rect = absoluteBoundingBoxRect();
+        m_vBar->setValue(itemBoundingBoxRect(rect.x(), rect.y(), newOffset + m_indexOffset).y() - rect.y());
+    }
+    m_indexOffset = newOffset;
+    
+    return true;
+}
+
+bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+    return m_vBar && m_vBar->scroll(direction, granularity, multiplier);
+}
+
+void RenderListBox::valueChanged(unsigned listIndex)
+{
+    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+    select->setSelectedIndex(select->listToOptionIndex(listIndex));
+    select->onChange();
+}
+
+void RenderListBox::valueChanged(ScrollBar*)
+{
+    if (m_vBar) {
+        int newOffset = max(0, m_vBar->value() / (style()->font().height() + optionsSpacingMiddle));
+        if (newOffset != m_indexOffset) {
+            m_indexOffset = newOffset;
+        //    printf("value changed: new offset index: %d\n", newOffset);
+            repaint();
+            // Fire the scroll DOM event.
+            EventTargetNodeCast(node())->dispatchHTMLEvent(scrollEvent, true, false);
+        }
+    }
+}
+
+}
diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h
new file mode 100644 (file)
index 0000000..f454a36
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006 Apple Computer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef RenderListBox_H
+#define RenderListBox_H
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class HTMLSelectElement;
+class HTMLOptionElement;
+
+class RenderListBox : public RenderBlock, public ScrollBarClient {
+public:
+    RenderListBox(HTMLSelectElement*);
+    ~RenderListBox();
+
+    virtual bool isListBox() const { return true; }
+
+    virtual void setStyle(RenderStyle*);
+    virtual void updateFromElement();
+    void setSelectionChanged(bool selectionChanged) { m_selectionChanged = selectionChanged; }
+
+    virtual bool canHaveChildren() const { return false; }
+    virtual const char* renderName() const { return "RenderListBox"; }
+    virtual void paintObject(PaintInfo&, int tx, int ty);
+    virtual bool isPointInScrollbar(int x, int y, int tx, int ty);
+
+    virtual bool scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier=1.0);
+
+    virtual void calcMinMaxWidth();
+    virtual short baselinePosition(bool, bool isRootLineBox) const;
+    virtual void calcHeight();
+    void setOptionsChanged(bool c) { m_optionsChanged = c; }
+    void valueChanged(unsigned listIndex);
+    virtual void valueChanged(ScrollBar*);
+    
+    HTMLOptionElement* optionAtPoint(int x, int y);
+    
+    PlatformScrollBar* scrollBarTarget();
+    
+    bool scrollToRevealElementAtListIndex(int index);
+    
+    virtual bool shouldAutoscroll() const { return numItems() > size(); }
+    virtual void autoscroll();
+
+private:
+    bool m_optionsChanged;
+    int m_optionsWidth;
+    int m_optionsMaxHeight;
+    int m_optionsTotalHeight;
+    int m_indexOffset;
+    bool m_selectionChanged;
+    bool m_scrollBarHit;
+    
+    int size() const;
+    int numItems() const;
+    IntRect itemBoundingBoxRect(int tx, int ty, int index);
+    void paintScrollbar(PaintInfo&);
+    void paintItemForeground(PaintInfo&, int tx, int ty, int listIndex);
+    void paintItemBackground(PaintInfo&, int tx, int ty, int listIndex);
+    
+    ScrollBar* m_vBar;
+};
+
+}
+
+#endif
index e4bd2b6801ead2ebca6b5eec1f433d0295e1fbc1..e3735afc9988f2e65befcafd331971883fcd4bfa 100644 (file)
@@ -669,6 +669,17 @@ bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granulari
     return false;
 }
 
+bool RenderObject::shouldAutoscroll() const
+{
+    return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable())));
+}
+
+void RenderObject::autoscroll()
+{
+    if (RenderLayer* l = layer())
+        l->autoscroll();
+}
+
 bool RenderObject::hasStaticX() const
 {
     return (style()->left().isAuto() && style()->right().isAuto()) ||
index 44443bc1fc15953dc60048c2e60da4b8a47091c0..a14aa21fb107524dd7addc01b29508222eed5124 100644 (file)
@@ -271,6 +271,7 @@ public:
     virtual bool isFrameSet() const { return false; }
     virtual bool isApplet() const { return false; }
     virtual bool isMenuList() const { return false; }
+    virtual bool isListBox() const { return false; }
     
 #ifdef SVG_SUPPORT
     virtual bool isKCanvasContainer() const { return false; }
@@ -621,6 +622,8 @@ public:
     virtual void setScrollTop(int);
 
     virtual bool scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier=1.0);
+    virtual bool shouldAutoscroll() const;
+    virtual void autoscroll();
 
     // The following seven functions are used to implement collapsing margins.
     // All objects know their maximal positive and negative margins.  The
index 9d084915e66a42d73fbe0f3230d155e362f58802..655f46d4293e5aa5f9d43eb943482fd94a033583 100644 (file)
@@ -106,6 +106,7 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& i, const
         case MenulistButtonAppearance:
         case TextFieldAppearance:
         case TextAreaAppearance:
+        case ListboxAppearance:
             return true;
         default:
             break;
@@ -123,6 +124,7 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo
     switch (o->style()->appearance()) {
         case TextFieldAppearance:
             return paintTextField(o, i, r);
+        case ListboxAppearance:
         case TextAreaAppearance:
             return paintTextArea(o, i, r);
         case MenulistButtonAppearance:
@@ -151,6 +153,7 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf
             return paintMenuListButton(o, i, r);
         case TextFieldAppearance:
         case TextAreaAppearance:
+        case ListboxAppearance:
         case CheckboxAppearance:
         case RadioAppearance:
         case PushButtonAppearance:
@@ -202,6 +205,26 @@ Color RenderTheme::platformInactiveSelectionForegroundColor() const
     return Color();
 }
 
+Color RenderTheme::activeListBoxSelectionBackgroundColor() const
+{
+    return Color(56, 117, 215);
+}
+
+Color RenderTheme::activeListBoxSelectionForegroundColor() const
+{
+    return Color(255, 255, 255);
+}
+
+Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
+{
+    return Color(212, 212, 212);
+}
+
+Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
+{
+    return Color(0, 0, 0);
+}
+
 short RenderTheme::baselinePosition(const RenderObject* o) const
 {
     return o->height() + o->marginTop();
@@ -221,6 +244,7 @@ bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& bo
         case PushButtonAppearance:
         case SquareButtonAppearance:
         case ButtonAppearance:
+        case ListboxAppearance:
         case MenulistAppearance:
         case TextFieldAppearance:
         case TextAreaAppearance: {
@@ -238,7 +262,7 @@ bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& bo
 
 bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
 {
-    return (style->hasAppearance() && style->appearance() != TextFieldAppearance && style->appearance() != TextAreaAppearance && style->appearance() != MenulistButtonAppearance);
+    return (style->hasAppearance() && style->appearance() != TextFieldAppearance && style->appearance() != TextAreaAppearance && style->appearance() != MenulistButtonAppearance && style->appearance() != ListboxAppearance);
 }
 
 bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
index 92a8b70b8a9e2a3b33e6cdf7cba5484ebd78e7b9..17c1d3a4ca5d576e48c11826a4be800936ba72be 100644 (file)
@@ -102,6 +102,13 @@ public:
     virtual Color platformInactiveSelectionBackgroundColor() const;
     virtual Color platformActiveSelectionForegroundColor() const;
     virtual Color platformInactiveSelectionForegroundColor() const;
+    
+    // List Box selection color
+    virtual Color activeListBoxSelectionBackgroundColor() const;
+    virtual Color activeListBoxSelectionForegroundColor() const;
+    virtual Color inactiveListBoxSelectionBackgroundColor() const;
+    virtual Color inactiveListBoxSelectionForegroundColor() const;
+
 
     // System fonts.
     virtual void systemFont(int propId, FontDescription&) const = 0;
index f0f661fd0b3d5eef9d482005fe755d68abe09932..03e3662176c69cc75e00a8c9e02994770124dde0 100644 (file)
@@ -142,7 +142,7 @@ void RenderThemeMac::systemFont(int propId, FontDescription& fontDescription) co
 bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border, 
                                      const BackgroundLayer& background, const Color& backgroundColor) const
 {
-    if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance)
+    if (style->appearance() == TextFieldAppearance || style->appearance() == TextAreaAppearance || style->appearance() == ListboxAppearance)
         return style->border() != border;
     return RenderTheme::isControlStyled(style, border, background, backgroundColor);
 }