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

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: Fixed tests for mac Created 5 years, 10 months 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
« no previous file with comments | « Source/web/PopupMenuImpl.h ('k') | Source/web/PopupMenuTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/web/PopupMenuImpl.cpp
diff --git a/Source/web/PopupMenuImpl.cpp b/Source/web/PopupMenuImpl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ecd34c87589ca3ccfce84b30bd2e6cd1193a63e
--- /dev/null
+++ b/Source/web/PopupMenuImpl.cpp
@@ -0,0 +1,309 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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 "platform/text/PlatformLocale.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 PassRefPtrWillBeRawPtr<PopupMenuCSSFontSelector> create(Document* document, CSSFontSelector* ownerFontSelector)
+ {
+ 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;
+
+ virtual void trace(Visitor*) 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);
+}
+
+void PopupMenuCSSFontSelector::trace(Visitor* visitor)
+{
+ visitor->trace(m_ownerFontSelector);
+ CSSFontSelector::trace(visitor);
+}
+
+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(nullptr)
+ , m_indexToSetOnClose(-1)
+{
+}
+
+PopupMenuImpl::~PopupMenuImpl()
+{
+ closePopup();
+}
+
+IntSize PopupMenuImpl::contentSize()
+{
+ return IntSize();
+}
+
+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";
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ return 0;
+}
+
+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);
+ m_indexToSetOnClose = -1;
+ closePopup();
+}
+
+void PopupMenuImpl::setValue(const String& value)
+{
+ ASSERT(m_client);
+ bool success;
+ int listIndex = value.toInt(&success);
+ ASSERT(success);
+ m_client->setTextFromItem(listIndex);
+ m_indexToSetOnClose = listIndex;
+}
+
+void PopupMenuImpl::didClosePopup()
+{
+ if (m_indexToSetOnClose >= 0)
+ m_client->valueChanged(m_indexToSetOnClose);
+ m_indexToSetOnClose = -1;
+ m_popup = nullptr;
+ m_client->popupDidHide();
+}
+
+Element& PopupMenuImpl::ownerElement()
+{
+ return m_client->ownerElement();
+}
+
+Locale& PopupMenuImpl::locale()
+{
+ return Locale::defaultLocale();
+}
+
+void PopupMenuImpl::closePopup()
+{
+ if (m_popup)
+ m_chromeClient->closePagePopup(m_popup);
+}
+
+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 = nullptr;
+#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
« no previous file with comments | « Source/web/PopupMenuImpl.h ('k') | Source/web/PopupMenuTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698