/* * Copyright (C) 2010 Apple Inc. All rights reserved. * * 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 INC. 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 INC. 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 "WindowedPluginTest.h" #include "PluginObject.h" using namespace std; // NPN_InvalidateRect should invalidate the plugin's HWND. static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.NPNInvalidateRectInvalidatesWindow.InstancePointer"; class TemporaryWindowMover { public: TemporaryWindowMover(HWND); ~TemporaryWindowMover(); bool moveSucceeded() const { return m_moveSucceeded; } private: static const UINT standardSetWindowPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER; bool m_moveSucceeded; HWND m_window; RECT m_savedWindowRect; }; TemporaryWindowMover::TemporaryWindowMover(HWND window) : m_window(window) { m_moveSucceeded = false; if (!::GetWindowRect(m_window, &m_savedWindowRect)) return; if (!::SetWindowPos(m_window, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | standardSetWindowPosFlags)) return; m_moveSucceeded = true; }; TemporaryWindowMover::~TemporaryWindowMover() { if (!m_moveSucceeded) return; ::SetWindowPos(m_window, 0, m_savedWindowRect.left, m_savedWindowRect.top, 0, 0, SWP_HIDEWINDOW | standardSetWindowPosFlags); } class NPNInvalidateRectInvalidatesWindow : public WindowedPluginTest { public: NPNInvalidateRectInvalidatesWindow(NPP, const string& identifier); ~NPNInvalidateRectInvalidatesWindow(); private: virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); void onPaint(); void testInvalidateRect(); virtual NPError NPP_SetWindow(NPP, NPWindow*); TemporaryWindowMover* m_windowMover; }; NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow(NPP npp, const string& identifier) : WindowedPluginTest(npp, identifier) , m_windowMover(0) { } NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow() { delete m_windowMover; } NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* npWindow) { NPError error = WindowedPluginTest::NPP_SetWindow(instance, npWindow); if (error != NPERR_NO_ERROR) return error; if (!window()) return NPERR_NO_ERROR; // The test harness's window (the one that contains the WebView) is off-screen and hidden. // We need to move it on-screen and make it visible in order for the plugin's window to // accumulate an update region when the DWM is disabled. HWND testHarnessWindow = ::GetAncestor(window(), GA_ROOT); if (!testHarnessWindow) { pluginLog(instance, "Failed to get test harness window"); return NPERR_GENERIC_ERROR; } m_windowMover = new TemporaryWindowMover(testHarnessWindow); if (!m_windowMover->moveSucceeded()) { pluginLog(instance, "Failed to move test harness window on-screen"); return NPERR_GENERIC_ERROR; } // Wait until we receive a WM_PAINT message to ensure that the window is on-screen before we do // the NPN_InvalidateRect test. waitUntilDone(); return NPERR_NO_ERROR; } LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) { if (message == WM_PAINT) onPaint(); handled = false; return 0; } void NPNInvalidateRectInvalidatesWindow::onPaint() { testInvalidateRect(); notifyDone(); delete m_windowMover; m_windowMover = 0; } void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() { RECT clientRect; if (!::GetClientRect(window(), &clientRect)) { pluginLog(m_npp, "::GetClientRect failed"); return; } if (::IsRectEmpty(&clientRect)) { pluginLog(m_npp, "Plugin's HWND has not been sized when NPP_SetWindow is called"); return; } // Clear the invalid region. if (!::ValidateRect(window(), 0)) { pluginLog(m_npp, "::ValidateRect failed"); return; } // Invalidate our lower-right quadrant. NPRect rectToInvalidate; rectToInvalidate.left = (clientRect.right - clientRect.left) / 2; rectToInvalidate.top = (clientRect.bottom - clientRect.top) / 2; rectToInvalidate.right = clientRect.right; rectToInvalidate.bottom = clientRect.bottom; NPN_InvalidateRect(&rectToInvalidate); RECT invalidRect; if (!::GetUpdateRect(window(), &invalidRect, FALSE)) { pluginLog(m_npp, "::GetUpdateRect failed"); return; } if (invalidRect.left != rectToInvalidate.left || invalidRect.top != rectToInvalidate.top || invalidRect.right != rectToInvalidate.right || invalidRect.bottom != rectToInvalidate.bottom) { 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); return; } pluginLog(m_npp, "Plugin's HWND has been invalidated as expected"); } static PluginTest::Register registrar("npn-invalidate-rect-invalidates-window");