1/* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "core/testing/MockPagePopupDriver.h" 28 29#include "bindings/core/v8/ExceptionStatePlaceholder.h" 30#include "core/CSSPropertyNames.h" 31#include "core/CSSValueKeywords.h" 32#include "core/frame/LocalFrame.h" 33#include "core/html/HTMLIFrameElement.h" 34#include "core/loader/FrameLoadRequest.h" 35#include "core/loader/FrameLoader.h" 36#include "core/page/PagePopup.h" 37#include "core/page/PagePopupController.h" 38#include "platform/Timer.h" 39 40namespace blink { 41 42class MockPagePopup : public PagePopup, public RefCounted<MockPagePopup> { 43public: 44 static PassRefPtr<MockPagePopup> create(PagePopupClient*, const IntRect& originBoundsInRootView, LocalFrame*); 45 virtual ~MockPagePopup(); 46 bool initialize(); 47 void closeLater(); 48 49private: 50 MockPagePopup(PagePopupClient*, const IntRect& originBoundsInRootView, LocalFrame*); 51 void close(Timer<MockPagePopup>*); 52 virtual AXObject* rootAXObject() OVERRIDE { return 0; } 53 54 PagePopupClient* m_popupClient; 55 RefPtrWillBePersistent<HTMLIFrameElement> m_iframe; 56 Timer<MockPagePopup> m_closeTimer; 57}; 58 59inline MockPagePopup::MockPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView, LocalFrame* mainFrame) 60 : m_popupClient(client) 61 , m_closeTimer(this, &MockPagePopup::close) 62{ 63 Document* document = mainFrame->document(); 64 ASSERT(document); 65 m_iframe = HTMLIFrameElement::create(*document); 66 m_iframe->setIdAttribute("mock-page-popup"); 67 m_iframe->setInlineStyleProperty(CSSPropertyBorderWidth, 0.0, CSSPrimitiveValue::CSS_PX); 68 m_iframe->setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute); 69 m_iframe->setInlineStyleProperty(CSSPropertyLeft, originBoundsInRootView.x(), CSSPrimitiveValue::CSS_PX, true); 70 m_iframe->setInlineStyleProperty(CSSPropertyTop, originBoundsInRootView.maxY(), CSSPrimitiveValue::CSS_PX, true); 71 if (document->body()) 72 document->body()->appendChild(m_iframe.get()); 73} 74 75bool MockPagePopup::initialize() 76{ 77 const char scriptToSetUpPagePopupController[] = "<script>window.pagePopupController = parent.internals.pagePopupController;</script>"; 78 RefPtr<SharedBuffer> data = SharedBuffer::create(scriptToSetUpPagePopupController, sizeof(scriptToSetUpPagePopupController)); 79 m_popupClient->writeDocument(data.get()); 80 LocalFrame* localFrame = toLocalFrame(m_iframe->contentFrame()); 81 if (!localFrame) 82 return false; 83 localFrame->loader().load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad))); 84 return true; 85} 86 87PassRefPtr<MockPagePopup> MockPagePopup::create(PagePopupClient* client, const IntRect& originBoundsInRootView, LocalFrame* mainFrame) 88{ 89 return adoptRef(new MockPagePopup(client, originBoundsInRootView, mainFrame)); 90} 91 92void MockPagePopup::closeLater() 93{ 94 ref(); 95 m_popupClient->didClosePopup(); 96 m_popupClient = 0; 97 // This can be called in detach(), and we should not change DOM structure 98 // during detach(). 99 m_closeTimer.startOneShot(0, FROM_HERE); 100} 101 102void MockPagePopup::close(Timer<MockPagePopup>*) 103{ 104 deref(); 105} 106 107MockPagePopup::~MockPagePopup() 108{ 109 if (m_iframe && m_iframe->parentNode()) 110 m_iframe->parentNode()->removeChild(m_iframe.get()); 111} 112 113inline MockPagePopupDriver::MockPagePopupDriver(LocalFrame* mainFrame) 114 : m_mainFrame(mainFrame) 115{ 116} 117 118PassOwnPtr<MockPagePopupDriver> MockPagePopupDriver::create(LocalFrame* mainFrame) 119{ 120 return adoptPtr(new MockPagePopupDriver(mainFrame)); 121} 122 123MockPagePopupDriver::~MockPagePopupDriver() 124{ 125 closePagePopup(m_mockPagePopup.get()); 126} 127 128PagePopup* MockPagePopupDriver::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView) 129{ 130 if (m_mockPagePopup) 131 closePagePopup(m_mockPagePopup.get()); 132 if (!client || !m_mainFrame) 133 return 0; 134 m_pagePopupController = PagePopupController::create(client); 135 m_mockPagePopup = MockPagePopup::create(client, originBoundsInRootView, m_mainFrame); 136 if (!m_mockPagePopup->initialize()) { 137 m_mockPagePopup->closeLater(); 138 m_mockPagePopup.clear(); 139 } 140 return m_mockPagePopup.get(); 141} 142 143void MockPagePopupDriver::closePagePopup(PagePopup* popup) 144{ 145 if (!popup || popup != m_mockPagePopup.get()) 146 return; 147 m_mockPagePopup->closeLater(); 148 m_mockPagePopup.clear(); 149 m_pagePopupController->clearPagePopupClient(); 150 m_pagePopupController.clear(); 151} 152 153} 154