|
1 /* ***** BEGIN LICENSE BLOCK ***** |
|
2 * |
|
3 * Copyright (c) 2008, Mozilla Corporation |
|
4 * All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * * Redistributions of source code must retain the above copyright notice, this |
|
10 * list of conditions and the following disclaimer. |
|
11 * * Redistributions in binary form must reproduce the above copyright notice, |
|
12 * this list of conditions and the following disclaimer in the documentation |
|
13 * and/or other materials provided with the distribution. |
|
14 * * Neither the name of the Mozilla Corporation nor the names of its |
|
15 * contributors may be used to endorse or promote products derived from this |
|
16 * software without specific prior written permission. |
|
17 * |
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
|
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
|
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Contributor(s): |
|
30 * Josh Aas <josh@mozilla.com> |
|
31 * Jim Mathies <jmathies@mozilla.com> |
|
32 * |
|
33 * ***** END LICENSE BLOCK ***** */ |
|
34 |
|
35 #include "nptest_platform.h" |
|
36 |
|
37 #include <windows.h> |
|
38 #include <windowsx.h> |
|
39 #include <stdio.h> |
|
40 |
|
41 #include <d3d10_1.h> |
|
42 |
|
43 using namespace std; |
|
44 |
|
45 void SetSubclass(HWND hWnd, InstanceData* instanceData); |
|
46 void ClearSubclass(HWND hWnd); |
|
47 LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
|
48 |
|
49 struct _PlatformData { |
|
50 HWND childWindow; |
|
51 ID3D10Device1 *device; |
|
52 ID3D10Texture2D *frontBuffer; |
|
53 ID3D10Texture2D *backBuffer; |
|
54 }; |
|
55 |
|
56 bool |
|
57 pluginSupportsWindowMode() |
|
58 { |
|
59 return true; |
|
60 } |
|
61 |
|
62 bool |
|
63 pluginSupportsWindowlessMode() |
|
64 { |
|
65 return true; |
|
66 } |
|
67 |
|
68 bool |
|
69 pluginSupportsAsyncBitmapDrawing() |
|
70 { |
|
71 return true; |
|
72 } |
|
73 |
|
74 NPError |
|
75 pluginInstanceInit(InstanceData* instanceData) |
|
76 { |
|
77 NPP npp = instanceData->npp; |
|
78 |
|
79 instanceData->platformData = static_cast<PlatformData*> |
|
80 (NPN_MemAlloc(sizeof(PlatformData))); |
|
81 if (!instanceData->platformData) |
|
82 return NPERR_OUT_OF_MEMORY_ERROR; |
|
83 |
|
84 instanceData->platformData->childWindow = nullptr; |
|
85 instanceData->platformData->device = nullptr; |
|
86 instanceData->platformData->frontBuffer = nullptr; |
|
87 instanceData->platformData->backBuffer = nullptr; |
|
88 return NPERR_NO_ERROR; |
|
89 } |
|
90 |
|
91 void |
|
92 pluginInstanceShutdown(InstanceData* instanceData) |
|
93 { |
|
94 PlatformData *pd = instanceData->platformData; |
|
95 if (pd->frontBuffer) { |
|
96 pd->frontBuffer->Release(); |
|
97 } |
|
98 if (pd->backBuffer) { |
|
99 pd->backBuffer->Release(); |
|
100 } |
|
101 if (pd->device) { |
|
102 pd->device->Release(); |
|
103 } |
|
104 NPN_MemFree(instanceData->platformData); |
|
105 instanceData->platformData = 0; |
|
106 } |
|
107 |
|
108 static ID3D10Device1* |
|
109 getD3D10Device() |
|
110 { |
|
111 ID3D10Device1 *device; |
|
112 |
|
113 HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); |
|
114 decltype(D3D10CreateDevice1)* createD3DDevice = |
|
115 (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, |
|
116 "D3D10CreateDevice1"); |
|
117 |
|
118 if (createD3DDevice) { |
|
119 HMODULE dxgiModule = LoadLibraryA("dxgi.dll"); |
|
120 decltype(CreateDXGIFactory1)* createDXGIFactory1 = |
|
121 (decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, |
|
122 "CreateDXGIFactory1"); |
|
123 |
|
124 HRESULT hr; |
|
125 |
|
126 // Try to use a DXGI 1.1 adapter in order to share resources |
|
127 // across processes. |
|
128 IDXGIAdapter1 *adapter1; |
|
129 if (createDXGIFactory1) { |
|
130 IDXGIFactory1 *factory1; |
|
131 hr = createDXGIFactory1(__uuidof(IDXGIFactory1), |
|
132 (void**)&factory1); |
|
133 |
|
134 if (FAILED(hr) || !factory1) { |
|
135 // Uh-oh |
|
136 return nullptr; |
|
137 } |
|
138 |
|
139 hr = factory1->EnumAdapters1(0, &adapter1); |
|
140 |
|
141 if (SUCCEEDED(hr) && adapter1) { |
|
142 hr = adapter1->CheckInterfaceSupport(__uuidof(ID3D10Device), |
|
143 nullptr); |
|
144 if (FAILED(hr)) { |
|
145 adapter1 = nullptr; |
|
146 } |
|
147 } |
|
148 factory1->Release(); |
|
149 } |
|
150 |
|
151 hr = createD3DDevice( |
|
152 adapter1, |
|
153 D3D10_DRIVER_TYPE_HARDWARE, |
|
154 nullptr, |
|
155 D3D10_CREATE_DEVICE_BGRA_SUPPORT | |
|
156 D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, |
|
157 D3D10_FEATURE_LEVEL_10_0, |
|
158 D3D10_1_SDK_VERSION, |
|
159 &device); |
|
160 |
|
161 adapter1->Release(); |
|
162 } |
|
163 |
|
164 return device; |
|
165 } |
|
166 |
|
167 void |
|
168 pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) |
|
169 { |
|
170 instanceData->window = *newWindow; |
|
171 NPP npp = instanceData->npp; |
|
172 |
|
173 if (instanceData->asyncDrawing == AD_DXGI) { |
|
174 if (instanceData->frontBuffer && |
|
175 instanceData->frontBuffer->size.width == newWindow->width && |
|
176 instanceData->frontBuffer->size.height == newWindow->height) { |
|
177 return; |
|
178 } |
|
179 if (instanceData->frontBuffer) { |
|
180 instanceData->platformData->frontBuffer->Release(); |
|
181 instanceData->platformData->frontBuffer = nullptr; |
|
182 NPN_FinalizeAsyncSurface(npp, instanceData->frontBuffer); |
|
183 NPN_MemFree(instanceData->frontBuffer); |
|
184 } |
|
185 if (instanceData->backBuffer) { |
|
186 instanceData->platformData->backBuffer->Release(); |
|
187 instanceData->platformData->backBuffer = nullptr; |
|
188 NPN_FinalizeAsyncSurface(npp, instanceData->backBuffer); |
|
189 NPN_MemFree(instanceData->backBuffer); |
|
190 } |
|
191 |
|
192 if (!instanceData->platformData->device) { |
|
193 instanceData->platformData->device = getD3D10Device(); |
|
194 } |
|
195 |
|
196 ID3D10Device1 *dev = instanceData->platformData->device; |
|
197 |
|
198 if (!dev) { |
|
199 return; |
|
200 } |
|
201 |
|
202 instanceData->frontBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface)); |
|
203 instanceData->backBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface)); |
|
204 |
|
205 NPSize size; |
|
206 size.width = newWindow->width; |
|
207 size.height = newWindow->height; |
|
208 |
|
209 memset(instanceData->frontBuffer, 0, sizeof(NPAsyncSurface)); |
|
210 memset(instanceData->backBuffer, 0, sizeof(NPAsyncSurface)); |
|
211 |
|
212 NPN_InitAsyncSurface(npp, &size, NPImageFormatBGRA32, nullptr, instanceData->frontBuffer); |
|
213 NPN_InitAsyncSurface(npp, &size, NPImageFormatBGRA32, nullptr, instanceData->backBuffer); |
|
214 |
|
215 dev->OpenSharedResource(instanceData->frontBuffer->sharedHandle, __uuidof(ID3D10Texture2D), (void**)&instanceData->platformData->frontBuffer); |
|
216 dev->OpenSharedResource(instanceData->backBuffer->sharedHandle, __uuidof(ID3D10Texture2D), (void**)&instanceData->platformData->backBuffer); |
|
217 |
|
218 pluginDrawAsyncDxgiColor(instanceData); |
|
219 } |
|
220 } |
|
221 |
|
222 #define CHILD_WIDGET_SIZE 10 |
|
223 |
|
224 void |
|
225 pluginWidgetInit(InstanceData* instanceData, void* oldWindow) |
|
226 { |
|
227 HWND hWnd = (HWND)instanceData->window.window; |
|
228 if (oldWindow) { |
|
229 // chrashtests/539897-1.html excercises this code |
|
230 HWND hWndOld = (HWND)oldWindow; |
|
231 ClearSubclass(hWndOld); |
|
232 if (instanceData->platformData->childWindow) { |
|
233 ::DestroyWindow(instanceData->platformData->childWindow); |
|
234 } |
|
235 } |
|
236 |
|
237 SetSubclass(hWnd, instanceData); |
|
238 |
|
239 instanceData->platformData->childWindow = |
|
240 ::CreateWindowW(L"SCROLLBAR", L"Dummy child window", |
|
241 WS_CHILD, 0, 0, CHILD_WIDGET_SIZE, CHILD_WIDGET_SIZE, hWnd, nullptr, |
|
242 nullptr, nullptr); |
|
243 } |
|
244 |
|
245 static void |
|
246 drawToDC(InstanceData* instanceData, HDC dc, |
|
247 int x, int y, int width, int height) |
|
248 { |
|
249 switch (instanceData->scriptableObject->drawMode) { |
|
250 case DM_DEFAULT: |
|
251 { |
|
252 const RECT fill = { x, y, x + width, y + height }; |
|
253 |
|
254 int oldBkMode = ::SetBkMode(dc, TRANSPARENT); |
|
255 HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); |
|
256 if (brush) { |
|
257 ::FillRect(dc, &fill, brush); |
|
258 ::DeleteObject(brush); |
|
259 } |
|
260 if (width > 6 && height > 6) { |
|
261 brush = ::CreateSolidBrush(RGB(192, 192, 192)); |
|
262 if (brush) { |
|
263 RECT inset = { x + 3, y + 3, x + width - 3, y + height - 3 }; |
|
264 ::FillRect(dc, &inset, brush); |
|
265 ::DeleteObject(brush); |
|
266 } |
|
267 } |
|
268 |
|
269 const char* uaString = NPN_UserAgent(instanceData->npp); |
|
270 if (uaString && width > 10 && height > 10) { |
|
271 HFONT font = |
|
272 ::CreateFontA(20, 0, 0, 0, 400, FALSE, FALSE, FALSE, |
|
273 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, |
|
274 CLIP_DEFAULT_PRECIS, 5, // CLEARTYPE_QUALITY |
|
275 DEFAULT_PITCH, "Arial"); |
|
276 if (font) { |
|
277 HFONT oldFont = (HFONT)::SelectObject(dc, font); |
|
278 RECT inset = { x + 5, y + 5, x + width - 5, y + height - 5 }; |
|
279 ::DrawTextA(dc, uaString, -1, &inset, |
|
280 DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK); |
|
281 ::SelectObject(dc, oldFont); |
|
282 ::DeleteObject(font); |
|
283 } |
|
284 } |
|
285 ::SetBkMode(dc, oldBkMode); |
|
286 } |
|
287 break; |
|
288 |
|
289 case DM_SOLID_COLOR: |
|
290 { |
|
291 HDC offscreenDC = ::CreateCompatibleDC(dc); |
|
292 if (!offscreenDC) |
|
293 return; |
|
294 |
|
295 const BITMAPV4HEADER bitmapheader = { |
|
296 sizeof(BITMAPV4HEADER), |
|
297 width, |
|
298 height, |
|
299 1, // planes |
|
300 32, // bits |
|
301 BI_BITFIELDS, |
|
302 0, // unused size |
|
303 0, 0, // unused metrics |
|
304 0, 0, // unused colors used/important |
|
305 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, // ARGB masks |
|
306 }; |
|
307 uint32_t *pixelData; |
|
308 HBITMAP offscreenBitmap = |
|
309 ::CreateDIBSection(dc, reinterpret_cast<const BITMAPINFO*>(&bitmapheader), |
|
310 0, reinterpret_cast<void**>(&pixelData), 0, 0); |
|
311 if (!offscreenBitmap) |
|
312 return; |
|
313 |
|
314 uint32_t rgba = instanceData->scriptableObject->drawColor; |
|
315 unsigned int alpha = ((rgba & 0xFF000000) >> 24); |
|
316 BYTE r = ((rgba & 0xFF0000) >> 16); |
|
317 BYTE g = ((rgba & 0xFF00) >> 8); |
|
318 BYTE b = (rgba & 0xFF); |
|
319 |
|
320 // Windows expects premultiplied |
|
321 r = BYTE(float(alpha * r) / 0xFF); |
|
322 g = BYTE(float(alpha * g) / 0xFF); |
|
323 b = BYTE(float(alpha * b) / 0xFF); |
|
324 uint32_t premultiplied = |
|
325 (alpha << 24) + (r << 16) + (g << 8) + b; |
|
326 |
|
327 for (uint32_t* lastPixel = pixelData + width * height; |
|
328 pixelData < lastPixel; |
|
329 ++pixelData) |
|
330 *pixelData = premultiplied; |
|
331 |
|
332 ::SelectObject(offscreenDC, offscreenBitmap); |
|
333 BLENDFUNCTION blendFunc; |
|
334 blendFunc.BlendOp = AC_SRC_OVER; |
|
335 blendFunc.BlendFlags = 0; |
|
336 blendFunc.SourceConstantAlpha = 255; |
|
337 blendFunc.AlphaFormat = AC_SRC_ALPHA; |
|
338 ::AlphaBlend(dc, x, y, width, height, offscreenDC, 0, 0, width, height, |
|
339 blendFunc); |
|
340 |
|
341 ::DeleteObject(offscreenDC); |
|
342 ::DeleteObject(offscreenBitmap); |
|
343 } |
|
344 break; |
|
345 } |
|
346 } |
|
347 |
|
348 void |
|
349 pluginDraw(InstanceData* instanceData) |
|
350 { |
|
351 NPP npp = instanceData->npp; |
|
352 if (!npp) |
|
353 return; |
|
354 |
|
355 HDC hdc = nullptr; |
|
356 PAINTSTRUCT ps; |
|
357 |
|
358 notifyDidPaint(instanceData); |
|
359 |
|
360 if (instanceData->hasWidget) |
|
361 hdc = ::BeginPaint((HWND)instanceData->window.window, &ps); |
|
362 else |
|
363 hdc = (HDC)instanceData->window.window; |
|
364 |
|
365 if (hdc == nullptr) |
|
366 return; |
|
367 |
|
368 // Push the browser's hdc on the resource stack. If this test plugin is windowless, |
|
369 // we share the drawing surface with the rest of the browser. |
|
370 int savedDCID = SaveDC(hdc); |
|
371 |
|
372 // When we have a widget, window.x/y are meaningless since our widget |
|
373 // is always positioned correctly and we just draw into it at 0,0. |
|
374 int x = instanceData->hasWidget ? 0 : instanceData->window.x; |
|
375 int y = instanceData->hasWidget ? 0 : instanceData->window.y; |
|
376 int width = instanceData->window.width; |
|
377 int height = instanceData->window.height; |
|
378 drawToDC(instanceData, hdc, x, y, width, height); |
|
379 |
|
380 // Pop our hdc changes off the resource stack |
|
381 RestoreDC(hdc, savedDCID); |
|
382 |
|
383 if (instanceData->hasWidget) |
|
384 ::EndPaint((HWND)instanceData->window.window, &ps); |
|
385 } |
|
386 |
|
387 /* script interface */ |
|
388 |
|
389 int32_t |
|
390 pluginGetEdge(InstanceData* instanceData, RectEdge edge) |
|
391 { |
|
392 if (!instanceData || !instanceData->hasWidget) |
|
393 return NPTEST_INT32_ERROR; |
|
394 |
|
395 // Get the plugin client rect in screen coordinates |
|
396 RECT rect = {0}; |
|
397 if (!::GetClientRect((HWND)instanceData->window.window, &rect)) |
|
398 return NPTEST_INT32_ERROR; |
|
399 ::MapWindowPoints((HWND)instanceData->window.window, nullptr, |
|
400 (LPPOINT)&rect, 2); |
|
401 |
|
402 // Get the toplevel window frame rect in screen coordinates |
|
403 HWND rootWnd = ::GetAncestor((HWND)instanceData->window.window, GA_ROOT); |
|
404 if (!rootWnd) |
|
405 return NPTEST_INT32_ERROR; |
|
406 RECT rootRect; |
|
407 if (!::GetWindowRect(rootWnd, &rootRect)) |
|
408 return NPTEST_INT32_ERROR; |
|
409 |
|
410 switch (edge) { |
|
411 case EDGE_LEFT: |
|
412 return rect.left - rootRect.left; |
|
413 case EDGE_TOP: |
|
414 return rect.top - rootRect.top; |
|
415 case EDGE_RIGHT: |
|
416 return rect.right - rootRect.left; |
|
417 case EDGE_BOTTOM: |
|
418 return rect.bottom - rootRect.top; |
|
419 } |
|
420 |
|
421 return NPTEST_INT32_ERROR; |
|
422 } |
|
423 |
|
424 static BOOL |
|
425 getWindowRegion(HWND wnd, HRGN rgn) |
|
426 { |
|
427 if (::GetWindowRgn(wnd, rgn) != ERROR) |
|
428 return TRUE; |
|
429 |
|
430 RECT clientRect; |
|
431 if (!::GetClientRect(wnd, &clientRect)) |
|
432 return FALSE; |
|
433 return ::SetRectRgn(rgn, 0, 0, clientRect.right, clientRect.bottom); |
|
434 } |
|
435 |
|
436 static RGNDATA* |
|
437 computeClipRegion(InstanceData* instanceData) |
|
438 { |
|
439 HWND wnd = (HWND)instanceData->window.window; |
|
440 HRGN rgn = ::CreateRectRgn(0, 0, 0, 0); |
|
441 if (!rgn) |
|
442 return nullptr; |
|
443 HRGN ancestorRgn = ::CreateRectRgn(0, 0, 0, 0); |
|
444 if (!ancestorRgn) { |
|
445 ::DeleteObject(rgn); |
|
446 return nullptr; |
|
447 } |
|
448 if (!getWindowRegion(wnd, rgn)) { |
|
449 ::DeleteObject(ancestorRgn); |
|
450 ::DeleteObject(rgn); |
|
451 return nullptr; |
|
452 } |
|
453 |
|
454 HWND ancestor = wnd; |
|
455 for (;;) { |
|
456 ancestor = ::GetAncestor(ancestor, GA_PARENT); |
|
457 if (!ancestor || ancestor == ::GetDesktopWindow()) { |
|
458 ::DeleteObject(ancestorRgn); |
|
459 |
|
460 DWORD size = ::GetRegionData(rgn, 0, nullptr); |
|
461 if (!size) { |
|
462 ::DeleteObject(rgn); |
|
463 return nullptr; |
|
464 } |
|
465 |
|
466 HANDLE heap = ::GetProcessHeap(); |
|
467 RGNDATA* data = static_cast<RGNDATA*>(::HeapAlloc(heap, 0, size)); |
|
468 if (!data) { |
|
469 ::DeleteObject(rgn); |
|
470 return nullptr; |
|
471 } |
|
472 DWORD result = ::GetRegionData(rgn, size, data); |
|
473 ::DeleteObject(rgn); |
|
474 if (!result) { |
|
475 ::HeapFree(heap, 0, data); |
|
476 return nullptr; |
|
477 } |
|
478 |
|
479 return data; |
|
480 } |
|
481 |
|
482 if (!getWindowRegion(ancestor, ancestorRgn)) { |
|
483 ::DeleteObject(ancestorRgn); |
|
484 ::DeleteObject(rgn); |
|
485 return 0; |
|
486 } |
|
487 |
|
488 POINT pt = { 0, 0 }; |
|
489 ::MapWindowPoints(ancestor, wnd, &pt, 1); |
|
490 if (::OffsetRgn(ancestorRgn, pt.x, pt.y) == ERROR || |
|
491 ::CombineRgn(rgn, rgn, ancestorRgn, RGN_AND) == ERROR) { |
|
492 ::DeleteObject(ancestorRgn); |
|
493 ::DeleteObject(rgn); |
|
494 return 0; |
|
495 } |
|
496 } |
|
497 } |
|
498 |
|
499 int32_t |
|
500 pluginGetClipRegionRectCount(InstanceData* instanceData) |
|
501 { |
|
502 RGNDATA* data = computeClipRegion(instanceData); |
|
503 if (!data) |
|
504 return NPTEST_INT32_ERROR; |
|
505 |
|
506 int32_t result = data->rdh.nCount; |
|
507 ::HeapFree(::GetProcessHeap(), 0, data); |
|
508 return result; |
|
509 } |
|
510 |
|
511 static int32_t |
|
512 addOffset(LONG coord, int32_t offset) |
|
513 { |
|
514 if (offset == NPTEST_INT32_ERROR) |
|
515 return NPTEST_INT32_ERROR; |
|
516 return coord + offset; |
|
517 } |
|
518 |
|
519 int32_t |
|
520 pluginGetClipRegionRectEdge(InstanceData* instanceData, |
|
521 int32_t rectIndex, RectEdge edge) |
|
522 { |
|
523 RGNDATA* data = computeClipRegion(instanceData); |
|
524 if (!data) |
|
525 return NPTEST_INT32_ERROR; |
|
526 |
|
527 HANDLE heap = ::GetProcessHeap(); |
|
528 if (rectIndex >= int32_t(data->rdh.nCount)) { |
|
529 ::HeapFree(heap, 0, data); |
|
530 return NPTEST_INT32_ERROR; |
|
531 } |
|
532 |
|
533 RECT rect = reinterpret_cast<RECT*>(data->Buffer)[rectIndex]; |
|
534 ::HeapFree(heap, 0, data); |
|
535 |
|
536 switch (edge) { |
|
537 case EDGE_LEFT: |
|
538 return addOffset(rect.left, pluginGetEdge(instanceData, EDGE_LEFT)); |
|
539 case EDGE_TOP: |
|
540 return addOffset(rect.top, pluginGetEdge(instanceData, EDGE_TOP)); |
|
541 case EDGE_RIGHT: |
|
542 return addOffset(rect.right, pluginGetEdge(instanceData, EDGE_LEFT)); |
|
543 case EDGE_BOTTOM: |
|
544 return addOffset(rect.bottom, pluginGetEdge(instanceData, EDGE_TOP)); |
|
545 } |
|
546 |
|
547 return NPTEST_INT32_ERROR; |
|
548 } |
|
549 |
|
550 /* windowless plugin events */ |
|
551 |
|
552 static bool |
|
553 handleEventInternal(InstanceData* instanceData, NPEvent* pe, LRESULT* result) |
|
554 { |
|
555 switch ((UINT)pe->event) { |
|
556 case WM_PAINT: |
|
557 pluginDraw(instanceData); |
|
558 return true; |
|
559 |
|
560 case WM_MOUSEACTIVATE: |
|
561 if (instanceData->hasWidget) { |
|
562 ::SetFocus((HWND)instanceData->window.window); |
|
563 *result = MA_ACTIVATEANDEAT; |
|
564 return true; |
|
565 } |
|
566 return false; |
|
567 |
|
568 case WM_MOUSEWHEEL: |
|
569 return true; |
|
570 |
|
571 case WM_WINDOWPOSCHANGED: { |
|
572 WINDOWPOS* pPos = (WINDOWPOS*)pe->lParam; |
|
573 instanceData->winX = instanceData->winY = 0; |
|
574 if (pPos) { |
|
575 instanceData->winX = pPos->x; |
|
576 instanceData->winY = pPos->y; |
|
577 return true; |
|
578 } |
|
579 return false; |
|
580 } |
|
581 |
|
582 case WM_MOUSEMOVE: |
|
583 case WM_LBUTTONDOWN: |
|
584 case WM_LBUTTONUP: |
|
585 case WM_MBUTTONDOWN: |
|
586 case WM_MBUTTONUP: |
|
587 case WM_RBUTTONDOWN: |
|
588 case WM_RBUTTONUP: { |
|
589 int x = instanceData->hasWidget ? 0 : instanceData->winX; |
|
590 int y = instanceData->hasWidget ? 0 : instanceData->winY; |
|
591 instanceData->lastMouseX = GET_X_LPARAM(pe->lParam) - x; |
|
592 instanceData->lastMouseY = GET_Y_LPARAM(pe->lParam) - y; |
|
593 if ((UINT)pe->event == WM_LBUTTONUP) { |
|
594 instanceData->mouseUpEventCount++; |
|
595 } |
|
596 return true; |
|
597 } |
|
598 |
|
599 case WM_KEYDOWN: |
|
600 instanceData->lastKeyText.erase(); |
|
601 *result = 0; |
|
602 return true; |
|
603 |
|
604 case WM_CHAR: { |
|
605 *result = 0; |
|
606 wchar_t uniChar = static_cast<wchar_t>(pe->wParam); |
|
607 if (!uniChar) { |
|
608 return true; |
|
609 } |
|
610 char utf8Char[6]; |
|
611 int len = |
|
612 ::WideCharToMultiByte(CP_UTF8, 0, &uniChar, 1, utf8Char, 6, |
|
613 nullptr, nullptr); |
|
614 if (len == 0 || len > 6) { |
|
615 return true; |
|
616 } |
|
617 instanceData->lastKeyText.append(utf8Char, len); |
|
618 return true; |
|
619 } |
|
620 |
|
621 default: |
|
622 return false; |
|
623 } |
|
624 } |
|
625 |
|
626 int16_t |
|
627 pluginHandleEvent(InstanceData* instanceData, void* event) |
|
628 { |
|
629 NPEvent* pe = (NPEvent*)event; |
|
630 |
|
631 if (pe == nullptr || instanceData == nullptr || |
|
632 instanceData->window.type != NPWindowTypeDrawable) |
|
633 return 0; |
|
634 |
|
635 LRESULT result = 0; |
|
636 return handleEventInternal(instanceData, pe, &result); |
|
637 } |
|
638 |
|
639 /* windowed plugin events */ |
|
640 |
|
641 LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
|
642 { |
|
643 WNDPROC wndProc = (WNDPROC)GetProp(hWnd, "MozillaWndProc"); |
|
644 if (!wndProc) |
|
645 return 0; |
|
646 InstanceData* pInstance = (InstanceData*)GetProp(hWnd, "InstanceData"); |
|
647 if (!pInstance) |
|
648 return 0; |
|
649 |
|
650 NPEvent event = { static_cast<uint16_t>(uMsg), wParam, lParam }; |
|
651 |
|
652 LRESULT result = 0; |
|
653 if (handleEventInternal(pInstance, &event, &result)) |
|
654 return result; |
|
655 |
|
656 if (uMsg == WM_CLOSE) { |
|
657 ClearSubclass((HWND)pInstance->window.window); |
|
658 } |
|
659 |
|
660 return CallWindowProc(wndProc, hWnd, uMsg, wParam, lParam); |
|
661 } |
|
662 |
|
663 void |
|
664 ClearSubclass(HWND hWnd) |
|
665 { |
|
666 if (GetProp(hWnd, "MozillaWndProc")) { |
|
667 ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)GetProp(hWnd, "MozillaWndProc")); |
|
668 RemoveProp(hWnd, "MozillaWndProc"); |
|
669 RemoveProp(hWnd, "InstanceData"); |
|
670 } |
|
671 } |
|
672 |
|
673 void |
|
674 SetSubclass(HWND hWnd, InstanceData* instanceData) |
|
675 { |
|
676 // Subclass the plugin window so we can handle our own windows events. |
|
677 SetProp(hWnd, "InstanceData", (HANDLE)instanceData); |
|
678 WNDPROC origProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); |
|
679 SetProp(hWnd, "MozillaWndProc", (HANDLE)origProc); |
|
680 } |
|
681 |
|
682 static void checkEquals(int a, int b, const char* msg, string& error) |
|
683 { |
|
684 if (a == b) { |
|
685 return; |
|
686 } |
|
687 |
|
688 error.append(msg); |
|
689 char buf[100]; |
|
690 sprintf(buf, " (got %d, expected %d)\n", a, b); |
|
691 error.append(buf); |
|
692 } |
|
693 |
|
694 void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error) |
|
695 { |
|
696 if (instanceData->platformData->childWindow) { |
|
697 RECT childRect; |
|
698 ::GetWindowRect(instanceData->platformData->childWindow, &childRect); |
|
699 RECT ourRect; |
|
700 HWND hWnd = (HWND)instanceData->window.window; |
|
701 ::GetWindowRect(hWnd, &ourRect); |
|
702 checkEquals(childRect.left, ourRect.left, "Child widget left", error); |
|
703 checkEquals(childRect.top, ourRect.top, "Child widget top", error); |
|
704 checkEquals(childRect.right, childRect.left + CHILD_WIDGET_SIZE, "Child widget width", error); |
|
705 checkEquals(childRect.bottom, childRect.top + CHILD_WIDGET_SIZE, "Child widget height", error); |
|
706 } |
|
707 } |
|
708 |
|
709 void |
|
710 pluginDrawAsyncDxgiColor(InstanceData* id) |
|
711 { |
|
712 PlatformData *pd = id->platformData; |
|
713 |
|
714 ID3D10Device1 *dev = pd->device; |
|
715 |
|
716 IDXGIKeyedMutex *mutex; |
|
717 pd->backBuffer->QueryInterface(&mutex); |
|
718 |
|
719 mutex->AcquireSync(0, INFINITE); |
|
720 ID3D10RenderTargetView *rtView; |
|
721 dev->CreateRenderTargetView(pd->backBuffer, nullptr, &rtView); |
|
722 |
|
723 uint32_t rgba = id->scriptableObject->drawColor; |
|
724 |
|
725 unsigned char subpixels[4]; |
|
726 subpixels[0] = rgba & 0xFF; |
|
727 subpixels[1] = (rgba & 0xFF00) >> 8; |
|
728 subpixels[2] = (rgba & 0xFF0000) >> 16; |
|
729 subpixels[3] = (rgba & 0xFF000000) >> 24; |
|
730 |
|
731 float color[4]; |
|
732 color[2] = float(subpixels[3] * subpixels[0]) / 0xFE01; |
|
733 color[1] = float(subpixels[3] * subpixels[1]) / 0xFE01; |
|
734 color[0] = float(subpixels[3] * subpixels[2]) / 0xFE01; |
|
735 color[3] = float(subpixels[3]) / 0xFF; |
|
736 dev->ClearRenderTargetView(rtView, color); |
|
737 rtView->Release(); |
|
738 |
|
739 mutex->ReleaseSync(0); |
|
740 mutex->Release(); |
|
741 |
|
742 NPN_SetCurrentAsyncSurface(id->npp, id->backBuffer, nullptr); |
|
743 NPAsyncSurface *oldFront = id->frontBuffer; |
|
744 id->frontBuffer = id->backBuffer; |
|
745 id->backBuffer = oldFront; |
|
746 ID3D10Texture2D *oldFrontT = pd->frontBuffer; |
|
747 pd->frontBuffer = pd->backBuffer; |
|
748 pd->backBuffer = oldFrontT; |
|
749 } |