diff --git a/mozilla/content/events/src/Makefile.in b/mozilla/content/events/src/Makefile.in index a5d272c8f3c..b23c83d1028 100644 --- a/mozilla/content/events/src/Makefile.in +++ b/mozilla/content/events/src/Makefile.in @@ -31,6 +31,7 @@ CPPSRCS = \ nsEventStateManager.cpp \ nsDOMEvent.cpp \ nsDOMEventsIIDs.cpp \ + nsDOMTextRange.cpp \ $(NULL) MODULE=layout @@ -40,6 +41,7 @@ EXPORTS = \ nsEventStateManager.h \ nsDOMEvent.h \ nsDOMEventsIIDs.h \ + nsDOMTextRange.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/mozilla/content/events/src/makefile.win b/mozilla/content/events/src/makefile.win index 2d30f4c3eb6..7785b222c46 100644 --- a/mozilla/content/events/src/makefile.win +++ b/mozilla/content/events/src/makefile.win @@ -30,16 +30,18 @@ CPPSRCS= nsEventListenerManager.cpp \ nsEventStateManager.cpp \ nsDOMEvent.cpp \ nsDOMEventsIIDs.cpp \ + nsDOMTextRange.cpp \ $(NULL) CPP_OBJS= .\$(OBJDIR)\nsEventListenerManager.obj \ .\$(OBJDIR)\nsEventStateManager.obj \ .\$(OBJDIR)\nsDOMEvent.obj \ .\$(OBJDIR)\nsDOMEventsIIDs.obj \ + .\$(OBJDIR)\nsDOMTextRange.obj \ $(NULL) -EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h +EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h nsDOMTextRange.h LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor \ -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src -I$(PUBLIC)\netlib diff --git a/mozilla/content/events/src/nsDOMEvent.cpp b/mozilla/content/events/src/nsDOMEvent.cpp index 0b204498008..b4bc84126f6 100644 --- a/mozilla/content/events/src/nsDOMEvent.cpp +++ b/mozilla/content/events/src/nsDOMEvent.cpp @@ -26,6 +26,7 @@ #include "nsIWidget.h" #include "nsIWebShell.h" #include "nsIPresShell.h" +#include "nsDOMTextRange.h" static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); @@ -50,10 +51,28 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent) { mEvent = aEvent; mTarget = nsnull; mText = nsnull; + mTextRange = nsnull; if (aEvent->eventStructType ==NS_TEXT_EVENT) { + // + // extract the IME composition string + // mText = new nsString(((nsTextEvent*)aEvent)->theText); - mCommitText = ((nsTextEvent*)aEvent)->commitText; + // + // build the range list -- ranges need to be DOM-ified since the IME transaction + // will hold a ref, the widget representation isn't persistent + // + nsIDOMTextRange** tempTextRangeList = new nsIDOMTextRange*[((nsTextEvent*)aEvent)->rangeCount]; + for(PRUint16 i=0;i<((nsTextEvent*)aEvent)->rangeCount;i++) { + nsDOMTextRange* tempDOMTextRange = new nsDOMTextRange((((nsTextEvent*)aEvent)->rangeArray[i]).mStartOffset, + (((nsTextEvent*)aEvent)->rangeArray[i]).mEndOffset, + (((nsTextEvent*)aEvent)->rangeArray[i]).mRangeType); + tempDOMTextRange->AddRef(); + tempTextRangeList[i] = (nsIDOMTextRange*)tempDOMTextRange; + } + + mTextRange = (nsIDOMTextRangeList*) new nsDOMTextRangeList(((nsTextEvent*)aEvent)->rangeCount,tempTextRangeList); + mTextRange->AddRef(); } NS_INIT_REFCNT(); @@ -62,8 +81,10 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent) { nsDOMEvent::~nsDOMEvent() { NS_RELEASE(mPresContext); NS_IF_RELEASE(mTarget); + NS_IF_RELEASE(mTextRange); - delete mText; + if (mText!=nsnull) + delete mText; } NS_IMPL_ADDREF(nsDOMEvent) @@ -182,18 +203,18 @@ NS_METHOD nsDOMEvent::GetText(nsString& aText) return NS_ERROR_FAILURE; } -NS_METHOD nsDOMEvent::GetCommitText(PRBool* aCommitText) +NS_METHOD nsDOMEvent::GetInputRange(nsIDOMTextRangeList** aInputRange) { if (mEvent->message == NS_TEXT_EVENT) { - *aCommitText = mCommitText; + *aInputRange = mTextRange; return NS_OK; } - + return NS_ERROR_FAILURE; } -NS_METHOD nsDOMEvent::SetCommitText(PRBool aCommitText) -{ +NS_METHOD nsDOMEvent::SetInputRange(nsIDOMTextRangeList* aInputRange) +{ return NS_ERROR_FAILURE; } diff --git a/mozilla/content/events/src/nsDOMEvent.h b/mozilla/content/events/src/nsDOMEvent.h index 519c50b3a75..1f0193dc1d9 100644 --- a/mozilla/content/events/src/nsDOMEvent.h +++ b/mozilla/content/events/src/nsDOMEvent.h @@ -81,10 +81,11 @@ public: NS_IMETHOD PreventDefault(); - NS_IMETHOD GetText(nsString& aText); + NS_IMETHOD GetText(nsString& aText); - NS_IMETHOD GetCommitText(PRBool* aCommitText); - NS_IMETHOD SetCommitText(PRBool aCommitText); + NS_IMETHOD GetInputRange(nsIDOMTextRangeList** aInputRange); + + NS_IMETHOD SetInputRange(nsIDOMTextRangeList* aInputRange); NS_IMETHOD GetScreenX(PRInt32* aScreenX); @@ -135,7 +136,7 @@ protected: nsIPresContext* mPresContext; nsIDOMNode* mTarget; nsString* mText; - PRBool mCommitText; + nsIDOMTextRangeList* mTextRange; const char* GetEventName(PRUint32 aEventType); }; diff --git a/mozilla/dom/public/coreEvents/Makefile.in b/mozilla/dom/public/coreEvents/Makefile.in index 3ae3d7b22bc..26cf15d0ecb 100644 --- a/mozilla/dom/public/coreEvents/Makefile.in +++ b/mozilla/dom/public/coreEvents/Makefile.in @@ -43,6 +43,8 @@ EXPORTS = \ nsIDOMEventTarget.h \ nsIDOMTextListener.h \ nsIDOMCompositionListener.h \ + nsIDOMTextRange.h \ + nsIDOMTextRangeList.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/mozilla/dom/public/coreEvents/makefile.win b/mozilla/dom/public/coreEvents/makefile.win index 4f60854f33a..9891b45a503 100644 --- a/mozilla/dom/public/coreEvents/makefile.win +++ b/mozilla/dom/public/coreEvents/makefile.win @@ -38,6 +38,8 @@ EXPORTS = \ nsIDOMEventTarget.h \ nsIDOMTextListener.h \ nsIDOMCompositionListener.h \ + nsIDOMTextRange.h \ + nsIDOMTextRangeList.h \ $(NULL) MODULE=dom diff --git a/mozilla/dom/public/coreEvents/nsIDOMTextRange.h b/mozilla/dom/public/coreEvents/nsIDOMTextRange.h new file mode 100644 index 00000000000..0d20f4e8b1d --- /dev/null +++ b/mozilla/dom/public/coreEvents/nsIDOMTextRange.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +/* AUTO-GENERATED. DO NOT EDIT!!! */ + +#ifndef nsIDOMTextRange_h__ +#define nsIDOMTextRange_h__ + +#include "nsISupports.h" +#include "nsString.h" +#include "nsIScriptContext.h" + + +#define NS_IDOMTEXTRANGE_IID \ + {0xb471ab41, 0x2a79, 0x11d3, \ + { 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b } } + +class nsIDOMTextRange : public nsISupports { +public: + static const nsIID& GetIID() { static nsIID iid = NS_IDOMTEXTRANGE_IID; return iid; } + enum { + TEXTRANGE_RAWINPUT = 1, + TEXTRANGE_SELECTEDRAWTEXT = 2, + TEXTRANGE_CONVERTEDTEXT = 3, + TEXTRANGE_SELECTEDCONVERTEDTEXT = 4 + }; + + NS_IMETHOD GetRangeStart(PRUint16* aRangeStart)=0; + NS_IMETHOD SetRangeStart(PRUint16 aRangeStart)=0; + + NS_IMETHOD GetRangeEnd(PRUint16* aRangeEnd)=0; + NS_IMETHOD SetRangeEnd(PRUint16 aRangeEnd)=0; + + NS_IMETHOD GetRangeType(PRUint16* aRangeType)=0; + NS_IMETHOD SetRangeType(PRUint16 aRangeType)=0; +}; + + +#define NS_DECL_IDOMTEXTRANGE \ + NS_IMETHOD GetRangeStart(PRUint16* aRangeStart); \ + NS_IMETHOD SetRangeStart(PRUint16 aRangeStart); \ + NS_IMETHOD GetRangeEnd(PRUint16* aRangeEnd); \ + NS_IMETHOD SetRangeEnd(PRUint16 aRangeEnd); \ + NS_IMETHOD GetRangeType(PRUint16* aRangeType); \ + NS_IMETHOD SetRangeType(PRUint16 aRangeType); \ + + + +#define NS_FORWARD_IDOMTEXTRANGE(_to) \ + NS_IMETHOD GetRangeStart(PRUint16* aRangeStart) { return _to GetRangeStart(aRangeStart); } \ + NS_IMETHOD SetRangeStart(PRUint16 aRangeStart) { return _to SetRangeStart(aRangeStart); } \ + NS_IMETHOD GetRangeEnd(PRUint16* aRangeEnd) { return _to GetRangeEnd(aRangeEnd); } \ + NS_IMETHOD SetRangeEnd(PRUint16 aRangeEnd) { return _to SetRangeEnd(aRangeEnd); } \ + NS_IMETHOD GetRangeType(PRUint16* aRangeType) { return _to GetRangeType(aRangeType); } \ + NS_IMETHOD SetRangeType(PRUint16 aRangeType) { return _to SetRangeType(aRangeType); } \ + + +extern "C" NS_DOM nsresult NS_InitTextRangeClass(nsIScriptContext *aContext, void **aPrototype); + +extern "C" NS_DOM nsresult NS_NewScriptTextRange(nsIScriptContext *aContext, nsISupports *aSupports, nsISupports *aParent, void **aReturn); + +#endif // nsIDOMTextRange_h__ diff --git a/mozilla/dom/public/coreEvents/nsIDOMTextRangeList.h b/mozilla/dom/public/coreEvents/nsIDOMTextRangeList.h new file mode 100644 index 00000000000..fcaa658af6b --- /dev/null +++ b/mozilla/dom/public/coreEvents/nsIDOMTextRangeList.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +/* AUTO-GENERATED. DO NOT EDIT!!! */ + +#ifndef nsIDOMTextRangeList_h__ +#define nsIDOMTextRangeList_h__ + +#include "nsISupports.h" +#include "nsString.h" +#include "nsIScriptContext.h" + +class nsIDOMTextRange; + +#define NS_IDOMTEXTRANGELIST_IID \ + { 0x1ee9d531, 0x2a79, 0x11d3, \ + { 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b} } + +class nsIDOMTextRangeList : public nsISupports { +public: + static const nsIID& GetIID() { static nsIID iid = NS_IDOMTEXTRANGELIST_IID; return iid; } + + NS_IMETHOD GetLength(PRUint16* aLength)=0; + + NS_IMETHOD Item(PRUint16 aIndex, nsIDOMTextRange** aReturn)=0; +}; + + +#define NS_DECL_IDOMTEXTRANGELIST \ + NS_IMETHOD GetLength(PRUint16* aLength); \ + NS_IMETHOD Item(PRUint16 aIndex, nsIDOMTextRange** aReturn); \ + + + +#define NS_FORWARD_IDOMTEXTRANGELIST(_to) \ + NS_IMETHOD GetLength(PRUint16* aLength) { return _to GetLength(aLength); } \ + NS_IMETHOD Item(PRUint16 aIndex, nsIDOMTextRange** aReturn) { return _to Item(aIndex, aReturn); } \ + + +#endif // nsIDOMTextRangeList_h__ diff --git a/mozilla/dom/public/coreEvents/nsIDOMUIEvent.h b/mozilla/dom/public/coreEvents/nsIDOMUIEvent.h index d8b2532237d..1d23a12383d 100644 --- a/mozilla/dom/public/coreEvents/nsIDOMUIEvent.h +++ b/mozilla/dom/public/coreEvents/nsIDOMUIEvent.h @@ -25,6 +25,7 @@ #include "nsIScriptContext.h" #include "nsIDOMEvent.h" +class nsIDOMTextRangeList; #define NS_IDOMUIEVENT_IID \ { 0xa6cf90c3, 0x15b3, 0x11d2, \ @@ -150,8 +151,8 @@ public: NS_IMETHOD GetText(nsString& aText)=0; - NS_IMETHOD GetCommitText(PRBool* aCommitText)=0; - NS_IMETHOD SetCommitText(PRBool aCommitText)=0; + NS_IMETHOD GetInputRange(nsIDOMTextRangeList** aInputRange)=0; + NS_IMETHOD SetInputRange(nsIDOMTextRangeList* aInputRange)=0; NS_IMETHOD GetScreenX(PRInt32* aScreenX)=0; @@ -179,8 +180,8 @@ public: #define NS_DECL_IDOMUIEVENT \ NS_IMETHOD GetText(nsString& aText); \ - NS_IMETHOD GetCommitText(PRBool* aCommitText); \ - NS_IMETHOD SetCommitText(PRBool aCommitText); \ + NS_IMETHOD GetInputRange(nsIDOMTextRangeList** aInputRange); \ + NS_IMETHOD SetInputRange(nsIDOMTextRangeList* aInputRange); \ NS_IMETHOD GetScreenX(PRInt32* aScreenX); \ NS_IMETHOD GetScreenY(PRInt32* aScreenY); \ NS_IMETHOD GetClientX(PRInt32* aClientX); \ @@ -197,8 +198,8 @@ public: #define NS_FORWARD_IDOMUIEVENT(_to) \ NS_IMETHOD GetText(nsString& aText) { return _to GetText(aText); } \ - NS_IMETHOD GetCommitText(PRBool* aCommitText) { return _to GetCommitText(aCommitText); } \ - NS_IMETHOD SetCommitText(PRBool aCommitText) { return _to SetCommitText(aCommitText); } \ + NS_IMETHOD GetInputRange(nsIDOMTextRangeList** aInputRange) { return _to GetInputRange(aInputRange); } \ + NS_IMETHOD SetInputRange(nsIDOMTextRangeList* aInputRange) { return _to SetInputRange(aInputRange); } \ NS_IMETHOD GetScreenX(PRInt32* aScreenX) { return _to GetScreenX(aScreenX); } \ NS_IMETHOD GetScreenY(PRInt32* aScreenY) { return _to GetScreenY(aScreenY); } \ NS_IMETHOD GetClientX(PRInt32* aClientX) { return _to GetClientX(aClientX); } \ diff --git a/mozilla/dom/public/idl/events/TextRange.idl b/mozilla/dom/public/idl/events/TextRange.idl new file mode 100644 index 00000000000..7b99336318b --- /dev/null +++ b/mozilla/dom/public/idl/events/TextRange.idl @@ -0,0 +1,19 @@ + interface TextRange { +/* IID: {0xb471ab41, 0x2a79, 0x11d3, \ + { 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b } } */ + const int TEXTRANGE_RAWINPUT = 1; + const int TEXTRANGE_SELECTEDRAWTEXT = 2; + const int TEXTRANGE_CONVERTEDTEXT = 3; + const int TEXTRANGE_SELECTEDCONVERTEDTEXT = 4; + + attribute unsigned short rangeStart; + attribute unsigned short rangeEnd; + attribute unsigned short rangeType; + }; + interface TextRangeList { +/* IID: { 0x1ee9d531, 0x2a79, 0x11d3, \ + { 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b} } */ + readonly attribute unsigned short length; + TextRange Item(in unsigned short index); + + }; diff --git a/mozilla/dom/public/idl/events/UIEvent.idl b/mozilla/dom/public/idl/events/UIEvent.idl index 76658abe2b4..09d94bcc2c9 100644 --- a/mozilla/dom/public/idl/events/UIEvent.idl +++ b/mozilla/dom/public/idl/events/UIEvent.idl @@ -124,7 +124,7 @@ const int VK_QUOTE = 0xDE; readonly attribute wstring text; - attribute boolean commitText; + attribute TextRangeList inputRange; readonly attribute int screenX; readonly attribute int screenY; diff --git a/mozilla/dom/public/idl/events/makefile.win b/mozilla/dom/public/idl/events/makefile.win index 16977d34ccc..7acbd48fdda 100644 --- a/mozilla/dom/public/idl/events/makefile.win +++ b/mozilla/dom/public/idl/events/makefile.win @@ -23,6 +23,7 @@ MODULE=raptor IDLSRCS = \ Event.idl \ UIEvent.idl \ + TextRange.idl XPCOM_DESTDIR=$(DEPTH)\dom\public\coreEvents JSSTUB_DESTDIR=$(DEPTH)\dom\src\events diff --git a/mozilla/dom/src/events/Makefile.in b/mozilla/dom/src/events/Makefile.in index c75db900b44..f498f81f000 100644 --- a/mozilla/dom/src/events/Makefile.in +++ b/mozilla/dom/src/events/Makefile.in @@ -31,6 +31,7 @@ CPPSRCS = \ nsJSDOMEventListener.cpp \ nsJSEvent.cpp \ nsJSUIEvent.cpp \ + nsJSTextRange.cpp \ $(NULL) MODULE=dom diff --git a/mozilla/dom/src/events/makefile.win b/mozilla/dom/src/events/makefile.win index 3acfc80d693..12e92a6e587 100644 --- a/mozilla/dom/src/events/makefile.win +++ b/mozilla/dom/src/events/makefile.win @@ -29,6 +29,7 @@ CPPSRCS = \ nsJSDOMEventListener.cpp \ nsJSEvent.cpp \ nsJSUIEvent.cpp \ + nsJSTextRange.cpp \ $(NULL) CPP_OBJS= \ diff --git a/mozilla/dom/src/events/nsJSTextRange.cpp b/mozilla/dom/src/events/nsJSTextRange.cpp new file mode 100644 index 00000000000..d74437c14b2 --- /dev/null +++ b/mozilla/dom/src/events/nsJSTextRange.cpp @@ -0,0 +1,512 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +/* AUTO-GENERATED. DO NOT EDIT!!! */ + +#include "jsapi.h" +#include "nsJSUtils.h" +#include "nscore.h" +#include "nsIScriptContext.h" +#include "nsIScriptSecurityManager.h" +#include "nsIJSScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIScriptGlobalObject.h" +#include "nsIPtr.h" +#include "nsString.h" +#include "nsIDOMTextRange.h" +#include "nsIDOMTextRangeList.h" + + +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +static NS_DEFINE_IID(kIJSScriptObjectIID, NS_IJSSCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptGlobalObjectIID, NS_ISCRIPTGLOBALOBJECT_IID); +static NS_DEFINE_IID(kITextRangeIID, NS_IDOMTEXTRANGE_IID); +static NS_DEFINE_IID(kITextRangeListIID, NS_IDOMTEXTRANGELIST_IID); + +NS_DEF_PTR(nsIDOMTextRange); +NS_DEF_PTR(nsIDOMTextRangeList); + +// +// TextRange property ids +// +enum TextRange_slots { + TEXTRANGE_RANGESTART = -1, + TEXTRANGE_RANGEEND = -2, + TEXTRANGE_RANGETYPE = -3, + TEXTRANGELIST_LENGTH = -4 +}; + +/***********************************************************************/ +// +// TextRange Properties Getter +// +PR_STATIC_CALLBACK(JSBool) +GetTextRangeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMTextRange *a = (nsIDOMTextRange*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { + case TEXTRANGE_RANGESTART: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangestart", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + if (NS_OK == a->GetRangeStart(&prop)) { + *vp = INT_TO_JSVAL(prop); + } + else { + return JS_FALSE; + } + break; + } + case TEXTRANGE_RANGEEND: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangeend", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + if (NS_OK == a->GetRangeEnd(&prop)) { + *vp = INT_TO_JSVAL(prop); + } + else { + return JS_FALSE; + } + break; + } + case TEXTRANGE_RANGETYPE: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangetype", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + if (NS_OK == a->GetRangeType(&prop)) { + *vp = INT_TO_JSVAL(prop); + } + else { + return JS_FALSE; + } + break; + } + case TEXTRANGELIST_LENGTH: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrangelist.length", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + nsIDOMTextRangeList* b; + if (NS_OK == a->QueryInterface(kITextRangeListIID, (void **)&b)) { + if(NS_OK == b->GetLength(&prop)) { + *vp = INT_TO_JSVAL(prop); + NS_RELEASE(b); + } + else { + NS_RELEASE(b); + return JS_FALSE; + } + } + else { + JS_ReportError(cx, "Object must be of type TextRangeList"); + return JS_FALSE; + } + break; + } + default: + return nsJSUtils::nsCallJSScriptObjectGetProperty(a, cx, id, vp); + } + NS_RELEASE(secMan); + } + else { + return nsJSUtils::nsCallJSScriptObjectGetProperty(a, cx, id, vp); + } + + return PR_TRUE; +} + +/***********************************************************************/ +// +// TextRange Properties Setter +// +PR_STATIC_CALLBACK(JSBool) +SetTextRangeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMTextRange *a = (nsIDOMTextRange*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { + case TEXTRANGE_RANGESTART: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangestart", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + int32 temp; + if (JSVAL_IS_NUMBER(*vp) && JS_ValueToInt32(cx, *vp, &temp)) { + prop = (PRUint16)temp; + } + else { + JS_ReportError(cx, "Parameter must be a number"); + return JS_FALSE; + } + + a->SetRangeStart(prop); + + break; + } + case TEXTRANGE_RANGEEND: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangeend", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + int32 temp; + if (JSVAL_IS_NUMBER(*vp) && JS_ValueToInt32(cx, *vp, &temp)) { + prop = (PRUint16)temp; + } + else { + JS_ReportError(cx, "Parameter must be a number"); + return JS_FALSE; + } + + a->SetRangeEnd(prop); + + break; + } + case TEXTRANGE_RANGETYPE: + { + secMan->CheckScriptAccess(scriptCX, obj, "textrange.rangetype", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + PRUint16 prop; + int32 temp; + if (JSVAL_IS_NUMBER(*vp) && JS_ValueToInt32(cx, *vp, &temp)) { + prop = (PRUint16)temp; + } + else { + JS_ReportError(cx, "Parameter must be a number"); + return JS_FALSE; + } + + a->SetRangeType(prop); + + break; + } + default: + return nsJSUtils::nsCallJSScriptObjectSetProperty(a, cx, id, vp); + } + NS_RELEASE(secMan); + } + else { + return nsJSUtils::nsCallJSScriptObjectSetProperty(a, cx, id, vp); + } + + return PR_TRUE; +} + + +// +// TextRange finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeTextRange(JSContext *cx, JSObject *obj) +{ + nsJSUtils::nsGenericFinalize(cx, obj); +} + + +// +// TextRange enumerate +// +PR_STATIC_CALLBACK(JSBool) +EnumerateTextRange(JSContext *cx, JSObject *obj) +{ + return nsJSUtils::nsGenericEnumerate(cx, obj); +} + + +// +// TextRange resolve +// +PR_STATIC_CALLBACK(JSBool) +ResolveTextRange(JSContext *cx, JSObject *obj, jsval id) +{ + return nsJSUtils::nsGenericResolve(cx, obj, id); +} + + +// +// Native method Item +// +PR_STATIC_CALLBACK(JSBool) +TextRangeListItem(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMTextRange *privateThis = (nsIDOMTextRange*)nsJSUtils::nsGetNativeThis(cx, obj); + nsIDOMTextRangeList *nativeThis = nsnull; + if (NS_OK != privateThis->QueryInterface(kITextRangeListIID, (void **)&nativeThis)) { + JS_ReportError(cx, "Object must be of type TextRangeList"); + return JS_FALSE; + } + + JSBool rBool = JS_FALSE; + nsIDOMTextRange* nativeRet; + PRUint32 b0; + + *rval = JSVAL_NULL; + + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; + if (NS_OK == scriptCX->GetSecurityManager(&secMan)) { + PRBool ok; + secMan->CheckScriptAccess(scriptCX, obj, "textrangelist.item", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + NS_RELEASE(secMan); + } + else { + return JS_FALSE; + } + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == nativeThis) { + return JS_TRUE; + } + + if (argc >= 1) { + + if (!JS_ValueToInt32(cx, argv[0], (int32 *)&b0)) { + JS_ReportError(cx, "Parameter must be a number"); + return JS_FALSE; + } + + if (NS_OK != nativeThis->Item(b0, &nativeRet)) { + return JS_FALSE; + } + + nsJSUtils::nsConvertObjectToJSVal(nativeRet, cx, rval); + } + else { + JS_ReportError(cx, "Function Item requires 1 parameters"); + return JS_FALSE; + } + + return JS_TRUE; +} + + +/***********************************************************************/ +// +// class for TextRange +// +JSClass TextRangeClass = { + "TextRange", + JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS, + JS_PropertyStub, + JS_PropertyStub, + GetTextRangeProperty, + SetTextRangeProperty, + EnumerateTextRange, + ResolveTextRange, + JS_ConvertStub, + FinalizeTextRange +}; + + +// +// TextRange class properties +// +static JSPropertySpec TextRangeProperties[] = +{ + {"rangeStart", TEXTRANGE_RANGESTART, JSPROP_ENUMERATE}, + {"rangeEnd", TEXTRANGE_RANGEEND, JSPROP_ENUMERATE}, + {"rangeType", TEXTRANGE_RANGETYPE, JSPROP_ENUMERATE}, + {"length", TEXTRANGELIST_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY}, + {0} +}; + + +// +// TextRange class methods +// +static JSFunctionSpec TextRangeMethods[] = +{ + {"Item", TextRangeListItem, 1}, + {0} +}; + + +// +// TextRange constructor +// +PR_STATIC_CALLBACK(JSBool) +TextRange(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_FALSE; +} + + +// +// TextRange class initialization +// +extern "C" NS_DOM nsresult NS_InitTextRangeClass(nsIScriptContext *aContext, void **aPrototype) +{ + JSContext *jscontext = (JSContext *)aContext->GetNativeContext(); + JSObject *proto = nsnull; + JSObject *constructor = nsnull; + JSObject *parent_proto = nsnull; + JSObject *global = JS_GetGlobalObject(jscontext); + jsval vp; + + if ((PR_TRUE != JS_LookupProperty(jscontext, global, "TextRange", &vp)) || + !JSVAL_IS_OBJECT(vp) || + ((constructor = JSVAL_TO_OBJECT(vp)) == nsnull) || + (PR_TRUE != JS_LookupProperty(jscontext, JSVAL_TO_OBJECT(vp), "prototype", &vp)) || + !JSVAL_IS_OBJECT(vp)) { + + proto = JS_InitClass(jscontext, // context + global, // global object + parent_proto, // parent proto + &TextRangeClass, // JSClass + TextRange, // JSNative ctor + 0, // ctor args + TextRangeProperties, // proto props + TextRangeMethods, // proto funcs + nsnull, // ctor props (static) + nsnull); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + + if ((PR_TRUE == JS_LookupProperty(jscontext, global, "TextRange", &vp)) && + JSVAL_IS_OBJECT(vp) && + ((constructor = JSVAL_TO_OBJECT(vp)) != nsnull)) { + vp = INT_TO_JSVAL(nsIDOMTextRange::TEXTRANGE_RAWINPUT); + JS_SetProperty(jscontext, constructor, "TEXTRANGE_RAWINPUT", &vp); + + vp = INT_TO_JSVAL(nsIDOMTextRange::TEXTRANGE_SELECTEDRAWTEXT); + JS_SetProperty(jscontext, constructor, "TEXTRANGE_SELECTEDRAWTEXT", &vp); + + vp = INT_TO_JSVAL(nsIDOMTextRange::TEXTRANGE_CONVERTEDTEXT); + JS_SetProperty(jscontext, constructor, "TEXTRANGE_CONVERTEDTEXT", &vp); + + vp = INT_TO_JSVAL(nsIDOMTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT); + JS_SetProperty(jscontext, constructor, "TEXTRANGE_SELECTEDCONVERTEDTEXT", &vp); + + } + + } + else if ((nsnull != constructor) && JSVAL_IS_OBJECT(vp)) { + proto = JSVAL_TO_OBJECT(vp); + } + else { + return NS_ERROR_FAILURE; + } + + if (aPrototype) { + *aPrototype = proto; + } + return NS_OK; +} + + +// +// Method for creating a new TextRange JavaScript object +// +extern "C" NS_DOM nsresult NS_NewScriptTextRange(nsIScriptContext *aContext, nsISupports *aSupports, nsISupports *aParent, void **aReturn) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aSupports && nsnull != aReturn, "null argument to NS_NewScriptTextRange"); + JSObject *proto; + JSObject *parent; + nsIScriptObjectOwner *owner; + JSContext *jscontext = (JSContext *)aContext->GetNativeContext(); + nsresult result = NS_OK; + nsIDOMTextRange *aTextRange; + + if (nsnull == aParent) { + parent = nsnull; + } + else if (NS_OK == aParent->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + if (NS_OK != owner->GetScriptObject(aContext, (void **)&parent)) { + NS_RELEASE(owner); + return NS_ERROR_FAILURE; + } + NS_RELEASE(owner); + } + else { + return NS_ERROR_FAILURE; + } + + if (NS_OK != NS_InitTextRangeClass(aContext, (void **)&proto)) { + return NS_ERROR_FAILURE; + } + + result = aSupports->QueryInterface(kITextRangeIID, (void **)&aTextRange); + if (NS_OK != result) { + return result; + } + + // create a js object for this class + *aReturn = JS_NewObject(jscontext, &TextRangeClass, proto, parent); + if (nsnull != *aReturn) { + // connect the native object to the js object + JS_SetPrivate(jscontext, (JSObject *)*aReturn, aTextRange); + } + else { + NS_RELEASE(aTextRange); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} diff --git a/mozilla/dom/src/events/nsJSUIEvent.cpp b/mozilla/dom/src/events/nsJSUIEvent.cpp index d1fd71fadba..a24abb77b21 100644 --- a/mozilla/dom/src/events/nsJSUIEvent.cpp +++ b/mozilla/dom/src/events/nsJSUIEvent.cpp @@ -30,6 +30,7 @@ #include "nsIDOMNSUIEvent.h" #include "nsIDOMNode.h" #include "nsIDOMUIEvent.h" +#include "nsIDOMTextRangeList.h" #include "nsIDOMRenderingContext.h" @@ -39,11 +40,13 @@ static NS_DEFINE_IID(kIScriptGlobalObjectIID, NS_ISCRIPTGLOBALOBJECT_IID); static NS_DEFINE_IID(kINSUIEventIID, NS_IDOMNSUIEVENT_IID); static NS_DEFINE_IID(kINodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIUIEventIID, NS_IDOMUIEVENT_IID); +static NS_DEFINE_IID(kITextRangeListIID, NS_IDOMTEXTRANGELIST_IID); static NS_DEFINE_IID(kIRenderingContextIID, NS_IDOMRENDERINGCONTEXT_IID); NS_DEF_PTR(nsIDOMNSUIEvent); NS_DEF_PTR(nsIDOMNode); NS_DEF_PTR(nsIDOMUIEvent); +NS_DEF_PTR(nsIDOMTextRangeList); NS_DEF_PTR(nsIDOMRenderingContext); // @@ -51,7 +54,7 @@ NS_DEF_PTR(nsIDOMRenderingContext); // enum UIEvent_slots { UIEVENT_TEXT = -1, - UIEVENT_COMMITTEXT = -2, + UIEVENT_INPUTRANGE = -2, UIEVENT_SCREENX = -3, UIEVENT_SCREENY = -4, UIEVENT_CLIENTX = -5, @@ -111,16 +114,17 @@ GetUIEventProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } break; } - case UIEVENT_COMMITTEXT: + case UIEVENT_INPUTRANGE: { - secMan->CheckScriptAccess(scriptCX, obj, "uievent.committext", &ok); + secMan->CheckScriptAccess(scriptCX, obj, "uievent.inputrange", &ok); if (!ok) { //Need to throw error here return JS_FALSE; } - PRBool prop; - if (NS_OK == a->GetCommitText(&prop)) { - *vp = BOOLEAN_TO_JSVAL(prop); + nsIDOMTextRangeList* prop; + if (NS_OK == a->GetInputRange(&prop)) { + // get the js object + nsJSUtils::nsConvertObjectToJSVal((nsISupports *)prop, cx, vp); } else { return JS_FALSE; @@ -539,20 +543,22 @@ SetUIEventProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return JS_FALSE; } switch(JSVAL_TO_INT(id)) { - case UIEVENT_COMMITTEXT: + case UIEVENT_INPUTRANGE: { - secMan->CheckScriptAccess(scriptCX, obj, "uievent.committext", &ok); + secMan->CheckScriptAccess(scriptCX, obj, "uievent.inputrange", &ok); if (!ok) { //Need to throw error here return JS_FALSE; } - PRBool prop; - if (PR_FALSE == nsJSUtils::nsConvertJSValToBool(&prop, cx, *vp)) { + nsIDOMTextRangeList* prop; + if (PR_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)&prop, + kITextRangeListIID, "TextRangeList", + cx, *vp)) { return JS_FALSE; } - a->SetCommitText(prop); - + a->SetInputRange(prop); + NS_IF_RELEASE(prop); break; } default: @@ -622,7 +628,7 @@ JSClass UIEventClass = { static JSPropertySpec UIEventProperties[] = { {"text", UIEVENT_TEXT, JSPROP_ENUMERATE | JSPROP_READONLY}, - {"commitText", UIEVENT_COMMITTEXT, JSPROP_ENUMERATE}, + {"inputRange", UIEVENT_INPUTRANGE, JSPROP_ENUMERATE}, {"screenX", UIEVENT_SCREENX, JSPROP_ENUMERATE | JSPROP_READONLY}, {"screenY", UIEVENT_SCREENY, JSPROP_ENUMERATE | JSPROP_READONLY}, {"clientX", UIEVENT_CLIENTX, JSPROP_ENUMERATE | JSPROP_READONLY}, diff --git a/mozilla/editor/base/IMECommitTxn.cpp b/mozilla/editor/base/IMECommitTxn.cpp new file mode 100644 index 00000000000..947db7d13dc --- /dev/null +++ b/mozilla/editor/base/IMECommitTxn.cpp @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "IMECommitTxn.h" +#include "nsEditor.h" + +static NS_DEFINE_IID(kIMECommitTxnIID, IME_COMMIT_TXN_IID); + +nsIAtom *IMECommitTxn::gIMECommitTxnName = nsnull; + +nsresult IMECommitTxn::ClassInit() +{ + if (nsnull==gIMECommitTxnName) + gIMECommitTxnName = NS_NewAtom("NS_IMECommitTxn"); + return NS_OK; +} + +IMECommitTxn::IMECommitTxn() + : EditTxn() +{ +} + +IMECommitTxn::~IMECommitTxn() +{ +} + +NS_IMETHODIMP IMECommitTxn::Init(void) +{ + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::Do(void) +{ +#ifdef DEBUG_TAGUE + printf("Do IME Commit); } +#endif + + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::Undo(void) +{ +#ifdef DEBUG_TAGUE + printf("Undo IME Commit"); +#endif + + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction) +{ +#ifdef DEBUG_TAGUE + printf("Merge IME Commit"); +#endif + + *aDidMerge=PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::Write(nsIOutputStream *aOutputStream) +{ + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::GetUndoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Remove IMECommit: "; + } + return NS_OK; +} + +NS_IMETHODIMP IMECommitTxn::GetRedoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Insert IMECommit: "; + } + return NS_OK; +} + +/* ============= nsISupports implementation ====================== */ + +NS_IMETHODIMP +IMECommitTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIMECommitTxnIID)) { + *aInstancePtr = (void*)(IMECommitTxn*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + return (EditTxn::QueryInterface(aIID, aInstancePtr)); +} + + diff --git a/mozilla/editor/base/IMECommitTxn.h b/mozilla/editor/base/IMECommitTxn.h new file mode 100644 index 00000000000..ec82d8fcb01 --- /dev/null +++ b/mozilla/editor/base/IMECommitTxn.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef IMECommitTxn_h__ +#define IMECommitTxn_h__ + +#include "EditTxn.h" +#include "nsIDOMCharacterData.h" +#include "nsCOMPtr.h" + +// {9C4994A1-281C-11d3-9EA3-0060089FE59B} +#define IME_COMMIT_TXN_IID \ +{ 0x9c4994a1, 0x281c, 0x11d3, \ +{ 0x9e, 0xa3, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b }} + + +/** + * A transaction representing an IME commit operation + */ +class IMECommitTxn : public EditTxn +{ +public: + virtual ~IMECommitTxn(); + + static nsIAtom *gIMECommitTxnName; + + /** initialize the transaction + */ + NS_IMETHOD Init(void); + +private: + + IMECommitTxn(); + +public: + + NS_IMETHOD Do(void); + + NS_IMETHOD Undo(void); + + NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction); + + NS_IMETHOD Write(nsIOutputStream *aOutputStream); + + NS_IMETHOD GetUndoString(nsString *aString); + + NS_IMETHOD GetRedoString(nsString *aString); + +// nsISupports declarations + + // override QueryInterface to handle IMECommitTxn request + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + static const nsIID& GetIID() { static nsIID iid = IME_COMMIT_TXN_IID; return iid; } + + /** must be called before any IMECommitTxn is instantiated */ + static nsresult ClassInit(); + +protected: + + friend class TransactionFactory; + + friend class nsDerivedSafe; // work around for a compiler bug + +}; + +#endif diff --git a/mozilla/editor/base/IMETextTxn.cpp b/mozilla/editor/base/IMETextTxn.cpp new file mode 100644 index 00000000000..4b4cc63e4e1 --- /dev/null +++ b/mozilla/editor/base/IMETextTxn.cpp @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "IMETextTxn.h" +#include "IMECommitTxn.h" +#include "nsEditor.h" +#include "nsIDOMCharacterData.h" +#include "nsIDOMTextRange.h" +#include "nsIDOMTextRangeList.h" +#include "nsIDOMSelection.h" +#include "nsIPresShell.h" +#include "EditAggregateTxn.h" + +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); + +nsIAtom *IMETextTxn::gIMETextTxnName = nsnull; + +nsresult IMETextTxn::ClassInit() +{ + if (nsnull==gIMETextTxnName) + gIMETextTxnName = NS_NewAtom("NS_IMETextTxn"); + return NS_OK; +} + +IMETextTxn::IMETextTxn() + : EditTxn() +{ +} + +IMETextTxn::~IMETextTxn() +{ + mRangeList = do_QueryInterface(nsnull); +} + +NS_IMETHODIMP IMETextTxn::Init(nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aReplaceLength, + nsIDOMTextRangeList* aTextRangeList, + const nsString &aStringToInsert, + nsIPresShell *aPresShell) +{ + mElement = do_QueryInterface(aElement); + mOffset = aOffset; + mReplaceLength = aReplaceLength; + mStringToInsert = aStringToInsert; + mPresShell = aPresShell; + mRangeList = do_QueryInterface(aTextRangeList); + mFixed = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::Do(void) +{ + +#ifdef DEBUG_TAGUE + printf("Do IME Text element = %p\n", mElement.get()); +#endif + + // advance caret: This requires the presentation shell to get the selection. + nsCOMPtr selection; + nsresult result = mPresShell->GetSelection(getter_AddRefs(selection)); + NS_ASSERTION(selection,"Could not get selection in IMEtextTxn::Do\n"); + if (NS_SUCCEEDED(result) && selection) { + if (mReplaceLength==0) { + result = mElement->InsertData(mOffset,mStringToInsert); + } else { + result = mElement->ReplaceData(mOffset,mReplaceLength,mStringToInsert); + } + if (NS_SUCCEEDED(result)) { + result = CollapseTextSelection(); + } + } + + return result; +} + +NS_IMETHODIMP IMETextTxn::Undo(void) +{ +#ifdef DEBUG_TAGUE + printf("Undo IME Text element = %p\n", mElement.get()); +#endif + + nsresult result; + PRUint32 length = mStringToInsert.Length(); + result = mElement->DeleteData(mOffset, length); + if (NS_SUCCEEDED(result)) + { // set the selection to the insertion point where the string was removed + nsCOMPtr selection; + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection) { + result = selection->Collapse(mElement, mOffset); + NS_ASSERTION((NS_SUCCEEDED(result)), "selection could not be collapsed after undo of IME insert."); + } + } + return result; +} + +NS_IMETHODIMP IMETextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction) +{ +#ifdef DEBUG_TAGUE + printf("Merge IME Text element = %p\n", mElement.get()); +#endif + + // + // check to make sure we have valid return pointers + // + if ((nsnull==aDidMerge) && (nsnull==aTransaction)) + { + return NS_OK; + } + + // + // check to make sure we aren't fixed, if we are then nothing get's absorbed + // + if (mFixed) { + *aDidMerge = PR_FALSE; + return NS_OK; + } + + // + // if aTransaction is another IMETextTxn then absorbe it + // + nsCOMPtr otherTxn(do_QueryInterface(aTransaction)); + if (otherTxn) + { + // + // we absorbe the next IME transaction by adopting it's insert string as our own + // + nsIDOMTextRangeList* newTextRangeList; + otherTxn->GetData(mStringToInsert,&newTextRangeList); + mRangeList = do_QueryInterface(newTextRangeList); + *aDidMerge = PR_TRUE; +#ifdef DEBUG_TAGUE + printf("IMETextTxn assimilated IMETextTxn:%p\n", aTransaction); +#endif + return NS_OK; + } + + // + // second possible case is that we have a commit transaction + // + nsCOMPtr commitTxn(do_QueryInterface(aTransaction)); + if (commitTxn) + { + (void)CollapseTextSelectionOnCommit(); + mFixed = PR_TRUE; + *aDidMerge = PR_TRUE; // absorbe the commit transaction +#ifdef DEBUG_TAGUE + printf("IMETextTxn assimilated IMECommitTxn%p\n", aTransaction); +#endif + return NS_OK; + } + + *aDidMerge = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::Write(nsIOutputStream *aOutputStream) +{ + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::GetUndoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Remove Text: "; + *aString += mStringToInsert; + } + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::GetRedoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Insert Text: "; + *aString += mStringToInsert; + } + return NS_OK; +} + +/* ============= nsISupports implementation ====================== */ + +NS_IMETHODIMP +IMETextTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIMETextTxnIID)) { + *aInstancePtr = (void*)(IMETextTxn*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + return (EditTxn::QueryInterface(aIID, aInstancePtr)); +} + +/* ============ protected methods ================== */ + +NS_IMETHODIMP IMETextTxn::GetData(nsString& aResult,nsIDOMTextRangeList** aTextRangeList) +{ + aResult = mStringToInsert; + *aTextRangeList = mRangeList; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void) +{ + nsresult result; + PRBool haveSelectedRange; + PRUint16 textRangeListLength,selectionStart,selectionEnd, + textRangeType, i; + nsIDOMTextRange* textRange; + + haveSelectedRange = PR_FALSE; + +#ifdef DEBUG_tague + PRUint16 listlen,start,stop,type; + nsIDOMTextRange* rangePtr; + result = mRangeList->GetLength(&listlen); + printf("nsIDOMTextRangeList[%p]\n",mRangeList); + for (i=0;iItem(i,&rangePtr); + rangePtr->GetRangeStart(&start); + rangePtr->GetRangeEnd(&stop); + rangePtr->GetRangeType(&type); + printf("range[%d] start=%d end=%d type=",i,start,stop,type); + if (type==nsIDOMTextRange::TEXTRANGE_RAWINPUT) printf("TEXTRANGE_RAWINPUT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_SELECTEDRAWTEXT) printf("TEXTRANGE_SELECTEDRAWTEXT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_CONVERTEDTEXT) printf("TEXTRANGE_CONVERTEDTEXT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT) printf("TEXTRANGE_SELECTEDCONVERTEDTEXT\n"); + } +#endif + + // + // run through the text range list + // + result = mRangeList->GetLength(&textRangeListLength); + if (NS_SUCCEEDED(result)) + { + for(i=0;iItem(i,&textRange); + if (NS_SUCCEEDED(result)) + { + result = textRange->GetRangeType(&textRangeType); + if (textRangeType==nsIDOMTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT) + { + haveSelectedRange = PR_TRUE; + textRange->GetRangeStart(&selectionStart); + textRange->GetRangeEnd(&selectionEnd); + } + } + } + } + + nsCOMPtr selection; + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection){ + if (haveSelectedRange) { + result = selection->Collapse(mElement,mOffset+selectionStart); + result = selection->Extend(mElement,mOffset+selectionEnd+1); + } else { + result = selection->Collapse(mElement,mOffset+mStringToInsert.Length()); + } + } + + return result; +} + +NS_IMETHODIMP IMETextTxn::CollapseTextSelectionOnCommit(void) +{ + nsCOMPtr selection; + nsresult result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection){ + result = selection->Collapse(mElement,mOffset+mStringToInsert.Length()); + } + + return result; +} diff --git a/mozilla/editor/base/IMETextTxn.h b/mozilla/editor/base/IMETextTxn.h new file mode 100644 index 00000000000..b75865a12a9 --- /dev/null +++ b/mozilla/editor/base/IMETextTxn.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef IMETextTxn_h__ +#define IMETextTxn_h__ + +#include "EditTxn.h" +#include "nsIDOMCharacterData.h" +#include "nsIDOMTextRangeList.h" +#include "nsCOMPtr.h" + +// {D4D25721-2813-11d3-9EA3-0060089FE59B} +#define IME_TEXT_TXN_IID \ +{0xd4d25721, 0x2813, 0x11d3, \ +{0x9e, 0xa3, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b }} + + + + +class nsIPresShell; + +/** + * A transaction that inserts text into a content node. + */ +class IMETextTxn : public EditTxn +{ +public: + virtual ~IMETextTxn(); + + /** used to name aggregate transactions that consist only of a single IMETextTxn, + * or a DeleteSelection followed by an IMETextTxn. + */ + static nsIAtom *gIMETextTxnName; + + /** initialize the transaction + * @param aElement the text content node + * @param aOffset the location in aElement to do the insertion + * @param aReplaceLength the length of text to replace (0= no replacement) + * @param aString the new text to insert + * @param aPresShell used to get and set the selection + */ + NS_IMETHOD Init(nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aReplaceLength, + nsIDOMTextRangeList* aTextRangeList, + const nsString& aString, + nsIPresShell* aPresShell); + +private: + + IMETextTxn(); + +public: + + NS_IMETHOD Do(void); + + NS_IMETHOD Undo(void); + + NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction); + + NS_IMETHOD Write(nsIOutputStream *aOutputStream); + + NS_IMETHOD GetUndoString(nsString *aString); + + NS_IMETHOD GetRedoString(nsString *aString); + +// nsISupports declarations + + // override QueryInterface to handle IMETextTxn request + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + static const nsIID& GetIID() { static nsIID iid = IME_TEXT_TXN_IID; return iid; } + + + /** return the string data associated with this transaction */ + NS_IMETHOD GetData(nsString& aResult, nsIDOMTextRangeList** aTextRangeList); + + /** must be called before any IMETextTxn is instantiated */ + static nsresult ClassInit(); + +protected: + + NS_IMETHOD CollapseTextSelection(void); + NS_IMETHOD CollapseTextSelectionOnCommit(void); + + /** the text element to operate upon */ + nsCOMPtr mElement; + + /** the offsets into mElement where the insertion should be placed*/ + PRUint32 mOffset; + + PRUint32 mReplaceLength; + + /** the text to insert into mElement at mOffset */ + nsString mStringToInsert; + + /** the range list **/ + nsCOMPtr mRangeList; + + /** the presentation shell, which we'll need to get the selection */ + nsIPresShell* mPresShell; + + PRBool mFixed; + + friend class TransactionFactory; + + friend class nsDerivedSafe; // work around for a compiler bug + +}; + +#endif diff --git a/mozilla/editor/base/InsertTextTxn.cpp b/mozilla/editor/base/InsertTextTxn.cpp index cc3e5936f9d..507dbb4c4be 100644 --- a/mozilla/editor/base/InsertTextTxn.cpp +++ b/mozilla/editor/base/InsertTextTxn.cpp @@ -25,6 +25,7 @@ static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID); static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); +static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID); #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; diff --git a/mozilla/editor/base/Makefile.in b/mozilla/editor/base/Makefile.in index a4a8fbb15e5..82cef9def53 100644 --- a/mozilla/editor/base/Makefile.in +++ b/mozilla/editor/base/Makefile.in @@ -67,6 +67,8 @@ CPPSRCS = \ nsEditorShellFactory.cpp \ nsJSEditorLog.cpp \ nsJSTxnLog.cpp \ + IMETextTxn.cpp \ + IMECommitTxn.cpp \ $(NULL) MODULE = editor diff --git a/mozilla/editor/base/TransactionFactory.cpp b/mozilla/editor/base/TransactionFactory.cpp index abe35f159f2..58b832ab8c7 100644 --- a/mozilla/editor/base/TransactionFactory.cpp +++ b/mozilla/editor/base/TransactionFactory.cpp @@ -39,7 +39,9 @@ #include "DeleteTableColumnTxn.h" #include "DeleteTableRowTxn.h" #include "JoinTableCellsTxn.h" +#include "IMETextTxn.h" +#include "IMECommitTxn.h" static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID); static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID); static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID); @@ -61,6 +63,8 @@ static NS_DEFINE_IID(kDeleteTableCellTxnIID, DELETE_CELL_TXN_IID); static NS_DEFINE_IID(kDeleteTableColumnTxnIID, DELETE_COLUMN_TXN_IID); static NS_DEFINE_IID(kDeleteTableRowTxnIID, DELETE_ROW_TXN_IID); static NS_DEFINE_IID(kJoinTableCellsTxnIID, JOIN_CELLS_TXN_IID); +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIMECommitTxnIID, IME_COMMIT_TXN_IID); TransactionFactory::TransactionFactory() { @@ -97,6 +101,10 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult) *aResult = new JoinElementTxn(); else if (aTxnType.Equals(kEditAggregateTxnIID)) *aResult = new EditAggregateTxn(); + else if (aTxnType.Equals(kIMETextTxnIID)) + *aResult = new IMETextTxn(); + else if (aTxnType.Equals(kIMECommitTxnIID)) + *aResult = new IMECommitTxn(); else if (aTxnType.Equals(kPlaceholderTxnIID)) *aResult = new PlaceholderTxn(); else diff --git a/mozilla/editor/base/makefile.win b/mozilla/editor/base/makefile.win index 7904d4018fc..25086c0e668 100644 --- a/mozilla/editor/base/makefile.win +++ b/mozilla/editor/base/makefile.win @@ -62,6 +62,8 @@ CPPSRCS = \ nsEditorShellFactory.cpp \ nsJSEditorLog.cpp \ nsJSTxnLog.cpp \ + IMETextTxn.cpp \ + IMECommitTxn.cpp \ $(NULL) CPP_OBJS = \ @@ -106,6 +108,8 @@ CPP_OBJS = \ .\$(OBJDIR)\nsEditorShellFactory.obj \ .\$(OBJDIR)\nsJSEditorLog.obj \ .\$(OBJDIR)\nsJSTxnLog.obj \ + .\$(OBJDIR)\IMETextTxn.obj \ + .\$(OBJDIR)\IMECommitTxn.obj \ $(NULL) MODULE=editor diff --git a/mozilla/editor/base/nsEditor.cpp b/mozilla/editor/base/nsEditor.cpp index fa9fb78fe84..ee674cf34c9 100644 --- a/mozilla/editor/base/nsEditor.cpp +++ b/mozilla/editor/base/nsEditor.cpp @@ -84,6 +84,8 @@ static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); #include "SplitElementTxn.h" #include "JoinElementTxn.h" #include "nsIStringStream.h" +#include "IMETextTxn.h" +#include "IMECommitTxn.h" // #define HACK_FORCE_REDRAW 1 @@ -128,6 +130,8 @@ static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID); static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID); static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID); static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID); +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIMECommitTxnIID, IME_COMMIT_TXN_IID); static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID); @@ -334,7 +338,6 @@ nsEditor::nsEditor() { //initialize member variables here NS_INIT_REFCNT(); - mIMEFirstTransaction=PR_FALSE; PR_EnterMonitor(GetEditorMonitor()); gInstanceCount++; mActionListeners = 0; @@ -519,6 +522,13 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell) mUpdateCount=0; InsertTextTxn::ClassInit(); + /* initalize IME stuff */ + IMETextTxn::ClassInit(); + IMECommitTxn::ClassInit(); + mIMETextNode = do_QueryInterface(nsnull); + mIMETextOffset = 0; + mIMEBufferLength = 0; + /* Show the caret */ nsCOMPtr caret; if (NS_SUCCEEDED(mPresShell->GetCaret(getter_AddRefs(caret)))) @@ -3188,93 +3198,102 @@ NS_IMETHODIMP nsEditor::GetLayoutObject(nsIDOMNode *aNode, nsISupports **aLayout return result; } +// +// The BeingComposition method is called from the Editor Composition event listeners. +// It caches the current text node and offset which is subsequently used for the +// created of IMETextTxn's. +// NS_IMETHODIMP nsEditor::BeginComposition(void) { - - if ((nsITransactionManager *)nsnull!=mTxnMgr.get()) - { #ifdef DEBUG_tague - printf("nsEditor::StartComposition -- begin batch.\n"); + printf("nsEditor::StartComposition\n"); #endif - mTxnMgr->BeginBatch(); - } - - if (!mIMESelectionRange) - { - nsresult result = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull, - nsIDOMRange::GetIID(), - getter_AddRefs(mIMESelectionRange)); - if (NS_FAILED(result)) + nsresult result; + PRInt32 offset; + nsCOMPtr selection; + nsCOMPtr nodeAsText; + + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) { - mTxnMgr->EndBatch(); - return result; + result = NS_ERROR_UNEXPECTED; + nsCOMPtr enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + result = NS_ERROR_UNEXPECTED; + nsCOMPtr range(do_QueryInterface(currentItem)); + if (range) + { + nsCOMPtr node; + result = range->GetStartParent(getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && (node)) + { + nodeAsText = do_QueryInterface(node); + range->GetStartOffset(&offset); + if (!nodeAsText) { + result = NS_ERROR_EDITOR_NO_TEXTNODE; + } + } + } + } + else + { + result = NS_ERROR_EDITOR_NO_SELECTION; + } + } } - } - mIMEFirstTransaction=PR_TRUE; - - return NS_OK; + if (NS_SUCCEEDED(result) && nodeAsText) + { + // + // store the information needed to construct IME transactions for this composition + // + mIMETextNode = nodeAsText; + mIMETextOffset = offset; + mIMEBufferLength = 0; + } + return result; } NS_IMETHODIMP nsEditor::EndComposition(void) { - if ((nsITransactionManager *)nsnull!=mTxnMgr.get()) - { -#ifdef DEBUG_tague - printf("nsEditor::EndComposition -- end batch.\n"); -#endif - mTxnMgr->EndBatch(); - mIMEFirstTransaction=PR_TRUE; - return NS_OK; - } + nsresult result; + IMECommitTxn *commitTxn; + + // + // create the commit transaction..we can do it directly from the transaction mgr + // + result = TransactionFactory::GetNewTransaction(kIMECommitTxnIID,(EditTxn**)&commitTxn); + if (NS_SUCCEEDED(result) && commitTxn!=nsnull) + { + commitTxn->Init(); + result = Do(commitTxn); + } - // mIMESelectionRange = nsCOMPtr(); + /* reset the data we need to construct a transaction */ + mIMETextNode = do_QueryInterface(nsnull); + mIMETextOffset = 0; + mIMEBufferLength = 0; - return NS_OK; + return result; } NS_IMETHODIMP -nsEditor::SetCompositionString(const nsString& aCompositionString) +nsEditor::SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList) { + nsresult result = SetInputMethodText(aCompositionString,aTextRangeList); + mIMEBufferLength = aCompositionString.Length(); - - if (mIMEFirstTransaction==PR_TRUE) { - mIMEFirstTransaction = PR_FALSE; - } else { - // printf("Undo!\n"); - // mTxnMgr->Undo(); - nsCOMPtr selection; - nsresult result; - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - nsCOMPtr node; - PRInt32 offset; - - result = mIMESelectionRange->GetStartParent(getter_AddRefs(node)); - result = mIMESelectionRange->GetStartOffset(&offset); - - result = selection->Collapse(node, offset); - - - result = mIMESelectionRange->GetEndParent(getter_AddRefs(node)); - result = mIMESelectionRange->GetEndOffset(&offset); - - result = selection->Extend(node, offset); - } -#ifdef DEBUG_tague - printf("nsEditor::SetCompositionString: string=%s\n",aCompositionString); -#endif - return SetPreeditText(aCompositionString); + return result; } NS_IMETHODIMP @@ -3450,176 +3469,130 @@ nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode) //END nsEditor Private methods -NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert) +NS_IMETHODIMP +nsEditor::SetInputMethodText(const nsString& aStringToInsert,nsIDOMTextRangeList *aTextRangeList) { - if (!mDoc) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtrnodeList; - nsAutoString bodyTag = "body"; - nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); - if ((NS_SUCCEEDED(result)) && nodeList) - { - PRUint32 count; - nodeList->GetLength(&count); - NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); - nsCOMPtrnode; - result = nodeList->Item(0, getter_AddRefs(node)); - if ((NS_SUCCEEDED(result)) && node) - { // now we've got the body tag. - // create transaction to insert the text node, - // and create a transaction to insert the text - CreateElementTxn *txn; - result = CreateTxnForCreateElement(GetTextNodeTag(), node, 0, &txn); - if ((NS_SUCCEEDED(result)) && txn) - { - result = Do(txn); - if (NS_SUCCEEDED(result)) - { - nsCOMPtrnewNode; - txn->GetNewNode(getter_AddRefs(newNode)); - if ((NS_SUCCEEDED(result)) && newNode) - { - nsCOMPtrnewTextNode; - newTextNode = do_QueryInterface(newNode); - if (newTextNode) - { - InsertTextTxn *insertTxn; - result = CreateTxnForInsertText(aStringToInsert, newTextNode, &insertTxn); - if (NS_SUCCEEDED(result)) { - result = Do(insertTxn); - } - } - else { - result = NS_ERROR_UNEXPECTED; - } - } - } - } - } - } - return result; + IMETextTxn *txn; + nsresult result; + + result = CreateTxnForIMEText(aStringToInsert,aTextRangeList,&txn); // insert at the current selection + if ((NS_SUCCEEDED(result)) && txn) { + BeginUpdateViewBatch(); + result = Do(txn); + EndUpdateViewBatch(); + } + else if (NS_ERROR_EDITOR_NO_SELECTION==result) { + result = DoInitialInputMethodInsert(aStringToInsert,aTextRangeList); + } + else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) + { + BeginTransaction(); + nsCOMPtr selection; + result = GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + nsCOMPtr selectedNode; + PRInt32 offset; + result = selection->GetAnchorNode(getter_AddRefs(selectedNode)); + if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode) + { + nsCOMPtr newNode; + result = CreateNode(GetTextNodeTag(), selectedNode, offset+1,getter_AddRefs(newNode)); + if (NS_SUCCEEDED(result) && newNode) + { + nsCOMPtrnewTextNode; + newTextNode = do_QueryInterface(newNode); + if (newTextNode) + { + nsAutoString placeholderText(" "); + newTextNode->SetData(placeholderText); + selection->Collapse(newNode, 0); + selection->Extend(newNode, 1); + result = SetInputMethodText(aStringToInsert,aTextRangeList); + } + } + } + } + + EndTransaction(); + } + + return result; } NS_IMETHODIMP -nsEditor::SetPreeditText(const nsString& aStringToInsert) +nsEditor::CreateTxnForIMEText(const nsString & aStringToInsert, + nsIDOMTextRangeList* aTextRangeList, + IMETextTxn ** aTxn) { - nsresult result; + nsresult result; - //EditAggregateTxn *aggTxn = nsnull; - // Create the "delete current selection" txn - nsCOMPtr selection; - - BeginTransaction(); - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_SUCCEEDED(result) && selection) - { - PRBool collapsed; - result = selection->GetIsCollapsed(&collapsed); - if (NS_SUCCEEDED(result) && !collapsed) { - EditAggregateTxn *delSelTxn; - // XXX should this be eDoNothing instead of eDeleteRight? - result = CreateTxnForDeleteSelection(nsIEditor::eDeleteRight, - &delSelTxn); - if (NS_SUCCEEDED(result) && delSelTxn) { - result = Do(delSelTxn); - - if (NS_FAILED(result)) { - EndTransaction(); - return result; - } - } - } - } - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - nsCOMPtr startRange; - nsCOMPtr endRange; - - result = selection->GetRangeAt(0, getter_AddRefs(startRange)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - InsertTextTxn *txn; - result = CreateTxnForInsertText(aStringToInsert, nsnull, &txn); // insert at the current selection - if ((NS_SUCCEEDED(result)) && txn) { - result = Do(txn); - } - else if (NS_ERROR_EDITOR_NO_SELECTION==result) { - result = DoInitialInsert(aStringToInsert); - } - else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) - { - result = GetSelection(getter_AddRefs(selection)); - if ((NS_SUCCEEDED(result)) && selection) - { - nsCOMPtr selectedNode; - PRInt32 offset; - result = selection->GetAnchorNode(getter_AddRefs(selectedNode)); - if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode) - { - nsCOMPtr newNode; - result = CreateNode(GetTextNodeTag(), selectedNode, offset+1, - getter_AddRefs(newNode)); - if (NS_SUCCEEDED(result) && newNode) - { - nsCOMPtrnewTextNode; - newTextNode = do_QueryInterface(newNode); - if (newTextNode) - { - nsAutoString placeholderText(" "); - newTextNode->SetData(placeholderText); - selection->Collapse(newNode, 0); - selection->Extend(newNode, 1); - result = SetPreeditText(aStringToInsert); - } - } - } - } - - } - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - result = selection->GetRangeAt(0, getter_AddRefs(endRange)); - - nsCOMPtr node; - PRInt32 offset; - - startRange->GetStartParent(getter_AddRefs(node)); - startRange->GetStartOffset(&offset); - mIMESelectionRange->SetStart(node, offset); - - endRange->GetStartParent(getter_AddRefs(node)); - endRange->GetStartOffset(&offset); - mIMESelectionRange->SetEnd(node, offset); - - EndTransaction(); - // HACKForceRedraw(); - return result; + result = TransactionFactory::GetNewTransaction(kIMETextTxnIID, (EditTxn **)aTxn); + if (nsnull!=*aTxn) { + result = (*aTxn)->Init(mIMETextNode,mIMETextOffset,mIMEBufferLength,aTextRangeList,aStringToInsert,mPresShell); + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + return result; } +NS_IMETHODIMP nsEditor::DoInitialInputMethodInsert(const nsString & aStringToInsert,nsIDOMTextRangeList* aTextRangeList) +{ + if (!mDoc) { + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtrnodeList; + nsAutoString bodyTag = "body"; + nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); + if ((NS_SUCCEEDED(result)) && nodeList) + { + PRUint32 count; + nodeList->GetLength(&count); + NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); + nsCOMPtrnode; + result = nodeList->Item(0, getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && node) + { // now we've got the body tag. + // create transaction to insert the text node, + // and create a transaction to insert the text + CreateElementTxn *txn; + result = CreateTxnForCreateElement(GetTextNodeTag(), node, 0, &txn); + if ((NS_SUCCEEDED(result)) && txn) + { + result = Do(txn); + if (NS_SUCCEEDED(result)) + { + nsCOMPtrnewNode; + txn->GetNewNode(getter_AddRefs(newNode)); + if ((NS_SUCCEEDED(result)) && newNode) + { + nsCOMPtrnewTextNode; + newTextNode = do_QueryInterface(newNode); + if (newTextNode) + { + mIMETextNode = newTextNode; + mIMETextOffset = 0; + mIMEBufferLength = 0; + IMETextTxn *IMETxn; + result = CreateTxnForIMEText(aStringToInsert,aTextRangeList,&IMETxn); + if (NS_SUCCEEDED(result)) { + result = Do(IMETxn); + } + } + else { + result = NS_ERROR_UNEXPECTED; + } + } + } + } + } + } + + return result; +} /////////////////////////////////////////////////////////////////////////// // GetTag: digs out the atom for the tag of this node // diff --git a/mozilla/editor/base/nsEditor.h b/mozilla/editor/base/nsEditor.h index 97855629233..2751c7cca25 100644 --- a/mozilla/editor/base/nsEditor.h +++ b/mozilla/editor/base/nsEditor.h @@ -26,6 +26,7 @@ #include "nsIDOMSelection.h" #include "nsIDOMEventListener.h" #include "nsIDOMRange.h" +#include "nsIDOMTextRangeList.h" #include "nsCOMPtr.h" #include "nsIStringBundle.h" #include "nsITransactionManager.h" @@ -54,6 +55,7 @@ class nsIPref; class nsIStringBundleService; class nsIStringBundle; class nsILocale; +class IMETextTxn; #ifdef ENABLE_JS_EDITOR_LOG class nsJSEditorLog; @@ -78,7 +80,12 @@ private: nsCOMPtr mTxnMgr; nsCOMPtr mEditProperty; - nsCOMPtr mIMESelectionRange; + // + // data necessary to build IME transactions + // + nsCOMPtr mIMETextNode; + PRUint32 mIMETextOffset; + PRUint32 mIMEBufferLength; friend PRBool NSCanUnload(nsISupports* serviceMgr); static PRInt32 gInstanceCount; @@ -163,7 +170,7 @@ public: NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList); NS_IMETHOD EndComposition(void); @@ -273,10 +280,16 @@ protected: nsIDOMCharacterData *aTextNode, InsertTextTxn ** aTxn); + NS_IMETHOD CreateTxnForIMEText(const nsString & aStringToInsert, + nsIDOMTextRangeList* aTextRangeList, + IMETextTxn ** aTxn); + /** insert aStringToInsert as the first text in the document */ NS_IMETHOD DoInitialInsert(const nsString & aStringToInsert); + NS_IMETHOD DoInitialInputMethodInsert(const nsString& aStringToInsert,nsIDOMTextRangeList* aTextRangeList); + NS_IMETHOD DeleteText(nsIDOMCharacterData *aElement, PRUint32 aOffset, @@ -314,10 +327,7 @@ protected: NS_IMETHOD DebugDumpContent() const; - // should these me methodimp? - NS_IMETHODIMP SetPreeditText(const nsString& aStringToInsert); - - NS_IMETHODIMP DoInitialPreeeditInsert(const nsString& aStringToInsert); + NS_IMETHOD SetInputMethodText(const nsString& aStringToInsert, nsIDOMTextRangeList* aTextRangeList); // called each time we modify the document. Increments the mod // count of the doc. @@ -344,8 +354,6 @@ protected: // document after a change via the DOM - gpk 2/13/99 void HACKForceRedraw(void); - PRBool mIMEFirstTransaction; - NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &parentSelectedNode, PRInt32& offsetOfNewNode); public: diff --git a/mozilla/editor/base/nsEditorEventListeners.cpp b/mozilla/editor/base/nsEditorEventListeners.cpp index 4e976e86fea..35d6fc39eb6 100644 --- a/mozilla/editor/base/nsEditorEventListeners.cpp +++ b/mozilla/editor/base/nsEditorEventListeners.cpp @@ -1090,16 +1090,19 @@ nsTextEditorTextListener::HandleText(nsIDOMEvent* aTextEvent) { nsString composedText; nsresult result; + nsCOMPtruiEvent; + nsIDOMTextRangeList *textRangeList; - nsCOMPtruiEvent; - uiEvent = do_QueryInterface(aTextEvent); - if (!uiEvent) { - //non-ui event passed in. bad things. - return NS_OK; - } + uiEvent = do_QueryInterface(aTextEvent); + if (!uiEvent) { + //non-ui event passed in. bad things. + return NS_OK; + } uiEvent->GetText(composedText); - result = mEditor->SetCompositionString(composedText); + uiEvent->GetInputRange(&textRangeList); + textRangeList->AddRef(); + result = mEditor->SetCompositionString(composedText,textRangeList); return result; } diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 62c9e1cb274..c9db5065b00 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -2488,9 +2488,9 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void) return nsTextEditor::EndComposition(); } -NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) +NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList) { - return nsTextEditor::SetCompositionString(aCompositionString); + return nsTextEditor::SetCompositionString(aCompositionString,aTextRangeList); } NS_IMETHODIMP diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h index c2de0cb3555..c59daa964e0 100644 --- a/mozilla/editor/base/nsHTMLEditor.h +++ b/mozilla/editor/base/nsHTMLEditor.h @@ -106,7 +106,7 @@ public: NS_IMETHOD InsertHTML(const nsString& aInputString); NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRange); NS_IMETHOD EndComposition(void); NS_IMETHOD OutputTextToString(nsString& aOutputString, PRBool aSelectionOnly); NS_IMETHOD OutputHTMLToString(nsString& aOutputString, PRBool aSelectionOnly); diff --git a/mozilla/editor/base/nsJSEditorLog.cpp b/mozilla/editor/base/nsJSEditorLog.cpp index e8ab2f873fd..0e6d7190e17 100644 --- a/mozilla/editor/base/nsJSEditorLog.cpp +++ b/mozilla/editor/base/nsJSEditorLog.cpp @@ -828,7 +828,7 @@ nsJSEditorLog::BeginComposition(void) } NS_IMETHODIMP -nsJSEditorLog::SetCompositionString(const nsString& aCompositionString) +nsJSEditorLog::SetCompositionString(const nsString& aCompositionString,nsIDOMTextRangeList* aTextRangeList) { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/mozilla/editor/base/nsJSEditorLog.h b/mozilla/editor/base/nsJSEditorLog.h index 085838abe84..cc530c2a871 100644 --- a/mozilla/editor/base/nsJSEditorLog.h +++ b/mozilla/editor/base/nsJSEditorLog.h @@ -138,7 +138,7 @@ public: NS_IMETHOD DeleteTableRow(PRInt32 aNumber); NS_IMETHOD JoinTableCells(PRBool aCellToRight); NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList); NS_IMETHOD EndComposition(void); NS_IMETHOD StartLogging(nsIFileSpec *aLogFile); NS_IMETHOD StopLogging(); diff --git a/mozilla/editor/base/nsTextEditor.cpp b/mozilla/editor/base/nsTextEditor.cpp index f0136792236..807ba92f12c 100644 --- a/mozilla/editor/base/nsTextEditor.cpp +++ b/mozilla/editor/base/nsTextEditor.cpp @@ -2804,9 +2804,9 @@ nsTextEditor::BeginComposition(void) } NS_IMETHODIMP -nsTextEditor::SetCompositionString(const nsString& aCompositionString) +nsTextEditor::SetCompositionString(const nsString& aCompositionString,nsIDOMTextRangeList* aTextRangeList) { - return nsEditor::SetCompositionString(aCompositionString); + return nsEditor::SetCompositionString(aCompositionString,aTextRangeList); } NS_IMETHODIMP diff --git a/mozilla/editor/base/nsTextEditor.h b/mozilla/editor/base/nsTextEditor.h index 67529614e1f..44c6b5846cc 100644 --- a/mozilla/editor/base/nsTextEditor.h +++ b/mozilla/editor/base/nsTextEditor.h @@ -110,7 +110,7 @@ public: // Input/Output NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aRangeList); NS_IMETHOD EndComposition(void); NS_IMETHOD OutputTextToString(nsString& aOutputString, PRBool aSelectionOnly); NS_IMETHOD OutputHTMLToString(nsString& aOutputString, PRBool aSelectionOnly); diff --git a/mozilla/editor/libeditor/base/IMETextTxn.cpp b/mozilla/editor/libeditor/base/IMETextTxn.cpp new file mode 100644 index 00000000000..4b4cc63e4e1 --- /dev/null +++ b/mozilla/editor/libeditor/base/IMETextTxn.cpp @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "IMETextTxn.h" +#include "IMECommitTxn.h" +#include "nsEditor.h" +#include "nsIDOMCharacterData.h" +#include "nsIDOMTextRange.h" +#include "nsIDOMTextRangeList.h" +#include "nsIDOMSelection.h" +#include "nsIPresShell.h" +#include "EditAggregateTxn.h" + +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); + +nsIAtom *IMETextTxn::gIMETextTxnName = nsnull; + +nsresult IMETextTxn::ClassInit() +{ + if (nsnull==gIMETextTxnName) + gIMETextTxnName = NS_NewAtom("NS_IMETextTxn"); + return NS_OK; +} + +IMETextTxn::IMETextTxn() + : EditTxn() +{ +} + +IMETextTxn::~IMETextTxn() +{ + mRangeList = do_QueryInterface(nsnull); +} + +NS_IMETHODIMP IMETextTxn::Init(nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aReplaceLength, + nsIDOMTextRangeList* aTextRangeList, + const nsString &aStringToInsert, + nsIPresShell *aPresShell) +{ + mElement = do_QueryInterface(aElement); + mOffset = aOffset; + mReplaceLength = aReplaceLength; + mStringToInsert = aStringToInsert; + mPresShell = aPresShell; + mRangeList = do_QueryInterface(aTextRangeList); + mFixed = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::Do(void) +{ + +#ifdef DEBUG_TAGUE + printf("Do IME Text element = %p\n", mElement.get()); +#endif + + // advance caret: This requires the presentation shell to get the selection. + nsCOMPtr selection; + nsresult result = mPresShell->GetSelection(getter_AddRefs(selection)); + NS_ASSERTION(selection,"Could not get selection in IMEtextTxn::Do\n"); + if (NS_SUCCEEDED(result) && selection) { + if (mReplaceLength==0) { + result = mElement->InsertData(mOffset,mStringToInsert); + } else { + result = mElement->ReplaceData(mOffset,mReplaceLength,mStringToInsert); + } + if (NS_SUCCEEDED(result)) { + result = CollapseTextSelection(); + } + } + + return result; +} + +NS_IMETHODIMP IMETextTxn::Undo(void) +{ +#ifdef DEBUG_TAGUE + printf("Undo IME Text element = %p\n", mElement.get()); +#endif + + nsresult result; + PRUint32 length = mStringToInsert.Length(); + result = mElement->DeleteData(mOffset, length); + if (NS_SUCCEEDED(result)) + { // set the selection to the insertion point where the string was removed + nsCOMPtr selection; + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection) { + result = selection->Collapse(mElement, mOffset); + NS_ASSERTION((NS_SUCCEEDED(result)), "selection could not be collapsed after undo of IME insert."); + } + } + return result; +} + +NS_IMETHODIMP IMETextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction) +{ +#ifdef DEBUG_TAGUE + printf("Merge IME Text element = %p\n", mElement.get()); +#endif + + // + // check to make sure we have valid return pointers + // + if ((nsnull==aDidMerge) && (nsnull==aTransaction)) + { + return NS_OK; + } + + // + // check to make sure we aren't fixed, if we are then nothing get's absorbed + // + if (mFixed) { + *aDidMerge = PR_FALSE; + return NS_OK; + } + + // + // if aTransaction is another IMETextTxn then absorbe it + // + nsCOMPtr otherTxn(do_QueryInterface(aTransaction)); + if (otherTxn) + { + // + // we absorbe the next IME transaction by adopting it's insert string as our own + // + nsIDOMTextRangeList* newTextRangeList; + otherTxn->GetData(mStringToInsert,&newTextRangeList); + mRangeList = do_QueryInterface(newTextRangeList); + *aDidMerge = PR_TRUE; +#ifdef DEBUG_TAGUE + printf("IMETextTxn assimilated IMETextTxn:%p\n", aTransaction); +#endif + return NS_OK; + } + + // + // second possible case is that we have a commit transaction + // + nsCOMPtr commitTxn(do_QueryInterface(aTransaction)); + if (commitTxn) + { + (void)CollapseTextSelectionOnCommit(); + mFixed = PR_TRUE; + *aDidMerge = PR_TRUE; // absorbe the commit transaction +#ifdef DEBUG_TAGUE + printf("IMETextTxn assimilated IMECommitTxn%p\n", aTransaction); +#endif + return NS_OK; + } + + *aDidMerge = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::Write(nsIOutputStream *aOutputStream) +{ + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::GetUndoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Remove Text: "; + *aString += mStringToInsert; + } + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::GetRedoString(nsString *aString) +{ + if (nsnull!=aString) + { + *aString="Insert Text: "; + *aString += mStringToInsert; + } + return NS_OK; +} + +/* ============= nsISupports implementation ====================== */ + +NS_IMETHODIMP +IMETextTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIMETextTxnIID)) { + *aInstancePtr = (void*)(IMETextTxn*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + return (EditTxn::QueryInterface(aIID, aInstancePtr)); +} + +/* ============ protected methods ================== */ + +NS_IMETHODIMP IMETextTxn::GetData(nsString& aResult,nsIDOMTextRangeList** aTextRangeList) +{ + aResult = mStringToInsert; + *aTextRangeList = mRangeList; + return NS_OK; +} + +NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void) +{ + nsresult result; + PRBool haveSelectedRange; + PRUint16 textRangeListLength,selectionStart,selectionEnd, + textRangeType, i; + nsIDOMTextRange* textRange; + + haveSelectedRange = PR_FALSE; + +#ifdef DEBUG_tague + PRUint16 listlen,start,stop,type; + nsIDOMTextRange* rangePtr; + result = mRangeList->GetLength(&listlen); + printf("nsIDOMTextRangeList[%p]\n",mRangeList); + for (i=0;iItem(i,&rangePtr); + rangePtr->GetRangeStart(&start); + rangePtr->GetRangeEnd(&stop); + rangePtr->GetRangeType(&type); + printf("range[%d] start=%d end=%d type=",i,start,stop,type); + if (type==nsIDOMTextRange::TEXTRANGE_RAWINPUT) printf("TEXTRANGE_RAWINPUT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_SELECTEDRAWTEXT) printf("TEXTRANGE_SELECTEDRAWTEXT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_CONVERTEDTEXT) printf("TEXTRANGE_CONVERTEDTEXT\n"); + if (type==nsIDOMTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT) printf("TEXTRANGE_SELECTEDCONVERTEDTEXT\n"); + } +#endif + + // + // run through the text range list + // + result = mRangeList->GetLength(&textRangeListLength); + if (NS_SUCCEEDED(result)) + { + for(i=0;iItem(i,&textRange); + if (NS_SUCCEEDED(result)) + { + result = textRange->GetRangeType(&textRangeType); + if (textRangeType==nsIDOMTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT) + { + haveSelectedRange = PR_TRUE; + textRange->GetRangeStart(&selectionStart); + textRange->GetRangeEnd(&selectionEnd); + } + } + } + } + + nsCOMPtr selection; + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection){ + if (haveSelectedRange) { + result = selection->Collapse(mElement,mOffset+selectionStart); + result = selection->Extend(mElement,mOffset+selectionEnd+1); + } else { + result = selection->Collapse(mElement,mOffset+mStringToInsert.Length()); + } + } + + return result; +} + +NS_IMETHODIMP IMETextTxn::CollapseTextSelectionOnCommit(void) +{ + nsCOMPtr selection; + nsresult result = mPresShell->GetSelection(getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection){ + result = selection->Collapse(mElement,mOffset+mStringToInsert.Length()); + } + + return result; +} diff --git a/mozilla/editor/libeditor/base/IMETextTxn.h b/mozilla/editor/libeditor/base/IMETextTxn.h new file mode 100644 index 00000000000..b75865a12a9 --- /dev/null +++ b/mozilla/editor/libeditor/base/IMETextTxn.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef IMETextTxn_h__ +#define IMETextTxn_h__ + +#include "EditTxn.h" +#include "nsIDOMCharacterData.h" +#include "nsIDOMTextRangeList.h" +#include "nsCOMPtr.h" + +// {D4D25721-2813-11d3-9EA3-0060089FE59B} +#define IME_TEXT_TXN_IID \ +{0xd4d25721, 0x2813, 0x11d3, \ +{0x9e, 0xa3, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b }} + + + + +class nsIPresShell; + +/** + * A transaction that inserts text into a content node. + */ +class IMETextTxn : public EditTxn +{ +public: + virtual ~IMETextTxn(); + + /** used to name aggregate transactions that consist only of a single IMETextTxn, + * or a DeleteSelection followed by an IMETextTxn. + */ + static nsIAtom *gIMETextTxnName; + + /** initialize the transaction + * @param aElement the text content node + * @param aOffset the location in aElement to do the insertion + * @param aReplaceLength the length of text to replace (0= no replacement) + * @param aString the new text to insert + * @param aPresShell used to get and set the selection + */ + NS_IMETHOD Init(nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aReplaceLength, + nsIDOMTextRangeList* aTextRangeList, + const nsString& aString, + nsIPresShell* aPresShell); + +private: + + IMETextTxn(); + +public: + + NS_IMETHOD Do(void); + + NS_IMETHOD Undo(void); + + NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction); + + NS_IMETHOD Write(nsIOutputStream *aOutputStream); + + NS_IMETHOD GetUndoString(nsString *aString); + + NS_IMETHOD GetRedoString(nsString *aString); + +// nsISupports declarations + + // override QueryInterface to handle IMETextTxn request + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + static const nsIID& GetIID() { static nsIID iid = IME_TEXT_TXN_IID; return iid; } + + + /** return the string data associated with this transaction */ + NS_IMETHOD GetData(nsString& aResult, nsIDOMTextRangeList** aTextRangeList); + + /** must be called before any IMETextTxn is instantiated */ + static nsresult ClassInit(); + +protected: + + NS_IMETHOD CollapseTextSelection(void); + NS_IMETHOD CollapseTextSelectionOnCommit(void); + + /** the text element to operate upon */ + nsCOMPtr mElement; + + /** the offsets into mElement where the insertion should be placed*/ + PRUint32 mOffset; + + PRUint32 mReplaceLength; + + /** the text to insert into mElement at mOffset */ + nsString mStringToInsert; + + /** the range list **/ + nsCOMPtr mRangeList; + + /** the presentation shell, which we'll need to get the selection */ + nsIPresShell* mPresShell; + + PRBool mFixed; + + friend class TransactionFactory; + + friend class nsDerivedSafe; // work around for a compiler bug + +}; + +#endif diff --git a/mozilla/editor/libeditor/base/InsertTextTxn.cpp b/mozilla/editor/libeditor/base/InsertTextTxn.cpp index cc3e5936f9d..507dbb4c4be 100644 --- a/mozilla/editor/libeditor/base/InsertTextTxn.cpp +++ b/mozilla/editor/libeditor/base/InsertTextTxn.cpp @@ -25,6 +25,7 @@ static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID); static NS_DEFINE_IID(kIDOMSelectionIID, NS_IDOMSELECTION_IID); +static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID); #ifdef NS_DEBUG static PRBool gNoisy = PR_FALSE; diff --git a/mozilla/editor/libeditor/base/TransactionFactory.cpp b/mozilla/editor/libeditor/base/TransactionFactory.cpp index abe35f159f2..58b832ab8c7 100644 --- a/mozilla/editor/libeditor/base/TransactionFactory.cpp +++ b/mozilla/editor/libeditor/base/TransactionFactory.cpp @@ -39,7 +39,9 @@ #include "DeleteTableColumnTxn.h" #include "DeleteTableRowTxn.h" #include "JoinTableCellsTxn.h" +#include "IMETextTxn.h" +#include "IMECommitTxn.h" static NS_DEFINE_IID(kEditAggregateTxnIID, EDIT_AGGREGATE_TXN_IID); static NS_DEFINE_IID(kPlaceholderTxnIID, PLACEHOLDER_TXN_IID); static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID); @@ -61,6 +63,8 @@ static NS_DEFINE_IID(kDeleteTableCellTxnIID, DELETE_CELL_TXN_IID); static NS_DEFINE_IID(kDeleteTableColumnTxnIID, DELETE_COLUMN_TXN_IID); static NS_DEFINE_IID(kDeleteTableRowTxnIID, DELETE_ROW_TXN_IID); static NS_DEFINE_IID(kJoinTableCellsTxnIID, JOIN_CELLS_TXN_IID); +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIMECommitTxnIID, IME_COMMIT_TXN_IID); TransactionFactory::TransactionFactory() { @@ -97,6 +101,10 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult) *aResult = new JoinElementTxn(); else if (aTxnType.Equals(kEditAggregateTxnIID)) *aResult = new EditAggregateTxn(); + else if (aTxnType.Equals(kIMETextTxnIID)) + *aResult = new IMETextTxn(); + else if (aTxnType.Equals(kIMECommitTxnIID)) + *aResult = new IMECommitTxn(); else if (aTxnType.Equals(kPlaceholderTxnIID)) *aResult = new PlaceholderTxn(); else diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp index fa9fb78fe84..ee674cf34c9 100644 --- a/mozilla/editor/libeditor/base/nsEditor.cpp +++ b/mozilla/editor/libeditor/base/nsEditor.cpp @@ -84,6 +84,8 @@ static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); #include "SplitElementTxn.h" #include "JoinElementTxn.h" #include "nsIStringStream.h" +#include "IMETextTxn.h" +#include "IMECommitTxn.h" // #define HACK_FORCE_REDRAW 1 @@ -128,6 +130,8 @@ static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID); static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID); static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID); static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID); +static NS_DEFINE_IID(kIMETextTxnIID, IME_TEXT_TXN_IID); +static NS_DEFINE_IID(kIMECommitTxnIID, IME_COMMIT_TXN_IID); static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID); @@ -334,7 +338,6 @@ nsEditor::nsEditor() { //initialize member variables here NS_INIT_REFCNT(); - mIMEFirstTransaction=PR_FALSE; PR_EnterMonitor(GetEditorMonitor()); gInstanceCount++; mActionListeners = 0; @@ -519,6 +522,13 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell) mUpdateCount=0; InsertTextTxn::ClassInit(); + /* initalize IME stuff */ + IMETextTxn::ClassInit(); + IMECommitTxn::ClassInit(); + mIMETextNode = do_QueryInterface(nsnull); + mIMETextOffset = 0; + mIMEBufferLength = 0; + /* Show the caret */ nsCOMPtr caret; if (NS_SUCCEEDED(mPresShell->GetCaret(getter_AddRefs(caret)))) @@ -3188,93 +3198,102 @@ NS_IMETHODIMP nsEditor::GetLayoutObject(nsIDOMNode *aNode, nsISupports **aLayout return result; } +// +// The BeingComposition method is called from the Editor Composition event listeners. +// It caches the current text node and offset which is subsequently used for the +// created of IMETextTxn's. +// NS_IMETHODIMP nsEditor::BeginComposition(void) { - - if ((nsITransactionManager *)nsnull!=mTxnMgr.get()) - { #ifdef DEBUG_tague - printf("nsEditor::StartComposition -- begin batch.\n"); + printf("nsEditor::StartComposition\n"); #endif - mTxnMgr->BeginBatch(); - } - - if (!mIMESelectionRange) - { - nsresult result = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull, - nsIDOMRange::GetIID(), - getter_AddRefs(mIMESelectionRange)); - if (NS_FAILED(result)) + nsresult result; + PRInt32 offset; + nsCOMPtr selection; + nsCOMPtr nodeAsText; + + result = mPresShell->GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) { - mTxnMgr->EndBatch(); - return result; + result = NS_ERROR_UNEXPECTED; + nsCOMPtr enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + result = NS_ERROR_UNEXPECTED; + nsCOMPtr range(do_QueryInterface(currentItem)); + if (range) + { + nsCOMPtr node; + result = range->GetStartParent(getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && (node)) + { + nodeAsText = do_QueryInterface(node); + range->GetStartOffset(&offset); + if (!nodeAsText) { + result = NS_ERROR_EDITOR_NO_TEXTNODE; + } + } + } + } + else + { + result = NS_ERROR_EDITOR_NO_SELECTION; + } + } } - } - mIMEFirstTransaction=PR_TRUE; - - return NS_OK; + if (NS_SUCCEEDED(result) && nodeAsText) + { + // + // store the information needed to construct IME transactions for this composition + // + mIMETextNode = nodeAsText; + mIMETextOffset = offset; + mIMEBufferLength = 0; + } + return result; } NS_IMETHODIMP nsEditor::EndComposition(void) { - if ((nsITransactionManager *)nsnull!=mTxnMgr.get()) - { -#ifdef DEBUG_tague - printf("nsEditor::EndComposition -- end batch.\n"); -#endif - mTxnMgr->EndBatch(); - mIMEFirstTransaction=PR_TRUE; - return NS_OK; - } + nsresult result; + IMECommitTxn *commitTxn; + + // + // create the commit transaction..we can do it directly from the transaction mgr + // + result = TransactionFactory::GetNewTransaction(kIMECommitTxnIID,(EditTxn**)&commitTxn); + if (NS_SUCCEEDED(result) && commitTxn!=nsnull) + { + commitTxn->Init(); + result = Do(commitTxn); + } - // mIMESelectionRange = nsCOMPtr(); + /* reset the data we need to construct a transaction */ + mIMETextNode = do_QueryInterface(nsnull); + mIMETextOffset = 0; + mIMEBufferLength = 0; - return NS_OK; + return result; } NS_IMETHODIMP -nsEditor::SetCompositionString(const nsString& aCompositionString) +nsEditor::SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList) { + nsresult result = SetInputMethodText(aCompositionString,aTextRangeList); + mIMEBufferLength = aCompositionString.Length(); - - if (mIMEFirstTransaction==PR_TRUE) { - mIMEFirstTransaction = PR_FALSE; - } else { - // printf("Undo!\n"); - // mTxnMgr->Undo(); - nsCOMPtr selection; - nsresult result; - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - nsCOMPtr node; - PRInt32 offset; - - result = mIMESelectionRange->GetStartParent(getter_AddRefs(node)); - result = mIMESelectionRange->GetStartOffset(&offset); - - result = selection->Collapse(node, offset); - - - result = mIMESelectionRange->GetEndParent(getter_AddRefs(node)); - result = mIMESelectionRange->GetEndOffset(&offset); - - result = selection->Extend(node, offset); - } -#ifdef DEBUG_tague - printf("nsEditor::SetCompositionString: string=%s\n",aCompositionString); -#endif - return SetPreeditText(aCompositionString); + return result; } NS_IMETHODIMP @@ -3450,176 +3469,130 @@ nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode) //END nsEditor Private methods -NS_IMETHODIMP nsEditor::DoInitialPreeeditInsert(const nsString& aStringToInsert) +NS_IMETHODIMP +nsEditor::SetInputMethodText(const nsString& aStringToInsert,nsIDOMTextRangeList *aTextRangeList) { - if (!mDoc) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtrnodeList; - nsAutoString bodyTag = "body"; - nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); - if ((NS_SUCCEEDED(result)) && nodeList) - { - PRUint32 count; - nodeList->GetLength(&count); - NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); - nsCOMPtrnode; - result = nodeList->Item(0, getter_AddRefs(node)); - if ((NS_SUCCEEDED(result)) && node) - { // now we've got the body tag. - // create transaction to insert the text node, - // and create a transaction to insert the text - CreateElementTxn *txn; - result = CreateTxnForCreateElement(GetTextNodeTag(), node, 0, &txn); - if ((NS_SUCCEEDED(result)) && txn) - { - result = Do(txn); - if (NS_SUCCEEDED(result)) - { - nsCOMPtrnewNode; - txn->GetNewNode(getter_AddRefs(newNode)); - if ((NS_SUCCEEDED(result)) && newNode) - { - nsCOMPtrnewTextNode; - newTextNode = do_QueryInterface(newNode); - if (newTextNode) - { - InsertTextTxn *insertTxn; - result = CreateTxnForInsertText(aStringToInsert, newTextNode, &insertTxn); - if (NS_SUCCEEDED(result)) { - result = Do(insertTxn); - } - } - else { - result = NS_ERROR_UNEXPECTED; - } - } - } - } - } - } - return result; + IMETextTxn *txn; + nsresult result; + + result = CreateTxnForIMEText(aStringToInsert,aTextRangeList,&txn); // insert at the current selection + if ((NS_SUCCEEDED(result)) && txn) { + BeginUpdateViewBatch(); + result = Do(txn); + EndUpdateViewBatch(); + } + else if (NS_ERROR_EDITOR_NO_SELECTION==result) { + result = DoInitialInputMethodInsert(aStringToInsert,aTextRangeList); + } + else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) + { + BeginTransaction(); + nsCOMPtr selection; + result = GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + nsCOMPtr selectedNode; + PRInt32 offset; + result = selection->GetAnchorNode(getter_AddRefs(selectedNode)); + if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode) + { + nsCOMPtr newNode; + result = CreateNode(GetTextNodeTag(), selectedNode, offset+1,getter_AddRefs(newNode)); + if (NS_SUCCEEDED(result) && newNode) + { + nsCOMPtrnewTextNode; + newTextNode = do_QueryInterface(newNode); + if (newTextNode) + { + nsAutoString placeholderText(" "); + newTextNode->SetData(placeholderText); + selection->Collapse(newNode, 0); + selection->Extend(newNode, 1); + result = SetInputMethodText(aStringToInsert,aTextRangeList); + } + } + } + } + + EndTransaction(); + } + + return result; } NS_IMETHODIMP -nsEditor::SetPreeditText(const nsString& aStringToInsert) +nsEditor::CreateTxnForIMEText(const nsString & aStringToInsert, + nsIDOMTextRangeList* aTextRangeList, + IMETextTxn ** aTxn) { - nsresult result; + nsresult result; - //EditAggregateTxn *aggTxn = nsnull; - // Create the "delete current selection" txn - nsCOMPtr selection; - - BeginTransaction(); - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_SUCCEEDED(result) && selection) - { - PRBool collapsed; - result = selection->GetIsCollapsed(&collapsed); - if (NS_SUCCEEDED(result) && !collapsed) { - EditAggregateTxn *delSelTxn; - // XXX should this be eDoNothing instead of eDeleteRight? - result = CreateTxnForDeleteSelection(nsIEditor::eDeleteRight, - &delSelTxn); - if (NS_SUCCEEDED(result) && delSelTxn) { - result = Do(delSelTxn); - - if (NS_FAILED(result)) { - EndTransaction(); - return result; - } - } - } - } - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - nsCOMPtr startRange; - nsCOMPtr endRange; - - result = selection->GetRangeAt(0, getter_AddRefs(startRange)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - InsertTextTxn *txn; - result = CreateTxnForInsertText(aStringToInsert, nsnull, &txn); // insert at the current selection - if ((NS_SUCCEEDED(result)) && txn) { - result = Do(txn); - } - else if (NS_ERROR_EDITOR_NO_SELECTION==result) { - result = DoInitialInsert(aStringToInsert); - } - else if (NS_ERROR_EDITOR_NO_TEXTNODE==result) - { - result = GetSelection(getter_AddRefs(selection)); - if ((NS_SUCCEEDED(result)) && selection) - { - nsCOMPtr selectedNode; - PRInt32 offset; - result = selection->GetAnchorNode(getter_AddRefs(selectedNode)); - if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offset)) && selectedNode) - { - nsCOMPtr newNode; - result = CreateNode(GetTextNodeTag(), selectedNode, offset+1, - getter_AddRefs(newNode)); - if (NS_SUCCEEDED(result) && newNode) - { - nsCOMPtrnewTextNode; - newTextNode = do_QueryInterface(newNode); - if (newTextNode) - { - nsAutoString placeholderText(" "); - newTextNode->SetData(placeholderText); - selection->Collapse(newNode, 0); - selection->Extend(newNode, 1); - result = SetPreeditText(aStringToInsert); - } - } - } - } - - } - - result = mPresShell->GetSelection(getter_AddRefs(selection)); - - if (NS_FAILED(result)) - { - EndTransaction(); - return result; - } - - result = selection->GetRangeAt(0, getter_AddRefs(endRange)); - - nsCOMPtr node; - PRInt32 offset; - - startRange->GetStartParent(getter_AddRefs(node)); - startRange->GetStartOffset(&offset); - mIMESelectionRange->SetStart(node, offset); - - endRange->GetStartParent(getter_AddRefs(node)); - endRange->GetStartOffset(&offset); - mIMESelectionRange->SetEnd(node, offset); - - EndTransaction(); - // HACKForceRedraw(); - return result; + result = TransactionFactory::GetNewTransaction(kIMETextTxnIID, (EditTxn **)aTxn); + if (nsnull!=*aTxn) { + result = (*aTxn)->Init(mIMETextNode,mIMETextOffset,mIMEBufferLength,aTextRangeList,aStringToInsert,mPresShell); + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + return result; } +NS_IMETHODIMP nsEditor::DoInitialInputMethodInsert(const nsString & aStringToInsert,nsIDOMTextRangeList* aTextRangeList) +{ + if (!mDoc) { + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtrnodeList; + nsAutoString bodyTag = "body"; + nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); + if ((NS_SUCCEEDED(result)) && nodeList) + { + PRUint32 count; + nodeList->GetLength(&count); + NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); + nsCOMPtrnode; + result = nodeList->Item(0, getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && node) + { // now we've got the body tag. + // create transaction to insert the text node, + // and create a transaction to insert the text + CreateElementTxn *txn; + result = CreateTxnForCreateElement(GetTextNodeTag(), node, 0, &txn); + if ((NS_SUCCEEDED(result)) && txn) + { + result = Do(txn); + if (NS_SUCCEEDED(result)) + { + nsCOMPtrnewNode; + txn->GetNewNode(getter_AddRefs(newNode)); + if ((NS_SUCCEEDED(result)) && newNode) + { + nsCOMPtrnewTextNode; + newTextNode = do_QueryInterface(newNode); + if (newTextNode) + { + mIMETextNode = newTextNode; + mIMETextOffset = 0; + mIMEBufferLength = 0; + IMETextTxn *IMETxn; + result = CreateTxnForIMEText(aStringToInsert,aTextRangeList,&IMETxn); + if (NS_SUCCEEDED(result)) { + result = Do(IMETxn); + } + } + else { + result = NS_ERROR_UNEXPECTED; + } + } + } + } + } + } + + return result; +} /////////////////////////////////////////////////////////////////////////// // GetTag: digs out the atom for the tag of this node // diff --git a/mozilla/editor/libeditor/base/nsEditor.h b/mozilla/editor/libeditor/base/nsEditor.h index 97855629233..2751c7cca25 100644 --- a/mozilla/editor/libeditor/base/nsEditor.h +++ b/mozilla/editor/libeditor/base/nsEditor.h @@ -26,6 +26,7 @@ #include "nsIDOMSelection.h" #include "nsIDOMEventListener.h" #include "nsIDOMRange.h" +#include "nsIDOMTextRangeList.h" #include "nsCOMPtr.h" #include "nsIStringBundle.h" #include "nsITransactionManager.h" @@ -54,6 +55,7 @@ class nsIPref; class nsIStringBundleService; class nsIStringBundle; class nsILocale; +class IMETextTxn; #ifdef ENABLE_JS_EDITOR_LOG class nsJSEditorLog; @@ -78,7 +80,12 @@ private: nsCOMPtr mTxnMgr; nsCOMPtr mEditProperty; - nsCOMPtr mIMESelectionRange; + // + // data necessary to build IME transactions + // + nsCOMPtr mIMETextNode; + PRUint32 mIMETextOffset; + PRUint32 mIMEBufferLength; friend PRBool NSCanUnload(nsISupports* serviceMgr); static PRInt32 gInstanceCount; @@ -163,7 +170,7 @@ public: NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList); NS_IMETHOD EndComposition(void); @@ -273,10 +280,16 @@ protected: nsIDOMCharacterData *aTextNode, InsertTextTxn ** aTxn); + NS_IMETHOD CreateTxnForIMEText(const nsString & aStringToInsert, + nsIDOMTextRangeList* aTextRangeList, + IMETextTxn ** aTxn); + /** insert aStringToInsert as the first text in the document */ NS_IMETHOD DoInitialInsert(const nsString & aStringToInsert); + NS_IMETHOD DoInitialInputMethodInsert(const nsString& aStringToInsert,nsIDOMTextRangeList* aTextRangeList); + NS_IMETHOD DeleteText(nsIDOMCharacterData *aElement, PRUint32 aOffset, @@ -314,10 +327,7 @@ protected: NS_IMETHOD DebugDumpContent() const; - // should these me methodimp? - NS_IMETHODIMP SetPreeditText(const nsString& aStringToInsert); - - NS_IMETHODIMP DoInitialPreeeditInsert(const nsString& aStringToInsert); + NS_IMETHOD SetInputMethodText(const nsString& aStringToInsert, nsIDOMTextRangeList* aTextRangeList); // called each time we modify the document. Increments the mod // count of the doc. @@ -344,8 +354,6 @@ protected: // document after a change via the DOM - gpk 2/13/99 void HACKForceRedraw(void); - PRBool mIMEFirstTransaction; - NS_IMETHOD DeleteSelectionAndPrepareToCreateNode(nsCOMPtr &parentSelectedNode, PRInt32& offsetOfNewNode); public: diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 62c9e1cb274..c9db5065b00 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -2488,9 +2488,9 @@ NS_IMETHODIMP nsHTMLEditor::EndComposition(void) return nsTextEditor::EndComposition(); } -NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString) +NS_IMETHODIMP nsHTMLEditor::SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList) { - return nsTextEditor::SetCompositionString(aCompositionString); + return nsTextEditor::SetCompositionString(aCompositionString,aTextRangeList); } NS_IMETHODIMP diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index c2de0cb3555..c59daa964e0 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -106,7 +106,7 @@ public: NS_IMETHOD InsertHTML(const nsString& aInputString); NS_IMETHOD BeginComposition(void); - NS_IMETHOD SetCompositionString(const nsString& aCompositionString); + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRange); NS_IMETHOD EndComposition(void); NS_IMETHOD OutputTextToString(nsString& aOutputString, PRBool aSelectionOnly); NS_IMETHOD OutputHTMLToString(nsString& aOutputString, PRBool aSelectionOnly); diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index 4e976e86fea..35d6fc39eb6 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -1090,16 +1090,19 @@ nsTextEditorTextListener::HandleText(nsIDOMEvent* aTextEvent) { nsString composedText; nsresult result; + nsCOMPtruiEvent; + nsIDOMTextRangeList *textRangeList; - nsCOMPtruiEvent; - uiEvent = do_QueryInterface(aTextEvent); - if (!uiEvent) { - //non-ui event passed in. bad things. - return NS_OK; - } + uiEvent = do_QueryInterface(aTextEvent); + if (!uiEvent) { + //non-ui event passed in. bad things. + return NS_OK; + } uiEvent->GetText(composedText); - result = mEditor->SetCompositionString(composedText); + uiEvent->GetInputRange(&textRangeList); + textRangeList->AddRef(); + result = mEditor->SetCompositionString(composedText,textRangeList); return result; } diff --git a/mozilla/editor/public/nsIEditor.h b/mozilla/editor/public/nsIEditor.h index f3158bfb88c..17298b51b17 100644 --- a/mozilla/editor/public/nsIEditor.h +++ b/mozilla/editor/public/nsIEditor.h @@ -27,6 +27,7 @@ class nsIDOMNode; class nsITransaction; class nsIEditActionListener; class nsIFileSpec; +class nsIDOMTextRangeList; /* Editor interface to outside world @@ -194,7 +195,7 @@ public: * BeginComposition must be called prior to this. */ - NS_IMETHOD SetCompositionString(const nsString& aCompositionString) = 0; + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList) = 0; /** * BeginComposition() Handles the end of inline input composition. diff --git a/mozilla/editor/public/nsIHTMLEditor.h b/mozilla/editor/public/nsIHTMLEditor.h index b5364454665..9bd05296602 100644 --- a/mozilla/editor/public/nsIHTMLEditor.h +++ b/mozilla/editor/public/nsIHTMLEditor.h @@ -192,7 +192,7 @@ public: // IME editing Methods NS_IMETHOD BeginComposition(void)=0; - NS_IMETHOD SetCompositionString(const nsString& aCompositionString)=0; + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList)=0; NS_IMETHOD EndComposition(void)=0; diff --git a/mozilla/editor/public/nsITextEditor.h b/mozilla/editor/public/nsITextEditor.h index 284b9723198..b1a01892abe 100644 --- a/mozilla/editor/public/nsITextEditor.h +++ b/mozilla/editor/public/nsITextEditor.h @@ -365,7 +365,7 @@ public: // IME Editing Methods NS_IMETHOD BeginComposition(void)=0; - NS_IMETHOD SetCompositionString(const nsString& aCompositionString)=0; + NS_IMETHOD SetCompositionString(const nsString& aCompositionString, nsIDOMTextRangeList* aTextRangeList)=0; NS_IMETHOD EndComposition(void)=0; diff --git a/mozilla/layout/events/src/Makefile.in b/mozilla/layout/events/src/Makefile.in index a5d272c8f3c..b23c83d1028 100644 --- a/mozilla/layout/events/src/Makefile.in +++ b/mozilla/layout/events/src/Makefile.in @@ -31,6 +31,7 @@ CPPSRCS = \ nsEventStateManager.cpp \ nsDOMEvent.cpp \ nsDOMEventsIIDs.cpp \ + nsDOMTextRange.cpp \ $(NULL) MODULE=layout @@ -40,6 +41,7 @@ EXPORTS = \ nsEventStateManager.h \ nsDOMEvent.h \ nsDOMEventsIIDs.h \ + nsDOMTextRange.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/mozilla/layout/events/src/makefile.win b/mozilla/layout/events/src/makefile.win index 2d30f4c3eb6..7785b222c46 100644 --- a/mozilla/layout/events/src/makefile.win +++ b/mozilla/layout/events/src/makefile.win @@ -30,16 +30,18 @@ CPPSRCS= nsEventListenerManager.cpp \ nsEventStateManager.cpp \ nsDOMEvent.cpp \ nsDOMEventsIIDs.cpp \ + nsDOMTextRange.cpp \ $(NULL) CPP_OBJS= .\$(OBJDIR)\nsEventListenerManager.obj \ .\$(OBJDIR)\nsEventStateManager.obj \ .\$(OBJDIR)\nsDOMEvent.obj \ .\$(OBJDIR)\nsDOMEventsIIDs.obj \ + .\$(OBJDIR)\nsDOMTextRange.obj \ $(NULL) -EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h +EXPORTS= nsEventListenerManager.h nsEventStateManager.h nsDOMEvent.h nsDOMEventsIIDs.h nsDOMTextRange.h LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor \ -I$(PUBLIC)\dom -I$(PUBLIC)\js -I..\..\html\base\src -I$(PUBLIC)\netlib diff --git a/mozilla/layout/events/src/nsDOMEvent.cpp b/mozilla/layout/events/src/nsDOMEvent.cpp index 0b204498008..b4bc84126f6 100644 --- a/mozilla/layout/events/src/nsDOMEvent.cpp +++ b/mozilla/layout/events/src/nsDOMEvent.cpp @@ -26,6 +26,7 @@ #include "nsIWidget.h" #include "nsIWebShell.h" #include "nsIPresShell.h" +#include "nsDOMTextRange.h" static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); @@ -50,10 +51,28 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent) { mEvent = aEvent; mTarget = nsnull; mText = nsnull; + mTextRange = nsnull; if (aEvent->eventStructType ==NS_TEXT_EVENT) { + // + // extract the IME composition string + // mText = new nsString(((nsTextEvent*)aEvent)->theText); - mCommitText = ((nsTextEvent*)aEvent)->commitText; + // + // build the range list -- ranges need to be DOM-ified since the IME transaction + // will hold a ref, the widget representation isn't persistent + // + nsIDOMTextRange** tempTextRangeList = new nsIDOMTextRange*[((nsTextEvent*)aEvent)->rangeCount]; + for(PRUint16 i=0;i<((nsTextEvent*)aEvent)->rangeCount;i++) { + nsDOMTextRange* tempDOMTextRange = new nsDOMTextRange((((nsTextEvent*)aEvent)->rangeArray[i]).mStartOffset, + (((nsTextEvent*)aEvent)->rangeArray[i]).mEndOffset, + (((nsTextEvent*)aEvent)->rangeArray[i]).mRangeType); + tempDOMTextRange->AddRef(); + tempTextRangeList[i] = (nsIDOMTextRange*)tempDOMTextRange; + } + + mTextRange = (nsIDOMTextRangeList*) new nsDOMTextRangeList(((nsTextEvent*)aEvent)->rangeCount,tempTextRangeList); + mTextRange->AddRef(); } NS_INIT_REFCNT(); @@ -62,8 +81,10 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent) { nsDOMEvent::~nsDOMEvent() { NS_RELEASE(mPresContext); NS_IF_RELEASE(mTarget); + NS_IF_RELEASE(mTextRange); - delete mText; + if (mText!=nsnull) + delete mText; } NS_IMPL_ADDREF(nsDOMEvent) @@ -182,18 +203,18 @@ NS_METHOD nsDOMEvent::GetText(nsString& aText) return NS_ERROR_FAILURE; } -NS_METHOD nsDOMEvent::GetCommitText(PRBool* aCommitText) +NS_METHOD nsDOMEvent::GetInputRange(nsIDOMTextRangeList** aInputRange) { if (mEvent->message == NS_TEXT_EVENT) { - *aCommitText = mCommitText; + *aInputRange = mTextRange; return NS_OK; } - + return NS_ERROR_FAILURE; } -NS_METHOD nsDOMEvent::SetCommitText(PRBool aCommitText) -{ +NS_METHOD nsDOMEvent::SetInputRange(nsIDOMTextRangeList* aInputRange) +{ return NS_ERROR_FAILURE; } diff --git a/mozilla/layout/events/src/nsDOMEvent.h b/mozilla/layout/events/src/nsDOMEvent.h index 519c50b3a75..1f0193dc1d9 100644 --- a/mozilla/layout/events/src/nsDOMEvent.h +++ b/mozilla/layout/events/src/nsDOMEvent.h @@ -81,10 +81,11 @@ public: NS_IMETHOD PreventDefault(); - NS_IMETHOD GetText(nsString& aText); + NS_IMETHOD GetText(nsString& aText); - NS_IMETHOD GetCommitText(PRBool* aCommitText); - NS_IMETHOD SetCommitText(PRBool aCommitText); + NS_IMETHOD GetInputRange(nsIDOMTextRangeList** aInputRange); + + NS_IMETHOD SetInputRange(nsIDOMTextRangeList* aInputRange); NS_IMETHOD GetScreenX(PRInt32* aScreenX); @@ -135,7 +136,7 @@ protected: nsIPresContext* mPresContext; nsIDOMNode* mTarget; nsString* mText; - PRBool mCommitText; + nsIDOMTextRangeList* mTextRange; const char* GetEventName(PRUint32 aEventType); }; diff --git a/mozilla/layout/events/src/nsDOMTextRange.cpp b/mozilla/layout/events/src/nsDOMTextRange.cpp new file mode 100644 index 00000000000..6461ed63dbb --- /dev/null +++ b/mozilla/layout/events/src/nsDOMTextRange.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsDOMTextRange.h" + +static NS_DEFINE_IID(kIDOMTextRange, NS_IDOMTEXTRANGE_IID); +static NS_DEFINE_IID(kIDOMTextRangeList,NS_IDOMTEXTRANGELIST_IID); + +nsDOMTextRange::nsDOMTextRange(PRUint16 aRangeStart, PRUint16 aRangeEnd, PRUint16 aRangeType) +: mRangeStart(aRangeStart), + mRangeEnd(aRangeEnd), + mRangeType(aRangeType) +{ + NS_INIT_REFCNT(); +} + +nsDOMTextRange::~nsDOMTextRange(void) +{ + +} + +NS_IMPL_ADDREF(nsDOMTextRange) +NS_IMPL_RELEASE(nsDOMTextRange) + +nsresult nsDOMTextRange::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDOMTextRange)) { + *aInstancePtrResult = (void*) ((nsIDOMTextRange*)this); + AddRef(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +NS_METHOD nsDOMTextRange::GetRangeStart(PRUint16* aRangeStart) +{ + *aRangeStart = mRangeStart; + return NS_OK; +} + +NS_METHOD nsDOMTextRange::SetRangeStart(PRUint16 aRangeStart) +{ + mRangeStart = aRangeStart; + return NS_OK; +} + +NS_METHOD nsDOMTextRange::GetRangeEnd(PRUint16* aRangeEnd) +{ + *aRangeEnd = mRangeEnd; + return NS_OK; +} + +NS_METHOD nsDOMTextRange::SetRangeEnd(PRUint16 aRangeEnd) +{ + mRangeEnd = aRangeEnd; + return NS_OK; +} + +NS_METHOD nsDOMTextRange::GetRangeType(PRUint16* aRangeType) +{ + *aRangeType = mRangeType; + return NS_OK; +} + +NS_METHOD nsDOMTextRange::SetRangeType(PRUint16 aRangeType) +{ + mRangeType = aRangeType; + return NS_OK; +} + + +nsDOMTextRangeList::nsDOMTextRangeList(PRUint16 aLength,nsIDOMTextRange** aList) +: mLength(aLength), + mList(aList) +{ + if (aList==nsnull) + aLength = 0; + + NS_INIT_REFCNT(); +} + +nsDOMTextRangeList::~nsDOMTextRangeList(void) +{ + int i; + for(i=0;iRelease(); +} + +NS_IMPL_ADDREF(nsDOMTextRangeList) +NS_IMPL_RELEASE(nsDOMTextRangeList) + +nsresult nsDOMTextRangeList::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDOMTextRangeList)) { + *aInstancePtrResult = (void*) ((nsIDOMTextRangeList*)this); + AddRef(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +NS_METHOD nsDOMTextRangeList::GetLength(PRUint16* aLength) +{ + *aLength = mLength; + return NS_OK; +} + +NS_METHOD nsDOMTextRangeList::Item(PRUint16 aIndex, nsIDOMTextRange** aReturn) +{ + if (aIndex>mLength) { + *aReturn = nsnull; + return NS_ERROR_FAILURE; + } + + mList[aIndex]->AddRef(); + *aReturn = mList[aIndex]; + + return NS_OK; +} + + + + diff --git a/mozilla/layout/events/src/nsDOMTextRange.h b/mozilla/layout/events/src/nsDOMTextRange.h new file mode 100644 index 00000000000..6aa47d8708e --- /dev/null +++ b/mozilla/layout/events/src/nsDOMTextRange.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsDOMTextRange_h__ +#define nsDOMTextRange_h__ + +#include "nsIDOMTextRange.h" +#include "nsIDOMTextRangeList.h" + +class nsDOMTextRange : public nsIDOMTextRange +{ + NS_DECL_ISUPPORTS +public: + + nsDOMTextRange(PRUint16 aRangeStart, PRUint16 aRangeEnd, PRUint16 aRangeType); + ~nsDOMTextRange(void); + + NS_IMETHOD GetRangeStart(PRUint16* aRangeStart); + NS_IMETHOD SetRangeStart(PRUint16 aRangeStart); + + NS_IMETHOD GetRangeEnd(PRUint16* aRangeEnd); + NS_IMETHOD SetRangeEnd(PRUint16 aRangeEnd); + + NS_IMETHOD GetRangeType(PRUint16* aRangeType); + NS_IMETHOD SetRangeType(PRUint16 aRangeType); + +protected: + + PRUint16 mRangeStart; + PRUint16 mRangeEnd; + PRUint16 mRangeType; +}; + +class nsDOMTextRangeList: public nsIDOMTextRangeList +{ + NS_DECL_ISUPPORTS +public: + + nsDOMTextRangeList(PRUint16 aLength,nsIDOMTextRange** aList); + ~nsDOMTextRangeList(void); + + NS_IMETHOD GetLength(PRUint16* aLength); + + NS_IMETHOD Item(PRUint16 aIndex, nsIDOMTextRange** aReturn); + +protected: + + PRUint16 mLength; + nsIDOMTextRange** mList; +}; + + +#endif diff --git a/mozilla/widget/public/nsGUIEvent.h b/mozilla/widget/public/nsGUIEvent.h index 8844e0a1600..fc30f5c4eef 100644 --- a/mozilla/widget/public/nsGUIEvent.h +++ b/mozilla/widget/public/nsGUIEvent.h @@ -137,18 +137,30 @@ struct nsKeyEvent : public nsInputEvent { }; /** - * Tooltip event + * IME Related Events */ +struct nsTextRange { + PRUint32 mStartOffset; + PRUint32 mEndOffset; + PRUint32 mRangeType; +}; + +typedef struct nsTextRange nsTextRange; +typedef nsTextRange* nsTextRangeArray; struct nsTextEvent : public nsInputEvent { PRUnichar* theText; - PRBool commitText; + PRUint32 rangeCount; + nsTextRangeArray rangeArray; }; struct nsCompositionEvent : public nsInputEvent { PRUint32 compositionMessage; }; +/** + * Tooltip event + */ struct nsTooltipEvent : public nsGUIEvent { /// Index of tooltip area which generated the event. @see SetTooltips in nsIWidget PRUint32 tipIndex; @@ -453,5 +465,11 @@ enum nsDragDropEventStatus { #define NS_EVENT_FLAG_CAPTURE 0x0004 #define NS_EVENT_FLAG_POST_PROCESS 0x0008 +// IME Constants -- keep in synch with nsIDOMTextRange.h +#define NS_TEXTRANGE_RAWINPUT 0X01 +#define NS_TEXTRANGE_SELECTEDRAWTEXT 0x02 +#define NS_TEXTRANGE_CONVERTEDTEXT 0x03 +#define NS_TEXTRANGE_SELECTEDCONVERTEDTEXT 0x04 + #endif // nsGUIEvent_h__ diff --git a/mozilla/widget/src/windows/nsWindow.cpp b/mozilla/widget/src/windows/nsWindow.cpp index 0d3ecc15728..8cb891fe832 100644 --- a/mozilla/widget/src/windows/nsWindow.cpp +++ b/mozilla/widget/src/windows/nsWindow.cpp @@ -112,8 +112,16 @@ nsWindow::nsWindow() : nsBaseWidget() mIMEIsComposing = PR_FALSE; mIMECompositionString = NULL; mIMECompositionStringSize = 0; - mIMECompositionStringSize = 0; + mIMECompositionStringLength = 0; mIMECompositionUniString = NULL; + mIMECompositionUniStringSize = 0; + mIMEAttributeString = NULL; + mIMEAttributeStringSize = 0; + mIMEAttributeStringLength = 0; + mIMECompClauseString = NULL; + mIMECompClauseStringSize = 0; + mIMECompClauseStringLength = 0; + #if 1 mHaveDBCSLeadByte = false; mDBCSLeadByte = '\0'; @@ -152,6 +160,13 @@ nsWindow::~nsWindow() //XXX Temporary: Should not be caching the font delete mFont; + + // + // delete any of the IME structures that we allocated + // + if (mIMECompositionString!=NULL) delete [] mIMECompositionString; + if (mIMEAttributeString!=NULL) delete [] mIMEAttributeString; + if (mIMECompositionUniString!=NULL) delete [] mIMECompositionUniString; } @@ -2641,6 +2656,40 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT return PR_TRUE; } + // + // This provides us with the attribute string necessary for doing hiliting + // + if (lParam & GCS_COMPATTR) { + long attrStrLen = ::ImmGetCompositionString(hIMEContext,GCS_COMPATTR,NULL,0); + if (attrStrLen+1>mIMEAttributeStringSize) { + if (mIMEAttributeString!=NULL) delete [] mIMEAttributeString; + mIMEAttributeString = new char[attrStrLen+32]; + mIMEAttributeStringSize = attrStrLen+32; + } + + ::ImmGetCompositionString(hIMEContext,GCS_COMPATTR,mIMEAttributeString,mIMEAttributeStringSize); + mIMEAttributeStringLength = attrStrLen; + mIMEAttributeString[attrStrLen]='\0'; + } + + if (lParam & GCS_COMPCLAUSE) { + long compClauseLen = ::ImmGetCompositionString(hIMEContext,GCS_COMPCLAUSE,NULL,0); + if (compClauseLen+1>mIMECompClauseStringSize) { + if (mIMECompClauseString!=NULL) delete [] mIMECompClauseString; + mIMECompClauseString = new char [compClauseLen+32]; + mIMECompClauseStringSize = compClauseLen+32; + } + + ::ImmGetCompositionString(hIMEContext,GCS_COMPCLAUSE,mIMECompClauseString,mIMECompClauseStringSize); + mIMECompClauseStringLength = compClauseLen; + mIMECompClauseString[compClauseLen]='\0'; + } else { + mIMECompClauseStringLength = 0; + } + + // + // This provides us with a composition string + // if (lParam & GCS_COMPSTR) { #ifdef DEBUG_tague fprintf(stderr,"nsWindow::WM_IME_COMPOSITION: handling GCS_COMPSTR\n"); @@ -2655,10 +2704,13 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT ::ImmGetCompositionString(hIMEContext,GCS_COMPSTR,mIMECompositionString,mIMECompositionStringSize); mIMECompositionStringLength = compStrLen; mIMECompositionString[compStrLen]='\0'; - HandleTextEvent(PR_FALSE); + HandleTextEvent(); result = PR_TRUE; } + // + // This catches a fixed result + // if (lParam & GCS_RESULTSTR) { #ifdef DEBUG_tague fprintf(stderr,"nsWindow::WM_IME_COMPOSITION: handling GCS_RESULTSTR\n"); @@ -2674,7 +2726,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT mIMECompositionStringLength = compStrLen; mIMECompositionString[compStrLen]='\0'; result = PR_TRUE; - HandleTextEvent(PR_TRUE); + HandleTextEvent(); HandleEndComposition(); HandleStartComposition(); } @@ -3304,31 +3356,42 @@ NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight) } void -nsWindow::HandleTextEvent(PRBool commit) +nsWindow::HandleTextEvent() { - nsTextEvent event; - nsPoint point; - size_t unicharSize; - + nsTextEvent event; + nsPoint point; + size_t unicharSize; + point.x = 0; point.y = 0; InitEvent(event, NS_TEXT_EVENT, &point); - if (mIMECompositionUniString!=NULL) - delete [] mIMECompositionUniString; - + + // + // convert the composition string text into unicode before it is sent to xp-land + // unicharSize = ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,mIMECompositionString,mIMECompositionStringLength, mIMECompositionUniString,0); - mIMECompositionUniString = new PRUnichar[unicharSize+1]; + + if (mIMECompositionUniStringSize < unicharSize) { + if (mIMECompositionUniString!=NULL) delete [] mIMECompositionUniString; + mIMECompositionUniString = new PRUnichar[unicharSize+32]; + mIMECompositionUniStringSize = unicharSize+32; + } ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,mIMECompositionString,mIMECompositionStringLength, mIMECompositionUniString,unicharSize); mIMECompositionUniString[unicharSize] = (PRUnichar)0; - event.theText = mIMECompositionUniString; - event.commitText = commit; - event.isShift = mIsShiftDown; + // + // we need to convert the attribute array, which is alligned with the mutibyte text into an array of offsets + // mapped to the unicode text + // + MapDBCSAtrributeArrayToUnicodeOffsets(&(event.rangeCount),&(event.rangeArray)); + + event.theText = mIMECompositionUniString; + event.isShift = mIsShiftDown; event.isControl = mIsControlDown; - event.isAlt = mIsAltDown; + event.isAlt = mIsAltDown; event.eventStructType = NS_TEXT_EVENT; (void)DispatchWindowEvent(&event); @@ -3367,3 +3430,88 @@ nsWindow::HandleEndComposition(void) (void)DispatchWindowEvent(&event); NS_RELEASE(event.widget); } + +// +// This function converters the composition string (CGS_COMPSTR) into Unicode while mapping the +// attribute (GCS_ATTR) string t +void +nsWindow::MapDBCSAtrributeArrayToUnicodeOffsets(PRUint32* textRangeListLengthResult,nsTextRangeArray* textRangeListResult) +{ + int i,rangePointer; + size_t lastUnicodeOffset, substringLength, lastMBCSOffset; + + // + // figure out the ranges from the compclause string + // + if (mIMECompClauseStringLength==0) { + *textRangeListLengthResult = 1; + *textRangeListResult = new nsTextRange[1]; + (*textRangeListResult)[0].mStartOffset=0; + substringLength = ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,mIMECompositionString, + mIMECompositionStringLength,NULL,0); + (*textRangeListResult)[0].mEndOffset = substringLength-1; + (*textRangeListResult)[0].mRangeType = mIMEAttributeString[0]; + } else { + + *textRangeListLengthResult = 0; + for(i=0;i