2009-04-07 Paul Godavari <paul@chromium.org>
authordglazkov@chromium.org <dglazkov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2009 21:42:31 +0000 (21:42 +0000)
committerdglazkov@chromium.org <dglazkov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2009 21:42:31 +0000 (21:42 +0000)
        Reviewed by Darin Fisher.

        https://bugs.webkit.org/show_bug.cgi?id=24692
        Enable PopupMenuChromium to handle HTML select popups using native
        cocoa controls on the Mac, all other platforms are unchanged.

        We also split out the storage container for the popup menu items
        so that ChromeClientChromium can access them for forwarding to
        the embedding host (Chromium.app or test_shell).

        * page/chromium/ChromeClientChromium.h:
        * platform/chromium/PopupMenuChromium.cpp:
        (WebCore::PopupListBox::items):
        (WebCore::PopupContainer::PopupContainer):
        (WebCore::PopupContainer::~PopupContainer):
        (WebCore::PopupContainer::showPopup):
        (WebCore::PopupContainer::showExternal):
        (WebCore::PopupContainer::menuItemHeight):
        (WebCore::popupData):
        (WebCore::PopupListBox::pointToRowIndex):
        (WebCore::PopupListBox::getRowBounds):
        (WebCore::PopupListBox::isSelectableItem):
        (WebCore::PopupListBox::updateFromElement):
        (WebCore::PopupListBox::layout):
        (WebCore::PopupListBox::clear):
        (WebCore::PopupMenu::show):
        * platform/chromium/PopupMenuChromium.h:
        (WebCore::PopupItem::):
        (WebCore::PopupItem::PopupItem):

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

WebCore/ChangeLog
WebCore/page/chromium/ChromeClientChromium.h
WebCore/platform/chromium/PopupMenuChromium.cpp
WebCore/platform/chromium/PopupMenuChromium.h

index edadcd4..a1ccae1 100644 (file)
@@ -1,3 +1,35 @@
+2009-04-07  Paul Godavari  <paul@chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24692
+        Enable PopupMenuChromium to handle HTML select popups using native
+        cocoa controls on the Mac, all other platforms are unchanged.
+
+        We also split out the storage container for the popup menu items
+        so that ChromeClientChromium can access them for forwarding to
+        the embedding host (Chromium.app or test_shell).
+
+        * page/chromium/ChromeClientChromium.h:
+        * platform/chromium/PopupMenuChromium.cpp:
+        (WebCore::PopupListBox::items):
+        (WebCore::PopupContainer::PopupContainer):
+        (WebCore::PopupContainer::~PopupContainer):
+        (WebCore::PopupContainer::showPopup):
+        (WebCore::PopupContainer::showExternal):
+        (WebCore::PopupContainer::menuItemHeight):
+        (WebCore::popupData):
+        (WebCore::PopupListBox::pointToRowIndex):
+        (WebCore::PopupListBox::getRowBounds):
+        (WebCore::PopupListBox::isSelectableItem):
+        (WebCore::PopupListBox::updateFromElement):
+        (WebCore::PopupListBox::layout):
+        (WebCore::PopupListBox::clear):
+        (WebCore::PopupMenu::show):
+        * platform/chromium/PopupMenuChromium.h:
+        (WebCore::PopupItem::):
+        (WebCore::PopupItem::PopupItem):
+
 2009-04-07  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Oliver Hunt.
index 5821dff..f6689d3 100644 (file)
@@ -35,8 +35,8 @@
 #include <wtf/Forward.h>
 
 namespace WebCore {
-    class FramelessScrollView;
     class IntRect;
+    class PopupContainer;
 
     // Contains Chromium-specific extensions to the ChromeClient.  Only put
     // things here that don't make sense for other ports.
@@ -44,7 +44,10 @@ namespace WebCore {
     public:
         // Notifies the client of a new popup widget.  The client should place
         // and size the widget with the given bounds, relative to the screen.
-        virtual void popupOpened(FramelessScrollView* popupView, const IntRect& bounds, bool focusOnShow) = 0;
+        // If handleExternal is true, then drawing and input handling for the
+        // popup will be handled by the external embedder.
+        virtual void popupOpened(PopupContainer* popupContainer, const IntRect& bounds,
+                                 bool focusOnShow, bool handleExternal) = 0;
     };
 
 } // namespace WebCore
index 53f565a..bc41a6f 100644 (file)
@@ -136,26 +136,19 @@ public:
     // Returns whether the popup wants to process events for the passed key.
     bool isInterestedInEventForKey(int keyCode);
 
+    // Gets the height of a row.
+    int getRowHeight(int index);
+
+    // Returns true if the selection can be changed to index.
+    // Disabled items, or labels cannot be selected.
+    bool isSelectableItem(int index);
+
+    const Vector<PopupItem*>& items() const { return m_items; }
+
 private:
     friend class PopupContainer;
     friend class RefCounted<PopupListBox>;
 
-    // A type of List Item
-    enum ListItemType {
-        TypeOption,
-        TypeGroup,
-        TypeSeparator
-    };
-
-    // A item (represented by <option> or <optgroup>) in the <select> widget. 
-    struct ListItem {
-        ListItem(const String& label, ListItemType type)
-            : label(label.copy()), type(type), y(0) {}
-        String label;
-        ListItemType type;
-        int y;  // y offset of this item, relative to the top of the popup.
-    };
-
     PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings)
         : m_settings(settings)
         , m_originalIndex(0)
@@ -184,10 +177,6 @@ private:
     // the web page, and closes the popup.
     void acceptIndex(int index);
 
-    // Returns true if the selection can be changed to index.
-    // Disabled items, or labels cannot be selected.
-    bool isSelectableItem(int index);
-
     // Clears the selection (so no row appears selected).
     void clearSelection();
 
@@ -198,8 +187,6 @@ private:
     // Invalidates the row at the given index. 
     void invalidateRow(int index);
 
-    // Gets the height of a row.
-    int getRowHeight(int index);
     // Get the bounds of a row. 
     IntRect getRowBounds(int index);
 
@@ -250,7 +237,7 @@ private:
     int m_baseWidth;
 
     // A list of the options contained within the <select>
-    Vector<ListItem*> m_items;
+    Vector<PopupItem*> m_items;
 
     // The <select> PopupMenuClient that opened us.
     PopupMenuClient* m_popupClient;
@@ -310,7 +297,8 @@ PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client,
     return adoptRef(new PopupContainer(client, settings));
 }
 
-PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSettings& settings)
+PopupContainer::PopupContainer(PopupMenuClient* client,
+                               const PopupContainerSettings& settings)
     : m_listBox(PopupListBox::create(client, settings))
     , m_settings(settings)
 {
@@ -319,7 +307,7 @@ PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSett
 
 PopupContainer::~PopupContainer()
 {
-    if (m_listBox)
+    if (m_listBox && m_listBox->parent())
         removeChild(m_listBox.get());
 }
 
@@ -342,7 +330,7 @@ void PopupContainer::showPopup(FrameView* view)
         if (widgetRect.bottom() > static_cast<int>(screen.bottom()))
             widgetRect.move(0, -(widgetRect.height() + selectHeight));
 
-        chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow);
+        chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow, false);
     }
 
     if (!m_listBox->parent())
@@ -357,6 +345,19 @@ void PopupContainer::showPopup(FrameView* view)
     invalidate();
 }
 
+void PopupContainer::showExternal(const IntRect& rect, FrameView* v, int index)
+{
+     if (!listBox())
+        return;
+
+     listBox()->updateFromElement();
+
+     // Get the ChromeClient and pass it the popup menu's listbox data.
+     ChromeClientChromium* client = static_cast<ChromeClientChromium*>(
+          v->frame()->page()->chrome()->client());
+     client->popupOpened(this, rect, true, true);
+}
+
 void PopupContainer::hidePopup()
 {
     if (client())
@@ -485,6 +486,16 @@ int PopupContainer::selectedIndex() const
     return m_listBox->selectedIndex();
 }
 
+int PopupContainer::menuItemHeight() const
+{
+    return m_listBox->getRowHeight(0);
+}
+
+const WTF::Vector<PopupItem*>& PopupContainer:: popupData() const
+{
+    return m_listBox->items();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // PopupListBox implementation
 
@@ -828,7 +839,7 @@ int PopupListBox::pointToRowIndex(const IntPoint& point)
 
     // FIXME: binary search if perf matters.
     for (int i = 0; i < numItems(); ++i) {
-        if (y < m_items[i]->y)
+        if (y < m_items[i]->yOffset)
             return i-1;
     }
 
@@ -890,7 +901,7 @@ IntRect PopupListBox::getRowBounds(int index)
     if (index < 0)
         return IntRect(0, 0, visibleWidth(), getRowHeight(index));
 
-    return IntRect(0, m_items[index]->y, visibleWidth(), getRowHeight(index));
+    return IntRect(0, m_items[index]->yOffset, visibleWidth(), getRowHeight(index));
 }
 
 void PopupListBox::invalidateRow(int index)
@@ -921,7 +932,7 @@ void PopupListBox::scrollToRevealRow(int index)
 
 bool PopupListBox::isSelectableItem(int index)
 {
-    return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(index);
+    return m_items[index]->type == PopupItem::TypeOption && m_popupClient->itemIsEnabled(index);
 }
 
 void PopupListBox::clearSelection()
@@ -1010,14 +1021,15 @@ void PopupListBox::updateFromElement()
 
     int size = m_popupClient->listSize();
     for (int i = 0; i < size; ++i) {
-        ListItemType type;
+        PopupItem::Type type;
         if (m_popupClient->itemIsSeparator(i))
-            type = PopupListBox::TypeSeparator;
+            type = PopupItem::TypeSeparator;
         else if (m_popupClient->itemIsLabel(i))
-            type = PopupListBox::TypeGroup;
+            type = PopupItem::TypeGroup;
         else
-            type = PopupListBox::TypeOption;
-        m_items.append(new ListItem(m_popupClient->itemText(i), type));
+            type = PopupItem::TypeOption;
+        m_items.append(new PopupItem(m_popupClient->itemText(i), type));
+        m_items[i]->enabled = isSelectableItem(i);
     }
 
     m_selectedIndex = m_popupClient->selectedIndex();
@@ -1036,7 +1048,7 @@ void PopupListBox::layout()
         Font itemFont = getRowFont(i);
 
         // Place the item vertically.
-        m_items[i]->y = y;
+        m_items[i]->yOffset = y;
         y += itemFont.height();
 
         // Ensure the popup is wide enough to fit this item.
@@ -1088,7 +1100,7 @@ void PopupListBox::layout()
 
 void PopupListBox::clear()
 {
-    for (Vector<ListItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it)
+    for (Vector<PopupItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it)
         delete *it;
     m_items.clear();
 }
@@ -1115,11 +1127,19 @@ PopupMenu::~PopupMenu()
     hide();
 }
 
-void PopupMenu::show(const IntRect& r, FrameView* v, int index) 
+// The Mac Chromium implementation relies on external control (a Cocoa control)
+// to display, handle the input tracking and menu item selection for the popup.
+// Windows and Linux Chromium let our WebKit port handle the display, while
+// another process manages the popup window and input handling.
+void PopupMenu::show(const IntRect& r, FrameView* v, int index)
 {
     if (!p.popup)
         p.popup = PopupContainer::create(client(), dropDownSettings);
+#if PLATFORM(DARWIN)
+    p.popup->showExternal(r, v, index);
+#else
     p.popup->show(r, v, index);
+#endif
 }
 
 void PopupMenu::hide()
index cd13c22..23003b1 100644 (file)
@@ -42,6 +42,23 @@ namespace WebCore {
     class FrameView;
     class PopupListBox;
 
+    // A container for the data for each menu item (e.g. represented by <option>
+    // or <optgroup> in a <select> widget) and is used by PopupListBox.
+    struct PopupItem {
+        enum Type {
+            TypeOption,
+            TypeGroup,
+            TypeSeparator
+        };
+
+        PopupItem(const String& label, Type type)
+            : label(label), type(type), yOffset(0) { }
+        String label;
+        Type type;
+        int yOffset;  // y offset of this item, relative to the top of the popup.
+        bool enabled;
+    };
+
     // FIXME: Our FramelessScrollView classes should probably implement HostWindow!
 
     // The PopupContainer class holds a PopupListBox (see cpp file).  Its sole purpose is to be
@@ -94,9 +111,14 @@ namespace WebCore {
         // Show the popup
         void showPopup(FrameView*);
 
+        // Used on Mac Chromium for HTML select popup menus.
+        void showExternal(const IntRect&, FrameView*, int index);
+
         // Show the popup in the specified rect for the specified frame.
         // Note: this code was somehow arbitrarily factored-out of the Popup class
-        // so WebViewImpl can create a PopupContainer.
+        // so WebViewImpl can create a PopupContainer. This method is used for
+        // displaying auto complete popup menus on Mac Chromium, and for all
+        // popups on other platforms.
         void show(const IntRect&, FrameView*, int index);
 
         // Hide the popup.  Do not call this directly: use client->hidePopup().
@@ -114,6 +136,12 @@ namespace WebCore {
         // Refresh the popup values from the PopupMenuClient.
         void refresh();
 
+        // The menu per-item data.
+        const WTF::Vector<PopupItem*>& popupData() const;
+
+        // The height of a row in the menu.
+        int menuItemHeight() const;
+
     private:
         friend class WTF::RefCounted<PopupContainer>;