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/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 40 namespace WebCore { 41 42 class MockPagePopup : public PagePopup, public RefCounted<MockPagePopup> { 43 public: 44 static PassRefPtr<MockPagePopup> create(PagePopupClient*, const IntRect& originBoundsInRootView, LocalFrame*); 45 virtual ~MockPagePopup(); 46 bool initialize(); 47 void closeLater(); 48 49 private: 50 MockPagePopup(PagePopupClient*, const IntRect& originBoundsInRootView, LocalFrame*); 51 void close(Timer<MockPagePopup>*); 52 53 PagePopupClient* m_popupClient; 54 RefPtrWillBePersistent<HTMLIFrameElement> m_iframe; 55 Timer<MockPagePopup> m_closeTimer; 56 }; 57 58 inline MockPagePopup::MockPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView, LocalFrame* mainFrame) 59 : m_popupClient(client) 60 , m_closeTimer(this, &MockPagePopup::close) 61 { 62 Document* document = mainFrame->document(); 63 ASSERT(document); 64 m_iframe = HTMLIFrameElement::create(*document); 65 m_iframe->setIdAttribute("mock-page-popup"); 66 m_iframe->setInlineStyleProperty(CSSPropertyBorderWidth, 0.0, CSSPrimitiveValue::CSS_PX); 67 m_iframe->setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute); 68 m_iframe->setInlineStyleProperty(CSSPropertyLeft, originBoundsInRootView.x(), CSSPrimitiveValue::CSS_PX, true); 69 m_iframe->setInlineStyleProperty(CSSPropertyTop, originBoundsInRootView.maxY(), CSSPrimitiveValue::CSS_PX, true); 70 if (document->body()) 71 document->body()->appendChild(m_iframe.get()); 72 } 73 74 bool MockPagePopup::initialize() 75 { 76 const char scriptToSetUpPagePopupController[] = "<script>window.pagePopupController = parent.internals.pagePopupController;</script>"; 77 RefPtr<SharedBuffer> data = SharedBuffer::create(scriptToSetUpPagePopupController, sizeof(scriptToSetUpPagePopupController)); 78 m_popupClient->writeDocument(data.get()); 79 LocalFrame* localFrame = toLocalFrame(m_iframe->contentFrame()); 80 if (!localFrame) 81 return false; 82 localFrame->loader().load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad))); 83 return true; 84 } 85 86 PassRefPtr<MockPagePopup> MockPagePopup::create(PagePopupClient* client, const IntRect& originBoundsInRootView, LocalFrame* mainFrame) 87 { 88 return adoptRef(new MockPagePopup(client, originBoundsInRootView, mainFrame)); 89 } 90 91 void MockPagePopup::closeLater() 92 { 93 ref(); 94 m_popupClient->didClosePopup(); 95 m_popupClient = 0; 96 // This can be called in detach(), and we should not change DOM structure 97 // during detach(). 98 m_closeTimer.startOneShot(0, FROM_HERE); 99 } 100 101 void MockPagePopup::close(Timer<MockPagePopup>*) 102 { 103 deref(); 104 } 105 106 MockPagePopup::~MockPagePopup() 107 { 108 if (m_iframe && m_iframe->parentNode()) 109 m_iframe->parentNode()->removeChild(m_iframe.get()); 110 } 111 112 inline MockPagePopupDriver::MockPagePopupDriver(LocalFrame* mainFrame) 113 : m_mainFrame(mainFrame) 114 { 115 } 116 117 PassOwnPtr<MockPagePopupDriver> MockPagePopupDriver::create(LocalFrame* mainFrame) 118 { 119 return adoptPtr(new MockPagePopupDriver(mainFrame)); 120 } 121 122 MockPagePopupDriver::~MockPagePopupDriver() 123 { 124 closePagePopup(m_mockPagePopup.get()); 125 } 126 127 PagePopup* MockPagePopupDriver::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView) 128 { 129 if (m_mockPagePopup) 130 closePagePopup(m_mockPagePopup.get()); 131 if (!client || !m_mainFrame) 132 return 0; 133 m_pagePopupController = PagePopupController::create(client); 134 m_mockPagePopup = MockPagePopup::create(client, originBoundsInRootView, m_mainFrame); 135 if (!m_mockPagePopup->initialize()) { 136 m_mockPagePopup->closeLater(); 137 m_mockPagePopup.clear(); 138 } 139 return m_mockPagePopup.get(); 140 } 141 142 void MockPagePopupDriver::closePagePopup(PagePopup* popup) 143 { 144 if (!popup || popup != m_mockPagePopup.get()) 145 return; 146 m_mockPagePopup->closeLater(); 147 m_mockPagePopup.clear(); 148 m_pagePopupController->clearPagePopupClient(); 149 m_pagePopupController.clear(); 150 } 151 152 } 153