1 /* 2 * Copyright (C) 2010 Apple 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "WindowedPluginTest.h" 27 28 #include "PluginObject.h" 29 30 using namespace std; 31 32 // NPN_InvalidateRect should invalidate the plugin's HWND. 33 34 static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.NPNInvalidateRectInvalidatesWindow.InstancePointer"; 35 36 class TemporaryWindowMover { 37 public: 38 TemporaryWindowMover(HWND); 39 ~TemporaryWindowMover(); 40 41 bool moveSucceeded() const { return m_moveSucceeded; } 42 43 private: 44 static const UINT standardSetWindowPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER; 45 bool m_moveSucceeded; 46 HWND m_window; 47 RECT m_savedWindowRect; 48 }; 49 50 TemporaryWindowMover::TemporaryWindowMover(HWND window) 51 : m_window(window) 52 { 53 m_moveSucceeded = false; 54 55 if (!::GetWindowRect(m_window, &m_savedWindowRect)) 56 return; 57 58 if (!::SetWindowPos(m_window, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | standardSetWindowPosFlags)) 59 return; 60 61 m_moveSucceeded = true; 62 }; 63 64 TemporaryWindowMover::~TemporaryWindowMover() 65 { 66 if (!m_moveSucceeded) 67 return; 68 69 ::SetWindowPos(m_window, 0, m_savedWindowRect.left, m_savedWindowRect.top, 0, 0, SWP_HIDEWINDOW | standardSetWindowPosFlags); 70 } 71 72 class NPNInvalidateRectInvalidatesWindow : public WindowedPluginTest { 73 public: 74 NPNInvalidateRectInvalidatesWindow(NPP, const string& identifier); 75 ~NPNInvalidateRectInvalidatesWindow(); 76 77 private: 78 virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); 79 80 void onPaint(); 81 void testInvalidateRect(); 82 83 virtual NPError NPP_SetWindow(NPP, NPWindow*); 84 85 TemporaryWindowMover* m_windowMover; 86 }; 87 88 NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow(NPP npp, const string& identifier) 89 : WindowedPluginTest(npp, identifier) 90 , m_windowMover(0) 91 { 92 } 93 94 NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow() 95 { 96 delete m_windowMover; 97 } 98 99 NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* npWindow) 100 { 101 NPError error = WindowedPluginTest::NPP_SetWindow(instance, npWindow); 102 if (error != NPERR_NO_ERROR) 103 return error; 104 105 if (!window()) 106 return NPERR_NO_ERROR; 107 108 // The test harness's window (the one that contains the WebView) is off-screen and hidden. 109 // We need to move it on-screen and make it visible in order for the plugin's window to 110 // accumulate an update region when the DWM is disabled. 111 112 HWND testHarnessWindow = ::GetAncestor(window(), GA_ROOT); 113 if (!testHarnessWindow) { 114 pluginLog(instance, "Failed to get test harness window"); 115 return NPERR_GENERIC_ERROR; 116 } 117 118 m_windowMover = new TemporaryWindowMover(testHarnessWindow); 119 if (!m_windowMover->moveSucceeded()) { 120 pluginLog(instance, "Failed to move test harness window on-screen"); 121 return NPERR_GENERIC_ERROR; 122 } 123 124 // Wait until we receive a WM_PAINT message to ensure that the window is on-screen before we do 125 // the NPN_InvalidateRect test. 126 waitUntilDone(); 127 return NPERR_NO_ERROR; 128 } 129 130 LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) 131 { 132 if (message == WM_PAINT) 133 onPaint(); 134 135 handled = false; 136 return 0; 137 } 138 139 void NPNInvalidateRectInvalidatesWindow::onPaint() 140 { 141 testInvalidateRect(); 142 notifyDone(); 143 delete m_windowMover; 144 m_windowMover = 0; 145 } 146 147 void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() 148 { 149 RECT clientRect; 150 if (!::GetClientRect(window(), &clientRect)) { 151 pluginLog(m_npp, "::GetClientRect failed"); 152 return; 153 } 154 155 if (::IsRectEmpty(&clientRect)) { 156 pluginLog(m_npp, "Plugin's HWND has not been sized when NPP_SetWindow is called"); 157 return; 158 } 159 160 // Clear the invalid region. 161 if (!::ValidateRect(window(), 0)) { 162 pluginLog(m_npp, "::ValidateRect failed"); 163 return; 164 } 165 166 // Invalidate our lower-right quadrant. 167 NPRect rectToInvalidate; 168 rectToInvalidate.left = (clientRect.right - clientRect.left) / 2; 169 rectToInvalidate.top = (clientRect.bottom - clientRect.top) / 2; 170 rectToInvalidate.right = clientRect.right; 171 rectToInvalidate.bottom = clientRect.bottom; 172 NPN_InvalidateRect(&rectToInvalidate); 173 174 RECT invalidRect; 175 if (!::GetUpdateRect(window(), &invalidRect, FALSE)) { 176 pluginLog(m_npp, "::GetUpdateRect failed"); 177 return; 178 } 179 180 if (invalidRect.left != rectToInvalidate.left || invalidRect.top != rectToInvalidate.top || invalidRect.right != rectToInvalidate.right || invalidRect.bottom != rectToInvalidate.bottom) { 181 pluginLog(m_npp, "Expected invalid rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", rectToInvalidate.left, rectToInvalidate.top, rectToInvalidate.right, rectToInvalidate.bottom, invalidRect.left, invalidRect.top, invalidRect.right, invalidRect.bottom); 182 return; 183 } 184 185 pluginLog(m_npp, "Plugin's HWND has been invalidated as expected"); 186 } 187 188 static PluginTest::Register<NPNInvalidateRectInvalidatesWindow> registrar("npn-invalidate-rect-invalidates-window"); 189