Chromium Code Reviews| Index: third_party/WebKit/Source/web/ExternalPopupMenu.cpp |
| diff --git a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp |
| index 939127f21b50ed87838cc08ba4ca34309021afef..0e25096e375432da0f4d466d881ad69d32cf6713 100644 |
| --- a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp |
| +++ b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp |
| @@ -30,12 +30,14 @@ |
| #include "web/ExternalPopupMenu.h" |
| +#include "core/dom/ExecutionContextTask.h" |
| #include "core/dom/NodeComputedStyle.h" |
| #include "core/frame/FrameHost.h" |
| #include "core/frame/FrameView.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/html/HTMLOptionElement.h" |
| #include "core/html/HTMLSelectElement.h" |
| +#include "core/layout/LayoutBox.h" |
| #include "core/page/Page.h" |
| #include "core/style/ComputedStyle.h" |
| #include "platform/geometry/FloatQuad.h" |
| @@ -71,11 +73,10 @@ DEFINE_TRACE(ExternalPopupMenu) |
| PopupMenu::trace(visitor); |
| } |
| -void ExternalPopupMenu::show(const FloatQuad& controlPosition, const IntSize&, int index) |
| +bool ExternalPopupMenu::showInternal() |
| { |
| - IntRect rect(controlPosition.enclosingBoundingBox()); |
| - // WebCore reuses the PopupMenu of an element. |
| - // For simplicity, we do recreate the actual external popup everytime. |
| + // Blink core reuses the PopupMenu of an element. For simplicity, we do |
| + // recreate the actual external popup everytime. |
| if (m_webExternalPopupMenu) { |
| m_webExternalPopupMenu->close(); |
| m_webExternalPopupMenu = 0; |
| @@ -84,29 +85,44 @@ void ExternalPopupMenu::show(const FloatQuad& controlPosition, const IntSize&, i |
| WebPopupMenuInfo info; |
| getPopupMenuInfo(info, *m_ownerElement); |
| if (info.items.isEmpty()) |
| - return; |
| + return false; |
| WebLocalFrameImpl* webframe = WebLocalFrameImpl::fromFrame(m_localFrame.get()); |
| m_webExternalPopupMenu = webframe->client()->createExternalPopupMenu(info, this); |
| if (m_webExternalPopupMenu) { |
| + LayoutObject* layoutObject = m_ownerElement->layoutObject(); |
| + if (!layoutObject || !layoutObject->isBox()) |
| + return false; |
| + FloatQuad quad(toLayoutBox(layoutObject)->localToAbsoluteQuad(FloatQuad(toLayoutBox(layoutObject)->borderBoundingBox()))); |
| + IntRect rect(quad.enclosingBoundingBox()); |
| IntRect rectInViewport = m_localFrame->view()->soonToBeRemovedContentsToUnscaledViewport(rect); |
| + // TODO(tkent): If the anchor rectangle is not visible, we should not |
| + // show a popup. |
| m_webExternalPopupMenu->show(rectInViewport); |
| -#if OS(MACOSX) |
| - const WebInputEvent* currentEvent = WebViewImpl::currentInputEvent(); |
| - if (currentEvent && currentEvent->type == WebInputEvent::MouseDown) { |
| - m_syntheticEvent = adoptPtr(new WebMouseEvent); |
| - *m_syntheticEvent = *static_cast<const WebMouseEvent*>(currentEvent); |
| - m_syntheticEvent->type = WebInputEvent::MouseUp; |
| - m_dispatchEventTimer.startOneShot(0, BLINK_FROM_HERE); |
| - // FIXME: show() is asynchronous. If preparing a popup is slow and |
| - // a user released the mouse button before showing the popup, |
| - // mouseup and click events are correctly dispatched. Dispatching |
| - // the synthetic mouseup event is redundant in this case. |
| - } |
| -#endif |
| + return true; |
| } else { |
| // The client might refuse to create a popup (when there is already one pending to be shown for example). |
| didCancel(); |
| + return false; |
| + } |
| +} |
| + |
| +void ExternalPopupMenu::show(const FloatQuad&, const IntSize&, int) |
| +{ |
| + if (!showInternal()) |
| + return; |
| +#if OS(MACOSX) |
| + const WebInputEvent* currentEvent = WebViewImpl::currentInputEvent(); |
| + if (currentEvent && currentEvent->type == WebInputEvent::MouseDown) { |
| + m_syntheticEvent = adoptPtr(new WebMouseEvent); |
| + *m_syntheticEvent = *static_cast<const WebMouseEvent*>(currentEvent); |
| + m_syntheticEvent->type = WebInputEvent::MouseUp; |
| + m_dispatchEventTimer.startOneShot(0, BLINK_FROM_HERE); |
| + // FIXME: show() is asynchronous. If preparing a popup is slow and a |
| + // user released the mouse button before showing the popup, mouseup and |
| + // click events are correctly dispatched. Dispatching the synthetic |
| + // mouseup event is redundant in this case. |
| } |
| +#endif |
| } |
| void ExternalPopupMenu::dispatchEvent(Timer<ExternalPopupMenu>*) |
| @@ -127,6 +143,26 @@ void ExternalPopupMenu::hide() |
| void ExternalPopupMenu::updateFromElement() |
| { |
| + if (m_needsUpdate) |
| + return; |
| + m_needsUpdate = true; |
| + m_ownerElement->document().postTask(BLINK_FROM_HERE, createSameThreadTask(&ExternalPopupMenu::update, PassRefPtrWillBeRawPtr<ExternalPopupMenu>(this))); |
| +} |
| + |
| +void ExternalPopupMenu::update() |
| +{ |
| + if (!m_webExternalPopupMenu || !m_ownerElement) |
| + return; |
| + m_ownerElement->document().updateLayoutTreeIfNeeded(); |
| + // disconnectClient() might have been called. |
| + if (!m_ownerElement) |
| + return; |
| + m_needsUpdate = false; |
| + |
| + if (showInternal()) |
| + return; |
| + // We failed to show a popup. Notice it to the owner. |
|
keishi
2016/01/20 03:39:34
nit: s/Notice/Notify/
tkent
2016/01/20 04:13:39
Done.
|
| + hide(); |
| } |
| void ExternalPopupMenu::disconnectClient() |