Bug 519972 part 6: Make TextInputHandler grabbed by nsChildView and its methods which dispatch events r=smichaud

This commit is contained in:
Masayuki Nakano 2011-05-08 19:19:23 +09:00
Родитель 6caadfb6f9
Коммит 34e8fcc741
5 изменённых файлов: 247 добавлений и 156 удалений

Просмотреть файл

@ -218,38 +218,55 @@ protected:
class TextInputHandlerBase
{
public:
/**
* Init must be called when aOwner is initializing and finished attaching
* an NSView.
*
* @param aOwner An owner nsChildView of the instance.
*/
virtual void Init(nsChildView* aOwner);
nsrefcnt AddRef()
{
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "mRefCnt is negative");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this));
return mRefCnt;
}
nsrefcnt Release()
{
NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase");
if (mRefCnt == 0) {
mRefCnt = 1; /* stabilize */
delete this;
return 0;
}
return mRefCnt;
}
protected:
nsAutoRefCnt mRefCnt;
public:
/**
* OnDestroyView must be called when mOwnerWidget is destroying and detaching
* mView.
* mWidget must not be destroyed without OnDestroyWidget being called.
*
* @param aDestroyingView Destroying view. This might not be mView.
* @param aDestroyingWidget Destroying widget. This might not be mWidget.
* @return This result doesn't have any meaning for
* callers. When the aDstroyingView isn't same
* as mView, FALSE. Then, inherited methods in
* callers. When aDstroyingWidget isn't the same
* as mWidget, FALSE. Then, inherited methods in
* sub classes should return from this method
* without cleaning up.
*/
virtual PRBool OnDestroyView(NSView<mozView> *aDestroyingView);
virtual PRBool OnDestroyWidget(nsChildView* aDestroyingWidget);
protected:
// The owner of this instance. The result of mOwnerWidget->TextInputHandler
// returns this instance. This must not be null after initialized.
nsChildView* mOwnerWidget;
// The creater of this instance and client.
// This must not be null after initialized until OnDestroyWidget() is called.
nsChildView* mWidget; // [WEAK]
// The native focused view, this is the native NSView of mOwnerWidget.
// The native view for mWidget.
// This view handles the actual text inputting.
NSView<mozView>* mView;
NSView<mozView>* mView; // [STRONG]
TextInputHandlerBase();
TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView);
virtual ~TextInputHandlerBase();
PRBool Destroyed() { return !mWidget; }
};
/**
@ -259,7 +276,7 @@ protected:
class PluginTextInputHandler : public TextInputHandlerBase
{
protected:
PluginTextInputHandler();
PluginTextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
~PluginTextInputHandler();
};
@ -279,12 +296,12 @@ protected:
class IMEInputHandler : public PluginTextInputHandler
{
public:
virtual PRBool OnDestroyView(NSView<mozView> *aDestroyingView);
virtual PRBool OnDestroyWidget(nsChildView* aDestroyingWidget);
virtual void OnFocusChangeInGecko(PRBool aFocus);
/**
* DispatchTextEvent() dispatches a text event on mOwnerWidget.
* DispatchTextEvent() dispatches a text event on mWidget.
*
* @param aText User text input.
* @param aAttrString An NSAttributedString instance which indicates
@ -436,7 +453,7 @@ protected:
};
PRUint32 mPendingMethods;
IMEInputHandler();
IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
virtual ~IMEInputHandler();
PRBool IsFocused();
@ -560,7 +577,7 @@ public:
static CFArrayRef CreateAllKeyboardLayoutList();
static void DebugPrintAllKeyboardLayouts(PRLogModuleInfo* aLogModuleInfo);
TextInputHandler();
TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
virtual ~TextInputHandler();
};

Просмотреть файл

@ -560,13 +560,16 @@ TextInputHandler::DebugPrintAllKeyboardLayouts(PRLogModuleInfo* aLogModuleInfo)
*
******************************************************************************/
TextInputHandler::TextInputHandler() :
IMEInputHandler()
TextInputHandler::TextInputHandler(nsChildView* aWidget,
NSView<mozView> *aNativeView) :
IMEInputHandler(aWidget, aNativeView)
{
[mView installTextInputHandler:this];
}
TextInputHandler::~TextInputHandler()
{
[mView uninstallTextInputHandler];
}
@ -741,8 +744,9 @@ IMEInputHandler::ResetIMEWindowLevel()
TrueOrFalse(IsFocused()), GetCurrentTSMDocumentID());
#endif // DEBUG_IME_HANDLER
if (!mView)
if (Destroyed()) {
return;
}
if (!IsFocused()) {
// retry at next focus event
@ -763,7 +767,7 @@ IMEInputHandler::ResetIMEWindowLevel()
// focused view is the panel's parent view (mView). But the editor is
// displayed on the popuped widget's view (editorView). So, their window
// level may be different.
NSView<mozView>* editorView = mOwnerWidget->GetEditorView();
NSView<mozView>* editorView = mWidget->GetEditorView();
if (!editorView) {
NS_ERROR("editorView is null");
return;
@ -801,8 +805,9 @@ IMEInputHandler::DiscardIMEComposition()
NSLog(@" currentInputManager:%p", [NSInputManager currentInputManager]);
#endif // DEBUG_IME_HANDLER
if (!mView)
if (Destroyed()) {
return;
}
if (!IsFocused()) {
// retry at next focus event
@ -838,8 +843,9 @@ IMEInputHandler::SyncASCIICapableOnly()
TrueOrFalse(IsFocused()), GetCurrentTSMDocumentID());
#endif
if (!mView)
if (Destroyed()) {
return;
}
if (!IsFocused()) {
// retry at next focus event
@ -1041,7 +1047,11 @@ IMEInputHandler::DispatchTextEvent(const nsString& aText,
aSelectedRange.location, aSelectedRange.length);
#endif
nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, mOwnerWidget);
NS_ENSURE_TRUE(!Destroyed(), PR_FALSE);
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, mWidget);
textEvent.time = PR_IntervalNow();
textEvent.theText = aText;
nsAutoTArray<nsTextRange, 4> textRanges;
@ -1051,7 +1061,7 @@ IMEInputHandler::DispatchTextEvent(const nsString& aText,
textEvent.rangeArray = textRanges.Elements();
textEvent.rangeCount = textRanges.Length();
return mOwnerWidget->DispatchWindowEvent(textEvent);
return mWidget->DispatchWindowEvent(textEvent);
}
void
@ -1071,7 +1081,11 @@ IMEInputHandler::InsertTextAsCommittingComposition(
NSLog(@" mMarkedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
#endif
nsRefPtr<nsChildView> kungFuDeathGrip(mOwnerWidget);
if (Destroyed()) {
return;
}
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsString str;
GetStringForNSString([aAttrString string], str);
@ -1079,12 +1093,12 @@ IMEInputHandler::InsertTextAsCommittingComposition(
if (!IsIMEComposing()) {
// XXXmnakano Probably, we shouldn't emulate composition in this case.
// I think that we should just fire DOM3 textInput event if we implement it.
nsCompositionEvent compStart(PR_TRUE, NS_COMPOSITION_START, mOwnerWidget);
nsCompositionEvent compStart(PR_TRUE, NS_COMPOSITION_START, mWidget);
InitCompositionEvent(compStart);
mOwnerWidget->DispatchWindowEvent(compStart);
if (!mView) {
return; // we're destroyed
mWidget->DispatchWindowEvent(compStart);
if (Destroyed()) {
return;
}
OnStartIMEComposition();
@ -1096,17 +1110,17 @@ IMEInputHandler::InsertTextAsCommittingComposition(
NSRange range = NSMakeRange(0, str.Length());
DispatchTextEvent(str, aAttrString, range, PR_TRUE);
if (!mView) {
return; // we're destroyed
if (Destroyed()) {
return;
}
OnUpdateIMEComposition([aAttrString string]);
nsCompositionEvent compEnd(PR_TRUE, NS_COMPOSITION_END, mOwnerWidget);
nsCompositionEvent compEnd(PR_TRUE, NS_COMPOSITION_END, mWidget);
InitCompositionEvent(compEnd);
mOwnerWidget->DispatchWindowEvent(compEnd);
if (!mView) {
return; // we're destroyed
mWidget->DispatchWindowEvent(compEnd);
if (Destroyed()) {
return;
}
OnEndIMEComposition();
@ -1129,11 +1143,11 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
NSLog(@" aAttrString = '%@'", aAttrString);
#endif
if (IgnoreIMEComposition()) {
if (Destroyed() || IgnoreIMEComposition()) {
return;
}
nsRefPtr<nsChildView> kungFuDeathGrip(mOwnerWidget);
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsString str;
GetStringForNSString([aAttrString string], str);
@ -1142,16 +1156,16 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
if (!IsIMEComposing() && !str.IsEmpty()) {
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT,
mOwnerWidget);
mOwnerWidget->DispatchWindowEvent(selection);
mWidget);
mWidget->DispatchWindowEvent(selection);
mMarkedRange.location = selection.mSucceeded ? selection.mReply.mOffset : 0;
nsCompositionEvent compStart(PR_TRUE, NS_COMPOSITION_START, mOwnerWidget);
nsCompositionEvent compStart(PR_TRUE, NS_COMPOSITION_START, mWidget);
InitCompositionEvent(compStart);
mOwnerWidget->DispatchWindowEvent(compStart);
if (!mView) {
return; // we're destroyed
mWidget->DispatchWindowEvent(compStart);
if (Destroyed()) {
return;
}
OnStartIMEComposition();
@ -1162,16 +1176,16 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
PRBool doCommit = str.IsEmpty();
DispatchTextEvent(str, aAttrString, aSelectedRange, doCommit);
if (!mView) {
return; // we're destroyed
if (Destroyed()) {
return;
}
if (doCommit) {
nsCompositionEvent compEnd(PR_TRUE, NS_COMPOSITION_END, mOwnerWidget);
nsCompositionEvent compEnd(PR_TRUE, NS_COMPOSITION_END, mWidget);
InitCompositionEvent(compEnd);
mOwnerWidget->DispatchWindowEvent(compEnd);
if (!mView) {
return; // we're destroyed
mWidget->DispatchWindowEvent(compEnd);
if (Destroyed()) {
return;
}
OnEndIMEComposition();
}
@ -1183,10 +1197,16 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
NSInteger
IMEInputHandler::ConversationIdentifier()
{
if (Destroyed()) {
return reinterpret_cast<NSInteger>(mView);
}
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
// NOTE: The size of NSInteger is same as pointer size.
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mOwnerWidget);
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mWidget);
textContent.InitForQueryTextContent(0, 0);
mOwnerWidget->DispatchWindowEvent(textContent);
mWidget->DispatchWindowEvent(textContent);
if (!textContent.mSucceeded) {
return reinterpret_cast<NSInteger>(mView);
}
@ -1205,14 +1225,16 @@ IMEInputHandler::GetAttributedSubstringFromRange(NSRange& aRange)
NSLog(@" aRange = %d, %d", aRange.location, aRange.length);
#endif
if (aRange.location == NSNotFound || aRange.length == 0) {
if (Destroyed() || aRange.location == NSNotFound || aRange.length == 0) {
return nil;
}
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsAutoString str;
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mOwnerWidget);
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mWidget);
textContent.InitForQueryTextContent(aRange.location, aRange.length);
mOwnerWidget->DispatchWindowEvent(textContent);
mWidget->DispatchWindowEvent(textContent);
if (!textContent.mSucceeded || textContent.mReply.mString.IsEmpty()) {
return nil;
@ -1235,10 +1257,18 @@ IMEInputHandler::SelectedRange()
#if DEBUG_IME_HANDLER
NSLog(@"****in SelectedRange");
#endif
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, mOwnerWidget);
mOwnerWidget->DispatchWindowEvent(selection);
NSRange range = NSMakeRange(NSNotFound, 0);
if (Destroyed()) {
return range;
}
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, mWidget);
mWidget->DispatchWindowEvent(selection);
if (!selection.mSucceeded) {
return NSMakeRange(NSNotFound, 0);
return range;
}
#if DEBUG_IME_HANDLER
@ -1260,21 +1290,24 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange)
NSLog(@"****in FirstRectForCharacterRange");
NSLog(@" aRange = %d, %d", aRange.location, aRange.length);
#endif
// XXX this returns first character rect or caret rect, it is limitation of
// now. We need more work for returns first line rect. But current
// implementation is enough for IMEs.
NSRect rect;
if (aRange.location == NSNotFound) {
if (Destroyed() || aRange.location == NSNotFound) {
return rect;
}
nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsIntRect r;
PRBool useCaretRect = (aRange.length == 0);
if (!useCaretRect) {
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, mOwnerWidget);
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, mWidget);
charRect.InitForQueryTextRect(aRange.location, 1);
mOwnerWidget->DispatchWindowEvent(charRect);
mWidget->DispatchWindowEvent(charRect);
if (charRect.mSucceeded) {
r = charRect.mReply.mRect;
} else {
@ -1283,9 +1316,9 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange)
}
if (useCaretRect) {
nsQueryContentEvent caretRect(PR_TRUE, NS_QUERY_CARET_RECT, mOwnerWidget);
nsQueryContentEvent caretRect(PR_TRUE, NS_QUERY_CARET_RECT, mWidget);
caretRect.InitForQueryCaretRect(aRange.location);
mOwnerWidget->DispatchWindowEvent(caretRect);
mWidget->DispatchWindowEvent(caretRect);
if (!caretRect.mSucceeded) {
return rect;
}
@ -1293,7 +1326,7 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange)
r.width = 0;
}
nsIWidget* rootWidget = mOwnerWidget->GetTopLevelWidget();
nsIWidget* rootWidget = mWidget->GetTopLevelWidget();
NSWindow* rootWindow =
static_cast<NSWindow*>(rootWidget->GetNativeData(NS_NATIVE_WINDOW));
NSView* rootView =
@ -1319,6 +1352,9 @@ IMEInputHandler::CharacterIndexForPoint(NSPoint& aPoint)
#if DEBUG_IME
NSLog(@"****in CharacterIndexForPoint");
#endif
//nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
// To implement this, we'd have to grovel in text frames looking at text
// offsets.
return 0;
@ -1333,6 +1369,8 @@ IMEInputHandler::GetValidAttributesForMarkedText()
NSLog(@"****in GetValidAttributesForMarkedText");
#endif
//nsRefPtr<IMEInputHandler> kungFuDeathGrip(this);
//return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName,
// NSMarkedClauseSegmentAttributeName,
// NSTextInputReplacementRangeAttributeName,
@ -1353,8 +1391,9 @@ IMEInputHandler::GetValidAttributesForMarkedText()
*
******************************************************************************/
IMEInputHandler::IMEInputHandler() :
PluginTextInputHandler(),
IMEInputHandler::IMEInputHandler(nsChildView* aWidget,
NSView<mozView> *aNativeView) :
PluginTextInputHandler(aWidget, aNativeView),
mPendingMethods(0), mIMECompositionString(nsnull),
mIsIMEComposing(PR_FALSE), mIsIMEEnabled(PR_TRUE),
mIsASCIICapableOnly(PR_FALSE), mIgnoreIMECommit(PR_FALSE),
@ -1408,21 +1447,20 @@ IMEInputHandler::OnFocusChangeInGecko(PRBool aFocus)
}
PRBool
IMEInputHandler::OnDestroyView(NSView<mozView> *aDestroyingView)
IMEInputHandler::OnDestroyWidget(nsChildView* aDestroyingWidget)
{
// If we're not focused, the destroying view might be composing with it in
// another instance.
// If we're not focused, the focused IMEInputHandler may have been
// created by another widget/nsChildView.
if (sFocusedIMEHandler && sFocusedIMEHandler != this) {
sFocusedIMEHandler->OnDestroyView(aDestroyingView);
sFocusedIMEHandler->OnDestroyWidget(aDestroyingWidget);
}
if (!PluginTextInputHandler::OnDestroyView(aDestroyingView)) {
if (!PluginTextInputHandler::OnDestroyWidget(aDestroyingWidget)) {
return PR_FALSE;
}
if (IsIMEComposing()) {
// If our view is in the composition, we should clean up it.
// XXX Might CancelIMEComposition() fail because mView is being destroyed?
CancelIMEComposition();
OnEndIMEComposition();
}
@ -1498,7 +1536,11 @@ IMEInputHandler::SendCommittedText(NSString *aString)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NS_ASSERTION(mView, "mView is null");
NS_ENSURE_TRUE(mWidget, );
// XXX We should send the string without mView.
if (!mView) {
return;
}
NSAttributedString* attrStr =
[[NSAttributedString alloc] initWithString:aString];
@ -1519,8 +1561,9 @@ IMEInputHandler::KillIMEComposition()
NSLog(@" currentInputManager:%p", [NSInputManager currentInputManager]);
#endif // DEBUG_IME_HANDLER
if (!mView)
if (Destroyed()) {
return;
}
if (IsFocused()) {
[[NSInputManager currentInputManager] markedTextAbandoned: mView];
@ -1604,7 +1647,7 @@ IMEInputHandler::IsFocused()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NS_ENSURE_TRUE(mView, PR_FALSE);
NS_ENSURE_TRUE(!Destroyed(), PR_FALSE);
NSWindow* window = [mView window];
NS_ENSURE_TRUE(window, PR_FALSE);
return [window firstResponder] == mView &&
@ -1730,8 +1773,9 @@ IMEInputHandler::OpenSystemPreferredLanguageIME()
*
******************************************************************************/
PluginTextInputHandler::PluginTextInputHandler() :
TextInputHandlerBase()
PluginTextInputHandler::PluginTextInputHandler(nsChildView* aWidget,
NSView<mozView> *aNativeView) :
TextInputHandlerBase(aWidget, aNativeView)
{
}
@ -1749,35 +1793,29 @@ PluginTextInputHandler::~PluginTextInputHandler()
*
******************************************************************************/
TextInputHandlerBase::TextInputHandlerBase() :
mOwnerWidget(nsnull), mView(nsnull)
TextInputHandlerBase::TextInputHandlerBase(nsChildView* aWidget,
NSView<mozView> *aNativeView) :
mWidget(aWidget)
{
gHandlerInstanceCount++;
mView = [aNativeView retain];
}
TextInputHandlerBase::~TextInputHandlerBase()
{
[mView release];
if (--gHandlerInstanceCount == 0) {
FinalizeCurrentKeyboardLayout();
}
}
void
TextInputHandlerBase::Init(nsChildView* aOwner)
{
mOwnerWidget = aOwner;
mView =
static_cast<NSView<mozView>*>(aOwner->GetNativeData(NS_NATIVE_WIDGET));
}
PRBool
TextInputHandlerBase::OnDestroyView(NSView<mozView> *aDestroyingView)
TextInputHandlerBase::OnDestroyWidget(nsChildView* aDestroyingWidget)
{
if (aDestroyingView != mView) {
if (aDestroyingWidget != mWidget) {
return PR_FALSE;
}
mView = nsnull;
mWidget = nsnull;
return PR_TRUE;
}

Просмотреть файл

@ -42,12 +42,24 @@
#import <Cocoa/Cocoa.h>
class nsIWidget;
namespace mozilla {
namespace widget{
class TextInputHandler;
} // namespace widget
} // namespace mozilla
// A protocol listing all the methods that an object which wants
// to live in gecko's widget hierarchy must implement. |nsChildView|
// makes assumptions that any NSView with which it comes in contact will
// implement this protocol.
@protocol mozView
// aHandler is Gecko's default text input handler: It implements the
// NSTextInput protocol to handle key events. Don't make aHandler a
// strong reference -- that causes a memory leak.
- (void)installTextInputHandler:(mozilla::widget::TextInputHandler*)aHandler;
- (void)uninstallTextInputHandler;
// access the nsIWidget associated with this view. DOES NOT ADDREF.
- (nsIWidget*)widget;

Просмотреть файл

@ -133,6 +133,15 @@ extern "C" long TSMProcessRawKeyEvent(EventRef carbonEvent);
// the link back to it must be weak.
nsChildView* mGeckoChild;
// Text input handler for mGeckoChild and us. Note that this is a weak
// reference. Ideally, this should be a strong reference but a ChildView
// object can live longer than the mGeckoChild that owns it. And if
// mTextInputHandler were a strong reference, this would make it difficult
// for Gecko's leak detector to detect leaked TextInputHandler objects.
// This is initialized by [mozView installTextInputHandler:aHandler] and
// cleared by [mozView uninstallTextInputHandler].
mozilla::widget::TextInputHandler* mTextInputHandler; // [WEAK]
BOOL mIsPluginView;
NPEventModel mPluginEventModel;
NPDrawingModel mPluginDrawingModel;
@ -418,11 +427,6 @@ public:
static PRUint32 GetCurrentInputEventCount();
static void UpdateCurrentInputEventCount();
mozilla::widget::TextInputHandler* TextInputHandler()
{
return &mTextInputHandler;
}
NSView<mozView>* GetEditorView();
PRBool IsPluginView() { return (mWindowType == eWindowType_plugin); }
@ -454,7 +458,7 @@ protected:
protected:
NSView<mozView>* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
mozilla::widget::TextInputHandler mTextInputHandler;
nsRefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
IMEContext mIMEContext;
NSView<mozView>* mParentView;

Просмотреть файл

@ -491,7 +491,8 @@ nsresult nsChildView::Create(nsIWidget *aParent,
if ([mView isKindOfClass:[ChildView class]])
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:[mView window]];
mTextInputHandler.Init(this);
NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed");
mTextInputHandler = new TextInputHandler(this, mView);
return NS_OK;
@ -1654,7 +1655,8 @@ NS_IMETHODIMP nsChildView::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStat
debug_DumpEvent(stdout, event->widget, event, nsCAutoString("something"), 0);
#endif
NS_ASSERTION(!(mTextInputHandler.IsIMEComposing() && NS_IS_KEY_EVENT(event)),
NS_ASSERTION(!(mTextInputHandler && mTextInputHandler->IsIMEComposing() &&
NS_IS_KEY_EVENT(event)),
"Any key events should not be fired during IME composing");
aStatus = nsEventStatus_eIgnore;
@ -1832,7 +1834,8 @@ NS_IMETHODIMP nsChildView::ResetInputState()
NSLog(@"**** ResetInputState");
#endif
mTextInputHandler.CommitIMEComposition();
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
mTextInputHandler->CommitIMEComposition();
return NS_OK;
}
@ -1843,7 +1846,8 @@ NS_IMETHODIMP nsChildView::SetIMEOpenState(PRBool aState)
NSLog(@"**** SetIMEOpenState aState = %d", aState);
#endif
mTextInputHandler.SetIMEOpenState(aState);
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
mTextInputHandler->SetIMEOpenState(aState);
return NS_OK;
}
@ -1854,7 +1858,8 @@ NS_IMETHODIMP nsChildView::GetIMEOpenState(PRBool* aState)
NSLog(@"**** GetIMEOpenState");
#endif
*aState = mTextInputHandler.IsIMEOpened();
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
*aState = mTextInputHandler->IsIMEOpened();
return NS_OK;
}
@ -1864,20 +1869,21 @@ NS_IMETHODIMP nsChildView::SetInputMode(const IMEContext& aContext)
NSLog(@"**** SetInputMode mStatus = %d", aContext.mStatus);
#endif
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
mIMEContext = aContext;
switch (aContext.mStatus) {
case nsIWidget::IME_STATUS_ENABLED:
case nsIWidget::IME_STATUS_PLUGIN:
mTextInputHandler.SetASCIICapableOnly(PR_FALSE);
mTextInputHandler.EnableIME(PR_TRUE);
mTextInputHandler->SetASCIICapableOnly(PR_FALSE);
mTextInputHandler->EnableIME(PR_TRUE);
break;
case nsIWidget::IME_STATUS_DISABLED:
mTextInputHandler.SetASCIICapableOnly(PR_FALSE);
mTextInputHandler.EnableIME(PR_FALSE);
mTextInputHandler->SetASCIICapableOnly(PR_FALSE);
mTextInputHandler->EnableIME(PR_FALSE);
break;
case nsIWidget::IME_STATUS_PASSWORD:
mTextInputHandler.SetASCIICapableOnly(PR_TRUE);
mTextInputHandler.EnableIME(PR_FALSE);
mTextInputHandler->SetASCIICapableOnly(PR_TRUE);
mTextInputHandler->EnableIME(PR_FALSE);
break;
default:
NS_ERROR("not implemented!");
@ -1902,7 +1908,8 @@ NS_IMETHODIMP nsChildView::CancelIMEComposition()
NSLog(@"**** CancelIMEComposition");
#endif
mTextInputHandler.CancelIMEComposition();
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
mTextInputHandler->CancelIMEComposition();
return NS_OK;
}
@ -1936,7 +1943,8 @@ NS_IMETHODIMP nsChildView::GetToggledKeyState(PRUint32 aKeyCode,
NS_IMETHODIMP nsChildView::OnIMEFocusChange(PRBool aFocus)
{
mTextInputHandler.OnFocusChangeInGecko(aFocus);
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
mTextInputHandler->OnFocusChangeInGecko(aFocus);
// XXX Return NS_ERROR_NOT_IMPLEMENTED, see bug 496360.
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -2267,6 +2275,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (void)installTextInputHandler:(TextInputHandler*)aHandler
{
mTextInputHandler = aHandler;
}
- (void)uninstallTextInputHandler
{
mTextInputHandler = nsnull;
}
// Work around bug 603134.
// OS X has a bug that causes new OpenGL windows to only paint once or twice,
// then stop painting altogether. By clearing the drawable from the GL context,
@ -2354,7 +2372,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
- (void)widgetDestroyed
{
mGeckoChild->TextInputHandler()->OnDestroyView(self);
if (mTextInputHandler) {
mTextInputHandler->OnDestroyWidget(mGeckoChild);
mTextInputHandler = nsnull;
}
mGeckoChild = nsnull;
// Just in case we're destroyed abruptly and missed the draggingExited
@ -4750,10 +4771,10 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
#if DEBUG_IME
NSLog(@"****in insertText: '%@'", insertString);
#endif
if (!mGeckoChild)
if (!mGeckoChild || !mTextInputHandler)
return;
if (mGeckoChild->TextInputHandler()->IgnoreIMEComposition())
if (mTextInputHandler->IgnoreIMEComposition())
return;
nsAutoRetainCocoaObject kungFuDeathGrip(self);
@ -4763,14 +4784,14 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
NSString *tmpStr = [insertString string];
unsigned int len = [tmpStr length];
if (!mGeckoChild->TextInputHandler()->IsIMEComposing() && len == 0)
if (!mTextInputHandler->IsIMEComposing() && len == 0)
return; // nothing to do
PRUnichar buffer[MAX_BUFFER_SIZE];
PRUnichar *bufPtr = (len >= MAX_BUFFER_SIZE) ? new PRUnichar[len + 1] : buffer;
[tmpStr getCharacters:bufPtr];
bufPtr[len] = PRUnichar('\0');
if (len == 1 && !mGeckoChild->TextInputHandler()->IsIMEComposing()) {
if (len == 1 && !mTextInputHandler->IsIMEComposing()) {
// don't let the same event be fired twice when hitting
// enter/return! (Bug 420502)
if (mKeyPressSent)
@ -4831,7 +4852,7 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
else {
NSAttributedString* attrStr =
static_cast<NSAttributedString*>(insertString);
mGeckoChild->TextInputHandler()->InsertTextAsCommittingComposition(attrStr);
mTextInputHandler->InsertTextAsCommittingComposition(attrStr);
}
if (bufPtr != buffer)
@ -4863,7 +4884,7 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NS_ENSURE_TRUE(mGeckoChild, );
NS_ENSURE_TRUE(mTextInputHandler, );
nsAutoRetainCocoaObject kungFuDeathGrip(self);
@ -4874,42 +4895,41 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease];
}
mGeckoChild->TextInputHandler()->SetMarkedText(attrStr, selRange);
mTextInputHandler->SetMarkedText(attrStr, selRange);
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void) unmarkText
{
NS_ENSURE_TRUE(mGeckoChild, );
mGeckoChild->TextInputHandler()->CommitIMEComposition();
NS_ENSURE_TRUE(mTextInputHandler, );
mTextInputHandler->CommitIMEComposition();
}
- (BOOL) hasMarkedText
{
NS_ENSURE_TRUE(mGeckoChild, NO);
return mGeckoChild->TextInputHandler()->HasMarkedText();
NS_ENSURE_TRUE(mTextInputHandler, NO);
return mTextInputHandler->HasMarkedText();
}
- (NSInteger) conversationIdentifier
{
NS_ENSURE_TRUE(mGeckoChild, reinterpret_cast<NSInteger>(self));
return mGeckoChild->TextInputHandler()->ConversationIdentifier();
NS_ENSURE_TRUE(mTextInputHandler, reinterpret_cast<NSInteger>(self));
return mTextInputHandler->ConversationIdentifier();
}
- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange
{
NS_ENSURE_TRUE(mGeckoChild, nil);
return mGeckoChild->TextInputHandler()->
GetAttributedSubstringFromRange(theRange);
NS_ENSURE_TRUE(mTextInputHandler, nil);
return mTextInputHandler->GetAttributedSubstringFromRange(theRange);
}
- (NSRange) markedRange
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
NS_ENSURE_TRUE(mGeckoChild, NSMakeRange(NSNotFound, 0));
return mGeckoChild->TextInputHandler()->MarkedRange();
NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0));
return mTextInputHandler->MarkedRange();
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0));
}
@ -4918,8 +4938,8 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
NS_ENSURE_TRUE(mGeckoChild, NSMakeRange(NSNotFound, 0));
return mGeckoChild->TextInputHandler()->SelectedRange();
NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0));
return mTextInputHandler->SelectedRange();
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0));
}
@ -4927,22 +4947,22 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
- (NSRect) firstRectForCharacterRange:(NSRange)theRange
{
NSRect rect;
NS_ENSURE_TRUE(mGeckoChild, rect);
return mGeckoChild->TextInputHandler()->FirstRectForCharacterRange(theRange);
NS_ENSURE_TRUE(mTextInputHandler, rect);
return mTextInputHandler->FirstRectForCharacterRange(theRange);
}
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
{
NS_ENSURE_TRUE(mGeckoChild, 0);
return mGeckoChild->TextInputHandler()->CharacterIndexForPoint(thePoint);
NS_ENSURE_TRUE(mTextInputHandler, 0);
return mTextInputHandler->CharacterIndexForPoint(thePoint);
}
- (NSArray*) validAttributesForMarkedText
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
NS_ENSURE_TRUE(mGeckoChild, [NSArray array]);
return mGeckoChild->TextInputHandler()->GetValidAttributesForMarkedText();
NS_ENSURE_TRUE(mTextInputHandler, [NSArray array]);
return mTextInputHandler->GetValidAttributesForMarkedText();
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
@ -4991,7 +5011,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
if (!mGeckoChild)
if (!mGeckoChild || !mTextInputHandler)
return NO;
#ifdef PR_LOGGING
@ -5009,7 +5029,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
mCurKeyEvent = theEvent;
BOOL nonDeadKeyPress = [[theEvent characters] length] > 0;
if (nonDeadKeyPress && !mGeckoChild->TextInputHandler()->IsIMEComposing()) {
if (nonDeadKeyPress && !mTextInputHandler->IsIMEComposing()) {
NSResponder* firstResponder = [[self window] firstResponder];
nsKeyEvent geckoKeydown(PR_TRUE, NS_KEY_DOWN, nsnull);
@ -5059,7 +5079,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
// control-letter combinations etc before Cocoa tries to use
// them for keybindings.
if ((!geckoKeypress.isChar || geckoKeypress.isControl) &&
!mGeckoChild->TextInputHandler()->IsIMEComposing()) {
!mTextInputHandler->IsIMEComposing()) {
if (mKeyDownHandled)
geckoKeypress.flags |= NS_EVENT_FLAG_NO_DEFAULT;
mKeyPressHandled = mGeckoChild->DispatchWindowEvent(geckoKeypress);
@ -5070,10 +5090,10 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
}
// Let Cocoa interpret the key events, caching IsIMEComposing first.
PRBool wasComposing = mGeckoChild->TextInputHandler()->IsIMEComposing();
PRBool wasComposing = mTextInputHandler->IsIMEComposing();
PRBool interpretKeyEventsCalled = PR_FALSE;
if (mGeckoChild->TextInputHandler()->IsIMEEnabled() ||
mGeckoChild->TextInputHandler()->IsASCIICapableOnly()) {
if (mTextInputHandler->IsIMEEnabled() ||
mTextInputHandler->IsASCIICapableOnly()) {
[super interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
interpretKeyEventsCalled = PR_TRUE;
}
@ -5083,7 +5103,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
}
if (!mKeyPressSent && nonDeadKeyPress && !wasComposing &&
!mGeckoChild->TextInputHandler()->IsIMEComposing()) {
!mTextInputHandler->IsIMEComposing()) {
nsKeyEvent geckoKeypress(PR_TRUE, NS_KEY_PRESS, nsnull);
[self convertCocoaKeyEvent:theEvent toGeckoEvent:&geckoKeypress];
@ -5327,7 +5347,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
ToEscapedString([theEvent characters], str1),
ToEscapedString([theEvent charactersIgnoringModifiers], str2)));
if (!mGeckoChild)
if (!mGeckoChild || !mTextInputHandler)
return;
if (mIgnoreNextKeyUpEvent) {
@ -5388,7 +5408,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
// if we don't have any characters we can't generate a keyUp event
if ([[theEvent characters] length] == 0 ||
mGeckoChild->TextInputHandler()->IsIMEComposing()) {
mTextInputHandler->IsIMEComposing()) {
return;
}
@ -5474,8 +5494,8 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!mGeckoChild || [theEvent type] != NSFlagsChanged ||
mGeckoChild->TextInputHandler()->IsIMEComposing()) {
if (!mGeckoChild || !mTextInputHandler || [theEvent type] != NSFlagsChanged ||
mTextInputHandler->IsIMEComposing()) {
return;
}