michael@0: /* ***** BEGIN LICENSE BLOCK ***** michael@0: * michael@0: * Copyright (c) 2008, Mozilla Corporation michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions are met: michael@0: * michael@0: * * Redistributions of source code must retain the above copyright notice, this michael@0: * list of conditions and the following disclaimer. michael@0: * * Redistributions in binary form must reproduce the above copyright notice, michael@0: * this list of conditions and the following disclaimer in the documentation michael@0: * and/or other materials provided with the distribution. michael@0: * * Neither the name of the Mozilla Corporation nor the names of its michael@0: * contributors may be used to endorse or promote products derived from this michael@0: * software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND michael@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED michael@0: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE michael@0: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR michael@0: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES michael@0: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; michael@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON michael@0: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS michael@0: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: * michael@0: * Contributor(s): michael@0: * Josh Aas michael@0: * Jim Mathies michael@0: * michael@0: * ***** END LICENSE BLOCK ***** */ michael@0: michael@0: #include "nptest_platform.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: michael@0: using namespace std; michael@0: michael@0: void SetSubclass(HWND hWnd, InstanceData* instanceData); michael@0: void ClearSubclass(HWND hWnd); michael@0: LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); michael@0: michael@0: struct _PlatformData { michael@0: HWND childWindow; michael@0: ID3D10Device1 *device; michael@0: ID3D10Texture2D *frontBuffer; michael@0: ID3D10Texture2D *backBuffer; michael@0: }; michael@0: michael@0: bool michael@0: pluginSupportsWindowMode() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: pluginSupportsWindowlessMode() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: pluginSupportsAsyncBitmapDrawing() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: NPError michael@0: pluginInstanceInit(InstanceData* instanceData) michael@0: { michael@0: NPP npp = instanceData->npp; michael@0: michael@0: instanceData->platformData = static_cast michael@0: (NPN_MemAlloc(sizeof(PlatformData))); michael@0: if (!instanceData->platformData) michael@0: return NPERR_OUT_OF_MEMORY_ERROR; michael@0: michael@0: instanceData->platformData->childWindow = nullptr; michael@0: instanceData->platformData->device = nullptr; michael@0: instanceData->platformData->frontBuffer = nullptr; michael@0: instanceData->platformData->backBuffer = nullptr; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: pluginInstanceShutdown(InstanceData* instanceData) michael@0: { michael@0: PlatformData *pd = instanceData->platformData; michael@0: if (pd->frontBuffer) { michael@0: pd->frontBuffer->Release(); michael@0: } michael@0: if (pd->backBuffer) { michael@0: pd->backBuffer->Release(); michael@0: } michael@0: if (pd->device) { michael@0: pd->device->Release(); michael@0: } michael@0: NPN_MemFree(instanceData->platformData); michael@0: instanceData->platformData = 0; michael@0: } michael@0: michael@0: static ID3D10Device1* michael@0: getD3D10Device() michael@0: { michael@0: ID3D10Device1 *device; michael@0: michael@0: HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); michael@0: decltype(D3D10CreateDevice1)* createD3DDevice = michael@0: (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, michael@0: "D3D10CreateDevice1"); michael@0: michael@0: if (createD3DDevice) { michael@0: HMODULE dxgiModule = LoadLibraryA("dxgi.dll"); michael@0: decltype(CreateDXGIFactory1)* createDXGIFactory1 = michael@0: (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, michael@0: "CreateDXGIFactory1"); michael@0: michael@0: HRESULT hr; michael@0: michael@0: // Try to use a DXGI 1.1 adapter in order to share resources michael@0: // across processes. michael@0: IDXGIAdapter1 *adapter1; michael@0: if (createDXGIFactory1) { michael@0: IDXGIFactory1 *factory1; michael@0: hr = createDXGIFactory1(__uuidof(IDXGIFactory1), michael@0: (void**)&factory1); michael@0: michael@0: if (FAILED(hr) || !factory1) { michael@0: // Uh-oh michael@0: return nullptr; michael@0: } michael@0: michael@0: hr = factory1->EnumAdapters1(0, &adapter1); michael@0: michael@0: if (SUCCEEDED(hr) && adapter1) { michael@0: hr = adapter1->CheckInterfaceSupport(__uuidof(ID3D10Device), michael@0: nullptr); michael@0: if (FAILED(hr)) { michael@0: adapter1 = nullptr; michael@0: } michael@0: } michael@0: factory1->Release(); michael@0: } michael@0: michael@0: hr = createD3DDevice( michael@0: adapter1, michael@0: D3D10_DRIVER_TYPE_HARDWARE, michael@0: nullptr, michael@0: D3D10_CREATE_DEVICE_BGRA_SUPPORT | michael@0: D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, michael@0: D3D10_FEATURE_LEVEL_10_0, michael@0: D3D10_1_SDK_VERSION, michael@0: &device); michael@0: michael@0: adapter1->Release(); michael@0: } michael@0: michael@0: return device; michael@0: } michael@0: michael@0: void michael@0: pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) michael@0: { michael@0: instanceData->window = *newWindow; michael@0: NPP npp = instanceData->npp; michael@0: michael@0: if (instanceData->asyncDrawing == AD_DXGI) { michael@0: if (instanceData->frontBuffer && michael@0: instanceData->frontBuffer->size.width == newWindow->width && michael@0: instanceData->frontBuffer->size.height == newWindow->height) { michael@0: return; michael@0: } michael@0: if (instanceData->frontBuffer) { michael@0: instanceData->platformData->frontBuffer->Release(); michael@0: instanceData->platformData->frontBuffer = nullptr; michael@0: NPN_FinalizeAsyncSurface(npp, instanceData->frontBuffer); michael@0: NPN_MemFree(instanceData->frontBuffer); michael@0: } michael@0: if (instanceData->backBuffer) { michael@0: instanceData->platformData->backBuffer->Release(); michael@0: instanceData->platformData->backBuffer = nullptr; michael@0: NPN_FinalizeAsyncSurface(npp, instanceData->backBuffer); michael@0: NPN_MemFree(instanceData->backBuffer); michael@0: } michael@0: michael@0: if (!instanceData->platformData->device) { michael@0: instanceData->platformData->device = getD3D10Device(); michael@0: } michael@0: michael@0: ID3D10Device1 *dev = instanceData->platformData->device; michael@0: michael@0: if (!dev) { michael@0: return; michael@0: } michael@0: michael@0: instanceData->frontBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface)); michael@0: instanceData->backBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface)); michael@0: michael@0: NPSize size; michael@0: size.width = newWindow->width; michael@0: size.height = newWindow->height; michael@0: michael@0: memset(instanceData->frontBuffer, 0, sizeof(NPAsyncSurface)); michael@0: memset(instanceData->backBuffer, 0, sizeof(NPAsyncSurface)); michael@0: michael@0: NPN_InitAsyncSurface(npp, &size, NPImageFormatBGRA32, nullptr, instanceData->frontBuffer); michael@0: NPN_InitAsyncSurface(npp, &size, NPImageFormatBGRA32, nullptr, instanceData->backBuffer); michael@0: michael@0: dev->OpenSharedResource(instanceData->frontBuffer->sharedHandle, __uuidof(ID3D10Texture2D), (void**)&instanceData->platformData->frontBuffer); michael@0: dev->OpenSharedResource(instanceData->backBuffer->sharedHandle, __uuidof(ID3D10Texture2D), (void**)&instanceData->platformData->backBuffer); michael@0: michael@0: pluginDrawAsyncDxgiColor(instanceData); michael@0: } michael@0: } michael@0: michael@0: #define CHILD_WIDGET_SIZE 10 michael@0: michael@0: void michael@0: pluginWidgetInit(InstanceData* instanceData, void* oldWindow) michael@0: { michael@0: HWND hWnd = (HWND)instanceData->window.window; michael@0: if (oldWindow) { michael@0: // chrashtests/539897-1.html excercises this code michael@0: HWND hWndOld = (HWND)oldWindow; michael@0: ClearSubclass(hWndOld); michael@0: if (instanceData->platformData->childWindow) { michael@0: ::DestroyWindow(instanceData->platformData->childWindow); michael@0: } michael@0: } michael@0: michael@0: SetSubclass(hWnd, instanceData); michael@0: michael@0: instanceData->platformData->childWindow = michael@0: ::CreateWindowW(L"SCROLLBAR", L"Dummy child window", michael@0: WS_CHILD, 0, 0, CHILD_WIDGET_SIZE, CHILD_WIDGET_SIZE, hWnd, nullptr, michael@0: nullptr, nullptr); michael@0: } michael@0: michael@0: static void michael@0: drawToDC(InstanceData* instanceData, HDC dc, michael@0: int x, int y, int width, int height) michael@0: { michael@0: switch (instanceData->scriptableObject->drawMode) { michael@0: case DM_DEFAULT: michael@0: { michael@0: const RECT fill = { x, y, x + width, y + height }; michael@0: michael@0: int oldBkMode = ::SetBkMode(dc, TRANSPARENT); michael@0: HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); michael@0: if (brush) { michael@0: ::FillRect(dc, &fill, brush); michael@0: ::DeleteObject(brush); michael@0: } michael@0: if (width > 6 && height > 6) { michael@0: brush = ::CreateSolidBrush(RGB(192, 192, 192)); michael@0: if (brush) { michael@0: RECT inset = { x + 3, y + 3, x + width - 3, y + height - 3 }; michael@0: ::FillRect(dc, &inset, brush); michael@0: ::DeleteObject(brush); michael@0: } michael@0: } michael@0: michael@0: const char* uaString = NPN_UserAgent(instanceData->npp); michael@0: if (uaString && width > 10 && height > 10) { michael@0: HFONT font = michael@0: ::CreateFontA(20, 0, 0, 0, 400, FALSE, FALSE, FALSE, michael@0: DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, michael@0: CLIP_DEFAULT_PRECIS, 5, // CLEARTYPE_QUALITY michael@0: DEFAULT_PITCH, "Arial"); michael@0: if (font) { michael@0: HFONT oldFont = (HFONT)::SelectObject(dc, font); michael@0: RECT inset = { x + 5, y + 5, x + width - 5, y + height - 5 }; michael@0: ::DrawTextA(dc, uaString, -1, &inset, michael@0: DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK); michael@0: ::SelectObject(dc, oldFont); michael@0: ::DeleteObject(font); michael@0: } michael@0: } michael@0: ::SetBkMode(dc, oldBkMode); michael@0: } michael@0: break; michael@0: michael@0: case DM_SOLID_COLOR: michael@0: { michael@0: HDC offscreenDC = ::CreateCompatibleDC(dc); michael@0: if (!offscreenDC) michael@0: return; michael@0: michael@0: const BITMAPV4HEADER bitmapheader = { michael@0: sizeof(BITMAPV4HEADER), michael@0: width, michael@0: height, michael@0: 1, // planes michael@0: 32, // bits michael@0: BI_BITFIELDS, michael@0: 0, // unused size michael@0: 0, 0, // unused metrics michael@0: 0, 0, // unused colors used/important michael@0: 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, // ARGB masks michael@0: }; michael@0: uint32_t *pixelData; michael@0: HBITMAP offscreenBitmap = michael@0: ::CreateDIBSection(dc, reinterpret_cast(&bitmapheader), michael@0: 0, reinterpret_cast(&pixelData), 0, 0); michael@0: if (!offscreenBitmap) michael@0: return; michael@0: michael@0: uint32_t rgba = instanceData->scriptableObject->drawColor; michael@0: unsigned int alpha = ((rgba & 0xFF000000) >> 24); michael@0: BYTE r = ((rgba & 0xFF0000) >> 16); michael@0: BYTE g = ((rgba & 0xFF00) >> 8); michael@0: BYTE b = (rgba & 0xFF); michael@0: michael@0: // Windows expects premultiplied michael@0: r = BYTE(float(alpha * r) / 0xFF); michael@0: g = BYTE(float(alpha * g) / 0xFF); michael@0: b = BYTE(float(alpha * b) / 0xFF); michael@0: uint32_t premultiplied = michael@0: (alpha << 24) + (r << 16) + (g << 8) + b; michael@0: michael@0: for (uint32_t* lastPixel = pixelData + width * height; michael@0: pixelData < lastPixel; michael@0: ++pixelData) michael@0: *pixelData = premultiplied; michael@0: michael@0: ::SelectObject(offscreenDC, offscreenBitmap); michael@0: BLENDFUNCTION blendFunc; michael@0: blendFunc.BlendOp = AC_SRC_OVER; michael@0: blendFunc.BlendFlags = 0; michael@0: blendFunc.SourceConstantAlpha = 255; michael@0: blendFunc.AlphaFormat = AC_SRC_ALPHA; michael@0: ::AlphaBlend(dc, x, y, width, height, offscreenDC, 0, 0, width, height, michael@0: blendFunc); michael@0: michael@0: ::DeleteObject(offscreenDC); michael@0: ::DeleteObject(offscreenBitmap); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: void michael@0: pluginDraw(InstanceData* instanceData) michael@0: { michael@0: NPP npp = instanceData->npp; michael@0: if (!npp) michael@0: return; michael@0: michael@0: HDC hdc = nullptr; michael@0: PAINTSTRUCT ps; michael@0: michael@0: notifyDidPaint(instanceData); michael@0: michael@0: if (instanceData->hasWidget) michael@0: hdc = ::BeginPaint((HWND)instanceData->window.window, &ps); michael@0: else michael@0: hdc = (HDC)instanceData->window.window; michael@0: michael@0: if (hdc == nullptr) michael@0: return; michael@0: michael@0: // Push the browser's hdc on the resource stack. If this test plugin is windowless, michael@0: // we share the drawing surface with the rest of the browser. michael@0: int savedDCID = SaveDC(hdc); michael@0: michael@0: // When we have a widget, window.x/y are meaningless since our widget michael@0: // is always positioned correctly and we just draw into it at 0,0. michael@0: int x = instanceData->hasWidget ? 0 : instanceData->window.x; michael@0: int y = instanceData->hasWidget ? 0 : instanceData->window.y; michael@0: int width = instanceData->window.width; michael@0: int height = instanceData->window.height; michael@0: drawToDC(instanceData, hdc, x, y, width, height); michael@0: michael@0: // Pop our hdc changes off the resource stack michael@0: RestoreDC(hdc, savedDCID); michael@0: michael@0: if (instanceData->hasWidget) michael@0: ::EndPaint((HWND)instanceData->window.window, &ps); michael@0: } michael@0: michael@0: /* script interface */ michael@0: michael@0: int32_t michael@0: pluginGetEdge(InstanceData* instanceData, RectEdge edge) michael@0: { michael@0: if (!instanceData || !instanceData->hasWidget) michael@0: return NPTEST_INT32_ERROR; michael@0: michael@0: // Get the plugin client rect in screen coordinates michael@0: RECT rect = {0}; michael@0: if (!::GetClientRect((HWND)instanceData->window.window, &rect)) michael@0: return NPTEST_INT32_ERROR; michael@0: ::MapWindowPoints((HWND)instanceData->window.window, nullptr, michael@0: (LPPOINT)&rect, 2); michael@0: michael@0: // Get the toplevel window frame rect in screen coordinates michael@0: HWND rootWnd = ::GetAncestor((HWND)instanceData->window.window, GA_ROOT); michael@0: if (!rootWnd) michael@0: return NPTEST_INT32_ERROR; michael@0: RECT rootRect; michael@0: if (!::GetWindowRect(rootWnd, &rootRect)) michael@0: return NPTEST_INT32_ERROR; michael@0: michael@0: switch (edge) { michael@0: case EDGE_LEFT: michael@0: return rect.left - rootRect.left; michael@0: case EDGE_TOP: michael@0: return rect.top - rootRect.top; michael@0: case EDGE_RIGHT: michael@0: return rect.right - rootRect.left; michael@0: case EDGE_BOTTOM: michael@0: return rect.bottom - rootRect.top; michael@0: } michael@0: michael@0: return NPTEST_INT32_ERROR; michael@0: } michael@0: michael@0: static BOOL michael@0: getWindowRegion(HWND wnd, HRGN rgn) michael@0: { michael@0: if (::GetWindowRgn(wnd, rgn) != ERROR) michael@0: return TRUE; michael@0: michael@0: RECT clientRect; michael@0: if (!::GetClientRect(wnd, &clientRect)) michael@0: return FALSE; michael@0: return ::SetRectRgn(rgn, 0, 0, clientRect.right, clientRect.bottom); michael@0: } michael@0: michael@0: static RGNDATA* michael@0: computeClipRegion(InstanceData* instanceData) michael@0: { michael@0: HWND wnd = (HWND)instanceData->window.window; michael@0: HRGN rgn = ::CreateRectRgn(0, 0, 0, 0); michael@0: if (!rgn) michael@0: return nullptr; michael@0: HRGN ancestorRgn = ::CreateRectRgn(0, 0, 0, 0); michael@0: if (!ancestorRgn) { michael@0: ::DeleteObject(rgn); michael@0: return nullptr; michael@0: } michael@0: if (!getWindowRegion(wnd, rgn)) { michael@0: ::DeleteObject(ancestorRgn); michael@0: ::DeleteObject(rgn); michael@0: return nullptr; michael@0: } michael@0: michael@0: HWND ancestor = wnd; michael@0: for (;;) { michael@0: ancestor = ::GetAncestor(ancestor, GA_PARENT); michael@0: if (!ancestor || ancestor == ::GetDesktopWindow()) { michael@0: ::DeleteObject(ancestorRgn); michael@0: michael@0: DWORD size = ::GetRegionData(rgn, 0, nullptr); michael@0: if (!size) { michael@0: ::DeleteObject(rgn); michael@0: return nullptr; michael@0: } michael@0: michael@0: HANDLE heap = ::GetProcessHeap(); michael@0: RGNDATA* data = static_cast(::HeapAlloc(heap, 0, size)); michael@0: if (!data) { michael@0: ::DeleteObject(rgn); michael@0: return nullptr; michael@0: } michael@0: DWORD result = ::GetRegionData(rgn, size, data); michael@0: ::DeleteObject(rgn); michael@0: if (!result) { michael@0: ::HeapFree(heap, 0, data); michael@0: return nullptr; michael@0: } michael@0: michael@0: return data; michael@0: } michael@0: michael@0: if (!getWindowRegion(ancestor, ancestorRgn)) { michael@0: ::DeleteObject(ancestorRgn); michael@0: ::DeleteObject(rgn); michael@0: return 0; michael@0: } michael@0: michael@0: POINT pt = { 0, 0 }; michael@0: ::MapWindowPoints(ancestor, wnd, &pt, 1); michael@0: if (::OffsetRgn(ancestorRgn, pt.x, pt.y) == ERROR || michael@0: ::CombineRgn(rgn, rgn, ancestorRgn, RGN_AND) == ERROR) { michael@0: ::DeleteObject(ancestorRgn); michael@0: ::DeleteObject(rgn); michael@0: return 0; michael@0: } michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: pluginGetClipRegionRectCount(InstanceData* instanceData) michael@0: { michael@0: RGNDATA* data = computeClipRegion(instanceData); michael@0: if (!data) michael@0: return NPTEST_INT32_ERROR; michael@0: michael@0: int32_t result = data->rdh.nCount; michael@0: ::HeapFree(::GetProcessHeap(), 0, data); michael@0: return result; michael@0: } michael@0: michael@0: static int32_t michael@0: addOffset(LONG coord, int32_t offset) michael@0: { michael@0: if (offset == NPTEST_INT32_ERROR) michael@0: return NPTEST_INT32_ERROR; michael@0: return coord + offset; michael@0: } michael@0: michael@0: int32_t michael@0: pluginGetClipRegionRectEdge(InstanceData* instanceData, michael@0: int32_t rectIndex, RectEdge edge) michael@0: { michael@0: RGNDATA* data = computeClipRegion(instanceData); michael@0: if (!data) michael@0: return NPTEST_INT32_ERROR; michael@0: michael@0: HANDLE heap = ::GetProcessHeap(); michael@0: if (rectIndex >= int32_t(data->rdh.nCount)) { michael@0: ::HeapFree(heap, 0, data); michael@0: return NPTEST_INT32_ERROR; michael@0: } michael@0: michael@0: RECT rect = reinterpret_cast(data->Buffer)[rectIndex]; michael@0: ::HeapFree(heap, 0, data); michael@0: michael@0: switch (edge) { michael@0: case EDGE_LEFT: michael@0: return addOffset(rect.left, pluginGetEdge(instanceData, EDGE_LEFT)); michael@0: case EDGE_TOP: michael@0: return addOffset(rect.top, pluginGetEdge(instanceData, EDGE_TOP)); michael@0: case EDGE_RIGHT: michael@0: return addOffset(rect.right, pluginGetEdge(instanceData, EDGE_LEFT)); michael@0: case EDGE_BOTTOM: michael@0: return addOffset(rect.bottom, pluginGetEdge(instanceData, EDGE_TOP)); michael@0: } michael@0: michael@0: return NPTEST_INT32_ERROR; michael@0: } michael@0: michael@0: /* windowless plugin events */ michael@0: michael@0: static bool michael@0: handleEventInternal(InstanceData* instanceData, NPEvent* pe, LRESULT* result) michael@0: { michael@0: switch ((UINT)pe->event) { michael@0: case WM_PAINT: michael@0: pluginDraw(instanceData); michael@0: return true; michael@0: michael@0: case WM_MOUSEACTIVATE: michael@0: if (instanceData->hasWidget) { michael@0: ::SetFocus((HWND)instanceData->window.window); michael@0: *result = MA_ACTIVATEANDEAT; michael@0: return true; michael@0: } michael@0: return false; michael@0: michael@0: case WM_MOUSEWHEEL: michael@0: return true; michael@0: michael@0: case WM_WINDOWPOSCHANGED: { michael@0: WINDOWPOS* pPos = (WINDOWPOS*)pe->lParam; michael@0: instanceData->winX = instanceData->winY = 0; michael@0: if (pPos) { michael@0: instanceData->winX = pPos->x; michael@0: instanceData->winY = pPos->y; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: case WM_MOUSEMOVE: michael@0: case WM_LBUTTONDOWN: michael@0: case WM_LBUTTONUP: michael@0: case WM_MBUTTONDOWN: michael@0: case WM_MBUTTONUP: michael@0: case WM_RBUTTONDOWN: michael@0: case WM_RBUTTONUP: { michael@0: int x = instanceData->hasWidget ? 0 : instanceData->winX; michael@0: int y = instanceData->hasWidget ? 0 : instanceData->winY; michael@0: instanceData->lastMouseX = GET_X_LPARAM(pe->lParam) - x; michael@0: instanceData->lastMouseY = GET_Y_LPARAM(pe->lParam) - y; michael@0: if ((UINT)pe->event == WM_LBUTTONUP) { michael@0: instanceData->mouseUpEventCount++; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: case WM_KEYDOWN: michael@0: instanceData->lastKeyText.erase(); michael@0: *result = 0; michael@0: return true; michael@0: michael@0: case WM_CHAR: { michael@0: *result = 0; michael@0: wchar_t uniChar = static_cast(pe->wParam); michael@0: if (!uniChar) { michael@0: return true; michael@0: } michael@0: char utf8Char[6]; michael@0: int len = michael@0: ::WideCharToMultiByte(CP_UTF8, 0, &uniChar, 1, utf8Char, 6, michael@0: nullptr, nullptr); michael@0: if (len == 0 || len > 6) { michael@0: return true; michael@0: } michael@0: instanceData->lastKeyText.append(utf8Char, len); michael@0: return true; michael@0: } michael@0: michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: int16_t michael@0: pluginHandleEvent(InstanceData* instanceData, void* event) michael@0: { michael@0: NPEvent* pe = (NPEvent*)event; michael@0: michael@0: if (pe == nullptr || instanceData == nullptr || michael@0: instanceData->window.type != NPWindowTypeDrawable) michael@0: return 0; michael@0: michael@0: LRESULT result = 0; michael@0: return handleEventInternal(instanceData, pe, &result); michael@0: } michael@0: michael@0: /* windowed plugin events */ michael@0: michael@0: LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: WNDPROC wndProc = (WNDPROC)GetProp(hWnd, "MozillaWndProc"); michael@0: if (!wndProc) michael@0: return 0; michael@0: InstanceData* pInstance = (InstanceData*)GetProp(hWnd, "InstanceData"); michael@0: if (!pInstance) michael@0: return 0; michael@0: michael@0: NPEvent event = { static_cast(uMsg), wParam, lParam }; michael@0: michael@0: LRESULT result = 0; michael@0: if (handleEventInternal(pInstance, &event, &result)) michael@0: return result; michael@0: michael@0: if (uMsg == WM_CLOSE) { michael@0: ClearSubclass((HWND)pInstance->window.window); michael@0: } michael@0: michael@0: return CallWindowProc(wndProc, hWnd, uMsg, wParam, lParam); michael@0: } michael@0: michael@0: void michael@0: ClearSubclass(HWND hWnd) michael@0: { michael@0: if (GetProp(hWnd, "MozillaWndProc")) { michael@0: ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)GetProp(hWnd, "MozillaWndProc")); michael@0: RemoveProp(hWnd, "MozillaWndProc"); michael@0: RemoveProp(hWnd, "InstanceData"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SetSubclass(HWND hWnd, InstanceData* instanceData) michael@0: { michael@0: // Subclass the plugin window so we can handle our own windows events. michael@0: SetProp(hWnd, "InstanceData", (HANDLE)instanceData); michael@0: WNDPROC origProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); michael@0: SetProp(hWnd, "MozillaWndProc", (HANDLE)origProc); michael@0: } michael@0: michael@0: static void checkEquals(int a, int b, const char* msg, string& error) michael@0: { michael@0: if (a == b) { michael@0: return; michael@0: } michael@0: michael@0: error.append(msg); michael@0: char buf[100]; michael@0: sprintf(buf, " (got %d, expected %d)\n", a, b); michael@0: error.append(buf); michael@0: } michael@0: michael@0: void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error) michael@0: { michael@0: if (instanceData->platformData->childWindow) { michael@0: RECT childRect; michael@0: ::GetWindowRect(instanceData->platformData->childWindow, &childRect); michael@0: RECT ourRect; michael@0: HWND hWnd = (HWND)instanceData->window.window; michael@0: ::GetWindowRect(hWnd, &ourRect); michael@0: checkEquals(childRect.left, ourRect.left, "Child widget left", error); michael@0: checkEquals(childRect.top, ourRect.top, "Child widget top", error); michael@0: checkEquals(childRect.right, childRect.left + CHILD_WIDGET_SIZE, "Child widget width", error); michael@0: checkEquals(childRect.bottom, childRect.top + CHILD_WIDGET_SIZE, "Child widget height", error); michael@0: } michael@0: } michael@0: michael@0: void michael@0: pluginDrawAsyncDxgiColor(InstanceData* id) michael@0: { michael@0: PlatformData *pd = id->platformData; michael@0: michael@0: ID3D10Device1 *dev = pd->device; michael@0: michael@0: IDXGIKeyedMutex *mutex; michael@0: pd->backBuffer->QueryInterface(&mutex); michael@0: michael@0: mutex->AcquireSync(0, INFINITE); michael@0: ID3D10RenderTargetView *rtView; michael@0: dev->CreateRenderTargetView(pd->backBuffer, nullptr, &rtView); michael@0: michael@0: uint32_t rgba = id->scriptableObject->drawColor; michael@0: michael@0: unsigned char subpixels[4]; michael@0: subpixels[0] = rgba & 0xFF; michael@0: subpixels[1] = (rgba & 0xFF00) >> 8; michael@0: subpixels[2] = (rgba & 0xFF0000) >> 16; michael@0: subpixels[3] = (rgba & 0xFF000000) >> 24; michael@0: michael@0: float color[4]; michael@0: color[2] = float(subpixels[3] * subpixels[0]) / 0xFE01; michael@0: color[1] = float(subpixels[3] * subpixels[1]) / 0xFE01; michael@0: color[0] = float(subpixels[3] * subpixels[2]) / 0xFE01; michael@0: color[3] = float(subpixels[3]) / 0xFF; michael@0: dev->ClearRenderTargetView(rtView, color); michael@0: rtView->Release(); michael@0: michael@0: mutex->ReleaseSync(0); michael@0: mutex->Release(); michael@0: michael@0: NPN_SetCurrentAsyncSurface(id->npp, id->backBuffer, nullptr); michael@0: NPAsyncSurface *oldFront = id->frontBuffer; michael@0: id->frontBuffer = id->backBuffer; michael@0: id->backBuffer = oldFront; michael@0: ID3D10Texture2D *oldFrontT = pd->frontBuffer; michael@0: pd->frontBuffer = pd->backBuffer; michael@0: pd->backBuffer = oldFrontT; michael@0: }