Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2120)

Unified Diff: Source/web/PopupMenuImpl.cpp

Issue 736883002: Implement <select> Popup Menu using PagePopup (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/web/PopupMenuImpl.cpp
diff --git a/Source/web/PopupMenuImpl.cpp b/Source/web/PopupMenuImpl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce156448d93bedf10e06d278aae648e8dab8359e
--- /dev/null
+++ b/Source/web/PopupMenuImpl.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
tkent 2014/12/15 09:26:04 I don't think this file is a copy of something. P
keishi 2014/12/16 03:53:24 Done.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "web/PopupMenuImpl.h"
+
+#include "core/HTMLNames.h"
+#include "core/css/CSSFontSelector.h"
+#include "core/dom/StyleEngine.h"
+#include "core/frame/FrameView.h"
+#include "core/html/HTMLHRElement.h"
+#include "core/html/HTMLOptGroupElement.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/page/PagePopup.h"
+#include "platform/geometry/IntRect.h"
+#include "public/platform/Platform.h"
+#include "public/web/WebColorChooser.h"
+#include "web/ChromeClientImpl.h"
+#include "web/WebViewImpl.h"
+
+namespace blink {
+
+class PopupMenuCSSFontSelector : public CSSFontSelector {
+public:
+ static PassRefPtr<PopupMenuCSSFontSelector> create(Document* document, CSSFontSelector* ownerFontSelector)
tkent 2014/12/15 09:26:04 PassRefPtrWillBeRawPtr
keishi 2014/12/16 03:53:24 Done.
+ {
+ return adoptRefWillBeNoop(new PopupMenuCSSFontSelector(document, ownerFontSelector));
+ }
+
+ // We don't override willUseFontData() for now because the old PopupListBox
+ // only worked with fonts loaded when opening the popup.
+ virtual PassRefPtr<FontData> getFontData(const FontDescription&, const AtomicString&) override;
+
+private:
+ PopupMenuCSSFontSelector(Document* document, CSSFontSelector* ownerFontSelector)
+ : CSSFontSelector(document)
+ , m_ownerFontSelector(ownerFontSelector) { }
+ RefPtrWillBeMember<CSSFontSelector> m_ownerFontSelector;
+};
+
+PassRefPtr<FontData> PopupMenuCSSFontSelector::getFontData(const FontDescription& description, const AtomicString& name)
+{
+ return m_ownerFontSelector->getFontData(description, name);
+}
+
+PassRefPtrWillBeRawPtr<PopupMenuImpl> PopupMenuImpl::create(ChromeClientImpl* chromeClient, PopupMenuClient* client)
+{
+ return adoptRefWillBeNoop(new PopupMenuImpl(chromeClient, client));
+}
+
+PopupMenuImpl::PopupMenuImpl(ChromeClientImpl* chromeClient, PopupMenuClient* client)
+ : m_chromeClient(chromeClient)
+ , m_client(client)
+ , m_popup(0)
tkent 2014/12/15 09:26:04 0 -> nullptr
keishi 2014/12/16 03:53:24 Done.
+{
+}
+
+PopupMenuImpl::~PopupMenuImpl()
+{
+ closePopup();
+}
+
+IntSize PopupMenuImpl::contentSize()
+{
+ return IntSize(0, 0);
tkent 2014/12/15 09:26:04 IntSize(0, 0) -> IntSize()
keishi 2014/12/16 03:53:24 Done.
+}
+
+void PopupMenuImpl::writeDocument(SharedBuffer* data)
+{
+ IntRect anchorRectInScreen = m_chromeClient->rootViewToScreen(m_client->elementRectRelativeToRootView());
+
+ PagePopupClient::addString("<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
+ data->append(Platform::current()->loadResource("pickerCommon.css"));
+ data->append(Platform::current()->loadResource("listPicker.css"));
+ PagePopupClient::addString("</style></head><body><div id=main>Loading...</div><script>\n"
+ "window.dialogArguments = {\n", data);
+ addProperty("selectedIndex", m_client->selectedIndex(), data);
+ PagePopupClient::addString("children: [\n", data);
+ for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(ownerElement())) {
+ if (isHTMLOptionElement(child))
+ addOption(toHTMLOptionElement(child), data);
+ if (isHTMLOptGroupElement(child))
+ addOptGroup(toHTMLOptGroupElement(child), data);
+ if (isHTMLHRElement(child))
+ addSeparator(toHTMLHRElement(child), data);
+ }
+ PagePopupClient::addString("],\n", data);
+ addProperty("anchorRectInScreen", anchorRectInScreen, data);
+ PagePopupClient::addString("};\n", data);
+ data->append(Platform::current()->loadResource("pickerCommon.js"));
+ data->append(Platform::current()->loadResource("listPicker.js"));
+ PagePopupClient::addString("</script></body>\n", data);
+}
+
+const char* fontWeightToString(FontWeight weight)
+{
+ switch (weight) {
+ case FontWeight100:
+ return "100";
+ case FontWeight200:
+ return "200";
+ case FontWeight300:
+ return "300";
+ case FontWeight400:
+ return "400";
+ case FontWeight500:
+ return "500";
+ case FontWeight600:
+ return "600";
+ case FontWeight700:
+ return "700";
+ case FontWeight800:
+ return "800";
+ case FontWeight900:
+ return "900";
+ }
+}
+
+void PopupMenuImpl::addElementStyle(HTMLElement& element, SharedBuffer* data)
+{
+ RenderStyle* style = m_client->renderStyleForItem(element);
+ ASSERT(style);
+ PagePopupClient::addString("style: {\n", data);
+ addProperty("color", style->visitedDependentColor(CSSPropertyColor).serialized(), data);
+ addProperty("backgroundColor", style->visitedDependentColor(CSSPropertyBackgroundColor).serialized(), data);
+ const FontDescription& fontDescription = style->font().fontDescription();
+ addProperty("fontSize", fontDescription.computedPixelSize(), data);
+ addProperty("fontWeight", String(fontWeightToString(fontDescription.weight())), data);
+ PagePopupClient::addString("fontFamily: [\n", data);
+ for (const FontFamily* f = &fontDescription.family(); f; f = f->next()) {
+ addJavaScriptString(f->family().string(), data);
+ if (f->next())
+ PagePopupClient::addString(",\n", data);
+ }
+ PagePopupClient::addString("],\n", data);
+ addProperty("visibility", String(style->visibility() == HIDDEN ? "hidden" : "visible"), data);
+ addProperty("display", String(style->display() == NONE ? "none" : "block"), data);
+ addProperty("direction", String(style->direction() == RTL ? "rtl" : "ltr"), data);
+ addProperty("unicodeBidi", String(isOverride(style->unicodeBidi()) ? "bidi-override" : "normal"), data);
+ PagePopupClient::addString("},\n", data);
+}
+
+void PopupMenuImpl::addOption(HTMLOptionElement& element, SharedBuffer* data)
+{
+ PagePopupClient::addString("{\n", data);
+ PagePopupClient::addString("type: \"option\",\n", data);
+ addProperty("label", element.text(), data);
+ addProperty("title", element.title(), data);
+ addProperty("value", element.listIndex(), data);
+ addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr), data);
+ addProperty("disabled", element.isDisabledFormControl(), data);
+ addElementStyle(element, data);
+ PagePopupClient::addString("},\n", data);
+}
+
+void PopupMenuImpl::addOptGroup(HTMLOptGroupElement& element, SharedBuffer* data)
+{
+ PagePopupClient::addString("{\n", data);
+ PagePopupClient::addString("type: \"optgroup\",\n", data);
+ addProperty("label", element.groupLabelText(), data);
+ addProperty("title", element.title(), data);
+ addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr), data);
+ addProperty("disabled", element.isDisabledFormControl(), data);
+ addElementStyle(element, data);
+ PagePopupClient::addString("children: [", data);
+ for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(element)) {
+ if (isHTMLOptionElement(child))
+ addOption(toHTMLOptionElement(child), data);
+ if (isHTMLOptGroupElement(child))
+ addOptGroup(toHTMLOptGroupElement(child), data);
+ if (isHTMLHRElement(child))
+ addSeparator(toHTMLHRElement(child), data);
+ }
+ PagePopupClient::addString("],\n", data);
+ PagePopupClient::addString("},\n", data);
+}
+
+void PopupMenuImpl::addSeparator(HTMLHRElement& element, SharedBuffer* data)
+{
+ PagePopupClient::addString("{\n", data);
+ PagePopupClient::addString("type: \"separator\",\n", data);
+ addProperty("title", element.title(), data);
+ addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr), data);
+ addProperty("disabled", element.isDisabledFormControl(), data);
+ addElementStyle(element, data);
+ PagePopupClient::addString("},\n", data);
+}
+
+void PopupMenuImpl::didWriteDocument(Document* document)
+{
+ Document& ownerDocument = ownerElement().document();
+ document->styleEngine()->setFontSelector(PopupMenuCSSFontSelector::create(document, ownerDocument.styleEngine()->fontSelector()));
+}
+
+void PopupMenuImpl::setValueAndClosePopup(int numValue, const String& stringValue)
+{
+ ASSERT(m_popup);
+ ASSERT(m_client);
+ bool success;
+ int listIndex = stringValue.toInt(&success);
+ ASSERT(success);
+ m_client->selectionChanged(listIndex);
+ m_client->valueChanged(listIndex);
+ closePopup();
+}
+
+void PopupMenuImpl::setValue(const String& value)
+{
+ ASSERT(m_client);
+ bool success;
+ int listIndex = value.toInt(&success);
+ ASSERT(success);
+ m_client->setTextFromItem(listIndex);
+ // FIXME: Wrong menu list text when switching from keyboard to mouse. We need something like PopupListBox::m_originalIndex.
+}
+
+void PopupMenuImpl::didClosePopup()
+{
+ m_popup = 0;
tkent 2014/12/15 09:26:04 0 -> nullptr
keishi 2014/12/16 03:53:24 Done.
+ m_client->popupDidHide();
+}
+
+Element& PopupMenuImpl::ownerElement()
+{
+ return m_client->ownerElement();
+}
+
+void PopupMenuImpl::closePopup()
+{
+ if (m_popup)
+ m_chromeClient->closePagePopup(m_popup);
+}
+
+void PopupMenuImpl::trace(Visitor* visitor)
tkent 2014/12/15 09:26:04 This function looks unnecessary.
keishi 2014/12/16 03:53:24 Done.
+{
+ PopupMenu::trace(visitor);
+}
+
+void PopupMenuImpl::dispose()
+{
+ closePopup();
+}
+
+void PopupMenuImpl::show(const FloatQuad& /*controlPosition*/, const IntSize& /*controlSize*/, int /*index*/)
+{
+ ASSERT(!m_popup);
+ m_popup = m_chromeClient->openPagePopup(this, m_client->elementRectRelativeToRootView());
+}
+
+void PopupMenuImpl::hide()
+{
+ if (m_popup)
+ m_chromeClient->closePagePopup(m_popup);
+}
+
+void PopupMenuImpl::updateFromElement()
+{
+ RefPtr<SharedBuffer> data = SharedBuffer::create();
+ PagePopupClient::addString("window.updateData = {\n", data.get());
+ PagePopupClient::addString("type: \"update\",\n", data.get());
+ PagePopupClient::addString("children: [", data.get());
+ for (HTMLElement& child : Traversal<HTMLElement>::childrenOf(ownerElement())) {
+ if (isHTMLOptionElement(child))
+ addOption(toHTMLOptionElement(child), data.get());
+ if (isHTMLOptGroupElement(child))
+ addOptGroup(toHTMLOptGroupElement(child), data.get());
+ if (isHTMLHRElement(child))
+ addSeparator(toHTMLHRElement(child), data.get());
+ }
+ PagePopupClient::addString("],\n", data.get());
+ PagePopupClient::addString("}\n", data.get());
+ m_popup->postMessage(String(data->data(), data->size()));
+}
+
+
+void PopupMenuImpl::disconnectClient()
+{
+ m_client = 0;
tkent 2014/12/15 09:26:04 0 -> nullptr
keishi 2014/12/16 03:53:24 Done.
+#if ENABLE(OILPAN)
+ // Cannot be done during finalization, so instead done when the
+ // render object is destroyed and disconnected.
+ //
+ // FIXME: do this always, regardless of ENABLE(OILPAN).
+ dispose();
+#endif
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698