mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 911951 part.1 Redesign nsIDOMWindowUtils::SendTextEvent() with nsICompositionStringSynthesizer r=smaug, sr=roc
This commit is contained in:
parent
18b4888466
commit
f0182b0d88
151
dom/base/CompositionStringSynthesizer.cpp
Normal file
151
dom/base/CompositionStringSynthesizer.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CompositionStringSynthesizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsView.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CompositionStringSynthesizer,
|
||||
nsICompositionStringSynthesizer)
|
||||
|
||||
CompositionStringSynthesizer::CompositionStringSynthesizer(
|
||||
nsPIDOMWindow* aWindow)
|
||||
{
|
||||
mWindow = do_GetWeakReference(aWindow);
|
||||
ClearInternal();
|
||||
}
|
||||
|
||||
CompositionStringSynthesizer::~CompositionStringSynthesizer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CompositionStringSynthesizer::ClearInternal()
|
||||
{
|
||||
mString.Truncate();
|
||||
mClauses.Clear();
|
||||
mCaret.mRangeType = 0;
|
||||
}
|
||||
|
||||
nsIWidget*
|
||||
CompositionStringSynthesizer::GetWidget()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIDocShell *docShell = window->GetDocShell();
|
||||
if (!docShell) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
|
||||
if (!presShell) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIFrame* frame = presShell->GetRootFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
return frame->GetView()->GetNearestWidget(nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CompositionStringSynthesizer::SetString(const nsAString& aString)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mString = aString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CompositionStringSynthesizer::AppendClause(uint32_t aLength,
|
||||
uint32_t aAttribute)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
switch (aAttribute) {
|
||||
case ATTR_RAWINPUT:
|
||||
case ATTR_SELECTEDRAWTEXT:
|
||||
case ATTR_CONVERTEDTEXT:
|
||||
case ATTR_SELECTEDCONVERTEDTEXT: {
|
||||
nsTextRange textRange;
|
||||
textRange.mStartOffset =
|
||||
mClauses.IsEmpty() ? 0 : mClauses[mClauses.Length() - 1].mEndOffset;
|
||||
textRange.mEndOffset = textRange.mStartOffset + aLength;
|
||||
textRange.mRangeType = aAttribute;
|
||||
mClauses.AppendElement(textRange);
|
||||
return NS_OK;
|
||||
}
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CompositionStringSynthesizer::SetCaret(uint32_t aOffset, uint32_t aLength)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mCaret.mStartOffset = aOffset;
|
||||
mCaret.mEndOffset = mCaret.mStartOffset + aLength;
|
||||
mCaret.mRangeType = NS_TEXTRANGE_CARETPOSITION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CompositionStringSynthesizer::DispatchEvent(bool* aDefaultPrevented)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDefaultPrevented);
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
if (!mClauses.IsEmpty()) {
|
||||
NS_ENSURE_TRUE(mClauses[mClauses.Length()-1].mEndOffset == mString.Length(),
|
||||
NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
if (mCaret.mRangeType == NS_TEXTRANGE_CARETPOSITION) {
|
||||
NS_ENSURE_TRUE(mCaret.mEndOffset <= mString.Length(),
|
||||
NS_ERROR_ILLEGAL_VALUE);
|
||||
mClauses.AppendElement(mCaret);
|
||||
}
|
||||
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, widget);
|
||||
textEvent.time = PR_IntervalNow();
|
||||
textEvent.theText = mString;
|
||||
textEvent.rangeCount = mClauses.Length();
|
||||
textEvent.rangeArray = mClauses.Elements();
|
||||
|
||||
// XXX How should we set false for this on b2g?
|
||||
textEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsresult rv = widget->DispatchEvent(&textEvent, status);
|
||||
*aDefaultPrevented = (status == nsEventStatus_eConsumeNoDefault);
|
||||
|
||||
ClearInternal();
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
45
dom/base/CompositionStringSynthesizer.h
Normal file
45
dom/base/CompositionStringSynthesizer.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_compositionstringsynthesizer_h__
|
||||
#define mozilla_dom_compositionstringsynthesizer_h__
|
||||
|
||||
#include "nsICompositionStringSynthesizer.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIWidget;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class CompositionStringSynthesizer MOZ_FINAL :
|
||||
public nsICompositionStringSynthesizer
|
||||
{
|
||||
public:
|
||||
CompositionStringSynthesizer(nsPIDOMWindow* aWindow);
|
||||
~CompositionStringSynthesizer();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICOMPOSITIONSTRINGSYNTHESIZER
|
||||
|
||||
private:
|
||||
nsWeakPtr mWindow; // refers an instance of nsPIDOMWindow
|
||||
nsString mString;
|
||||
nsAutoTArray<nsTextRange, 10> mClauses;
|
||||
nsTextRange mCaret;
|
||||
|
||||
nsIWidget* GetWidget();
|
||||
void ClearInternal();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef mozilla_dom_compositionstringsynthesizer_h__
|
@ -65,6 +65,7 @@ EXPORTS.mozilla.dom += [
|
||||
|
||||
CPP_SOURCES += [
|
||||
'BarProps.cpp',
|
||||
'CompositionStringSynthesizer.cpp',
|
||||
'Crypto.cpp',
|
||||
'DOMCursor.cpp',
|
||||
'DOMError.cpp',
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsDOMWindowUtils.h"
|
||||
#include "nsQueryContentEventResult.h"
|
||||
#include "CompositionStringSynthesizer.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsFocusManager.h"
|
||||
@ -1816,82 +1817,21 @@ nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
AppendClause(int32_t aClauseLength, uint32_t aClauseAttr,
|
||||
nsTArray<nsTextRange>* aRanges)
|
||||
{
|
||||
NS_PRECONDITION(aRanges, "aRange is null");
|
||||
if (aClauseLength == 0) {
|
||||
return;
|
||||
}
|
||||
nsTextRange range;
|
||||
range.mStartOffset = aRanges->Length() == 0 ? 0 :
|
||||
aRanges->ElementAt(aRanges->Length() - 1).mEndOffset + 1;
|
||||
range.mEndOffset = range.mStartOffset + aClauseLength;
|
||||
NS_ASSERTION(range.mStartOffset <= range.mEndOffset, "range is invalid");
|
||||
NS_PRECONDITION(aClauseAttr == NS_TEXTRANGE_RAWINPUT ||
|
||||
aClauseAttr == NS_TEXTRANGE_SELECTEDRAWTEXT ||
|
||||
aClauseAttr == NS_TEXTRANGE_CONVERTEDTEXT ||
|
||||
aClauseAttr == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT,
|
||||
"aClauseAttr is invalid value");
|
||||
range.mRangeType = aClauseAttr;
|
||||
aRanges->AppendElement(range);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendTextEvent(const nsAString& aCompositionString,
|
||||
int32_t aFirstClauseLength,
|
||||
uint32_t aFirstClauseAttr,
|
||||
int32_t aSecondClauseLength,
|
||||
uint32_t aSecondClauseAttr,
|
||||
int32_t aThirdClauseLength,
|
||||
uint32_t aThirdClauseAttr,
|
||||
int32_t aCaretStart,
|
||||
int32_t aCaretLength)
|
||||
nsDOMWindowUtils::CreateCompositionStringSynthesizer(
|
||||
nsICompositionStringSynthesizer** aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = nullptr;
|
||||
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, widget);
|
||||
InitEvent(textEvent);
|
||||
|
||||
nsAutoTArray<nsTextRange, 4> textRanges;
|
||||
NS_ENSURE_TRUE(aFirstClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aSecondClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aThirdClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
AppendClause(aFirstClauseLength, aFirstClauseAttr, &textRanges);
|
||||
AppendClause(aSecondClauseLength, aSecondClauseAttr, &textRanges);
|
||||
AppendClause(aThirdClauseLength, aThirdClauseAttr, &textRanges);
|
||||
int32_t len = aFirstClauseLength + aSecondClauseLength + aThirdClauseLength;
|
||||
NS_ENSURE_TRUE(len == 0 || uint32_t(len) == aCompositionString.Length(),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
if (aCaretStart >= 0) {
|
||||
nsTextRange range;
|
||||
range.mStartOffset = aCaretStart;
|
||||
range.mEndOffset = range.mStartOffset + aCaretLength;
|
||||
range.mRangeType = NS_TEXTRANGE_CARETPOSITION;
|
||||
textRanges.AppendElement(range);
|
||||
}
|
||||
|
||||
textEvent.theText = aCompositionString;
|
||||
|
||||
textEvent.rangeCount = textRanges.Length();
|
||||
textEvent.rangeArray = textRanges.Elements();
|
||||
|
||||
textEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
|
||||
nsEventStatus status;
|
||||
nsresult rv = widget->DispatchEvent(&textEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
NS_ADDREF(*aResult = new CompositionStringSynthesizer(window));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
XPIDL_SOURCES += [
|
||||
'domstubs.idl',
|
||||
'nsIBrowserDOMWindow.idl',
|
||||
'nsICompositionStringSynthesizer.idl',
|
||||
'nsIContentPermissionPrompt.idl',
|
||||
'nsIContentPrefService.idl',
|
||||
'nsIContentPrefService2.idl',
|
||||
|
53
dom/interfaces/base/nsICompositionStringSynthesizer.idl
Normal file
53
dom/interfaces/base/nsICompositionStringSynthesizer.idl
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Stores composition clauses information and caret information for synthesizing
|
||||
* composition string.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(9a7d7851-8c0a-4061-9edc-60d6693f86c9)]
|
||||
interface nsICompositionStringSynthesizer : nsISupports
|
||||
{
|
||||
/**
|
||||
* Set composition string or committed string.
|
||||
*/
|
||||
void setString(in AString aString);
|
||||
|
||||
// NOTE: These values must be same to NS_TEXTRANGE_* in nsGUIEvent.h
|
||||
const unsigned long ATTR_RAWINPUT = 0x02;
|
||||
const unsigned long ATTR_SELECTEDRAWTEXT = 0x03;
|
||||
const unsigned long ATTR_CONVERTEDTEXT = 0x04;
|
||||
const unsigned long ATTR_SELECTEDCONVERTEDTEXT = 0x05;
|
||||
|
||||
/**
|
||||
* Append a clause.
|
||||
*
|
||||
* TODO: Should be able to specify custom clause style.
|
||||
*/
|
||||
void appendClause(in unsigned long aLength,
|
||||
in unsigned long aAttribute);
|
||||
|
||||
/**
|
||||
* Set caret information.
|
||||
*/
|
||||
void setCaret(in unsigned long aOffset,
|
||||
in unsigned long aLength);
|
||||
|
||||
/**
|
||||
* Synthesize composition string with given information by dispatching
|
||||
* a proper event.
|
||||
*
|
||||
* If clauses have never been set, this dispatches a commit event.
|
||||
* If clauses are not filled all over the composition string, this throw an
|
||||
* error.
|
||||
*
|
||||
* After dispatching event, this clears all the information about the
|
||||
* composition string. So, you can reuse this instance.
|
||||
*/
|
||||
bool dispatchEvent();
|
||||
};
|
@ -41,8 +41,9 @@ interface nsIDOMClientRect;
|
||||
interface nsIURI;
|
||||
interface nsIDOMEventTarget;
|
||||
interface nsIRunnable;
|
||||
interface nsICompositionStringSynthesizer;
|
||||
|
||||
[scriptable, uuid(d18a8d69-7609-4165-ae20-af8aead36833)]
|
||||
[scriptable, uuid(dd45c6ae-9d80-46ef-86d7-f2795a48a77b)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -787,44 +788,12 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
in AString aLocale);
|
||||
|
||||
/**
|
||||
* Synthesize a text event to the window.
|
||||
* Creating synthesizer of composition string on the window.
|
||||
*
|
||||
* Cannot be accessed from unprivileged context (not content-accessible)
|
||||
* Will throw a DOM security error if called without chrome privileges.
|
||||
*
|
||||
* Currently, this method doesn't support 4 or more clauses composition
|
||||
* string.
|
||||
*
|
||||
* @param aCompositionString composition string
|
||||
* @param a*ClauseLengh the length of nth clause, set 0 when you
|
||||
* don't need second or third clause.
|
||||
* @param a*ClauseAttr the attribute of nth clause, uese following
|
||||
* const values.
|
||||
* @param aCaretStart the caret position in the composition string,
|
||||
* if you set negative value, this method don't
|
||||
* set the caret position to the event.
|
||||
* @param aCaretLength the caret length, if this is one or more,
|
||||
* the caret will be wide caret, otherwise,
|
||||
* it's collapsed.
|
||||
* XXX nsEditor doesn't support wide caret yet.
|
||||
*/
|
||||
|
||||
// NOTE: These values must be same to NS_TEXTRANGE_* in nsGUIEvent.h
|
||||
|
||||
const unsigned long COMPOSITION_ATTR_RAWINPUT = 0x02;
|
||||
const unsigned long COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03;
|
||||
const unsigned long COMPOSITION_ATTR_CONVERTEDTEXT = 0x04;
|
||||
const unsigned long COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
|
||||
|
||||
void sendTextEvent(in AString aCompositionString,
|
||||
in long aFirstClauseLength,
|
||||
in unsigned long aFirstClauseAttr,
|
||||
in long aSecondClauseLength,
|
||||
in unsigned long aSecondClauseAttr,
|
||||
in long aThirdClauseLength,
|
||||
in unsigned long aThirdClauseAttr,
|
||||
in long aCaretStart,
|
||||
in long aCaretLength);
|
||||
nsICompositionStringSynthesizer createCompositionStringSynthesizer();
|
||||
|
||||
/**
|
||||
* Synthesize a query content event. Note that the result value returned here
|
||||
|
Loading…
Reference in New Issue
Block a user