зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1208944 - Part 9. Hook IMM32 APIs on plugin process. r=masayuki
This commit is contained in:
Родитель
d7699eb987
Коммит
836a9aee5c
|
@ -281,6 +281,11 @@ parent:
|
|||
*/
|
||||
prio(urgent) async SetPluginFocused(bool aFocused);
|
||||
|
||||
/**
|
||||
* Set IME candidate window by windowless plugin if plugin has focus.
|
||||
*/
|
||||
async SetCandidateWindowForPlugin(int32_t aX, int32_t aY);
|
||||
|
||||
/**
|
||||
* Request that the parent process move focus to the browser's frame. If
|
||||
* canRaise is true, the window can be raised if it is inactive.
|
||||
|
|
|
@ -2396,6 +2396,19 @@ TabParent::RecvSetPluginFocused(const bool& aFocused)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSetCandidateWindowForPlugin(const int32_t& aX,
|
||||
const int32_t& aY)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return true;
|
||||
}
|
||||
|
||||
widget->SetCandidateWindowForPlugin(aX, aY);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
|
||||
int32_t* aIMEOpen)
|
||||
|
|
|
@ -196,6 +196,8 @@ public:
|
|||
const int32_t& aPanelY,
|
||||
nsString* aCommitted) override;
|
||||
virtual bool RecvSetPluginFocused(const bool& aFocused) override;
|
||||
virtual bool RecvSetCandidateWindowForPlugin(const int32_t& aX,
|
||||
const int32_t& aY) override;
|
||||
virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
|
||||
int32_t* aIMEOpen) override;
|
||||
virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
|
||||
|
|
|
@ -60,6 +60,8 @@ using mozilla::DefaultXDisplay;
|
|||
#include "nsFrameSelection.h"
|
||||
#include "PuppetWidget.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/TextComposition.h"
|
||||
|
||||
#include "nsContentCID.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
|
@ -791,7 +793,182 @@ nsPluginInstanceOwner::SetNetscapeWindowAsParent(HWND aWindowToAdopt)
|
|||
reinterpret_cast<uintptr_t>(aWindowToAdopt));
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
nsPluginInstanceOwner::GetCompositionString(uint32_t aType,
|
||||
nsTArray<uint8_t>* aDist,
|
||||
int32_t* aLength)
|
||||
{
|
||||
RefPtr<TextComposition> composition = GetTextComposition();
|
||||
if (NS_WARN_IF(!composition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(aType) {
|
||||
case GCS_COMPSTR: {
|
||||
if (!composition->IsComposing()) {
|
||||
*aLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t len = composition->LastData().Length() * sizeof(char16_t);
|
||||
if (len) {
|
||||
aDist->SetLength(len);
|
||||
memcpy(aDist->Elements(), composition->LastData().get(), len);
|
||||
}
|
||||
*aLength = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_RESULTSTR: {
|
||||
if (composition->IsComposing()) {
|
||||
*aLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t len = composition->LastData().Length() * sizeof(char16_t);
|
||||
if (len) {
|
||||
aDist->SetLength(len);
|
||||
memcpy(aDist->Elements(), composition->LastData().get(), len);
|
||||
}
|
||||
*aLength = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_CURSORPOS: {
|
||||
*aLength = 0;
|
||||
TextRangeArray* ranges = composition->GetLastRanges();
|
||||
if (!ranges) {
|
||||
return true;
|
||||
}
|
||||
*aLength = ranges->GetCaretPosition();
|
||||
if (*aLength < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_COMPATTR: {
|
||||
TextRangeArray* ranges = composition->GetLastRanges();
|
||||
if (!ranges || ranges->IsEmpty()) {
|
||||
*aLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
aDist->SetLength(composition->LastData().Length());
|
||||
memset(aDist->Elements(), ATTR_INPUT, aDist->Length());
|
||||
|
||||
for (TextRange& range : *ranges) {
|
||||
uint8_t type = ATTR_INPUT;
|
||||
switch(range.mRangeType) {
|
||||
case NS_TEXTRANGE_RAWINPUT:
|
||||
type = ATTR_INPUT;
|
||||
break;
|
||||
case NS_TEXTRANGE_SELECTEDRAWTEXT:
|
||||
type = ATTR_TARGET_NOTCONVERTED;
|
||||
break;
|
||||
case NS_TEXTRANGE_CONVERTEDTEXT:
|
||||
type = ATTR_CONVERTED;
|
||||
break;
|
||||
case NS_TEXTRANGE_SELECTEDCONVERTEDTEXT:
|
||||
type = ATTR_TARGET_CONVERTED;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t minLen = std::min<size_t>(range.mEndOffset, aDist->Length());
|
||||
for (size_t i = range.mStartOffset; i < minLen; i++) {
|
||||
(*aDist)[i] = type;
|
||||
}
|
||||
}
|
||||
*aLength = aDist->Length();
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_COMPCLAUSE: {
|
||||
RefPtr<TextRangeArray> ranges = composition->GetLastRanges();
|
||||
if (!ranges || ranges->IsEmpty()) {
|
||||
aDist->SetLength(sizeof(uint32_t));
|
||||
memset(aDist->Elements(), 0, sizeof(uint32_t));
|
||||
*aLength = aDist->Length();
|
||||
return true;
|
||||
}
|
||||
nsAutoTArray<uint32_t, 16> clauses;
|
||||
clauses.AppendElement(0);
|
||||
for (TextRange& range : *ranges) {
|
||||
if (!range.IsClause()) {
|
||||
continue;
|
||||
}
|
||||
clauses.AppendElement(range.mEndOffset);
|
||||
}
|
||||
|
||||
aDist->SetLength(clauses.Length() * sizeof(uint32_t));
|
||||
memcpy(aDist->Elements(), clauses.Elements(), aDist->Length());
|
||||
*aLength = aDist->Length();
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_RESULTREADSTR: {
|
||||
// When returning error causes unexpected error, so we return 0 instead.
|
||||
*aLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GCS_RESULTCLAUSE: {
|
||||
// When returning error causes unexpected error, so we return 0 instead.
|
||||
*aLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Unsupported type %x of ImmGetCompositionStringW hook",
|
||||
aType).get());
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsPluginInstanceOwner::SetCandidateWindow(int32_t aX, int32_t aY)
|
||||
{
|
||||
if (NS_WARN_IF(!mPluginFrame)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
|
||||
if (!widget) {
|
||||
widget = GetRootWidgetForPluginFrame(mPluginFrame);
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
widget->SetCandidateWindowForPlugin(aX, aY);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsPluginInstanceOwner::RequestCommitOrCancel(bool aCommitted)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
|
||||
if (!widget) {
|
||||
widget = GetRootWidgetForPluginFrame(mPluginFrame);
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aCommitted) {
|
||||
widget->NotifyIME(widget::REQUEST_TO_COMMIT_COMPOSITION);
|
||||
} else {
|
||||
widget->NotifyIME(widget::REQUEST_TO_CANCEL_COMPOSITION);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // #ifdef XP_WIN
|
||||
|
||||
NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
|
||||
{
|
||||
|
@ -1597,6 +1774,32 @@ nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
already_AddRefed<TextComposition>
|
||||
nsPluginInstanceOwner::GetTextComposition()
|
||||
{
|
||||
if (NS_WARN_IF(!mPluginFrame)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
|
||||
if (!widget) {
|
||||
widget = GetRootWidgetForPluginFrame(mPluginFrame);
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<TextComposition> composition =
|
||||
IMEStateManager::GetTextCompositionFor(widget);
|
||||
if (NS_WARN_IF(!composition)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return composition.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsPluginInstanceOwner::DispatchCompositionToPlugin(nsIDOMEvent* aEvent)
|
||||
{
|
||||
|
@ -1611,6 +1814,16 @@ nsPluginInstanceOwner::DispatchCompositionToPlugin(nsIDOMEvent* aEvent)
|
|||
if (NS_WARN_IF(!compositionEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (compositionEvent->mMessage == eCompositionChange) {
|
||||
RefPtr<TextComposition> composition = GetTextComposition();
|
||||
if (NS_WARN_IF(!composition)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
TextComposition::CompositionChangeEventHandlingMarker
|
||||
compositionChangeEventHandlingMarker(composition, compositionEvent);
|
||||
}
|
||||
|
||||
nsEventStatus rv = ProcessEvent(*compositionEvent);
|
||||
// XXX This isn't e10s aware.
|
||||
// If the event isn't consumed, we cannot post result to chrome process.
|
||||
|
|
|
@ -29,6 +29,7 @@ class nsPluginFrame;
|
|||
class nsDisplayListBuilder;
|
||||
|
||||
namespace mozilla {
|
||||
class TextComposition;
|
||||
namespace dom {
|
||||
struct MozPluginParameter;
|
||||
} // namespace dom
|
||||
|
@ -260,6 +261,11 @@ public:
|
|||
void NotifyHostCreateWidget();
|
||||
void NotifyDestroyPending();
|
||||
|
||||
bool GetCompositionString(uint32_t aIndex, nsTArray<uint8_t>* aString,
|
||||
int32_t* aLength);
|
||||
bool SetCandidateWindow(int32_t aX, int32_t aY);
|
||||
bool RequestCommitOrCancel(bool aCommitted);
|
||||
|
||||
private:
|
||||
virtual ~nsPluginInstanceOwner();
|
||||
|
||||
|
@ -282,6 +288,7 @@ private:
|
|||
|
||||
#if defined(XP_WIN)
|
||||
nsIWidget* GetContainingWidgetIfOffset();
|
||||
already_AddRefed<mozilla::TextComposition> GetTextComposition();
|
||||
#endif
|
||||
|
||||
nsPluginNativeWindow *mPluginWindow;
|
||||
|
|
|
@ -260,6 +260,15 @@ parent:
|
|||
// returned by NPN_GetValue_NPNVnetscapeWindow. Only used on Windows.
|
||||
async SetNetscapeWindowAsParent(NativeWindowHandle childWindow);
|
||||
|
||||
sync GetCompositionString(uint32_t aType)
|
||||
returns (uint8_t[] aDist, int32_t aLength);
|
||||
// Set candidate window position.
|
||||
//
|
||||
// @param aX x position of candidate window
|
||||
// @param aY y position of candidate window
|
||||
async SetCandidateWindow(int32_t aX, int32_t aY);
|
||||
sync RequestCommitOrCancel(bool aCommitted);
|
||||
|
||||
both:
|
||||
async PPluginScriptableObject();
|
||||
|
||||
|
|
|
@ -73,6 +73,25 @@ static WindowsDllInterceptor sUser32Intercept;
|
|||
static HWND sWinlessPopupSurrogateHWND = nullptr;
|
||||
static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr;
|
||||
|
||||
typedef HIMC (WINAPI *Imm32ImmGetContext)(HWND hWND);
|
||||
typedef BOOL (WINAPI *Imm32ImmReleaseContext)(HWND hWND, HIMC hIMC);
|
||||
typedef LONG (WINAPI *Imm32ImmGetCompositionString)(HIMC hIMC,
|
||||
DWORD dwIndex,
|
||||
LPVOID lpBuf,
|
||||
DWORD dwBufLen);
|
||||
typedef BOOL (WINAPI *Imm32ImmSetCandidateWindow)(HIMC hIMC,
|
||||
LPCANDIDATEFORM lpCandidate);
|
||||
typedef BOOL (WINAPI *Imm32ImmNotifyIME)(HIMC hIMC, DWORD dwAction,
|
||||
DWORD dwIndex, DWORD dwValue);
|
||||
static WindowsDllInterceptor sImm32Intercept;
|
||||
static Imm32ImmGetContext sImm32ImmGetContextStub = nullptr;
|
||||
static Imm32ImmReleaseContext sImm32ImmReleaseContextStub = nullptr;
|
||||
static Imm32ImmGetCompositionString sImm32ImmGetCompositionStringStub = nullptr;
|
||||
static Imm32ImmSetCandidateWindow sImm32ImmSetCandidateWindowStub = nullptr;
|
||||
static Imm32ImmNotifyIME sImm32ImmNotifyIME = nullptr;
|
||||
static PluginInstanceChild* sCurrentPluginInstance = nullptr;
|
||||
static const HIMC sHookIMC = (const HIMC)0xefefefef;
|
||||
|
||||
using mozilla::gfx::SharedDIB;
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -197,6 +216,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
|
|||
if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
|
||||
SetUnityHooks();
|
||||
}
|
||||
InitImm32Hook();
|
||||
#endif // OS_WIN
|
||||
}
|
||||
|
||||
|
@ -1983,6 +2003,135 @@ PluginInstanceChild::CreateWinlessPopupSurrogate()
|
|||
SendSetNetscapeWindowAsParent(mWinlessPopupSurrogateHWND);
|
||||
}
|
||||
|
||||
// static
|
||||
HIMC
|
||||
PluginInstanceChild::ImmGetContextProc(HWND aWND)
|
||||
{
|
||||
if (!sCurrentPluginInstance) {
|
||||
return sImm32ImmGetContextStub(aWND);
|
||||
}
|
||||
|
||||
wchar_t szClass[21];
|
||||
int haveClass = GetClassNameW(aWND, szClass, ArrayLength(szClass));
|
||||
if (!haveClass || wcscmp(szClass, L"SWFlash_PlaceholderX")) {
|
||||
NS_WARNING("We cannot recongnize hooked window class");
|
||||
return sImm32ImmGetContextStub(aWND);
|
||||
}
|
||||
|
||||
return sHookIMC;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL
|
||||
PluginInstanceChild::ImmReleaseContextProc(HWND aWND, HIMC aIMC)
|
||||
{
|
||||
if (aIMC == sHookIMC) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return sImm32ImmReleaseContextStub(aWND, aIMC);
|
||||
}
|
||||
|
||||
// static
|
||||
LONG
|
||||
PluginInstanceChild::ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
||||
LPVOID aBuf, DWORD aLen)
|
||||
{
|
||||
if (aIMC != sHookIMC) {
|
||||
return sImm32ImmGetCompositionStringStub(aIMC, aIndex, aBuf, aLen);
|
||||
}
|
||||
if (!sCurrentPluginInstance) {
|
||||
return IMM_ERROR_GENERAL;
|
||||
}
|
||||
nsAutoTArray<uint8_t, 16> dist;
|
||||
int32_t length = 0; // IMM_ERROR_NODATA
|
||||
sCurrentPluginInstance->SendGetCompositionString(aIndex, &dist, &length);
|
||||
if (length == IMM_ERROR_NODATA || length == IMM_ERROR_GENERAL) {
|
||||
return length;
|
||||
}
|
||||
|
||||
if (aBuf && aLen >= static_cast<DWORD>(length)) {
|
||||
memcpy(aBuf, dist.Elements(), length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
// staitc
|
||||
BOOL
|
||||
PluginInstanceChild::ImmSetCandidateWindowProc(HIMC aIMC, LPCANDIDATEFORM aForm)
|
||||
{
|
||||
if (aIMC != sHookIMC) {
|
||||
return sImm32ImmSetCandidateWindowStub(aIMC, aForm);
|
||||
}
|
||||
|
||||
if (!sCurrentPluginInstance ||
|
||||
aForm->dwIndex != 0 ||
|
||||
!(aForm->dwStyle & CFS_CANDIDATEPOS)) {
|
||||
// Flash only uses CFS_CANDIDATEPOS with index == 0.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sCurrentPluginInstance->SendSetCandidateWindow(
|
||||
aForm->ptCurrentPos.x, aForm->ptCurrentPos.y);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL
|
||||
PluginInstanceChild::ImmNotifyIME(HIMC aIMC, DWORD aAction, DWORD aIndex,
|
||||
DWORD aValue)
|
||||
{
|
||||
if (aIMC != sHookIMC) {
|
||||
return sImm32ImmNotifyIME(aIMC, aAction, aIndex, aValue);
|
||||
}
|
||||
|
||||
// We only supports NI_COMPOSITIONSTR because Flash uses it only
|
||||
if (!sCurrentPluginInstance ||
|
||||
aAction != NI_COMPOSITIONSTR ||
|
||||
(aIndex != CPS_COMPLETE && aIndex != CPS_CANCEL)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sCurrentPluginInstance->SendRequestCommitOrCancel(aAction == CPS_COMPLETE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::InitImm32Hook()
|
||||
{
|
||||
if (!(GetQuirks() & QUIRK_WINLESS_HOOK_IME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sImm32ImmGetContextStub) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When using windowless plugin, IMM API won't work due ot OOP.
|
||||
|
||||
sImm32Intercept.Init("imm32.dll");
|
||||
sImm32Intercept.AddHook(
|
||||
"ImmGetContext",
|
||||
reinterpret_cast<intptr_t>(ImmGetContextProc),
|
||||
(void**)&sImm32ImmGetContextStub);
|
||||
sImm32Intercept.AddHook(
|
||||
"ImmReleaseContext",
|
||||
reinterpret_cast<intptr_t>(ImmReleaseContextProc),
|
||||
(void**)&sImm32ImmReleaseContextStub);
|
||||
sImm32Intercept.AddHook(
|
||||
"ImmGetCompositionStringW",
|
||||
reinterpret_cast<intptr_t>(ImmGetCompositionStringProc),
|
||||
(void**)&sImm32ImmGetCompositionStringStub);
|
||||
sImm32Intercept.AddHook(
|
||||
"ImmSetCandidateWindow",
|
||||
reinterpret_cast<intptr_t>(ImmSetCandidateWindowProc),
|
||||
(void**)&sImm32ImmSetCandidateWindowStub);
|
||||
sImm32Intercept.AddHook(
|
||||
"ImmNotifyIME",
|
||||
reinterpret_cast<intptr_t>(ImmNotifyIME),
|
||||
(void**)&sImm32ImmNotifyIME);
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::DestroyWinlessPopupSurrogate()
|
||||
{
|
||||
|
@ -2016,6 +2165,13 @@ PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
|
|||
focusHwnd = SetFocus(mWinlessPopupSurrogateHWND);
|
||||
}
|
||||
|
||||
AutoRestore<PluginInstanceChild *> pluginInstance(sCurrentPluginInstance);
|
||||
if (event.event == WM_IME_STARTCOMPOSITION ||
|
||||
event.event == WM_IME_COMPOSITION ||
|
||||
event.event == WM_KILLFOCUS) {
|
||||
sCurrentPluginInstance = this;
|
||||
}
|
||||
|
||||
MessageLoop* loop = MessageLoop::current();
|
||||
AutoRestore<bool> modalLoop(loop->os_modal_loop());
|
||||
|
||||
|
|
|
@ -305,6 +305,7 @@ private:
|
|||
void HookSetWindowLongPtr();
|
||||
void SetUnityHooks();
|
||||
void ClearUnityHooks();
|
||||
void InitImm32Hook();
|
||||
static inline bool SetWindowLongHookCheck(HWND hWnd,
|
||||
int nIndex,
|
||||
LONG_PTR newLong);
|
||||
|
@ -350,6 +351,15 @@ private:
|
|||
LONG newLong);
|
||||
#endif
|
||||
|
||||
static HIMC WINAPI ImmGetContextProc(HWND aWND);
|
||||
static BOOL WINAPI ImmReleaseContextProc(HWND aWND, HIMC aIMC);
|
||||
static LONG WINAPI ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
||||
LPVOID aBuf, DWORD aLen);
|
||||
static BOOL WINAPI ImmSetCandidateWindowProc(HIMC hIMC,
|
||||
LPCANDIDATEFORM plCandidate);
|
||||
static BOOL WINAPI ImmNotifyIME(HIMC aIMC, DWORD aAction, DWORD aIndex,
|
||||
DWORD aValue);
|
||||
|
||||
class FlashThrottleAsyncMsg : public ChildAsyncCall
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1568,6 +1568,16 @@ PluginInstanceParent::NPP_HandleEvent(void* event)
|
|||
// We send this in nsPluginFrame just before painting
|
||||
return SendWindowPosChanged(npremoteevent);
|
||||
}
|
||||
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
case WM_IME_COMPOSITION:
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
if (!(mParent->GetQuirks() & QUIRK_WINLESS_HOOK_IME)) {
|
||||
// IME message will be posted on allowed plugins only such as
|
||||
// Flash. Because if we cannot know that plugin can handle
|
||||
// IME correctly.
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2368,6 +2378,50 @@ PluginInstanceParent::Cast(NPP aInstance, PluginAsyncSurrogate** aSurrogate)
|
|||
return instancePtr;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::RecvGetCompositionString(const uint32_t& aIndex,
|
||||
nsTArray<uint8_t>* aDist,
|
||||
int32_t* aLength)
|
||||
{
|
||||
#if defined(OS_WIN)
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (!owner) {
|
||||
*aLength = IMM_ERROR_GENERAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!owner->GetCompositionString(aIndex, aDist, aLength)) {
|
||||
*aLength = IMM_ERROR_NODATA;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::RecvSetCandidateWindow(const int32_t& aX,
|
||||
const int32_t& aY)
|
||||
{
|
||||
#if defined(OS_WIN)
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (owner) {
|
||||
owner->SetCandidateWindow(aX, aY);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::RecvRequestCommitOrCancel(const bool& aCommitted)
|
||||
{
|
||||
#if defined(OS_WIN)
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (owner) {
|
||||
owner->RequestCommitOrCancel(aCommitted);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::RecordDrawingModel()
|
||||
{
|
||||
|
|
|
@ -352,6 +352,16 @@ public:
|
|||
static PluginInstanceParent* Cast(NPP instance,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
|
||||
// for IME hook
|
||||
virtual bool
|
||||
RecvGetCompositionString(const uint32_t& aIndex,
|
||||
nsTArray<uint8_t>* aBuffer,
|
||||
int32_t* aLength) override;
|
||||
virtual bool
|
||||
RecvSetCandidateWindow(const int32_t& aX, const int32_t& aY) override;
|
||||
virtual bool
|
||||
RecvRequestCommitOrCancel(const bool& aCommitted) override;
|
||||
|
||||
private:
|
||||
// Create an appropriate platform surface for a background of size
|
||||
// |aSize|. Return true if successful.
|
||||
|
|
|
@ -34,6 +34,7 @@ int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
|
|||
quirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
|
||||
quirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
|
||||
quirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
|
||||
quirks |= QUIRK_WINLESS_HOOK_IME;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -62,6 +63,12 @@ int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef OS_WIN
|
||||
if (specialType == nsPluginHost::eSpecialType_Test) {
|
||||
quirks |= QUIRK_WINLESS_HOOK_IME;
|
||||
}
|
||||
#endif
|
||||
|
||||
return quirks;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ enum PluginQuirks {
|
|||
QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN = 1 << 11,
|
||||
// Win: Addresses a Unity bug with mouse capture.
|
||||
QUIRK_UNITY_FIXUP_MOUSE_CAPTURE = 1 << 12,
|
||||
// Win: Hook IMM32 API to handle IME event on windowless plugin
|
||||
QUIRK_WINLESS_HOOK_IME = 1 << 13,
|
||||
};
|
||||
|
||||
int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
|
||||
|
|
|
@ -1404,5 +1404,15 @@ PuppetWidget::GetCurrentWidgetListener()
|
|||
return mAttachedWidgetListener;
|
||||
}
|
||||
|
||||
void
|
||||
PuppetWidget::SetCandidateWindowForPlugin(int32_t aX, int32_t aY)
|
||||
{
|
||||
if (!mTabChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTabChild->SendSetCandidateWindowForPlugin(aX, aY);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -254,6 +254,9 @@ public:
|
|||
virtual uint32_t GetMaxTouchPoints() const override;
|
||||
|
||||
virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
|
||||
|
||||
virtual void SetCandidateWindowForPlugin(int32_t aX, int32_t aY) override;
|
||||
|
||||
protected:
|
||||
virtual nsresult NotifyIMEInternal(
|
||||
const IMENotification& aIMENotification) override;
|
||||
|
|
|
@ -266,6 +266,16 @@ public:
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GetCaretPosition() const
|
||||
{
|
||||
for (const TextRange& range : *this) {
|
||||
if (range.mRangeType == NS_TEXTRANGE_CARETPOSITION) {
|
||||
return range.mStartOffset;
|
||||
}
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -217,6 +217,9 @@ public:
|
|||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
NS_IMETHOD SetPluginFocused(bool& aFocused) override
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
virtual void SetCandidateWindowForPlugin(int32_t aX,
|
||||
int32_t aY) override
|
||||
{ }
|
||||
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) override { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
|
||||
NativeKeyBindingsType aType,
|
||||
|
|
|
@ -133,8 +133,8 @@ typedef void* nsNativeWidget;
|
|||
#endif
|
||||
|
||||
#define NS_IWIDGET_IID \
|
||||
{ 0xaaa79c8d, 0xc99d, 0x4fe1, \
|
||||
{ 0xa5, 0x11, 0xd3, 0xeb, 0xb1, 0x61, 0x9e, 0x26 } }
|
||||
{ 0xa3db64d2, 0x5a73, 0x425f, \
|
||||
{ 0x9b, 0xb0, 0x57, 0x7f, 0xe5, 0x56, 0x43, 0x15 } }
|
||||
|
||||
/*
|
||||
* Window shadow styles
|
||||
|
@ -1799,6 +1799,11 @@ public:
|
|||
return GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set IME candidate window position by windowless plugin.
|
||||
*/
|
||||
virtual void SetCandidateWindowForPlugin(int32_t aX, int32_t aY) = 0;
|
||||
|
||||
/*
|
||||
* Notifies the input context changes.
|
||||
*/
|
||||
|
|
|
@ -2749,6 +2749,14 @@ IMMHandler::OnKeyDownEvent(nsWindow* aWindow,
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMMHandler::SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm)
|
||||
{
|
||||
IMEContext context(aWindow);
|
||||
ImmSetCandidateWindow(context.get(), aForm);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* IMMHandler::Selection
|
||||
******************************************************************************/
|
||||
|
|
|
@ -150,6 +150,7 @@ public:
|
|||
// IME. Otherwise, NS_OK.
|
||||
static nsresult OnMouseButtonEvent(nsWindow* aWindow,
|
||||
const IMENotification& aIMENotification);
|
||||
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
|
||||
|
||||
protected:
|
||||
static void EnsureHandlerInstance();
|
||||
|
|
|
@ -948,5 +948,16 @@ IMEHandler::GetOnScreenKeyboardWindow()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEHandler::SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm)
|
||||
{
|
||||
if (!sPluginHasFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
IMMHandler::SetCandidateWindow(aWindow, aForm);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -103,6 +103,11 @@ public:
|
|||
*/
|
||||
static void InitInputContext(nsWindow* aWindow, InputContext& aInputContext);
|
||||
|
||||
/*
|
||||
* For windowless plugin helper.
|
||||
*/
|
||||
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Returns true when current keyboard layout has IME. Otherwise, false.
|
||||
|
|
|
@ -7751,6 +7751,18 @@ nsWindow::ComputeShouldAccelerate()
|
|||
return nsBaseWidget::ComputeShouldAccelerate();
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::SetCandidateWindowForPlugin(int32_t aX, int32_t aY)
|
||||
{
|
||||
CANDIDATEFORM form;
|
||||
form.dwIndex = 0;
|
||||
form.dwStyle = CFS_CANDIDATEPOS;
|
||||
form.ptCurrentPos.x = aX;
|
||||
form.ptCurrentPos.y = aY;
|
||||
|
||||
IMEHandler::SetCandidateWindow(this, &form);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
**************************************************************
|
||||
**
|
||||
|
|
|
@ -297,6 +297,9 @@ public:
|
|||
|
||||
const IMEContext& DefaultIMC() const { return mDefaultIMC; }
|
||||
|
||||
virtual void SetCandidateWindowForPlugin(int32_t aX,
|
||||
int32_t aY) override;
|
||||
|
||||
protected:
|
||||
virtual ~nsWindow();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче