OSDN Git Service

Fix for <select> elements.
authorLeon Scroggins <scroggo@google.com>
Mon, 6 Dec 2010 21:24:29 +0000 (16:24 -0500)
committerLeon Scroggins <scroggo@google.com>
Tue, 7 Dec 2010 15:53:11 +0000 (10:53 -0500)
Bug:3230016

Allow webkit to handle the click on a <select> element if
it is a RenderMenuList.

Implement PopupMenu class, using PopupMenuClient to
interact with the <select> element.

Change-Id: I9611c23304fc2fc3eb01ecbd7a46fa02cd52df9a

WebCore/Android.mk
WebCore/platform/android/PopupMenuAndroid.cpp
WebCore/platform/android/PopupMenuAndroid.h
WebCore/platform/android/SearchPopupMenuAndroid.h
WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
WebKit/android/jni/WebViewCore.cpp
WebKit/android/jni/WebViewCore.h

index 85ac7ee..fda5318 100644 (file)
@@ -542,6 +542,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        platform/android/LocalizedStringsAndroid.cpp \
        platform/android/PlatformTouchEventAndroid.cpp \
        platform/android/PlatformTouchPointAndroid.cpp \
+       platform/android/PopupMenuAndroid.cpp \
        platform/android/RenderThemeAndroid.cpp \
        platform/android/PackageNotifier.cpp \
        platform/android/ScreenAndroid.cpp \
index 8a1ed07..3e36ea4 100644 (file)
  */
 
 #include "config.h"
-#include "PopupMenu.h"
+#include "PopupMenuAndroid.h"
+
+#include "PopupMenuClient.h"
+#include "SkTDArray.h"
+#include "WebViewCore.h"
+
+class PopupReply : public android::WebCoreReply {
+public:
+    PopupReply(const IntRect& rect, android::WebViewCore* view, PopupMenuClient* client)
+        : m_rect(rect)
+        , m_viewImpl(view)
+        , m_popupClient(client)
+    {}
+
+    virtual ~PopupReply() {}
+
+    virtual void replyInt(int value) {
+        if (m_popupClient) {
+            m_popupClient->popupDidHide();
+            m_popupClient->valueChanged(value, true);
+        }
+        if (m_viewImpl)
+            m_viewImpl->contentInvalidate(m_rect);
+    }
+
+    virtual void replyIntArray(const int* array, int count) {
+        // Should never be called.
+    }
+private:
+    IntRect m_rect;
+    // Not needed if we handle ChromeClientAndroid::formStateDidChange
+    android::WebViewCore* m_viewImpl;
+    PopupMenuClient* m_popupClient;
+};
 
 namespace WebCore {
 
-// Now we handle all of this in WebViewCore.cpp.
-PopupMenu::PopupMenu(PopupMenuClient* menuList)
+PopupMenuAndroid::PopupMenuAndroid(PopupMenuClient* menuList)
     : m_popupClient(menuList)
 {
 }
 
-PopupMenu::~PopupMenu()
-{
-}
-
-void PopupMenu::show(const IntRect&, FrameView*, int)
+// Copied from WebViewCore.cpp.  Once we move ListBox handling to this class,
+// we can remove the one in WebViewCore.cpp.
+// Convert a WTF::String into an array of characters where the first
+// character represents the length, for easy conversion to java.
+static uint16_t* stringConverter(const WTF::String& text)
 {
+    size_t length = text.length();
+    uint16_t* itemName = new uint16_t[length+1];
+    itemName[0] = (uint16_t)length;
+    uint16_t* firstChar = &(itemName[1]);
+    memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
+    return itemName;
 }
 
-void PopupMenu::hide()
+void PopupMenuAndroid::show(const IntRect& rect, FrameView* frameView, int)
 {
-}
+    android::WebViewCore* viewImpl = android::WebViewCore::getWebViewCore(frameView);
+    android::WebCoreReply* reply = new PopupReply(rect, viewImpl, m_popupClient);
 
-void PopupMenu::updateFromElement() 
-{
-}
+    SkTDArray<const uint16_t*> names;
+    // Possible values for enabledArray.  Keep in Sync with values in
+    // InvokeListBox.Container in WebView.java
+    enum OptionStatus {
+        OPTGROUP = -1,
+        OPTION_DISABLED = 0,
+        OPTION_ENABLED = 1,
+    };
+    SkTDArray<int> enabledArray;
+    SkTDArray<int> selectedArray;
+    int size = m_popupClient->listSize();
+    // If we use this for ListBoxes in addition to MenuLists, we will need to
+    // account for 'multiple'
+    bool multiple = false;
+    for (int i = 0; i < size; i++) {
+        *names.append() = stringConverter(m_popupClient->itemText(i));
+        if (m_popupClient->itemIsSeparator(i)) {
+            *enabledArray.append() = OPTION_DISABLED;
+        } else if (m_popupClient->itemIsLabel(i)) {
+            *enabledArray.append() = OPTGROUP;
+        } else {
+            // Must be an Option
+            *enabledArray.append() = m_popupClient->itemIsEnabled(i)
+                    ? OPTION_ENABLED : OPTION_DISABLED;
+            if (multiple && m_popupClient->itemIsSelected(i))
+                *selectedArray.append() = i;
+        }
+    }
 
-bool PopupMenu::itemWritingDirectionIsNatural()
-{
-    return false;
+    viewImpl->listBoxRequest(reply,
+                             names.begin(),
+                             size,
+                             enabledArray.begin(),
+                             enabledArray.count(),
+                             multiple,
+                             selectedArray.begin(),
+                             multiple ? selectedArray.count() : m_popupClient->selectedIndex());
 }
 
 } // namespace WebCore
index 07b1da0..a0a2452 100644 (file)
 namespace WebCore {
 
 class FrameView;
+class PopupMenuClient;
 
 class PopupMenuAndroid : public PopupMenu {
 public:
-    virtual void show(const IntRect&, FrameView*, int) { }
+    PopupMenuAndroid(PopupMenuClient* client);
+    virtual void show(const IntRect&, FrameView*, int);
     virtual void hide() { }
     virtual void updateFromElement() { }
     virtual void disconnectClient() { }
+private:
+    PopupMenuClient* m_popupClient;
 };
 
 }
index 599a2ac..4a7dedb 100644 (file)
 #ifndef SearchPopupMenuAndroid_h
 #define SearchPopupMenuAndroid_h
 
-#include "PopupMenuAndroid.h"
 #include "SearchPopupMenu.h"
 
 namespace WebCore {
 
-class PopupMenuClient;
+class IntRect;
+class PopupMenu;
 class FrameView;
 
+class DummyPopup : public PopupMenu {
+ public:
+     virtual ~DummyPopup() {}
+     virtual void show(const IntRect&, FrameView*, int index) { }
+     virtual void hide() { }
+     virtual void updateFromElement() { }
+     virtual void disconnectClient() { }
+};
+
 class SearchPopupMenuAndroid : public SearchPopupMenu {
 public:
-    SearchPopupMenuAndroid() : m_popup(adoptRef(new PopupMenuAndroid)) { }
+    SearchPopupMenuAndroid() : m_popup(adoptRef(new DummyPopup)) { }
     virtual PopupMenu* popupMenu() { return m_popup.get(); }
     virtual void saveRecentSearches(const AtomicString&, const Vector<String>&) { }
     virtual void loadRecentSearches(const AtomicString&, Vector<String>&) { }
     virtual bool enabled() { return false; }
 
 private:
-    RefPtr<PopupMenuAndroid> m_popup;
+    RefPtr<PopupMenu> m_popup;
 };
 
 }
index 80a90fe..20ad5b9 100644 (file)
@@ -531,9 +531,9 @@ bool ChromeClientAndroid::selectItemWritingDirectionIsNatural()
     return false;
 }
 
-PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient*) const
+PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const
 {
-    return adoptRef(new PopupMenuAndroid);
+    return adoptRef(new PopupMenuAndroid(client));
 }
 
 PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const
index 6b1ca44..228c16b 100644 (file)
@@ -2490,26 +2490,11 @@ public:
         , m_viewImpl(view)
     {}
 
-    // Response used if the listbox only allows single selection.
-    // index is listIndex of the selected item, or -1 if nothing is selected.
+    // Response used for a multiple selection listbox if the user did not change
+    // anything, in which case -2 is used.
     virtual void replyInt(int index)
     {
-        if (-2 == index) {
-            // Special value for cancel. Do nothing.
-            return;
-        }
-        // If the select element no longer exists, due to a page change, etc,
-        // silently return.
-        if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
-                m_frame, m_select))
-            return;
-        // Use a pointer to HTMLSelectElement's superclass, where
-        // listToOptionIndex is public.
-        SelectElement* selectElement = m_select;
-        int optionIndex = selectElement->listToOptionIndex(index);
-        m_select->setSelectedIndex(optionIndex, true);
-        m_select->dispatchFormControlChangeEvent();
-        m_viewImpl->contentInvalidate(m_select->getRect());
+        LOG_ASSERT(-2 == index, "ListBoxReply::replyInt should only be called with -2");
     }
 
     // Response if the listbox allows multiple selection.  array stores the listIndices
@@ -2522,9 +2507,6 @@ public:
                 m_frame, m_select))
             return;
 
-        // If count is 1 or 0, use replyInt.
-        SkASSERT(count > 1);
-
         const WTF::Vector<Element*>& items = m_select->listItems();
         int totalItems = static_cast<int>(items.size());
         // Keep track of the position of the value we are comparing against.
@@ -2872,7 +2854,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node
         }
 
         WebCore::RenderObject* renderer = nodePtr->renderer();
-        if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
+        if (renderer && renderer->isListBox()) {
             WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
             const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
             SkTDArray<const uint16_t*> names;
@@ -2907,7 +2889,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node
             listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
                     multiple, selectedArray.begin(), multiple ? selectedArray.count() :
                     selectElement->optionToListIndex(select->selectedIndex()));
-            DBG_NAV_LOG("menu list");
+            DBG_NAV_LOG("list box");
             return true;
         }
     }
index 4278261..41dc2e0 100644 (file)
@@ -514,6 +514,10 @@ namespace android {
 
         DeviceMotionAndOrientationManager* deviceMotionAndOrientationManager() { return &m_deviceMotionAndOrientationManager; }
 
+        void listBoxRequest(WebCoreReply* reply, const uint16_t** labels,
+                size_t count, const int enabled[], size_t enabledCount,
+                bool multiple, const int selected[], size_t selectedCountOrSelection);
+
         // these members are shared with webview.cpp
         static Mutex gFrameCacheMutex;
         CachedRoot* m_frameCacheKit; // nav data being built by webcore
@@ -552,10 +556,6 @@ namespace android {
         void updateButtonList(WTF::Vector<Container>* buttons);
         void reset(bool fromConstructor);
 
-        void listBoxRequest(WebCoreReply* reply, const uint16_t** labels,
-                size_t count, const int enabled[], size_t enabledCount,
-                bool multiple, const int selected[], size_t selectedCountOrSelection);
-
         friend class ListBoxReply;
         struct JavaGlue;
         struct JavaGlue*       m_javaGlue;