diff --git a/dom/plugins/test/mochitest/mochitest.ini b/dom/plugins/test/mochitest/mochitest.ini index 6494bc7ac9b2..6ed983d34c6b 100644 --- a/dom/plugins/test/mochitest/mochitest.ini +++ b/dom/plugins/test/mochitest/mochitest.ini @@ -116,6 +116,8 @@ skip-if = toolkit != "cocoa" [test_twostreams.html] [test_windowed_invalidate.html] skip-if = os != "win" +[test_windowless_ime.html] +skip-if = os != "win" [test_visibility.html] skip-if = toolkit == "cocoa" [test_zero_opacity.html] diff --git a/dom/plugins/test/mochitest/test_windowless_ime.html b/dom/plugins/test/mochitest/test_windowless_ime.html new file mode 100644 index 000000000000..8a1264fdc2a9 --- /dev/null +++ b/dom/plugins/test/mochitest/test_windowless_ime.html @@ -0,0 +1,46 @@ + + + + + Test #1 for Bug 539565 + + + + + + + + + + + + diff --git a/dom/plugins/test/testplugin/nptest.cpp b/dom/plugins/test/testplugin/nptest.cpp index 6e3dc640a9b0..6651ce349681 100644 --- a/dom/plugins/test/testplugin/nptest.cpp +++ b/dom/plugins/test/testplugin/nptest.cpp @@ -173,6 +173,7 @@ static bool startAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t static bool stopAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool getAudioMuted(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool getLastCompositionText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static const NPUTF8* sPluginMethodIdentifierNames[] = { "npnEvaluateTest", @@ -244,6 +245,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = { "stopAudioPlayback", "audioMuted", "nativeWidgetIsVisible", + "getLastCompositionText", }; static NPIdentifier sPluginMethodIdentifiers[MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames)]; static const ScriptableFunction sPluginMethodFunctions[] = { @@ -316,6 +318,7 @@ static const ScriptableFunction sPluginMethodFunctions[] = { stopAudioPlayback, getAudioMuted, nativeWidgetIsVisible, + getLastCompositionText, }; static_assert(MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames) == @@ -852,6 +855,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* instanceData->asyncDrawing = AD_NONE; instanceData->frontBuffer = nullptr; instanceData->backBuffer = nullptr; + instanceData->placeholderWnd = nullptr; instance->pdata = instanceData; TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass); @@ -3514,6 +3518,26 @@ nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args, } #endif +bool +getLastCompositionText(NPObject* npobj, const NPVariant* args, + uint32_t argCount, NPVariant* result) +{ +#ifdef XP_WIN + if (argCount != 0) { + return false; + } + + NPP npp = static_cast(npobj)->npp; + InstanceData* id = static_cast(npp->pdata); + char *outval = NPN_StrDup(id->lastComposition.c_str()); + STRINGZ_TO_NPVARIANT(outval, *result); + return true; +#else + // XXX not implemented + return false; +#endif +} + bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { diff --git a/dom/plugins/test/testplugin/nptest.h b/dom/plugins/test/testplugin/nptest.h index 12e427a5e60f..2fbc2d4b437c 100644 --- a/dom/plugins/test/testplugin/nptest.h +++ b/dom/plugins/test/testplugin/nptest.h @@ -156,6 +156,8 @@ typedef struct InstanceData { AsyncDrawing asyncDrawing; NPAsyncSurface *frontBuffer; NPAsyncSurface *backBuffer; + std::string lastComposition; + void* placeholderWnd; } InstanceData; void notifyDidPaint(InstanceData* instanceData); diff --git a/dom/plugins/test/testplugin/nptest_windows.cpp b/dom/plugins/test/testplugin/nptest_windows.cpp index 3d807bc532ec..8b02872e9540 100644 --- a/dom/plugins/test/testplugin/nptest_windows.cpp +++ b/dom/plugins/test/testplugin/nptest_windows.cpp @@ -654,6 +654,29 @@ pluginGetClipRegionRectEdge(InstanceData* instanceData, return NPTEST_INT32_ERROR; } +static +void +createDummyWindowForIME(InstanceData* instanceData) +{ + WNDCLASSW wndClass; + wndClass.style = 0; + wndClass.lpfnWndProc = DefWindowProcW; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = GetModuleHandleW(NULL); + wndClass.hIcon = nullptr; + wndClass.hCursor = nullptr; + wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW; + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = L"SWFlash_PlaceholderX"; + RegisterClassW(&wndClass); + + instanceData->placeholderWnd = + static_cast(CreateWindowW(L"SWFlash_PlaceholderX", L"", WS_CHILD, 0, + 0, 0, 0, HWND_MESSAGE, NULL, + GetModuleHandleW(NULL), NULL)); +} + /* windowless plugin events */ static bool @@ -725,6 +748,35 @@ handleEventInternal(InstanceData* instanceData, NPEvent* pe, LRESULT* result) return true; } + case WM_IME_STARTCOMPOSITION: + instanceData->lastComposition.erase(); + if (!instanceData->placeholderWnd) { + createDummyWindowForIME(instanceData); + } + return true; + + case WM_IME_ENDCOMPOSITION: + instanceData->lastComposition.erase(); + return true; + + case WM_IME_COMPOSITION: { + if (pe->lParam & GCS_COMPSTR) { + HIMC hIMC = ImmGetContext((HWND)instanceData->placeholderWnd); + if (!hIMC) { + return false; + } + WCHAR compStr[256]; + LONG len = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, compStr, + 256 * sizeof(WCHAR)); + CHAR buffer[256]; + len = ::WideCharToMultiByte(CP_UTF8, 0, compStr, len / sizeof(WCHAR), + buffer, 256, nullptr, nullptr); + instanceData->lastComposition.append(buffer, len); + ::ImmReleaseContext((HWND)instanceData->placeholderWnd, hIMC); + } + return true; + } + default: return false; } diff --git a/dom/plugins/test/testplugin/testplugin.mozbuild b/dom/plugins/test/testplugin/testplugin.mozbuild index e8e1a7615cce..86e3fc24a7c9 100644 --- a/dom/plugins/test/testplugin/testplugin.mozbuild +++ b/dom/plugins/test/testplugin/testplugin.mozbuild @@ -38,6 +38,7 @@ elif toolkit == 'windows': ] OS_LIBS += [ 'msimg32', + 'imm32' ] # must link statically with the CRT; nptest isn't Gecko code