import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1130935 part.7 Set composition font when selection is changed since some IMEs need to be set candidate window position even before WM_IME_STARTCOMPOSITION r=emk (57b43c453)
- Bug 1130935 part.8 nsIMM32Handler should set focused editor rect to the result of IMR_QUERYCHARPOSITION r=emk (b534d4921)
- Bug 1130935 part.9 Needs some hack for Google Japanese Input in nsIMM32Handle because it doesn't support vertical writing mode r=emk (01555b5cc)
- Bug 1130935 part.10 nsIMM32Handler should forcibly update composition font when active IME is changed r=emk (84748aa9c)
- Bug 1130935 part.11 Disable test_backspace_delete.xul due to bug 1163311 r=smontagu (8bdbe49d3)
- Bug 1130935 - mingw fixup. (55841cba1)
- Bug 1168219 - Make nsIWidget::Configuration::mChild a smart pointer. r=vlad (4a8804a1e)
- Add an API for snapshotting widgets as they are presented by the operating system. (bug 1167477, r=mattwoodrow, dom r=khuey) (c2592f279)
- Bug 1130937 part.1 nsGtkIMModule should cache selection r=m_kato (b0d7c550d)
- Bug 1174287: Use mozilla:: prefix for namespaced classes in nsGtkIMModule.h. r=Ms2ger (dcf6732db)
- Bug 1130937 part.2 nsGtkIMModule should set candidiate window position to bottom left of the target clause in vertical writing mode r=m_kato (5c8d74129)
- Bug 1130937 part.3 nsGtkIMModule should adjust candidate window position when layout is changed r=m_kato (88c472773)
- Bug 1165903: For Windows NPAPI do window re-parenting in the chrome process to allow for sandboxing. r=jimm (27254a070)
This commit is contained in:
2021-02-08 11:52:04 +08:00
parent d35c605135
commit d110e4bff5
31 changed files with 688 additions and 126 deletions
+2
View File
@@ -918,6 +918,8 @@ pref("browser.tabs.remote", false);
// This will require a restart.
pref("security.sandbox.windows.log", false);
pref("dom.ipc.plugins.sandbox-level.flash", 0);
#if defined(MOZ_CONTENT_SANDBOX)
// This controls the strength of the Windows content process sandbox for testing
// purposes. This will require a restart.
+46
View File
@@ -4807,6 +4807,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
if (!sw || !sh) {
return;
}
nsRefPtr<gfxContext> thebes;
RefPtr<DrawTarget> drawDT;
// Rendering directly is faster and can be done if mTarget supports Azure
@@ -4961,6 +4962,51 @@ CanvasRenderingContext2D::AsyncDrawXULElement(nsXULElement& elem,
#endif
}
void
CanvasRenderingContext2D::DrawWidgetAsOnScreen(nsGlobalWindow& aWindow,
mozilla::ErrorResult& error)
{
EnsureTarget();
// This is an internal API.
if (!nsContentUtils::IsCallerChrome()) {
error.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsRefPtr<nsPresContext> presContext;
nsIDocShell* docshell = aWindow.GetDocShell();
if (docshell) {
docshell->GetPresContext(getter_AddRefs(presContext));
}
if (!presContext) {
error.Throw(NS_ERROR_FAILURE);
return;
}
nsIWidget* widget = presContext->GetRootWidget();
if (!widget) {
error.Throw(NS_ERROR_FAILURE);
return;
}
RefPtr<SourceSurface> snapshot = widget->SnapshotWidgetOnScreen();
if (!snapshot) {
error.Throw(NS_ERROR_FAILURE);
return;
}
mgfx::Rect sourceRect(mgfx::Point(0, 0), mgfx::Size(snapshot->GetSize()));
mTarget->DrawSurface(snapshot, sourceRect, sourceRect,
DrawSurfaceOptions(mgfx::Filter::POINT),
DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER,
AntialiasMode::NONE));
mTarget->Flush();
RedrawUser(gfxRect(0, 0,
std::min(mWidth, snapshot->GetSize().width),
std::min(mHeight, snapshot->GetSize().height)));
}
//
// device pixel getting/setting
//
+1
View File
@@ -471,6 +471,7 @@ public:
void DrawWindow(nsGlobalWindow& window, double x, double y, double w, double h,
const nsAString& bgColor, uint32_t flags,
mozilla::ErrorResult& error);
void DrawWidgetAsOnScreen(nsGlobalWindow& aWindow, mozilla::ErrorResult& error);
void AsyncDrawXULElement(nsXULElement& elem, double x, double y, double w,
double h, const nsAString& bgColor, uint32_t flags,
mozilla::ErrorResult& error);
+6
View File
@@ -41,6 +41,12 @@ parent:
* native HWND of the plugin widget.
*/
sync GetNativePluginPort() returns (uintptr_t value);
/**
* Sends an NS_NATIVE_CHILD_WINDOW to be adopted by the widget's native window
* on the chrome side. This is only currently used on Windows.
*/
sync SetNativeChildWindow(uintptr_t childWindow);
};
}
+1 -1
View File
@@ -49,7 +49,7 @@ public:
return NS_OK;
}
nsresult GetPluginWidget(nsIWidget **aWidget) {
nsresult GetPluginWidget(nsIWidget **aWidget) const {
NS_IF_ADDREF(*aWidget = mWidget);
return NS_OK;
}
+4 -1
View File
@@ -68,7 +68,10 @@ intr protocol PPluginInstance
child:
intr __delete__();
intr NPP_SetWindow(NPRemoteWindow window);
// Return value is only used on Windows and only when the window needs its
// parent set to the chrome widget native window.
intr NPP_SetWindow(NPRemoteWindow window)
returns (NPRemoteWindow childWindowToBeAdopted);
intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
returns (bool value, NPError result);
+26 -23
View File
@@ -1122,7 +1122,8 @@ void PluginInstanceChild::DeleteWindow()
#endif
bool
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
NPRemoteWindow* aChildWindowToBeAdopted)
{
PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
FULLFUNCTION,
@@ -1213,9 +1214,32 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
if (!CreatePluginWindow())
return false;
ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
SizePluginWindow(aWindow.width, aWindow.height);
// If the window is not our parent set the return child window so that
// it can be re-parented in the chrome process. Re-parenting now
// happens there as we might not have sufficient permission.
// Also, this needs to be after SizePluginWindow because SetWindowPos
// relies on things that it sets.
HWND parentWindow = reinterpret_cast<HWND>(aWindow.window);
if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) {
mPluginParentHWND = parentWindow;
aChildWindowToBeAdopted->window =
reinterpret_cast<uint64_t>(mPluginWindowHWND);
} else {
// Now we know that the window has the correct parent we can show
// it. The actual visibility is controlled by its parent.
// First time round, these calls are made by our caller after the
// parent is set.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
// This used to be called in SizePluginWindow, but we need to make
// sure that mPluginWindowHWND has had it's parent set correctly,
// otherwise it can cause a focus issue.
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width,
aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION);
}
mWindow.window = (void*)mPluginWindowHWND;
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
@@ -1401,25 +1425,6 @@ PluginInstanceChild::DestroyPluginWindow()
}
}
void
PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
{
if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
// Fix the child window's style to be a child window.
LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
style &= ~WS_POPUP;
SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
// Do the reparenting.
SetParent(mPluginWindowHWND, hWndParent);
// Make sure we're visible.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
}
mPluginParentHWND = hWndParent;
}
void
PluginInstanceChild::SizePluginWindow(int width,
int height)
@@ -1427,8 +1432,6 @@ PluginInstanceChild::SizePluginWindow(int width,
if (mPluginWindowHWND) {
mPluginSize.x = width;
mPluginSize.y = height;
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
}
+2 -2
View File
@@ -65,7 +65,8 @@ class PluginInstanceChild : public PPluginInstanceChild
#endif
protected:
virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
bool AnswerNPP_SetWindow(const NPRemoteWindow& window,
NPRemoteWindow* aChildWindowToBeAdopted) override;
virtual bool
AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;
@@ -276,7 +277,6 @@ private:
static bool RegisterWindowClass();
bool CreatePluginWindow();
void DestroyPluginWindow();
void ReparentPluginWindow(HWND hWndParent);
void SizePluginWindow(int width, int height);
int16_t WinlessHandleEvent(NPEvent& event);
void CreateWinlessPopupSurrogate();
+25 -1
View File
@@ -49,6 +49,8 @@
#include "mozilla/plugins/PluginSurfaceParent.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsIWidget.h"
#include "nsPluginNativeWindow.h"
extern const wchar_t* kFlashFullscreenClass;
#elif defined(MOZ_WIDGET_GTK)
#include <gdk/gdk.h>
@@ -1025,8 +1027,30 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
window.colormap = ws_info->colormap;
#endif
if (!CallNPP_SetWindow(window))
NPRemoteWindow childWindow;
if (!CallNPP_SetWindow(window, &childWindow)) {
return NPERR_GENERIC_ERROR;
}
#if defined(XP_WIN)
// If a child window is returned it means that we need to re-parent it.
if (childWindow.window) {
nsCOMPtr<nsIWidget> widget;
static_cast<const nsPluginNativeWindow*>(aWindow)->
GetPluginWidget(getter_AddRefs(widget));
if (widget) {
widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
static_cast<uintptr_t>(childWindow.window));
}
// Now it has got the correct parent, make sure it is visible.
// In subsequent calls to SetWindow these calls happen in the Child.
HWND childHWND = reinterpret_cast<HWND>(childWindow.window);
ShowWindow(childHWND, SW_SHOWNA);
SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
#endif
return NPERR_NO_ERROR;
}
+15
View File
@@ -210,5 +210,20 @@ PluginWidgetParent::RecvGetNativePluginPort(uintptr_t* value)
return true;
}
bool
PluginWidgetParent::RecvSetNativeChildWindow(const uintptr_t& aChildWindow)
{
#if defined(XP_WIN)
ENSURE_CHANNEL;
PWLOG("PluginWidgetParent::RecvSetNativeChildWindow(%p)\n",
static_cast<void*>(aChildWindow));
mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow);
return true;
#else
NS_NOTREACHED("PluginWidgetParent::RecvSetNativeChildWindow not implemented!");
return false;
#endif
}
} // namespace plugins
} // namespace mozilla
+1
View File
@@ -31,6 +31,7 @@ public:
virtual bool RecvCreate(nsresult* aResult) override;
virtual bool RecvSetFocus(const bool& aRaise) override;
virtual bool RecvGetNativePluginPort(uintptr_t* value) override;
bool RecvSetNativeChildWindow(const uintptr_t& aChildWindow) override;
// Helper for compositor checks on the channel
bool ActorDestroyed() { return !mWidget; }
@@ -223,6 +223,18 @@ interface CanvasRenderingContext2D {
void asyncDrawXULElement(XULElement elem, double x, double y, double w,
double h, DOMString bgColor,
optional unsigned long flags = 0);
/**
* Render the root widget of a window into the canvas. Unlike drawWindow,
* this uses the operating system to snapshot the widget on-screen, rather
* than reading from our own compositor.
*
* Currently, this is only supported on Windows, and only on widgets that
* use OMTC, and only from within the chrome process.
*/
[Throws, ChromeOnly]
void drawWidgetAsOnScreen(Window window);
/**
* This causes a context that is currently using a hardware-accelerated
* backend to fallback to a software one. All state should be preserved.
+14
View File
@@ -804,6 +804,18 @@ CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
return true;
}
bool
CompositorParent::RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot)
{
if (!mCompositor || !mCompositor->GetWidget()) {
return false;
}
RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
mCompositor->GetWidget()->CaptureWidgetOnScreen(target);
return true;
}
bool
CompositorParent::RecvFlushRendering()
{
@@ -1700,6 +1712,8 @@ public:
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
const gfx::IntRect& aRect) override
{ return true; }
virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override
{ return true; }
virtual bool RecvFlushRendering() override { return true; }
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
+1
View File
@@ -241,6 +241,7 @@ public:
virtual bool RecvAdoptChild(const uint64_t& child) override;
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
const gfx::IntRect& aRect) override;
virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override;
virtual bool RecvFlushRendering() override;
virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override;
+8
View File
@@ -115,6 +115,14 @@ parent:
// and so forth being interpolated. That's what we want to happen.
sync MakeSnapshot(SurfaceDescriptor inSnapshot, IntRect dirtyRect);
// Same as Makesnapshot(), except the snapshot is read from the underlying
// operating system desktop rather than the compositor's backbuffer. This
// is intended for testing whether hardware acceleration works.
//
// This call is part of IPDL, even though it simply wraps an nsIWidget
// call, to make sure it does not occur in the middle of a composite.
sync MakeWidgetSnapshot(SurfaceDescriptor inSnapshot);
// Make sure any pending composites are started immediately and
// block until they are completed.
sync FlushRendering();
+1
View File
@@ -7,6 +7,7 @@ support-files =
frame_selection_underline.xhtml
[test_backspace_delete.xul]
skip-if = true # Bug 1163311
[test_bug348681.html]
[test_bug469613.xul]
[test_bug469774.xul]
+7
View File
@@ -3403,6 +3403,13 @@ pref("intl.imm.composition_font.japanist_2003", "MS PGothic");
// FYI: Changing this pref requires to restart.
pref("intl.imm.vertical_writing.always_assume_not_supported", false);
// We cannot retrieve active IME name with IMM32 API if a TIP of TSF is active.
// This pref can specify active IME name when Japanese TIP is active.
// For example:
// Google Japanese Input: "Google 日本語入力 IMM32 モジュール"
// ATOK 2011: "ATOK 2011" (similarly, e.g., ATOK 2013 is "ATOK 2013")
pref("intl.imm.japanese.assume_active_tip_name_as", "");
// See bug 448927, on topmost panel, some IMEs are not usable on Windows.
pref("ui.panel.default_level_parent", false);
+23
View File
@@ -141,6 +141,29 @@ PluginWidgetProxy::GetNativeData(uint32_t aDataType)
return (void*)value;
}
#if defined(XP_WIN)
void
PluginWidgetProxy::SetNativeData(uint32_t aDataType, uintptr_t aVal)
{
if (!mActor) {
return;
}
auto tab = static_cast<mozilla::dom::TabChild*>(mActor->Manager());
if (tab && tab->IsDestroyed()) {
return;
}
switch (aDataType) {
case NS_NATIVE_CHILD_WINDOW:
mActor->SendSetNativeChildWindow(aVal);
break;
default:
NS_ERROR("SetNativeData called with unsupported data type.");
}
}
#endif
NS_IMETHODIMP
PluginWidgetProxy::SetFocus(bool aRaise)
{
+3
View File
@@ -43,6 +43,9 @@ public:
virtual nsIWidget* GetParent(void) override;
virtual void* GetNativeData(uint32_t aDataType) override;
#if defined(XP_WIN)
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
#endif
virtual nsTransparencyMode GetTransparencyMode() override
{ return eTransparencyOpaque; }
virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) override;
+1 -1
View File
@@ -227,7 +227,7 @@ PuppetWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild);
PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild.get());
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
w->SetWindowClipRegion(configuration.mClipRegion, true);
+152 -73
View File
@@ -56,8 +56,30 @@ GetEnabledStateName(uint32_t aState)
}
}
class GetWritingModeName : public nsAutoCString
{
public:
explicit GetWritingModeName(const WritingMode& aWritingMode)
{
if (!aWritingMode.IsVertical()) {
AssignLiteral("Horizontal");
return;
}
if (aWritingMode.IsVerticalLR()) {
AssignLiteral("Vertical (LTR)");
return;
}
AssignLiteral("Vertical (RTL)");
}
virtual ~GetWritingModeName() {}
};
const static bool kUseSimpleContextDefault = MOZ_WIDGET_GTK == 2;
/******************************************************************************
* nsGtkIMModule
******************************************************************************/
nsGtkIMModule* nsGtkIMModule::sLastFocusedModule = nullptr;
bool nsGtkIMModule::sUseSimpleContext;
@@ -74,6 +96,7 @@ nsGtkIMModule::nsGtkIMModule(nsWindow* aOwnerWindow)
, mCompositionState(eCompositionState_NotComposing)
, mIsIMFocused(false)
, mIsDeletingSurrounding(false)
, mLayoutChanged(false)
{
if (!gGtkIMLog) {
gGtkIMLog = PR_NewLogModule("nsGtkIMModuleWidgets");
@@ -396,6 +419,7 @@ nsGtkIMModule::OnFocusChangeInGecko(bool aFocus)
// We shouldn't carry over the removed string to another editor.
mSelectedString.Truncate();
mSelection.Clear();
}
void
@@ -452,13 +476,28 @@ nsGtkIMModule::EndIMEComposition(nsWindow* aCaller)
}
void
nsGtkIMModule::OnUpdateComposition()
nsGtkIMModule::OnLayoutChange()
{
if (MOZ_UNLIKELY(IsDestroyed())) {
return;
}
SetCursorPosition(GetActiveContext(), mCompositionTargetOffset);
mLayoutChanged = true;
}
void
nsGtkIMModule::OnUpdateComposition()
{
if (MOZ_UNLIKELY(IsDestroyed())) {
return;
}
// If we've already set candidate window position, we don't need to update
// the position with update composition notification.
if (!mLayoutChanged) {
SetCursorPosition(GetActiveContext(), mCompositionTargetOffset);
}
}
void
@@ -660,8 +699,11 @@ nsGtkIMModule::Blur()
}
void
nsGtkIMModule::OnSelectionChange(nsWindow* aCaller)
nsGtkIMModule::OnSelectionChange(nsWindow* aCaller,
const IMENotification& aIMENotification)
{
mSelection.Assign(aIMENotification);
if (MOZ_UNLIKELY(IsDestroyed())) {
return;
}
@@ -685,42 +727,13 @@ nsGtkIMModule::OnSelectionChange(nsWindow* aCaller)
// event handler. So, we're dispatching NS_COMPOSITION_START,
// we should ignore selection change notification.
if (mCompositionState == eCompositionState_CompositionStartDispatched) {
nsCOMPtr<nsIWidget> focusedWindow(mLastFocusedWindow);
nsEventStatus status;
WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT,
focusedWindow);
InitEvent(selection);
mLastFocusedWindow->DispatchEvent(&selection, status);
bool cannotContinueComposition = false;
if (MOZ_UNLIKELY(IsDestroyed())) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" ERROR: nsGtkIMModule instance is destroyed during "
"querying selection offset"));
return;
} else if (NS_WARN_IF(!selection.mSucceeded)) {
cannotContinueComposition = true;
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" ERROR: failed to retrieve new caret offset"));
} else if (selection.mReply.mOffset == UINT32_MAX) {
cannotContinueComposition = true;
if (NS_WARN_IF(!mSelection.IsValid())) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" ERROR: new offset is too large, cannot keep composing"));
} else if (!mLastFocusedWindow || focusedWindow != mLastFocusedWindow) {
cannotContinueComposition = true;
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" ERROR: focus is changed during querying selection "
"offset"));
} else if (focusedWindow->Destroyed()) {
cannotContinueComposition = true;
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" ERROR: focused window started to be being destroyed "
"during querying selection offset"));
}
if (!cannotContinueComposition) {
} else {
// Modify the selection start offset with new offset.
mCompositionStart = selection.mReply.mOffset;
mCompositionStart = mSelection.mOffset;
// XXX We should modify mSelectedString? But how?
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" NOTE: mCompositionStart is updated to %u, "
"the selection change doesn't cause resetting IM context",
@@ -1023,13 +1036,7 @@ nsGtkIMModule::DispatchCompositionStart(GtkIMContext* aContext)
return false;
}
nsEventStatus status;
WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT,
mLastFocusedWindow);
InitEvent(selection);
mLastFocusedWindow->DispatchEvent(&selection, status);
if (!selection.mSucceeded || selection.mReply.mOffset == UINT32_MAX) {
if (NS_WARN_IF(!EnsureToCacheSelection())) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" FAILED, cannot query the selection offset"));
return false;
@@ -1039,7 +1046,7 @@ nsGtkIMModule::DispatchCompositionStart(GtkIMContext* aContext)
// even though we strongly hope it doesn't happen.
// Every composition event should have the start offset for the result
// because it may high cost if we query the offset every time.
mCompositionStart = selection.mReply.mOffset;
mCompositionStart = mSelection.mOffset;
mDispatchedCompositionString.Truncate();
if (mProcessingKeyEvent && !mKeyDownEventWasSent &&
@@ -1067,6 +1074,7 @@ nsGtkIMModule::DispatchCompositionStart(GtkIMContext* aContext)
mLastFocusedWindow);
InitEvent(compEvent);
nsCOMPtr<nsIWidget> kungFuDeathGrip = mLastFocusedWindow;
nsEventStatus status;
mLastFocusedWindow->DispatchEvent(&compEvent, status);
if (static_cast<nsWindow*>(kungFuDeathGrip.get())->IsDestroyed() ||
kungFuDeathGrip != mLastFocusedWindow) {
@@ -1108,15 +1116,12 @@ nsGtkIMModule::DispatchCompositionChangeEvent(
// Store the selected string which will be removed by following
// compositionchange event.
if (mCompositionState == eCompositionState_CompositionStartDispatched) {
// XXX We should assume, for now, any web applications don't change
// selection at handling this compositionchange event.
WidgetQueryContentEvent querySelectedTextEvent(true,
NS_QUERY_SELECTED_TEXT,
mLastFocusedWindow);
mLastFocusedWindow->DispatchEvent(&querySelectedTextEvent, status);
if (querySelectedTextEvent.mSucceeded) {
mSelectedString = querySelectedTextEvent.mReply.mString;
mCompositionStart = querySelectedTextEvent.mReply.mOffset;
if (NS_WARN_IF(!EnsureToCacheSelection(&mSelectedString))) {
// XXX How should we behave in this case??
} else {
// XXX We should assume, for now, any web applications don't change
// selection at handling this compositionchange event.
mCompositionStart = mSelection.mOffset;
}
}
@@ -1135,6 +1140,14 @@ nsGtkIMModule::DispatchCompositionChangeEvent(
mCompositionState = eCompositionState_CompositionChangeEventDispatched;
// We cannot call SetCursorPosition for e10s-aware.
// DispatchEvent is async on e10s, so composition rect isn't updated now
// on tab parent.
mLayoutChanged = false;
mCompositionTargetRange.mOffset = targetOffset;
mCompositionTargetRange.mLength =
compositionChangeEvent.mRanges->TargetClauseLength();
mLastFocusedWindow->DispatchEvent(&compositionChangeEvent, status);
if (lastFocusedWindow->IsDestroyed() ||
lastFocusedWindow != mLastFocusedWindow) {
@@ -1143,12 +1156,6 @@ nsGtkIMModule::DispatchCompositionChangeEvent(
"compositionchange event"));
return false;
}
// We cannot call SetCursorPosition for e10s-aware.
// DispatchEvent is async on e10s, so composition rect isn't updated now
// on tab parent.
mCompositionTargetOffset = targetOffset;
return true;
}
@@ -1424,14 +1431,14 @@ nsGtkIMModule::GetCurrentParagraph(nsAString& aText, uint32_t& aCursorPos)
// current selection.
if (!EditorHasCompositionString()) {
// Query cursor position & selection
WidgetQueryContentEvent querySelectedTextEvent(true,
NS_QUERY_SELECTED_TEXT,
mLastFocusedWindow);
mLastFocusedWindow->DispatchEvent(&querySelectedTextEvent, status);
NS_ENSURE_TRUE(querySelectedTextEvent.mSucceeded, NS_ERROR_FAILURE);
if (NS_WARN_IF(!EnsureToCacheSelection())) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" FAILED, due to no valid selection information"));
return NS_ERROR_FAILURE;
}
selOffset = querySelectedTextEvent.mReply.mOffset;
selLength = querySelectedTextEvent.mReply.mString.Length();
selOffset = mSelection.mOffset;
selLength = mSelection.mLength;
}
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
@@ -1529,14 +1536,12 @@ nsGtkIMModule::DeleteText(GtkIMContext* aContext,
return NS_ERROR_FAILURE;
}
} else {
// Query cursor position & selection
WidgetQueryContentEvent querySelectedTextEvent(true,
NS_QUERY_SELECTED_TEXT,
mLastFocusedWindow);
lastFocusedWindow->DispatchEvent(&querySelectedTextEvent, status);
NS_ENSURE_TRUE(querySelectedTextEvent.mSucceeded, NS_ERROR_FAILURE);
selOffset = querySelectedTextEvent.mReply.mOffset;
if (NS_WARN_IF(!EnsureToCacheSelection())) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" FAILED, due to no valid selection information"));
return NS_ERROR_FAILURE;
}
selOffset = mSelection.mOffset;
}
// Get all text contents of the focused editor
@@ -1659,3 +1664,77 @@ nsGtkIMModule::InitEvent(WidgetGUIEvent& aEvent)
{
aEvent.time = PR_Now() / 1000;
}
bool
nsGtkIMModule::EnsureToCacheSelection(nsAString* aSelectedString)
{
if (aSelectedString) {
aSelectedString->Truncate();
}
if (mSelection.IsValid() &&
(!mSelection.Collapsed() || !aSelectedString)) {
return true;
}
if (NS_WARN_IF(!mLastFocusedWindow)) {
PR_LOG(gGtkIMLog, PR_LOG_ERROR,
("GtkIMModule(%p): EnsureToCacheSelection(), FAILED, due to "
"no focused window", this));
return false;
}
nsEventStatus status;
WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT,
mLastFocusedWindow);
InitEvent(selection);
mLastFocusedWindow->DispatchEvent(&selection, status);
if (NS_WARN_IF(!selection.mSucceeded)) {
PR_LOG(gGtkIMLog, PR_LOG_ERROR,
("GtkIMModule(%p): EnsureToCacheSelection(), FAILED, due to "
"failure of query selection event", this));
return false;
}
mSelection.Assign(selection);
if (!mSelection.IsValid()) {
PR_LOG(gGtkIMLog, PR_LOG_ERROR,
("GtkIMModule(%p): EnsureToCacheSelection(), FAILED, due to "
"failure of query selection event (invalid result)", this));
return false;
}
if (!mSelection.Collapsed() && aSelectedString) {
aSelectedString->Assign(selection.mReply.mString);
}
PR_LOG(gGtkIMLog, PR_LOG_DEBUG,
("GtkIMModule(%p): EnsureToCacheSelection(), Succeeded, mSelection="
"{ mOffset=%u, mLength=%u, mWritingMode=%s }",
this, mSelection.mOffset, mSelection.mLength,
GetWritingModeName(mSelection.mWritingMode).get()));
return true;
}
/******************************************************************************
* nsGtkIMModule::Selection
******************************************************************************/
void
nsGtkIMModule::Selection::Assign(const IMENotification& aIMENotification)
{
MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
mOffset = aIMENotification.mSelectionChangeData.mOffset;
mLength = aIMENotification.mSelectionChangeData.mLength;
mWritingMode = aIMENotification.mSelectionChangeData.GetWritingMode();
}
void
nsGtkIMModule::Selection::Assign(const WidgetQueryContentEvent& aEvent)
{
MOZ_ASSERT(aEvent.message == NS_QUERY_SELECTED_TEXT);
MOZ_ASSERT(aEvent.mSucceeded);
mOffset = aEvent.mReply.mOffset;
mLength = aEvent.mReply.mString.Length();
mWritingMode = aEvent.GetWritingMode();
}
+47 -1
View File
@@ -16,13 +16,16 @@
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIWidget.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/EventForwards.h"
#include "WritingModes.h"
class nsWindow;
class nsGtkIMModule
{
protected:
typedef mozilla::widget::IMENotification IMENotification;
typedef mozilla::widget::InputContext InputContext;
typedef mozilla::widget::InputContextAction InputContextAction;
@@ -48,7 +51,8 @@ public:
void OnFocusChangeInGecko(bool aFocus);
// OnSelectionChange is a notification that selection (caret) is changed
// in the focused editor.
void OnSelectionChange(nsWindow* aCaller);
void OnSelectionChange(nsWindow* aCaller,
const IMENotification& aIMENotification);
// OnKeyEvent is called when aWindow gets a native key press event or a
// native key release event. If this returns TRUE, the key event was
@@ -65,6 +69,7 @@ public:
const InputContextAction* aAction);
InputContext GetInputContext();
void OnUpdateComposition();
void OnLayoutChange();
protected:
~nsGtkIMModule();
@@ -167,6 +172,44 @@ protected:
}
}
struct Selection final
{
uint32_t mOffset;
uint32_t mLength;
mozilla::WritingMode mWritingMode;
Selection()
: mOffset(UINT32_MAX)
, mLength(UINT32_MAX)
{
}
void Clear()
{
mOffset = UINT32_MAX;
mLength = UINT32_MAX;
mWritingMode = mozilla::WritingMode();
}
void Assign(const IMENotification& aIMENotification);
void Assign(const mozilla::WidgetQueryContentEvent& aSelectedTextEvent);
bool IsValid() const { return mOffset != UINT32_MAX; }
bool Collapsed() const { return !mLength; }
uint32_t EndOffset() const
{
if (NS_WARN_IF(!IsValid())) {
return UINT32_MAX;
}
mozilla::CheckedInt<uint32_t> endOffset =
mozilla::CheckedInt<uint32_t>(mOffset) + mLength;
if (NS_WARN_IF(!endOffset.isValid())) {
return UINT32_MAX;
}
return endOffset.value();
}
} mSelection;
bool EnsureToCacheSelection(nsAString* aSelectedString = nullptr);
// mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And
// it's set to FALSE when we call gtk_im_context_focus_out().
@@ -184,6 +227,9 @@ protected:
// mIsDeletingSurrounding is true while OnDeleteSurroundingNative() is
// trying to delete the surrounding text.
bool mIsDeletingSurrounding;
// mLayoutChanged is true after OnLayoutChange() is called. This is reset
// when NS_COMPOSITION_CHANGE is being dispatched.
bool mLayoutChanged;
// sLastFocusedModule is a pointer to the last focused instance of this
// class. When a instance is destroyed and sLastFocusedModule refers it,
+7 -3
View File
@@ -4159,7 +4159,7 @@ nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
nsWindow* w = static_cast<nsWindow*>(configuration.mChild.get());
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
w->SetWindowClipRegion(configuration.mClipRegion, true);
@@ -6027,11 +6027,14 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
case NOTIFY_IME_OF_BLUR:
mIMModule->OnFocusChangeInGecko(false);
return NS_OK;
case NOTIFY_IME_OF_POSITION_CHANGE:
mIMModule->OnLayoutChange();
return NS_OK;
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
mIMModule->OnUpdateComposition();
return NS_OK;
case NOTIFY_IME_OF_SELECTION_CHANGE:
mIMModule->OnSelectionChange(this);
mIMModule->OnSelectionChange(this, aIMENotification);
return NS_OK;
default:
return NS_ERROR_NOT_IMPLEMENTED;
@@ -6070,7 +6073,8 @@ nsIMEUpdatePreference
nsWindow::GetIMEUpdatePreference()
{
nsIMEUpdatePreference updatePreference(
nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE);
nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE |
nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE);
// We shouldn't notify IME of selection change caused by changes of
// composition string. Therefore, we don't need to be notified selection
// changes which are caused by compositionchange events handled.
+54
View File
@@ -1930,6 +1930,60 @@ nsIWidget::UpdateRegisteredPluginWindowVisibility(nsTArray<uintptr_t>& aVisibleL
#endif
}
already_AddRefed<mozilla::gfx::SourceSurface>
nsIWidget::SnapshotWidgetOnScreen()
{
// This is only supported on a widget with a compositor.
LayerManager* layerManager = GetLayerManager();
if (!layerManager) {
return nullptr;
}
ClientLayerManager* lm = layerManager->AsClientLayerManager();
if (!lm) {
return nullptr;
}
CompositorChild* cc = lm->GetRemoteRenderer();
if (!cc) {
return nullptr;
}
nsIntRect bounds;
GetBounds(bounds);
if (bounds.IsEmpty()) {
return nullptr;
}
gfx::IntSize size(bounds.width, bounds.height);
ShadowLayerForwarder* forwarder = lm->AsShadowForwarder();
SurfaceDescriptor surface;
if (!forwarder->AllocSurfaceDescriptor(size, gfxContentType::COLOR_ALPHA, &surface)) {
return nullptr;
}
if (!cc->SendMakeWidgetSnapshot(surface)) {
return nullptr;
}
RefPtr<gfx::DataSourceSurface> snapshot = GetSurfaceForDescriptor(surface);
RefPtr<gfx::DrawTarget> dt =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(size, gfx::SurfaceFormat::B8G8R8A8);
if (!snapshot || !dt) {
forwarder->DestroySharedSurface(&surface);
return nullptr;
}
dt->DrawSurface(snapshot,
gfx::Rect(gfx::Point(), gfx::Size(size)),
gfx::Rect(gfx::Point(), gfx::Size(size)),
gfx::DrawSurfaceOptions(gfx::Filter::POINT));
forwarder->DestroySharedSurface(&surface);
return dt->Snapshot();
}
#ifdef DEBUG
//////////////////////////////////////////////////////////////
//
+4
View File
@@ -294,6 +294,10 @@ public:
virtual const SizeConstraints& GetSizeConstraints() const override;
virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override;
virtual bool CaptureWidgetOnScreen(mozilla::RefPtr<mozilla::gfx::DrawTarget> aDT) override {
return false;
}
/**
* Use this when GetLayerManager() returns a BasicLayerManager
* (nsBaseWidget::GetLayerManager() does). This sets up the widget's
+20 -1
View File
@@ -58,6 +58,7 @@ struct ScrollableLayerGuid;
}
namespace gfx {
class DrawTarget;
class SourceSurface;
}
namespace widget {
class TextEventDispatcher;
@@ -109,6 +110,7 @@ typedef void* nsNativeWidget;
#define NS_NATIVE_TSF_CATEGORY_MGR 101
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
#define NS_NATIVE_ICOREWINDOW 103 // winrt specific
#define NS_NATIVE_CHILD_WINDOW 104
#endif
#if defined(MOZ_WIDGET_GTK)
// set/get nsPluginNativeWindowGtk, e10s specific
@@ -1464,7 +1466,7 @@ class nsIWidget : public nsISupports {
* a child widget.
*/
struct Configuration {
nsIWidget* mChild;
nsCOMPtr<nsIWidget> mChild;
uintptr_t mWindowID; // e10s specific, the unique plugin port id
bool mVisible; // e10s specific, widget visibility
nsIntRect mBounds;
@@ -2118,6 +2120,23 @@ class nsIWidget : public nsISupports {
*/
virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver);
/*
* Snapshot the contents of the widget by reading pixels back from the
* Operating System. Unlike RenderDocument(), this does not read from our
* own backbuffers, so that we can test if there is a difference in how
* our buffers are being presented.
*
* This is only supported for widgets using OMTC.
*/
already_AddRefed<mozilla::gfx::SourceSurface> SnapshotWidgetOnScreen();
/*
* Implementation of SnapshotWidgetOnScreen. This is invoked by the
* compositor for SnapshotWidgetOnScreen(), and should not be called
* otherwise.
*/
virtual bool CaptureWidgetOnScreen(mozilla::RefPtr<mozilla::gfx::DrawTarget> aDT) = 0;
private:
class LongTapInfo
{
+4
View File
@@ -180,6 +180,7 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
// composition window position.
if (IsIMMActive()) {
nsIMM32Handler::OnUpdateComposition(aWindow);
nsIMM32Handler::OnSelectionChange(aWindow, aIMENotification);
}
return rv;
}
@@ -238,6 +239,9 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
nsIMM32Handler::OnUpdateComposition(aWindow);
return NS_OK;
case NOTIFY_IME_OF_SELECTION_CHANGE:
nsIMM32Handler::OnSelectionChange(aWindow, aIMENotification);
return NS_OK;
case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
return nsIMM32Handler::OnMouseButtonEvent(aWindow, aIMENotification);
#ifdef NS_ENABLE_TSF
+111 -13
View File
@@ -11,7 +11,6 @@
#include "nsWindowDefs.h"
#include "WinUtils.h"
#include "KeyboardLayout.h"
#include "WritingModes.h"
#include <algorithm>
#include "mozilla/MiscEvents.h"
@@ -132,6 +131,7 @@ static UINT sWM_MSIME_MOUSE = 0; // mouse message for MSIME 98/2000
#define IMEMOUSE_WUP 0x10 // wheel up
#define IMEMOUSE_WDOWN 0x20 // wheel down
WritingMode nsIMM32Handler::sWritingModeOfCompositionFont;
nsString nsIMM32Handler::sIMEName;
UINT nsIMM32Handler::sCodePage = 0;
DWORD nsIMM32Handler::sIMEProperty = 0;
@@ -158,7 +158,7 @@ nsIMM32Handler::Initialize()
sAssumeVerticalWritingModeNotSupported =
Preferences::GetBool(
"intl.imm.vertical_writing.always_assume_not_supported", false);
InitKeyboardLayout(::GetKeyboardLayout(0));
InitKeyboardLayout(nullptr, ::GetKeyboardLayout(0));
}
/* static */ void
@@ -205,6 +205,15 @@ nsIMM32Handler::IsJapanist2003Active()
return sIMEName.EqualsLiteral("Japanist 2003");
}
/* static */ bool
nsIMM32Handler::IsGoogleJapaneseInputActive()
{
// NOTE: Even on Windows for en-US, the name of Google Japanese Input is
// written in Japanese.
return sIMEName.Equals(L"Google \x65E5\x672C\x8A9E\x5165\x529B "
L"IMM32 \x30E2\x30B8\x30E5\x30FC\x30EB");
}
/* static */ bool
nsIMM32Handler::ShouldDrawCompositionStringOurselves()
{
@@ -223,18 +232,24 @@ nsIMM32Handler::IsVerticalWritingSupported()
if (sAssumeVerticalWritingModeNotSupported) {
return false;
}
// Google Japanese Input doesn't support vertical writing mode. We should
// return false if it's active IME.
if (IsGoogleJapaneseInputActive()) {
return false;
}
return !!(sIMEUIProperty & (UI_CAP_2700 | UI_CAP_ROT90 | UI_CAP_ROTANY));
}
/* static */ void
nsIMM32Handler::InitKeyboardLayout(HKL aKeyboardLayout)
nsIMM32Handler::InitKeyboardLayout(nsWindow* aWindow,
HKL aKeyboardLayout)
{
UINT IMENameLength = ::ImmGetDescriptionW(aKeyboardLayout, nullptr, 0);
if (IMENameLength) {
// Add room for the terminating null character
sIMEName.SetLength(++IMENameLength);
IMENameLength =
::ImmGetDescriptionW(aKeyboardLayout, sIMEName.BeginWriting(),
::ImmGetDescriptionW(aKeyboardLayout, wwc(sIMEName.BeginWriting()),
IMENameLength);
// Adjust the length to ignore the terminating null character
sIMEName.SetLength(IMENameLength);
@@ -248,6 +263,22 @@ nsIMM32Handler::InitKeyboardLayout(HKL aKeyboardLayout)
(PWSTR)&sCodePage, sizeof(sCodePage) / sizeof(WCHAR));
sIMEProperty = ::ImmGetProperty(aKeyboardLayout, IGP_PROPERTY);
sIMEUIProperty = ::ImmGetProperty(aKeyboardLayout, IGP_UI);
// If active IME is a TIP of TSF, we cannot retrieve the name with IMM32 API.
// For hacking some bugs of some TIP, we should set an IME name from the
// pref.
if (sCodePage == 932 && sIMEName.IsEmpty()) {
sIMEName =
Preferences::GetString("intl.imm.japanese.assume_active_tip_name_as");
}
// Whether the IME supports vertical writing mode might be changed or
// some IMEs may need specific font for their UI. Therefore, we should
// update composition font forcibly here.
if (aWindow) {
MaybeAdjustCompositionFont(aWindow, sWritingModeOfCompositionFont, true);
}
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: InitKeyboardLayout, aKeyboardLayout=%08x (\"%s\"), sCodePage=%lu, "
"sIMEProperty=%s, sIMEUIProperty=%s",
@@ -268,6 +299,7 @@ nsIMM32Handler::GetIMEUpdatePreference()
{
return nsIMEUpdatePreference(
nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE |
nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE |
nsIMEUpdatePreference::NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR);
}
@@ -389,6 +421,43 @@ nsIMM32Handler::OnUpdateComposition(nsWindow* aWindow)
gIMM32Handler->SetIMERelatedWindowsPos(aWindow, IMEContext);
}
// static
void
nsIMM32Handler::OnSelectionChange(nsWindow* aWindow,
const IMENotification& aIMENotification)
{
if (aIMENotification.mSelectionChangeData.mCausedByComposition) {
return;
}
MaybeAdjustCompositionFont(aWindow,
aIMENotification.mSelectionChangeData.GetWritingMode());
}
// static
void
nsIMM32Handler::MaybeAdjustCompositionFont(nsWindow* aWindow,
const WritingMode& aWritingMode,
bool aForceUpdate)
{
switch (sCodePage) {
case 932: // Japanese Shift-JIS
case 936: // Simlified Chinese GBK
case 949: // Korean
case 950: // Traditional Chinese Big5
EnsureHandlerInstance();
break;
default:
// If there is no instance of nsIMM32Hander, we shouldn't waste footprint.
if (!gIMM32Handler) {
return;
}
}
// Like Navi-Bar of ATOK, some IMEs may require proper composition font even
// before sending WM_IME_STARTCOMPOSITION.
nsIMEContext IMEContext(aWindow->GetWindowHandle());
gIMM32Handler->AdjustCompositionFont(IMEContext, aWritingMode, aForceUpdate);
}
/* static */ bool
nsIMM32Handler::ProcessInputLangChangeMessage(nsWindow* aWindow,
@@ -402,7 +471,7 @@ nsIMM32Handler::ProcessInputLangChangeMessage(nsWindow* aWindow,
if (gIMM32Handler) {
gIMM32Handler->OnInputLangChange(aWindow, wParam, lParam, aResult);
}
InitKeyboardLayout(reinterpret_cast<HKL>(lParam));
InitKeyboardLayout(aWindow, reinterpret_cast<HKL>(lParam));
// We can release the instance here, because the instance may be never
// used. E.g., the new keyboard layout may not use IME, or it may use TSF.
Terminate();
@@ -1487,18 +1556,46 @@ nsIMM32Handler::HandleQueryCharPosition(nsWindow* aWindow,
// even if the content of the popup window has focus.
ResolveIMECaretPos(aWindow->GetTopLevelWindow(false),
r, nullptr, screenRect);
// XXX This might need to check writing mode. However, MSDN doesn't explain
// how to set the values in vertical writing mode. Additionally, IME
// doesn't work well with top-left of the character (this is explicitly
// documented) and its horizontal width. So, it might be better to set
// top-right corner of the character and horizontal width, but we're not
// sure if it doesn't cause any problems with a lot of IMEs...
pCharPosition->pt.x = screenRect.x;
pCharPosition->pt.y = screenRect.y;
pCharPosition->cLineHeight = r.height;
// XXX we should use NS_QUERY_EDITOR_RECT event here.
::GetWindowRect(aWindow->GetWindowHandle(), &pCharPosition->rcDocument);
WidgetQueryContentEvent editorRect(true, NS_QUERY_EDITOR_RECT, aWindow);
aWindow->InitEvent(editorRect);
aWindow->DispatchWindowEvent(&editorRect);
if (NS_WARN_IF(!editorRect.mSucceeded)) {
PR_LOG(gIMM32Log, PR_LOG_ERROR,
("IMM32: HandleQueryCharPosition, NS_QUERY_EDITOR_RECT failed"));
::GetWindowRect(aWindow->GetWindowHandle(), &pCharPosition->rcDocument);
} else {
nsIntRect editorRectInWindow =
LayoutDevicePixel::ToUntyped(editorRect.mReply.mRect);
nsWindow* window = editorRect.mReply.mFocusedWidget ?
static_cast<nsWindow*>(editorRect.mReply.mFocusedWidget) : aWindow;
nsIntRect editorRectInScreen;
ResolveIMECaretPos(window, editorRectInWindow, nullptr, editorRectInScreen);
::SetRect(&pCharPosition->rcDocument,
editorRectInScreen.x, editorRectInScreen.y,
editorRectInScreen.XMost(), editorRectInScreen.YMost());
}
*oResult = TRUE;
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleQueryCharPosition, SUCCEEDED\n"));
("IMM32: HandleQueryCharPosition, SUCCEEDED, pCharPosition={ pt={ x=%d, "
"y=%d }, cLineHeight=%d, rcDocument={ left=%d, top=%d, right=%d, "
"bottom=%d } }",
pCharPosition->pt.x, pCharPosition->pt.y, pCharPosition->cLineHeight,
pCharPosition->rcDocument.left, pCharPosition->rcDocument.top,
pCharPosition->rcDocument.right, pCharPosition->rcDocument.bottom));
return true;
}
@@ -2252,7 +2349,8 @@ SetVerticalFontToLogFont(const nsAString& aFontFace,
void
nsIMM32Handler::AdjustCompositionFont(const nsIMEContext& aIMEContext,
const WritingMode& aWritingMode)
const WritingMode& aWritingMode,
bool aForceUpdate)
{
// An instance of nsIMM32Handler is destroyed when active IME is changed.
// Therefore, we need to store the information which are set to the IM
@@ -2264,13 +2362,13 @@ nsIMM32Handler::AdjustCompositionFont(const nsIMEContext& aIMEContext,
// If composition font is customized by pref, we need to modify the
// composition font of the IME context at first time even if the writing mode
// is horizontal.
bool setCompositionFontForcibly =
!sCompositionFontsInitialized && !sCompositionFont.IsEmpty();
bool setCompositionFontForcibly = aForceUpdate ||
(!sCompositionFontsInitialized && !sCompositionFont.IsEmpty());
static WritingMode sCurrentWritingMode;
static nsString sCurrentIMEName;
if (!setCompositionFontForcibly &&
sCurrentWritingMode == aWritingMode &&
sWritingModeOfCompositionFont == aWritingMode &&
sCurrentIMEName == sIMEName) {
// Nothing to do if writing mode isn't being changed.
return;
@@ -2319,7 +2417,7 @@ nsIMM32Handler::AdjustCompositionFont(const nsIMEContext& aIMEContext,
}
}
sCurrentWritingMode = aWritingMode;
sWritingModeOfCompositionFont = aWritingMode;
sCurrentIMEName = sIMEName;
LOGFONTW logFont;
+22 -5
View File
@@ -14,13 +14,11 @@
#include "nsIWidget.h"
#include "mozilla/EventForwards.h"
#include "nsRect.h"
#include "WritingModes.h"
class nsWindow;
namespace mozilla {
class WritingMode;
namespace widget {
struct MSGResult;
@@ -146,6 +144,8 @@ public:
static void CommitComposition(nsWindow* aWindow, bool aForce = false);
static void CancelComposition(nsWindow* aWindow, bool aForce = false);
static void OnUpdateComposition(nsWindow* aWindow);
static void OnSelectionChange(nsWindow* aWindow,
const IMENotification& aIMENotification);
static nsIMEUpdatePreference GetIMEUpdatePreference();
@@ -162,10 +162,12 @@ protected:
static bool IsComposingWindow(nsWindow* aWindow);
static bool IsJapanist2003Active();
static bool IsGoogleJapaneseInputActive();
static bool ShouldDrawCompositionStringOurselves();
static bool IsVerticalWritingSupported();
static void InitKeyboardLayout(HKL aKeyboardLayout);
// aWindow can be nullptr if it's called without receiving WM_INPUTLANGCHANGE.
static void InitKeyboardLayout(nsWindow* aWindow, HKL aKeyboardLayout);
static UINT GetKeyboardCodePage();
/**
@@ -295,9 +297,23 @@ protected:
/**
* AdjustCompositionFont() makes IME vertical writing mode if it's supported.
* If aForceUpdate is true, it will update composition font even if writing
* mode isn't being changed.
*/
void AdjustCompositionFont(const nsIMEContext& aIMEContext,
const mozilla::WritingMode& aWritingMode);
const mozilla::WritingMode& aWritingMode,
bool aForceUpdate = false);
/**
* MaybeAdjustCompositionFont() calls AdjustCompositionFont() when the
* locale of active IME is CJK. Note that this creates an instance even
* when there is no composition but the locale is CJK.
*/
static void MaybeAdjustCompositionFont(
nsWindow* aWindow,
const mozilla::WritingMode& aWritingMode,
bool aForceUpdate = false);
/**
* Get the current target clause of composition string.
* If there are one or more characters whose attribute is ATTR_TARGET_*,
@@ -375,6 +391,7 @@ protected:
bool mIsComposingOnPlugin;
bool mNativeCaretIsCreated;
static mozilla::WritingMode sWritingModeOfCompositionFont;
static nsString sIMEName;
static UINT sCodePage;
static DWORD sIMEProperty;
+65 -1
View File
@@ -2939,6 +2939,29 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
return nullptr;
}
void
nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
{
switch (aDataType) {
case NS_NATIVE_CHILD_WINDOW:
{
HWND childWindow = reinterpret_cast<HWND>(aVal);
// Make sure the window is styled to be a child window.
LONG_PTR style = GetWindowLongPtr(childWindow, GWL_STYLE);
style |= WS_CHILD;
style &= ~WS_POPUP;
SetWindowLongPtr(childWindow, GWL_STYLE, style);
// Do the reparenting.
::SetParent(childWindow, mWnd);
break;
}
default:
NS_ERROR("SetNativeData called with unsupported data type.");
}
}
// Free some native data according to aDataType
void nsWindow::FreeNativeData(void * data, uint32_t aDataType)
{
@@ -6388,7 +6411,7 @@ nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
// need.
for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
nsWindow* w = static_cast<nsWindow*>(configuration.mChild.get());
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, true);
@@ -7599,6 +7622,47 @@ void nsWindow::PickerClosed()
}
}
bool nsWindow::CaptureWidgetOnScreen(RefPtr<DrawTarget> aDT)
{
BOOL dwmEnabled = false;
if (WinUtils::dwmIsCompositionEnabledPtr &&
WinUtils::dwmFlushProcPtr &&
WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled) &&
dwmEnabled)
{
WinUtils::dwmFlushProcPtr();
}
HDC dc = ::GetDC(mWnd);
uint32_t flags = (mTransparencyMode == eTransparencyOpaque)
? 0
: gfxWindowsSurface::FLAG_IS_TRANSPARENT;
nsRefPtr<gfxASurface> surf = new gfxWindowsSurface(dc, flags);
IntSize size(surf->GetSize().width, surf->GetSize().height);
if (size.width < 0 || size.height < 0) {
::ReleaseDC(mWnd, dc);
return false;
}
RefPtr<DrawTarget> source = Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
if (!source) {
::ReleaseDC(mWnd, dc);
return false;
}
RefPtr<SourceSurface> snapshot = source->Snapshot();
if (!snapshot) {
::ReleaseDC(mWnd, dc);
return false;
}
aDT->DrawSurface(snapshot,
Rect(0, 0, size.width, size.height),
Rect(0, 0, size.width, size.height));
::ReleaseDC(mWnd, dc);
return true;
}
bool nsWindow::PreRender(LayerManagerComposite*)
{
// This can block waiting for WM_SETTEXT to finish
+3
View File
@@ -133,6 +133,7 @@ public:
bool aIncludeChildren = false);
NS_IMETHOD Invalidate(const nsIntRect & aRect);
virtual void* GetNativeData(uint32_t aDataType);
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
virtual void FreeNativeData(void * data, uint32_t aDataType);
NS_IMETHOD SetTitle(const nsAString& aTitle);
NS_IMETHOD SetIcon(const nsAString& aIconSpec);
@@ -281,6 +282,8 @@ public:
bool IsPopup();
virtual bool ShouldUseOffMainThreadCompositing();
bool CaptureWidgetOnScreen(mozilla::RefPtr<mozilla::gfx::DrawTarget> aDT);
protected:
virtual ~nsWindow();