Chromium Code Reviews| 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 |