From 02c9a9592a06f57e16b89f321b3588d4efaa9daf Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Sat, 7 Feb 2009 09:13:30 -0800 Subject: [PATCH] Revert changeset fc8d54ab29a6 (Bug 88831, Support new IME API "Text Services Framework" from Office XP and Windows XP) due to failure (every time) of the new unit test it added (Test WinTSF) on the Windows tinderbox. --HG-- rename : content/events/src/nsContentEventHandler.cpp => content/events/src/nsQueryContentEventHandler.cpp rename : content/events/src/nsContentEventHandler.h => content/events/src/nsQueryContentEventHandler.h --- content/base/src/nsGenericElement.cpp | 12 +- content/base/src/nsGkAtomList.h | 2 - content/events/src/Makefile.in | 2 +- content/events/src/nsEventStateManager.cpp | 45 +- content/events/src/nsIMEStateManager.cpp | 312 --- content/events/src/nsIMEStateManager.h | 24 - ...ler.cpp => nsQueryContentEventHandler.cpp} | 408 +--- ...Handler.h => nsQueryContentEventHandler.h} | 48 +- .../html/content/src/nsGenericHTMLElement.h | 13 +- view/src/nsViewManager.cpp | 1 - widget/Makefile.in | 2 +- widget/public/nsGUIEvent.h | 61 +- widget/public/nsIWidget.h | 32 +- widget/src/cocoa/nsChildView.mm | 4 +- widget/src/windows/Makefile.in | 1 - widget/src/windows/nsTextStore.cpp | 1274 ------------ widget/src/windows/nsTextStore.h | 232 --- widget/src/windows/nsWindow.cpp | 85 +- widget/src/windows/nsWindow.h | 16 +- widget/src/xpwidgets/nsBaseWidget.h | 7 +- widget/tests/Makefile.in | 43 +- widget/tests/TestWinTSF.cpp | 1822 ----------------- 22 files changed, 150 insertions(+), 4296 deletions(-) rename content/events/src/{nsContentEventHandler.cpp => nsQueryContentEventHandler.cpp} (58%) rename content/events/src/{nsContentEventHandler.h => nsQueryContentEventHandler.h} (73%) delete mode 100644 widget/src/windows/nsTextStore.cpp delete mode 100644 widget/src/windows/nsTextStore.h delete mode 100644 widget/tests/TestWinTSF.cpp diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 5fa68a145b32..471108ed33f9 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -118,7 +118,7 @@ #include "nsIDOMNSFeatureFactory.h" #include "nsIDOMDocumentType.h" #include "nsIDOMUserDataHandler.h" -#include "nsGenericHTMLElement.h" +#include "nsIDOMNSEditableElement.h" #include "nsIEditor.h" #include "nsIEditorDocShell.h" #include "nsEventDispatcher.h" @@ -343,15 +343,13 @@ nsINode::GetTextEditorRootContent(nsIEditor** aEditor) if (aEditor) *aEditor = nsnull; for (nsINode* node = this; node; node = node->GetNodeParent()) { - if (!node->IsNodeOfType(eHTML)) + nsCOMPtr editableElement(do_QueryInterface(node)); + if (!editableElement) continue; nsCOMPtr editor; - static_cast(node)-> - GetEditorInternal(getter_AddRefs(editor)); - if (!editor) - continue; - + editableElement->GetEditor(getter_AddRefs(editor)); + NS_ENSURE_TRUE(editor, nsnull); nsIContent* rootContent = GetEditorRootContent(editor); if (aEditor) editor.swap(*aEditor); diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index c856ad8bb66a..ad16a6b1162a 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -62,9 +62,7 @@ //--------------------------------------------------------------------------- GK_ATOM(_empty, "") -GK_ATOM(moz, "_moz") GK_ATOM(mozdirty, "_moz_dirty") -GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node") GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before") GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after") GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image") diff --git a/content/events/src/Makefile.in b/content/events/src/Makefile.in index 6d69bddef2a7..7c5e73c1cf3c 100644 --- a/content/events/src/Makefile.in +++ b/content/events/src/Makefile.in @@ -91,7 +91,7 @@ CPPSRCS = \ nsPLDOMEvent.cpp \ nsEventDispatcher.cpp \ nsIMEStateManager.cpp \ - nsContentEventHandler.cpp \ + nsQueryContentEventHandler.cpp \ nsDOMProgressEvent.cpp \ nsDOMDataTransfer.cpp \ nsDOMNotifyPaintEvent.cpp \ diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index fa83d6bfe0c4..bf82ccafdc39 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -28,7 +28,6 @@ * Ginn Chen * Simon Bünzli * Ehsan Akhgari - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -48,7 +47,7 @@ #include "nsEventStateManager.h" #include "nsEventListenerManager.h" #include "nsIMEStateManager.h" -#include "nsContentEventHandler.h" +#include "nsQueryContentEventHandler.h" #include "nsIContent.h" #include "nsINodeInfo.h" #include "nsIDocument.h" @@ -960,8 +959,6 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, break; if (mDocument) { - nsIMEStateManager::OnTextStateBlur(mPresContext, mCurrentFocus); - if (gLastFocusedDocument && gLastFocusedPresContextWeak) { nsCOMPtr ourWindow = gLastFocusedDocument->GetWindow(); @@ -1079,8 +1076,6 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, NS_IF_RELEASE(gLastFocusedContent); gLastFocusedContent = mCurrentFocus; NS_IF_ADDREF(gLastFocusedContent); - - nsIMEStateManager::OnTextStateFocus(mPresContext, mCurrentFocus); } // Try to keep the focus controllers and the globals in synch @@ -1152,8 +1147,6 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, NS_RELEASE(gLastFocusedContent); } - nsIMEStateManager::OnTextStateBlur(nsnull, nsnull); - // Now fire blurs. We fire a blur on the focused document, element, // and window. @@ -1327,8 +1320,6 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, if (focusController) focusController->SetSuppressFocus(PR_TRUE, "Deactivate Suppression"); - nsIMEStateManager::OnTextStateBlur(nsnull, nsnull); - // Now fire blurs. Blur the content, then the document, then the window. if (gLastFocusedDocument && gLastFocusedDocument == mDocument && @@ -1503,40 +1494,28 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, break; case NS_QUERY_SELECTED_TEXT: { - nsContentEventHandler handler(mPresContext); + nsQueryContentEventHandler handler(mPresContext); handler.OnQuerySelectedText((nsQueryContentEvent*)aEvent); } break; case NS_QUERY_TEXT_CONTENT: { - nsContentEventHandler handler(mPresContext); + nsQueryContentEventHandler handler(mPresContext); handler.OnQueryTextContent((nsQueryContentEvent*)aEvent); } break; + case NS_QUERY_CHARACTER_RECT: + { + nsQueryContentEventHandler handler(mPresContext); + handler.OnQueryCharacterRect((nsQueryContentEvent*)aEvent); + } + break; case NS_QUERY_CARET_RECT: { - nsContentEventHandler handler(mPresContext); + nsQueryContentEventHandler handler(mPresContext); handler.OnQueryCaretRect((nsQueryContentEvent*)aEvent); } break; - case NS_QUERY_TEXT_RECT: - { - nsContentEventHandler handler(mPresContext); - handler.OnQueryTextRect((nsQueryContentEvent*)aEvent); - } - break; - case NS_QUERY_EDITOR_RECT: - { - nsContentEventHandler handler(mPresContext); - handler.OnQueryEditorRect((nsQueryContentEvent*)aEvent); - } - break; - case NS_SELECTION_SET: - { - nsContentEventHandler handler(mPresContext); - handler.OnSelectionEvent((nsSelectionEvent*)aEvent); - } - break; } return NS_OK; } @@ -5052,8 +5031,6 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext, // Track the old focus controller if any focus suppressions is used on it. nsFocusSuppressor oldFocusSuppressor; - nsIMEStateManager::OnTextStateBlur(aPresContext, aContent); - if (nsnull != gLastFocusedPresContextWeak) { nsCOMPtr focusAfterBlur; @@ -5284,8 +5261,6 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext, if (clearFirstFocusEvent) { mFirstFocusEvent = nsnull; } - - nsIMEStateManager::OnTextStateFocus(mPresContext, mCurrentFocus); } else if (!aContent) { //fire focus on document even if the content isn't focusable (ie. text) //see bugzilla bug 93521 diff --git a/content/events/src/nsIMEStateManager.cpp b/content/events/src/nsIMEStateManager.cpp index 8261130383c2..fa08fdd203ee 100644 --- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -22,7 +22,6 @@ * * Contributor(s): * Masayuki Nakano - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -54,16 +53,6 @@ #include "nsIFocusController.h" #include "nsIDOMWindow.h" #include "nsContentUtils.h" -#include "nsINode.h" -#include "nsIFrame.h" -#include "nsRange.h" -#include "nsIDOMRange.h" -#include "nsISelection.h" -#include "nsISelectionPrivate.h" -#include "nsISelectionListener.h" -#include "nsISelectionController.h" -#include "nsIMutationObserver.h" -#include "nsContentEventHandler.h" /******************************************************************/ /* nsIMEStateManager */ @@ -74,8 +63,6 @@ nsPresContext* nsIMEStateManager::sPresContext = nsnull; nsPIDOMWindow* nsIMEStateManager::sActiveWindow = nsnull; PRBool nsIMEStateManager::sInstalledMenuKeyboardListener = PR_FALSE; -nsTextStateManager* nsIMEStateManager::sTextStateObserver = nsnull; - nsresult nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext) { @@ -84,7 +71,6 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext) return NS_OK; sContent = nsnull; sPresContext = nsnull; - OnTextStateBlur(nsnull, nsnull); return NS_OK; } @@ -283,301 +269,3 @@ nsIMEStateManager::GetWidget(nsPresContext* aPresContext) return widget; } - -// nsTextStateManager notifies widget of any text and selection changes -// in the currently focused editor -// sTextStateObserver points to the currently active nsTextStateManager -// sTextStateObserver is null if there is no focused editor - -class nsTextStateManager : public nsISelectionListener, - public nsStubMutationObserver -{ -public: - nsTextStateManager(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISELECTIONLISTENER - NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED - NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED - NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED - NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED - - nsresult Init(nsIWidget* aWidget, - nsPresContext* aPresContext, - nsINode* aNode); - void Destroy(void); - - nsCOMPtr mWidget; - nsCOMPtr mSel; - nsCOMPtr mRootContent; - nsCOMPtr mEditableNode; - PRBool mDestroying; - -private: - void NotifyContentAdded(nsINode* aContainer, PRInt32 aStart, PRInt32 aEnd); -}; - -nsTextStateManager::nsTextStateManager() -{ - mDestroying = PR_FALSE; -} - -nsresult -nsTextStateManager::Init(nsIWidget* aWidget, - nsPresContext* aPresContext, - nsINode* aNode) -{ - mWidget = aWidget; - - nsIPresShell* presShell = aPresContext->PresShell(); - - // get selection and root content - nsCOMPtr selCon; - if (aNode->IsNodeOfType(nsINode::eCONTENT)) { - nsIFrame* frame = presShell->GetPrimaryFrameFor( - static_cast(aNode)); - NS_ENSURE_TRUE(frame, NS_ERROR_UNEXPECTED); - - frame->GetSelectionController(aPresContext, - getter_AddRefs(selCon)); - } else { - // aNode is a document - selCon = do_QueryInterface(presShell); - } - NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); - - nsCOMPtr sel; - nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, - getter_AddRefs(sel)); - NS_ENSURE_TRUE(sel, NS_ERROR_UNEXPECTED); - - nsCOMPtr selDomRange; - rv = sel->GetRangeAt(0, getter_AddRefs(selDomRange)); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr selRange(do_QueryInterface(selDomRange)); - NS_ENSURE_TRUE(selRange && selRange->GetStartParent(), NS_ERROR_UNEXPECTED); - - mRootContent = selRange->GetStartParent()-> - GetSelectionRootContent(presShell); - - // add text change observer - mRootContent->AddMutationObserver(this); - - // add selection change listener - nsCOMPtr selPrivate(do_QueryInterface(sel)); - NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED); - rv = selPrivate->AddSelectionListener(this); - NS_ENSURE_SUCCESS(rv, rv); - mSel = sel; - - mEditableNode = aNode; - return NS_OK; -} - -void -nsTextStateManager::Destroy(void) -{ - if (mSel) { - nsCOMPtr selPrivate(do_QueryInterface(mSel)); - if (selPrivate) - selPrivate->RemoveSelectionListener(this); - mSel = nsnull; - } - if (mRootContent) { - mRootContent->RemoveMutationObserver(this); - mRootContent = nsnull; - } - mEditableNode = nsnull; - mWidget = nsnull; -} - -NS_IMPL_ISUPPORTS2(nsTextStateManager, - nsIMutationObserver, - nsISelectionListener) - -nsresult -nsTextStateManager::NotifySelectionChanged(nsIDOMDocument* aDoc, - nsISelection* aSel, - PRInt16 aReason) -{ - PRInt32 count = 0; - nsresult rv = aSel->GetRangeCount(&count); - NS_ENSURE_SUCCESS(rv, rv); - if (count > 0) { - mWidget->OnIMESelectionChange(); - } - return NS_OK; -} - -void -nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) -{ - NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), - "character data changed for non-text node"); - - PRUint32 offset = 0; - // get offsets of change and fire notification - if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange( - mRootContent, aContent, aInfo->mChangeStart, &offset))) - return; - - PRUint32 oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart; - PRUint32 newEnd = offset + aInfo->mReplaceLength; - mWidget->OnIMETextChange(offset, oldEnd, newEnd); -} - -void -nsTextStateManager::NotifyContentAdded(nsINode* aContainer, - PRInt32 aStartIndex, - PRInt32 aEndIndex) -{ - PRUint32 offset = 0, newOffset = 0; - if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange( - mRootContent, aContainer, aStartIndex, &offset))) - return; - - // get offset at the end of the last added node - if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange( - aContainer->GetChildAt(aStartIndex), - aContainer, aEndIndex, &newOffset))) - return; - - // fire notification - if (newOffset) - mWidget->OnIMETextChange(offset, offset, offset + newOffset); -} - -void -nsTextStateManager::ContentAppended(nsIDocument* aDocument, - nsIContent* aContainer, - PRInt32 aNewIndexInContainer) -{ - NotifyContentAdded(aContainer, aNewIndexInContainer, - aContainer->GetChildCount()); -} - -void -nsTextStateManager::ContentInserted(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInContainer) -{ - NotifyContentAdded(NODE_FROM(aContainer, aDocument), - aIndexInContainer, aIndexInContainer + 1); -} - -void -nsTextStateManager::ContentRemoved(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInContainer) -{ - PRUint32 offset = 0, childOffset = 1; - if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange( - mRootContent, NODE_FROM(aContainer, aDocument), - aIndexInContainer, &offset))) - return; - - // get offset at the end of the deleted node - if (aChild->IsNodeOfType(nsINode::eTEXT)) - childOffset = aChild->TextLength(); - else if (0 < aChild->GetChildCount()) - childOffset = aChild->GetChildCount(); - - if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange( - aChild, aChild, childOffset, &childOffset))) - return; - - // fire notification - if (childOffset) - mWidget->OnIMETextChange(offset, offset + childOffset, offset); -} - -static nsINode* GetRootEditableNode(nsPresContext* aPresContext, - nsIContent* aContent) -{ - if (aContent) { - nsINode* root = nsnull; - nsINode* node = aContent; - while (node && node->IsEditable()) { - root = node; - node = node->GetParent(); - } - return root; - } - if (aPresContext) { - nsIDocument* document = aPresContext->Document(); - if (document && document->IsEditable()) - return document; - } - return nsnull; -} - -nsresult -nsIMEStateManager::OnTextStateBlur(nsPresContext* aPresContext, - nsIContent* aContent) -{ - if (!sTextStateObserver || sTextStateObserver->mDestroying || - sTextStateObserver->mEditableNode == - GetRootEditableNode(aPresContext, aContent)) - return NS_OK; - - sTextStateObserver->mDestroying = PR_TRUE; - sTextStateObserver->mWidget->OnIMEFocusChange(PR_FALSE); - sTextStateObserver->Destroy(); - NS_RELEASE(sTextStateObserver); - return NS_OK; -} - -nsresult -nsIMEStateManager::OnTextStateFocus(nsPresContext* aPresContext, - nsIContent* aContent) -{ - if (sTextStateObserver) return NS_OK; - - nsINode *editableNode = GetRootEditableNode(aPresContext, aContent); - if (!editableNode) return NS_OK; - - nsIViewManager* vm = aPresContext->GetViewManager(); - NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE); - - nsCOMPtr widget; - nsresult rv = vm->GetWidget(getter_AddRefs(widget)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE); - - rv = widget->OnIMEFocusChange(PR_TRUE); - NS_ENSURE_SUCCESS(rv, NS_OK); - - // OnIMEFocusChange may cause focus and sTextStateObserver to change - // In that case return and keep the current sTextStateObserver - NS_ENSURE_TRUE(!sTextStateObserver, NS_OK); - - sTextStateObserver = new nsTextStateManager(); - NS_ENSURE_TRUE(sTextStateObserver, NS_ERROR_OUT_OF_MEMORY); - NS_ADDREF(sTextStateObserver); - rv = sTextStateObserver->Init(widget, aPresContext, editableNode); - if (NS_FAILED(rv)) { - sTextStateObserver->mDestroying = PR_TRUE; - sTextStateObserver->Destroy(); - NS_RELEASE(sTextStateObserver); - widget->OnIMEFocusChange(PR_FALSE); - return rv; - } - return NS_OK; -} - -nsresult -nsIMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSel, - nsIContent** aRoot) -{ - if (!sTextStateObserver || !sTextStateObserver->mEditableNode) - return NS_ERROR_NOT_AVAILABLE; - - NS_ASSERTION(sTextStateObserver->mSel && sTextStateObserver->mRootContent, - "uninitialized text state observer"); - NS_ADDREF(*aSel = sTextStateObserver->mSel); - NS_ADDREF(*aRoot = sTextStateObserver->mRootContent); - return NS_OK; -} diff --git a/content/events/src/nsIMEStateManager.h b/content/events/src/nsIMEStateManager.h index 9fec1c2ff2a7..e9d648f0f99e 100644 --- a/content/events/src/nsIMEStateManager.h +++ b/content/events/src/nsIMEStateManager.h @@ -40,15 +40,12 @@ #define nsIMEStateManager_h__ #include "nscore.h" -#include "nsGUIEvent.h" class nsIContent; class nsPIDOMWindow; class nsPresContext; class nsIWidget; class nsIFocusController; -class nsTextStateManager; -class nsISelection; /* * IME state manager @@ -65,25 +62,6 @@ public: static nsresult OnActivate(nsPresContext* aPresContext); static nsresult OnDeactivate(nsPresContext* aPresContext); static void OnInstalledMenuKeyboardListener(PRBool aInstalling); - - // These two methods manage focus and selection/text observers. - // They are separate from OnChangeFocus above because this offers finer - // control compared to having the two methods incorporated into OnChangeFocus - - // OnTextStateBlur should be called *before* NS_BLUR_CONTENT fires - // aPresContext is the nsPresContext receiving focus (not lost focus) - // aContent is the nsIContent receiving focus (not lost focus) - // aPresContext and/or aContent may be null - static nsresult OnTextStateBlur(nsPresContext* aPresContext, - nsIContent* aContent); - // OnTextStateFocus should be called *after* NS_FOCUS_CONTENT fires - // aPresContext is the nsPresContext receiving focus - // aContent is the nsIContent receiving focus - static nsresult OnTextStateFocus(nsPresContext* aPresContext, - nsIContent* aContent); - // Get the focused editor's selection and root - static nsresult GetFocusSelectionAndRoot(nsISelection** aSel, - nsIContent** aRoot); protected: static void SetIMEState(nsPresContext* aPresContext, PRUint32 aState, @@ -100,8 +78,6 @@ protected: static nsPresContext* sPresContext; static nsPIDOMWindow* sActiveWindow; static PRBool sInstalledMenuKeyboardListener; - - static nsTextStateManager* sTextStateObserver; }; #endif // nsIMEStateManager_h__ diff --git a/content/events/src/nsContentEventHandler.cpp b/content/events/src/nsQueryContentEventHandler.cpp similarity index 58% rename from content/events/src/nsContentEventHandler.cpp rename to content/events/src/nsQueryContentEventHandler.cpp index 80d6df5cabfe..1e4641a00f5e 100644 --- a/content/events/src/nsContentEventHandler.cpp +++ b/content/events/src/nsQueryContentEventHandler.cpp @@ -22,7 +22,6 @@ * * Contributor(s): * Masayuki Nakano - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -38,7 +37,7 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsContentEventHandler.h" +#include "nsQueryContentEventHandler.h" #include "nsCOMPtr.h" #include "nsPresContext.h" #include "nsIPresShell.h" @@ -54,19 +53,14 @@ #include "nsIContentIterator.h" #include "nsTextFragment.h" #include "nsTextFrame.h" -#include "nsISelectionController.h" -#include "nsISelectionPrivate.h" -#include "nsContentUtils.h" -#include "nsISelection2.h" -#include "nsIMEStateManager.h" nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult); /******************************************************************/ -/* nsContentEventHandler */ +/* nsQueryContentEventHandler */ /******************************************************************/ -nsContentEventHandler::nsContentEventHandler( +nsQueryContentEventHandler::nsQueryContentEventHandler( nsPresContext* aPresContext) : mPresContext(aPresContext), mPresShell(aPresContext->GetPresShell()), mSelection(nsnull), @@ -75,7 +69,7 @@ nsContentEventHandler::nsContentEventHandler( } nsresult -nsContentEventHandler::Init(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::Init(nsQueryContentEvent* aEvent) { NS_ASSERTION(aEvent, "aEvent must not be null"); @@ -123,24 +117,6 @@ nsContentEventHandler::Init(nsQueryContentEvent* aEvent) return NS_OK; } -// Editor places a bogus BR node under its root content if the editor doesn't -// have any text. This happens even for single line editors. -// When we get text content and when we change the selection, -// we don't want to include the bogus BRs at the end. -static PRBool IsContentBR(nsIContent* aContent) -{ - return aContent->IsNodeOfType(nsINode::eHTML) && - aContent->Tag() == nsGkAtoms::br && - !aContent->AttrValueIs(kNameSpaceID_None, - nsGkAtoms::type, - nsGkAtoms::moz, - eIgnoreCase) && - !aContent->AttrValueIs(kNameSpaceID_None, - nsGkAtoms::mozeditorbogusnode, - nsGkAtoms::_true, - eIgnoreCase); -} - static void ConvertToNativeNewlines(nsAFlatString& aString) { #if defined(XP_MACOSX) @@ -185,7 +161,8 @@ static PRUint32 GetNativeTextLength(nsIContent* aContent) nsAutoString str; if (aContent->IsNodeOfType(nsINode::eTEXT)) AppendString(str, aContent); - else if (IsContentBR(aContent)) + else if (aContent->IsNodeOfType(nsINode::eHTML) && + aContent->Tag() == nsGkAtoms::br) str.Assign(PRUnichar('\n')); ConvertToNativeNewlines(str); return str.Length(); @@ -204,8 +181,9 @@ static PRUint32 ConvertToXPOffset(nsIContent* aContent, PRUint32 aNativeOffset) return str.Length(); } -static nsresult GenerateFlatTextContent(nsIRange* aRange, - nsAFlatString& aString) +nsresult +nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange, + nsAFlatString& aString) { nsCOMPtr iter; nsresult rv = NS_NewContentIterator(getter_AddRefs(iter)); @@ -243,7 +221,8 @@ static nsresult GenerateFlatTextContent(nsIRange* aRange, AppendSubString(aString, content, 0, aRange->EndOffset()); else AppendString(aString, content); - } else if (IsContentBR(content)) + } else if (content->IsNodeOfType(nsINode::eHTML) && + content->Tag() == nsGkAtoms::br) aString.Append(PRUnichar('\n')); } ConvertToNativeNewlines(aString); @@ -251,19 +230,18 @@ static nsresult GenerateFlatTextContent(nsIRange* aRange, } nsresult -nsContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent, +nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent, PRBool aForward, PRUint32* aXPOffset) { + NS_ASSERTION(*aXPOffset >= 0 && *aXPOffset <= aContent->TextLength(), + "offset is out of range."); + // XXX This method assumes that the frame boundaries must be cluster // boundaries. It's false, but no problem now, maybe. if (!aContent->IsNodeOfType(nsINode::eTEXT) || *aXPOffset == 0 || *aXPOffset == aContent->TextLength()) return NS_OK; - - NS_ASSERTION(*aXPOffset >= 0 && *aXPOffset <= aContent->TextLength(), - "offset is out of range."); - nsCOMPtr fs = mPresShell->FrameSelection(); PRInt32 offsetInFrame; nsFrameSelection::HINT hint = @@ -287,7 +265,7 @@ nsContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent, if (frame->GetType() != nsGkAtoms::textFrame) return NS_ERROR_FAILURE; nsTextFrame* textFrame = static_cast(frame); - PRInt32 newOffsetInFrame = *aXPOffset - startOffset; + PRInt32 newOffsetInFrame = offsetInFrame; newOffsetInFrame += aForward ? -1 : 1; textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame); *aXPOffset = startOffset + newOffsetInFrame; @@ -295,7 +273,7 @@ nsContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent, } nsresult -nsContentEventHandler::SetRangeFromFlatTextOffset( +nsQueryContentEventHandler::SetRangeFromFlatTextOffset( nsIRange* aRange, PRUint32 aNativeOffset, PRUint32 aNativeLength, @@ -391,7 +369,7 @@ nsContentEventHandler::SetRangeFromFlatTextOffset( } nsresult -nsContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) @@ -400,32 +378,21 @@ nsContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent) NS_ASSERTION(aEvent->mReply.mString.IsEmpty(), "The reply string must be empty"); - rv = GetFlatTextOffsetOfRange(mRootContent, - mFirstSelectedRange, &aEvent->mReply.mOffset); + rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &aEvent->mReply.mOffset); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr anchorDomNode, focusDomNode; - rv = mSelection->GetAnchorNode(getter_AddRefs(anchorDomNode)); - NS_ENSURE_TRUE(anchorDomNode, NS_ERROR_FAILURE); - rv = mSelection->GetFocusNode(getter_AddRefs(focusDomNode)); - NS_ENSURE_TRUE(focusDomNode, NS_ERROR_FAILURE); - - PRInt32 anchorOffset, focusOffset; - rv = mSelection->GetAnchorOffset(&anchorOffset); - NS_ENSURE_SUCCESS(rv, rv); - rv = mSelection->GetFocusOffset(&focusOffset); + PRBool isCollapsed; + rv = mSelection->GetIsCollapsed(&isCollapsed); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr anchorNode(do_QueryInterface(anchorDomNode)); - nsCOMPtr focusNode(do_QueryInterface(focusDomNode)); - NS_ENSURE_TRUE(anchorNode && focusNode, NS_ERROR_UNEXPECTED); + if (!isCollapsed) { + nsCOMPtr domRange; + rv = mSelection->GetRangeAt(0, getter_AddRefs(domRange)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(domRange, "GetRangeAt succeeded, but the result is null"); - PRInt16 compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset, - focusNode, focusOffset); - aEvent->mReply.mReversed = compare > 0; - - if (compare) { - nsCOMPtr range = mFirstSelectedRange; + nsCOMPtr range(do_QueryInterface(domRange)); + NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); rv = GenerateFlatTextContent(range, aEvent->mReply.mString); NS_ENSURE_SUCCESS(rv, rv); } @@ -435,7 +402,7 @@ nsContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent) } nsresult -nsContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) @@ -458,168 +425,65 @@ nsContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent) return NS_OK; } -// Adjust to use a child node if possible -// to make the returned rect more accurate -static nsINode* AdjustTextRectNode(nsINode* aNode, - PRInt32& aOffset) -{ - PRInt32 childCount = PRInt32(aNode->GetChildCount()); - nsINode* node = aNode; - if (childCount) { - if (aOffset < childCount) { - node = aNode->GetChildAt(aOffset); - aOffset = 0; - } else if (aOffset == childCount) { - node = aNode->GetChildAt(childCount - 1); - aOffset = node->IsNodeOfType(nsINode::eTEXT) ? - static_cast(node)->TextLength() : 1; - } - } - return node; -} - -// Similar to nsFrameSelection::GetFrameForNodeOffset, -// but this is more flexible for OnQueryTextRect to use -static nsresult GetFrameForTextRect(nsIPresShell* aPresShell, - nsINode* aNode, - PRInt32 aOffset, - PRBool aHint, - nsIFrame** aReturnFrame) -{ - NS_ENSURE_TRUE(aNode && aNode->IsNodeOfType(nsINode::eCONTENT), - NS_ERROR_UNEXPECTED); - nsIContent* content = static_cast(aNode); - nsIFrame* frame = aPresShell->GetPrimaryFrameFor(content); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); - PRInt32 childOffset = 0; - return frame->GetChildFrameContainingOffset(aOffset, aHint, &childOffset, - aReturnFrame); -} - nsresult -nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::QueryRectFor(nsQueryContentEvent* aEvent, + nsIRange* aRange, + nsCaret* aCaret) { - nsresult rv = Init(aEvent); - if (NS_FAILED(rv)) - return rv; - - nsRefPtr range = new nsRange(); - if (!range) { - return NS_ERROR_OUT_OF_MEMORY; - } - rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, - aEvent->mInput.mLength, PR_TRUE); + PRInt32 offsetInFrame; + nsIFrame* frame; + nsresult rv = GetStartFrameAndOffset(aRange, &frame, &offsetInFrame); NS_ENSURE_SUCCESS(rv, rv); - // used to iterate over all contents and their frames - nsCOMPtr iter; - rv = NS_NewContentIterator(getter_AddRefs(iter)); - NS_ENSURE_SUCCESS(rv, rv); - iter->Init(range); + nsPoint posInFrame; + rv = frame->GetPointFromOffset(aRange->StartOffset(), &posInFrame); NS_ENSURE_SUCCESS(rv, rv); - // get the starting frame - PRInt32 offset = range->StartOffset(); - nsINode* node = iter->GetCurrentNode(); - if (!node) { - node = AdjustTextRectNode(range->GetStartParent(), offset); - } - nsIFrame* firstFrame = nsnull; - rv = GetFrameForTextRect(mPresShell, node, offset, - PR_TRUE, &firstFrame); - NS_ENSURE_SUCCESS(rv, rv); + nsRect rect; + rect.y = posInFrame.y; + rect.height = frame->GetSize().height; - // get the starting frame rect - nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(firstFrame, rect); - NS_ENSURE_SUCCESS(rv, rv); - nsRect frameRect = rect; - nsPoint ptOffset; - firstFrame->GetPointFromOffset(offset, &ptOffset); - // minus 1 to avoid creating an empty rect - rect.x += ptOffset.x - 1; - rect.width -= ptOffset.x - 1; - - // get the ending frame - offset = range->EndOffset(); - node = AdjustTextRectNode(range->GetEndParent(), offset); - nsIFrame* lastFrame = nsnull; - rv = GetFrameForTextRect(mPresShell, node, offset, - range->Collapsed(), &lastFrame); - NS_ENSURE_SUCCESS(rv, rv); - - // iterate over all covered frames - for (nsIFrame* frame = firstFrame; frame != lastFrame;) { - frame = frame->GetNextContinuation(); - if (!frame) { - do { - iter->Next(); - node = iter->GetCurrentNode(); - if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) - continue; - frame = mPresShell->GetPrimaryFrameFor(static_cast(node)); - } while (!frame && !iter->IsDone()); - if (!frame) { - // this can happen when the end offset of the range is 0. - frame = lastFrame; - } - } - frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(frame, frameRect); + if (aEvent->message == NS_QUERY_CHARACTER_RECT) { + nsPoint nextPos; + rv = frame->GetPointFromOffset(aRange->EndOffset(), &nextPos); NS_ENSURE_SUCCESS(rv, rv); - if (frame != lastFrame) { - // not last frame, so just add rect to previous result - rect.UnionRect(rect, frameRect); - } - } - - // get the ending frame rect - lastFrame->GetPointFromOffset(offset, &ptOffset); - // minus 1 to avoid creating an empty rect - frameRect.width -= lastFrame->GetRect().width - ptOffset.x - 1; - - if (firstFrame == lastFrame) { - rect.IntersectRect(rect, frameRect); + rect.x = PR_MIN(posInFrame.x, nextPos.x); + rect.width = PR_ABS(posInFrame.x - nextPos.x); } else { - rect.UnionRect(rect, frameRect); + rect.x = posInFrame.x; + rect.width = aCaret->GetCaretRect().width; } - aEvent->mReply.mRect = - nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel()); + + rv = ConvertToRootViewRelativeOffset(frame, rect); + NS_ENSURE_SUCCESS(rv, rv); + + aEvent->mReply.mRect = nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel()); aEvent->mSucceeded = PR_TRUE; return NS_OK; } nsresult -nsContentEventHandler::OnQueryEditorRect(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::OnQueryCharacterRect(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) return rv; - nsIFrame* frame = mPresShell->GetPrimaryFrameFor(mRootContent); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); - - // get rect for first frame - nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(frame, resultRect); + nsCOMPtr range = new nsRange(); + NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY); + rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 1, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); - // account for any additional frames - while ((frame = frame->GetNextContinuation()) != nsnull) { - nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(frame, frameRect); - NS_ENSURE_SUCCESS(rv, rv); - resultRect.UnionRect(resultRect, frameRect); + if (range->Collapsed()) { + // There is no character at the offset. + return NS_OK; } - aEvent->mReply.mRect = - nsRect::ToOutsidePixels(resultRect, mPresContext->AppUnitsPerDevPixel()); - aEvent->mSucceeded = PR_TRUE; - return NS_OK; + return QueryRectFor(aEvent, range, nsnull); } nsresult -nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent) +nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) @@ -638,7 +502,7 @@ nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent) if (selectionIsCollapsed) { PRUint32 offset; - rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset); + rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &offset); NS_ENSURE_SUCCESS(rv, rv); if (offset == aEvent->mInput.mOffset) { PRBool isCollapsed; @@ -646,8 +510,7 @@ nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent) rv = caret->GetCaretCoordinates(nsCaret::eTopLevelWindowCoordinates, mSelection, &rect, &isCollapsed, nsnull); - aEvent->mReply.mRect = - nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel()); + aEvent->mReply.mRect = nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel()); NS_ENSURE_SUCCESS(rv, rv); aEvent->mSucceeded = PR_TRUE; return NS_OK; @@ -660,36 +523,12 @@ nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent) rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); - PRInt32 offsetInFrame; - nsIFrame* frame; - rv = GetStartFrameAndOffset(range, &frame, &offsetInFrame); - NS_ENSURE_SUCCESS(rv, rv); - - nsPoint posInFrame; - rv = frame->GetPointFromOffset(range->StartOffset(), &posInFrame); - NS_ENSURE_SUCCESS(rv, rv); - - nsRect rect; - rect.x = posInFrame.x; - rect.y = posInFrame.y; - rect.width = caret->GetCaretRect().width; - rect.height = frame->GetSize().height; - - rv = ConvertToRootViewRelativeOffset(frame, rect); - NS_ENSURE_SUCCESS(rv, rv); - - aEvent->mReply.mRect = - nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel()); - - aEvent->mSucceeded = PR_TRUE; - return NS_OK; + return QueryRectFor(aEvent, range, caret); } nsresult -nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, - nsINode* aNode, - PRInt32 aNodeOffset, - PRUint32* aNativeOffset) +nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange, + PRUint32* aNativeOffset) { NS_ASSERTION(aNativeOffset, "param is invalid"); @@ -697,12 +536,16 @@ nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr domPrev(do_QueryInterface(prev)); NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??"); - nsCOMPtr rootDOMNode(do_QueryInterface(aRootContent)); + nsCOMPtr rootDOMNode(do_QueryInterface(mRootContent)); domPrev->SetStart(rootDOMNode, 0); - nsCOMPtr startDOMNode(do_QueryInterface(aNode)); + nsINode* startNode = aRange->GetStartParent(); + NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); + + PRInt32 startOffset = aRange->StartOffset(); + nsCOMPtr startDOMNode(do_QueryInterface(startNode)); NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode"); - domPrev->SetEnd(startDOMNode, aNodeOffset); + domPrev->SetEnd(startDOMNode, startOffset); nsAutoString prevStr; nsresult rv = GenerateFlatTextContent(prev, prevStr); @@ -712,21 +555,9 @@ nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, } nsresult -nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, - nsIRange* aRange, - PRUint32* aNativeOffset) -{ - nsINode* startNode = aRange->GetStartParent(); - NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); - PRInt32 startOffset = aRange->StartOffset(); - return GetFlatTextOffsetOfRange(aRootContent, startNode, startOffset, - aNativeOffset); -} - -nsresult -nsContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange, - nsIFrame** aFrame, - PRInt32* aOffsetInFrame) +nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange, + nsIFrame** aFrame, + PRInt32* aOffsetInFrame) { NS_ASSERTION(aRange && aFrame && aOffsetInFrame, "params are invalid"); @@ -746,8 +577,8 @@ nsContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange, } nsresult -nsContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame, - nsRect& aRect) +nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame, + nsRect& aRect) { NS_ASSERTION(aFrame, "aFrame must not be null"); @@ -759,86 +590,3 @@ nsContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame, aRect += posInView + view->GetOffsetTo(nsnull); return NS_OK; } - -static void AdjustRangeForSelection(nsIContent* aRoot, - nsINode** aNode, - PRInt32* aOffset) -{ - nsINode* node = *aNode; - PRInt32 offset = *aOffset; - if (aRoot != node && node->GetParent() && - !node->IsNodeOfType(nsINode::eTEXT)) { - node = node->GetParent(); - offset = node->IndexOf(*aNode) + (offset ? 1 : 0); - } - nsINode* brNode = node->GetChildAt(offset - 1); - while (brNode && brNode->IsNodeOfType(nsINode::eHTML)) { - nsIContent* brContent = static_cast(brNode); - if (brContent->Tag() != nsGkAtoms::br || IsContentBR(brContent)) - break; - brNode = node->GetChildAt(--offset - 1); - } - *aNode = node; - *aOffset = PR_MAX(offset, 0); -} - -nsresult -nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent) -{ - aEvent->mSucceeded = PR_FALSE; - - // Get selection to manipulate - nsCOMPtr sel; - nsresult rv = nsIMEStateManager:: - GetFocusSelectionAndRoot(getter_AddRefs(sel), - getter_AddRefs(mRootContent)); - NS_ENSURE_SUCCESS(rv, rv); - - // Get range from offset and length - nsRefPtr range = new nsRange(); - NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY); - rv = SetRangeFromFlatTextOffset(range, aEvent->mOffset, - aEvent->mLength, PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); - - nsINode* startNode = range->GetStartParent(); - nsINode* endNode = range->GetEndParent(); - PRInt32 startOffset = range->StartOffset(); - PRInt32 endOffset = range->EndOffset(); - AdjustRangeForSelection(mRootContent, &startNode, &startOffset); - AdjustRangeForSelection(mRootContent, &endNode, &endOffset); - - nsCOMPtr startDomNode(do_QueryInterface(startNode)); - nsCOMPtr endDomNode(do_QueryInterface(endNode)); - NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED); - - nsCOMPtr selPrivate = do_QueryInterface(sel); - NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED); - selPrivate->StartBatchChanges(); - - // Clear selection first before setting - rv = sel->RemoveAllRanges(); - // Need to call EndBatchChanges at the end even if call failed - if (NS_SUCCEEDED(rv)) { - if (aEvent->mReversed) { - rv = sel->Collapse(endDomNode, endOffset); - } else { - rv = sel->Collapse(startDomNode, startOffset); - } - if (NS_SUCCEEDED(rv) && - (startDomNode != endDomNode || startOffset != endOffset)) { - if (aEvent->mReversed) { - rv = sel->Extend(startDomNode, startOffset); - } else { - rv = sel->Extend(endDomNode, endOffset); - } - } - } - selPrivate->EndBatchChanges(); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr(do_QueryInterface(sel))->ScrollIntoView( - nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE, -1, -1); - aEvent->mSucceeded = PR_TRUE; - return NS_OK; -} diff --git a/content/events/src/nsContentEventHandler.h b/content/events/src/nsQueryContentEventHandler.h similarity index 73% rename from content/events/src/nsContentEventHandler.h rename to content/events/src/nsQueryContentEventHandler.h index b3f45b5149ca..3ecb299f61ab 100644 --- a/content/events/src/nsContentEventHandler.h +++ b/content/events/src/nsQueryContentEventHandler.h @@ -21,7 +21,6 @@ * * Contributor(s): * Masayuki Nakano - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -37,8 +36,8 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsContentEventHandler_h__ -#define nsContentEventHandler_h__ +#ifndef nsQueryContentEventHandler_h__ +#define nsQueryContentEventHandler_h__ #include "nscore.h" #include "nsCOMPtr.h" @@ -51,36 +50,29 @@ class nsPresContext; class nsIPresShell; class nsQueryContentEvent; -class nsSelectionEvent; class nsCaret; struct nsRect; /* * Query Content Event Handler - * nsContentEventHandler is a helper class for nsEventStateManager. + * nsQueryContentEventHandler is a helper class for nsEventStateManager. * The platforms request some content informations, e.g., the selected text, * the offset of the selected text and the text for specified range. * This class answers to NS_QUERY_* events from actual contents. */ -class NS_STACK_CLASS nsContentEventHandler { +class NS_STACK_CLASS nsQueryContentEventHandler { public: - nsContentEventHandler(nsPresContext *aPresContext); + nsQueryContentEventHandler(nsPresContext *aPresContext); // NS_QUERY_SELECTED_TEXT event handler nsresult OnQuerySelectedText(nsQueryContentEvent* aEvent); // NS_QUERY_TEXT_CONTENT event handler nsresult OnQueryTextContent(nsQueryContentEvent* aEvent); + // NS_QUERY_CHARACTER_RECT event handler + nsresult OnQueryCharacterRect(nsQueryContentEvent* aEvent); // NS_QUERY_CARET_RECT event handler nsresult OnQueryCaretRect(nsQueryContentEvent* aEvent); - // NS_QUERY_TEXT_RECT event handler - nsresult OnQueryTextRect(nsQueryContentEvent* aEvent); - // NS_QUERY_EDITOR_RECT event handler - nsresult OnQueryEditorRect(nsQueryContentEvent* aEvent); - - // NS_SELECTION_* event - nsresult OnSelectionEvent(nsSelectionEvent* aEvent); - protected: nsPresContext* mPresContext; nsIPresShell* mPresShell; @@ -90,19 +82,11 @@ protected: nsresult Init(nsQueryContentEvent* aEvent); -public: // FlatText means the text that is generated from DOM tree. The BR elements // are replaced to native linefeeds. Other elements are ignored. - // Get the offset in FlatText of the range. (also used by nsIMEStateManager) - static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent, - nsINode* aNode, - PRInt32 aNodeOffset, - PRUint32* aOffset); - static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent, - nsIRange* aRange, - PRUint32* aOffset); -protected: + // Generate the FlatText from DOM range. + nsresult GenerateFlatTextContent(nsIRange* aRange, nsAFlatString& aString); // Make the DOM range from the offset of FlatText and the text length. // If aExpandToClusterBoundaries is true, the start offset and the end one are // expanded to nearest cluster boundaries. @@ -110,18 +94,22 @@ protected: PRUint32 aNativeOffset, PRUint32 aNativeLength, PRBool aExpandToClusterBoundaries); + // Get the offset in FlatText of the range. + nsresult GetFlatTextOffsetOfRange(nsIRange* aRange, PRUint32* aOffset); // Find the first textframe for the range, and get the start offset in // the frame. nsresult GetStartFrameAndOffset(nsIRange* aRange, - nsIFrame** aFrame, - PRInt32* aOffsetInFrame); + nsIFrame** aFrame, PRInt32* aOffsetInFrame); // Convert the frame relative offset to the root view relative offset. - nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame, - nsRect& aRect); + nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame, nsRect& aRect); + // The helper for OnQueryCharacterRect/OnQueryCaretRect. + // Don't call for another event. + nsresult QueryRectFor(nsQueryContentEvent* aEvent, nsIRange* aRange, + nsCaret* aCaret); // Expand aXPOffset to the nearest offset in cluster boundary. aForward is // true, it is expanded to forward. nsresult ExpandToClusterBoundary(nsIContent* aContent, PRBool aForward, PRUint32* aXPOffset); }; -#endif // nsContentEventHandler_h__ +#endif // nsQueryContentEventHandler_h__ diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 9b7296fcbe46..52d11c9af0ea 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -569,13 +569,6 @@ public: static nsresult GetHashFromHrefString(const nsAString &aHref, nsAString& aHash); - - /** - * Locate an nsIEditor rooted at this content node, if there is one. - */ - NS_HIDDEN_(nsresult) GetEditor(nsIEditor** aEditor); - NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor); - protected: /** * Focus or blur the element. This is what you should call if you want to @@ -735,6 +728,12 @@ protected: */ NS_HIDDEN_(nsresult) GetURIListAttr(nsIAtom* aAttr, nsAString& aResult); + /** + * Locate an nsIEditor rooted at this content node, if there is one. + */ + NS_HIDDEN_(nsresult) GetEditor(nsIEditor** aEditor); + NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor); + /** * Locates the nsIEditor associated with this node. In general this is * equivalent to GetEditorInternal(), but for designmode or contenteditable, diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index efb0db41121f..45fb56c0b0cc 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1249,7 +1249,6 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS if (!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) && !NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) && !NS_IS_QUERY_CONTENT_EVENT(aEvent) && !NS_IS_PLUGIN_EVENT(aEvent) && - !NS_IS_SELECTION_EVENT(aEvent) && aEvent->eventStructType != NS_ACCESSIBLE_EVENT) { // will dispatch using coordinates. Pretty bogus but it's consistent // with what presshell does. diff --git a/widget/Makefile.in b/widget/Makefile.in index ce8fa5c349cc..f495accb88ef 100644 --- a/widget/Makefile.in +++ b/widget/Makefile.in @@ -45,7 +45,7 @@ include $(DEPTH)/config/autoconf.mk DIRS = public src ifdef ENABLE_TESTS -TOOL_DIRS += tests +DIRS += tests endif include $(topsrcdir)/config/rules.mk diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 244a19bf63f1..8a1f5fcd0063 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -105,7 +105,6 @@ class nsHashKey; #define NS_DRAG_EVENT 35 #define NS_NOTIFYPAINT_EVENT 36 #define NS_SIMPLE_GESTURE_EVENT 37 -#define NS_SELECTION_EVENT 38 // These flags are sort of a mess. They're sort of shared between event // listener flags and event flags, but only some of them. You've been @@ -345,18 +344,14 @@ class nsHashKey; #define NS_QUERY_SELECTED_TEXT (NS_QUERY_CONTENT_EVENT_START) // Query for the text content of specified range, it returns actual lengh (if // the specified range is too long) and the text of the specified range. -// Returns the entire text if requested length > actual length. #define NS_QUERY_TEXT_CONTENT (NS_QUERY_CONTENT_EVENT_START + 1) +// Query for the character rect of nth character. If there is no character at +// the offset, the query will be failed. The offset of the result is relative +// position from the top level widget. +#define NS_QUERY_CHARACTER_RECT (NS_QUERY_CONTENT_EVENT_START + 2) // Query for the caret rect of nth insertion point. The offset of the result is // relative position from the top level widget. #define NS_QUERY_CARET_RECT (NS_QUERY_CONTENT_EVENT_START + 3) -// Query for the bounding rect of a range of characters. This works on any -// valid character range given offset and length. Result is relative to top -// level widget coordinates -#define NS_QUERY_TEXT_RECT (NS_QUERY_CONTENT_EVENT_START + 4) -// Query for the bounding rect of the current focused frame. Result is relative -// to top level widget coordinates -#define NS_QUERY_EDITOR_RECT (NS_QUERY_CONTENT_EVENT_START + 5) // Video events #ifdef MOZ_MEDIA @@ -402,11 +397,6 @@ class nsHashKey; #define NS_PLUGIN_EVENT_START 3600 #define NS_PLUGIN_EVENT (NS_PLUGIN_EVENT_START) -// Events to manipulate selection (nsSelectionEvent) -#define NS_SELECTION_EVENT_START 3700 -// Clear any previous selection and set the given range as the selection -#define NS_SELECTION_SET (NS_SELECTION_EVENT_START) - /** * Return status for event processors, nsEventStatus, is defined in * nsEvent.h. @@ -868,11 +858,11 @@ class nsTextEvent : public nsInputEvent public: nsTextEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w) : nsInputEvent(isTrusted, msg, w, NS_TEXT_EVENT), - rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE) + theText(nsnull), rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE) { } - nsString theText; + const PRUnichar* theText; nsTextEventReply theReply; PRUint32 rangeCount; // Note that the range array may not specify a caret position; in that @@ -975,6 +965,13 @@ public: mInput.mLength = aLength; } + void InitForQueryCharacterRect(PRUint32 aOffset) + { + NS_ASSERTION(message == NS_QUERY_CHARACTER_RECT, + "wrong initializer is called"); + mInput.mOffset = aOffset; + } + void InitForQueryCaretRect(PRUint32 aOffset) { NS_ASSERTION(message == NS_QUERY_CARET_RECT, @@ -982,14 +979,6 @@ public: mInput.mOffset = aOffset; } - void InitForQueryTextRect(PRUint32 aOffset, PRUint32 aLength) - { - NS_ASSERTION(message == NS_QUERY_TEXT_RECT, - "wrong initializer is called"); - mInput.mOffset = aOffset; - mInput.mLength = aLength; - } - PRBool mSucceeded; struct { PRUint32 mOffset; @@ -1002,25 +991,9 @@ public: nsIntRect mRect; // Finally, the coordinates is system coordinates. // The return widget has the caret. This is set at all query events. nsIWidget* mFocusedWidget; - PRPackedBool mReversed; // true if selection is reversed (end < start) } mReply; }; -class nsSelectionEvent : public nsGUIEvent -{ -public: - nsSelectionEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) : - nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_SELECTION_EVENT), - mSucceeded(PR_FALSE) - { - } - - PRUint32 mOffset; // start offset of selection - PRUint32 mLength; // length of selection - PRPackedBool mReversed; // selection "anchor" should be in front - PRPackedBool mSucceeded; -}; - /** * MenuItem event * @@ -1259,12 +1232,8 @@ enum nsDragDropEventStatus { #define NS_IS_QUERY_CONTENT_EVENT(evnt) \ (((evnt)->message == NS_QUERY_SELECTED_TEXT) || \ ((evnt)->message == NS_QUERY_TEXT_CONTENT) || \ - ((evnt)->message == NS_QUERY_CARET_RECT) || \ - ((evnt)->message == NS_QUERY_TEXT_RECT) || \ - ((evnt)->message == NS_QUERY_EDITOR_RECT)) - -#define NS_IS_SELECTION_EVENT(evnt) \ - (((evnt)->message == NS_SELECTION_SET)) + ((evnt)->message == NS_QUERY_CHARACTER_RECT) || \ + ((evnt)->message == NS_QUERY_CARET_RECT)) #define NS_IS_PLUGIN_EVENT(evnt) \ (((evnt)->message == NS_PLUGIN_EVENT)) diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index b14585eccdfe..b7ec83fc3252 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -93,14 +93,11 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event); #define NS_NATIVE_PLUGIN_PORT_QD 100 #define NS_NATIVE_PLUGIN_PORT_CG 101 #endif -#ifdef XP_WIN -#define NS_NATIVE_TSF_POINTER 100 -#endif -// {51C24E3B-229F-4c4f-ADA5-BE891FD9EFE9} +// a85944af-7fce-4e45-bf04-ac12c823394b #define NS_IWIDGET_IID \ -{ 0x51c24e3b, 0x229f, 0x4c4f, \ - { 0xad, 0xa5, 0xbe, 0x89, 0x1f, 0xd9, 0xef, 0xe9 } } +{ 0xa85944af, 0x7fce, 0x4e45, \ + { 0xbf, 0x04, 0xac, 0x12, 0xc8, 0x23, 0x39, 0x4b } } // Hide the native window systems real window type so as to avoid // including native window system types and APIs. This is necessary @@ -1245,29 +1242,6 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) = 0; - /* - * An editable node (i.e. input/textarea/design mode document) - * is receiving or giving up focus - * aFocus is true if node is receiving focus - * aFocus is false if node is giving up focus (blur) - */ - NS_IMETHOD OnIMEFocusChange(PRBool aFocus) = 0; - - /* - * Text content of the focused node has changed - * aStart is the starting offset of the change - * aOldEnd is the ending offset of the change - * aNewEnd is the caret offset after the change - */ - NS_IMETHOD OnIMETextChange(PRUint32 aStart, - PRUint32 aOldEnd, - PRUint32 aNewEnd) = 0; - - /* - * Selection has changed in the focused node - */ - NS_IMETHOD OnIMESelectionChange(void) = 0; - protected: // keep the list of children. We also keep track of our siblings. // The ownership model is as follows: parent holds a strong ref to diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 6cbfcd644962..c6d0f6e2959c 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -5490,8 +5490,8 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers) nsIntRect r; PRBool useCaretRect = theRange.length == 0; if (!useCaretRect) { - nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, mGeckoChild); - charRect.InitForQueryTextRect(theRange.location, 1); + nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_CHARACTER_RECT, mGeckoChild); + charRect.InitForQueryCharacterRect(theRange.location); mGeckoChild->DispatchWindowEvent(charRect); if (charRect.mSucceeded) r = charRect.mReply.mRect; diff --git a/widget/src/windows/Makefile.in b/widget/src/windows/Makefile.in index a608f43496e8..64887ab765fe 100644 --- a/widget/src/windows/Makefile.in +++ b/widget/src/windows/Makefile.in @@ -107,7 +107,6 @@ CPPSRCS += \ nsBidiKeyboard.cpp \ nsSound.cpp \ nsIdleServiceWin.cpp \ - nsTextStore.cpp \ $(NULL) endif diff --git a/widget/src/windows/nsTextStore.cpp b/widget/src/windows/nsTextStore.cpp deleted file mode 100644 index 97c4589171c0..000000000000 --- a/widget/src/windows/nsTextStore.cpp +++ /dev/null @@ -1,1274 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ningjie Chen - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include - -#include "nscore.h" -#include "nsTextStore.h" -#include "nsWindow.h" -#include "nsIPrefBranch.h" -#include "nsIPrefService.h" -#include "prlog.h" - -/******************************************************************/ -/* nsTextStore */ -/******************************************************************/ - -ITfThreadMgr* nsTextStore::sTsfThreadMgr = NULL; -DWORD nsTextStore::sTsfClientId = 0; -nsTextStore* nsTextStore::sTsfTextStore = NULL; - -UINT nsTextStore::sFlushTIPInputMessage = 0; - -#ifdef PR_LOGGING -PRLogModuleInfo* sTextStoreLog = nsnull; -#endif - -nsTextStore::nsTextStore() -{ - mRefCnt = 1; - mEditCookie = 0; - mSinkMask = 0; - mWindow = nsnull; - mLock = 0; - mLockQueued = 0; - mTextChange.acpStart = PR_INT32_MAX; - mTextChange.acpOldEnd = mTextChange.acpNewEnd = 0; -} - -nsTextStore::~nsTextStore() -{ -} - -PRBool -nsTextStore::Create(nsWindow* aWindow, - PRUint32 aIMEState) -{ - if (!mDocumentMgr) { - // Create document manager - HRESULT hr = sTsfThreadMgr->CreateDocumentMgr( - getter_AddRefs(mDocumentMgr)); - NS_ENSURE_TRUE(SUCCEEDED(hr), PR_FALSE); - mWindow = aWindow; - // Create context and add it to document manager - hr = mDocumentMgr->CreateContext(sTsfClientId, 0, - static_cast(this), - getter_AddRefs(mContext), &mEditCookie); - if (SUCCEEDED(hr)) { - SetIMEEnabledInternal(aIMEState); - hr = mDocumentMgr->Push(mContext); - } - if (SUCCEEDED(hr)) { - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Created, window=%08x\n", aWindow)); - return PR_TRUE; - } - mContext = NULL; - mDocumentMgr = NULL; - } - return PR_FALSE; -} - -PRBool -nsTextStore::Destroy(void) -{ - Blur(); - if (mWindow) { - // When blurred, Tablet Input Panel posts "blur" messages - // and try to insert text when the message is retrieved later. - // But by that time the text store is already destroyed, - // so try to get the message early - MSG msg; - if (::PeekMessageW(&msg, mWindow->GetWindowHandle(), - sFlushTIPInputMessage, sFlushTIPInputMessage, - PM_REMOVE)) { - ::DispatchMessageW(&msg); - } - } - mContext = NULL; - if (mDocumentMgr) { - mDocumentMgr->Pop(TF_POPF_ALL); - mDocumentMgr = NULL; - } - mSink = NULL; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Destroyed, window=%08x\n", mWindow)); - mWindow = NULL; - return PR_TRUE; -} - -PRBool -nsTextStore::Focus(void) -{ - HRESULT hr = sTsfThreadMgr->SetFocus(mDocumentMgr); - NS_ENSURE_TRUE(SUCCEEDED(hr), PR_FALSE); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Focused\n")); - return PR_TRUE; -} - -PRBool -nsTextStore::Blur(void) -{ - sTsfThreadMgr->SetFocus(NULL); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Blurred\n")); - return PR_TRUE; -} - -STDMETHODIMP -nsTextStore::QueryInterface(REFIID riid, - void** ppv) -{ - *ppv=NULL; - if ( (IID_IUnknown == riid) || (IID_ITextStoreACP == riid) ) { - *ppv = static_cast(this); - } else if (IID_ITfContextOwnerCompositionSink == riid) { - *ppv = static_cast(this); - } - if (*ppv) { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; -} - -STDMETHODIMP_(ULONG) nsTextStore::AddRef() -{ - return ++mRefCnt; -} - -STDMETHODIMP_(ULONG) nsTextStore::Release() -{ - --mRefCnt; - if (0 != mRefCnt) - return mRefCnt; - delete this; - return 0; -} - -STDMETHODIMP -nsTextStore::AdviseSink(REFIID riid, - IUnknown *punk, - DWORD dwMask) -{ - NS_ENSURE_TRUE(punk && IID_ITextStoreACPSink == riid, E_INVALIDARG); - if (!mSink) { - // Install sink - punk->QueryInterface(IID_ITextStoreACPSink, getter_AddRefs(mSink)); - NS_ENSURE_TRUE(mSink, E_UNEXPECTED); - } else { - // If sink is already installed we check to see if they are the same - // Get IUnknown from both sides for comparison - nsRefPtr comparison1, comparison2; - punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); - mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); - if (comparison1 != comparison2) - return CONNECT_E_ADVISELIMIT; - } - // Update mask either for a new sink or an existing sink - mSinkMask = dwMask; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Sink installed, punk=%08x\n", punk)); - return S_OK; -} - -STDMETHODIMP -nsTextStore::UnadviseSink(IUnknown *punk) -{ - NS_ENSURE_TRUE(punk, E_INVALIDARG); - NS_ENSURE_TRUE(mSink, CONNECT_E_NOCONNECTION); - // Get IUnknown from both sides for comparison - nsRefPtr comparison1, comparison2; - punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1)); - mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); - // Unadvise only if sinks are the same - NS_ENSURE_TRUE(comparison1 == comparison2, CONNECT_E_NOCONNECTION); - mSink = NULL; - mSinkMask = 0; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: Sink removed, punk=%08x\n", punk)); - return S_OK; -} - -STDMETHODIMP -nsTextStore::RequestLock(DWORD dwLockFlags, - HRESULT *phrSession) -{ - NS_ENSURE_TRUE(mSink, E_FAIL); - NS_ENSURE_TRUE(phrSession, E_INVALIDARG); - if (mLock) { - // only time when reentrant lock is allowed is when caller holds a - // read-only lock and is requesting an async write lock - if (TS_LF_READ == (mLock & TS_LF_READWRITE) && - TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE) && - !(dwLockFlags & TS_LF_SYNC)) { - *phrSession = TS_S_ASYNC; - mLockQueued = dwLockFlags & (~TS_LF_SYNC); - } else { - // no more locks allowed - *phrSession = TS_E_SYNCHRONOUS; - return E_FAIL; - } - } else { - // put on lock - mLock = dwLockFlags & (~TS_LF_SYNC); - *phrSession = mSink->OnLockGranted(mLock); - while (mLockQueued) { - mLock = mLockQueued; - mLockQueued = 0; - mSink->OnLockGranted(mLock); - } - mLock = 0; - } - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetStatus(TS_STATUS *pdcs) -{ - NS_ENSURE_TRUE(pdcs, E_INVALIDARG); - pdcs->dwDynamicFlags = 0; - // we use a "flat" text model for TSF support so no hidden text - pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT; - return S_OK; -} - -STDMETHODIMP -nsTextStore::QueryInsert(LONG acpTestStart, - LONG acpTestEnd, - ULONG cch, - LONG *pacpResultStart, - LONG *pacpResultEnd) -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: QueryInsert, start=%ld end=%ld cch=%lu\n", - acpTestStart, acpTestEnd, cch)); - // We don't test to see if these positions are - // after the end of document for performance reasons - NS_ENSURE_TRUE(0 <= acpTestStart && acpTestStart <= acpTestEnd && - pacpResultStart && pacpResultEnd, E_INVALIDARG); - - // XXX need to adjust to cluster boundary - // Assume we are given good offsets for now - *pacpResultStart = acpTestStart; - *pacpResultEnd = acpTestStart + cch; - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: QueryInsert SUCCEEDED\n")); - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetSelection(ULONG ulIndex, - ULONG ulCount, - TS_SELECTION_ACP *pSelection, - ULONG *pcFetched) -{ - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(ulCount && pSelection && pcFetched, E_INVALIDARG); - - *pcFetched = 0; - NS_ENSURE_TRUE(TS_DEFAULT_SELECTION == ulIndex || 0 == ulIndex, - TS_E_NOSELECTION); - if (mCompositionView) { - // Emulate selection during compositions - *pSelection = mCompositionSelection; - } else { - // Construct and initialize an event to get selection info - nsQueryContentEvent event(PR_TRUE, NS_QUERY_SELECTED_TEXT, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); - // Usually the selection anchor (beginning) position corresponds to the - // TSF start and the selection focus (ending) position corresponds to - // the TSF end, but if selection is reversed the focus now corresponds - // to the TSF start and the anchor now corresponds to the TSF end - pSelection->acpStart = event.mReply.mOffset; - pSelection->acpEnd = pSelection->acpStart + event.mReply.mString.Length(); - pSelection->style.ase = event.mReply.mString.Length() && - event.mReply.mReversed ? TS_AE_START : TS_AE_END; - // No support for interim character - pSelection->style.fInterimChar = 0; - } - *pcFetched = 1; - return S_OK; -} - -HRESULT -nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection) -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetSelection, sel=%ld-%ld\n", - pSelection->acpStart, pSelection->acpEnd)); - if (mCompositionView) { - // Emulate selection during compositions - NS_ENSURE_TRUE(pSelection->acpStart >= mCompositionStart && - pSelection->acpEnd <= mCompositionStart + - LONG(mCompositionString.Length()), TS_E_INVALIDPOS); - mCompositionSelection = *pSelection; - } else { - nsSelectionEvent event(PR_TRUE, NS_SELECTION_SET, mWindow); - event.mOffset = pSelection->acpStart; - event.mLength = PRUint32(pSelection->acpEnd - pSelection->acpStart); - event.mReversed = pSelection->style.ase == TS_AE_START; - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); - } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetSelection SUCCEEDED\n")); - return S_OK; -} - -STDMETHODIMP -nsTextStore::SetSelection(ULONG ulCount, - const TS_SELECTION_ACP *pSelection) -{ - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); - NS_ENSURE_TRUE(1 == ulCount && pSelection, E_INVALIDARG); - - return SetSelectionInternal(pSelection); -} - -STDMETHODIMP -nsTextStore::GetText(LONG acpStart, - LONG acpEnd, - WCHAR *pchPlain, - ULONG cchPlainReq, - ULONG *pcchPlainOut, - TS_RUNINFO *prgRunInfo, - ULONG ulRunInfoReq, - ULONG *pulRunInfoOut, - LONG *pacpNext) -{ - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(pcchPlainOut && (pchPlain || prgRunInfo) && - (!cchPlainReq == !pchPlain) && - (!ulRunInfoReq == !prgRunInfo), E_INVALIDARG); - NS_ENSURE_TRUE(0 <= acpStart && -1 <= acpEnd && - (-1 == acpEnd || acpStart <= acpEnd), TS_E_INVALIDPOS); - - // Making sure to NULL-terminate string just to be on the safe side - *pcchPlainOut = 0; - if (pchPlain && cchPlainReq) *pchPlain = NULL; - if (pulRunInfoOut) *pulRunInfoOut = 0; - if (pacpNext) *pacpNext = acpStart; - if (prgRunInfo && ulRunInfoReq) { - prgRunInfo->uCount = 0; - prgRunInfo->type = TS_RT_PLAIN; - } - PRUint32 length = -1 == acpEnd ? PR_UINT32_MAX : PRUint32(acpEnd - acpStart); - if (cchPlainReq && cchPlainReq - 1 < length) { - length = cchPlainReq - 1; - } - if (length) { - LONG compNewStart = 0, compOldEnd = 0, compNewEnd = 0; - if (mCompositionView) { - // Sometimes GetText gets called between InsertTextAtSelection and - // OnUpdateComposition. In this case the returned text would - // be out of sync because we haven't sent NS_TEXT_TEXT in - // OnUpdateComposition yet. Manually resync here. - compOldEnd = PR_MIN(LONG(length) + acpStart, - mCompositionLength + mCompositionStart); - compNewEnd = PR_MIN(LONG(length) + acpStart, - LONG(mCompositionString.Length()) + mCompositionStart); - compNewStart = PR_MAX(acpStart, mCompositionStart); - // Check if the range is affected - if (compOldEnd > compNewStart || compNewEnd > compNewStart) { - NS_ASSERTION(compOldEnd >= mCompositionStart && - compNewEnd >= mCompositionStart, "Range end is less than start\n"); - length = PRUint32(LONG(length) + compOldEnd - compNewEnd); - } - } - // Send NS_QUERY_TEXT_CONTENT to get text content - nsQueryContentEvent event(PR_TRUE, NS_QUERY_TEXT_CONTENT, mWindow); - mWindow->InitEvent(event); - event.InitForQueryTextContent(PRUint32(acpStart), length); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); - - if (compOldEnd > compNewStart || compNewEnd > compNewStart) { - // Resync composition string - const PRUnichar* compStrStart = mCompositionString.BeginReading() + - PR_MAX(compNewStart - mCompositionStart, 0); - event.mReply.mString.Replace(compNewStart - acpStart, - compOldEnd - mCompositionStart, compStrStart, - compNewEnd - mCompositionStart); - length = PRUint32(LONG(length) - compOldEnd + compNewEnd); - } - NS_ENSURE_TRUE(-1 == acpEnd || event.mReply.mString.Length() == length, - TS_E_INVALIDPOS); - length = PR_MIN(length, event.mReply.mString.Length()); - - if (pchPlain && cchPlainReq) { - memcpy(pchPlain, event.mReply.mString.BeginReading(), - length * sizeof(*pchPlain)); - pchPlain[length] = NULL; - *pcchPlainOut = length; - } - if (prgRunInfo && ulRunInfoReq) { - prgRunInfo->uCount = length; - prgRunInfo->type = TS_RT_PLAIN; - if (pulRunInfoOut) *pulRunInfoOut = 1; - } - if (pacpNext) *pacpNext = acpStart + length; - } - return S_OK; -} - -STDMETHODIMP -nsTextStore::SetText(DWORD dwFlags, - LONG acpStart, - LONG acpEnd, - const WCHAR *pchText, - ULONG cch, - TS_TEXTCHANGE *pChange) -{ - // Per SDK documentation, and since we don't have better - // ways to do this, this method acts as a helper to - // call SetSelection followed by InsertTextAtSelection - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); - TS_SELECTION_ACP selection; - selection.acpStart = acpStart; - selection.acpEnd = acpEnd; - selection.style.ase = TS_AE_END; - selection.style.fInterimChar = 0; - // Set selection to desired range - NS_ENSURE_TRUE(SUCCEEDED(SetSelectionInternal(&selection)), E_FAIL); - // Replace just selected text - return InsertTextAtSelection(TS_IAS_NOQUERY, pchText, cch, - NULL, NULL, pChange); -} - -STDMETHODIMP -nsTextStore::GetFormattedText(LONG acpStart, - LONG acpEnd, - IDataObject **ppDataObject) -{ - // no support for formatted text - return E_NOTIMPL; -} - -STDMETHODIMP -nsTextStore::GetEmbedded(LONG acpPos, - REFGUID rguidService, - REFIID riid, - IUnknown **ppunk) -{ - // embedded objects are not supported - return E_NOTIMPL; -} - -STDMETHODIMP -nsTextStore::QueryInsertEmbedded(const GUID *pguidService, - const FORMATETC *pFormatEtc, - BOOL *pfInsertable) -{ - // embedded objects are not supported - *pfInsertable = FALSE; - return S_OK; -} - -STDMETHODIMP -nsTextStore::InsertEmbedded(DWORD dwFlags, - LONG acpStart, - LONG acpEnd, - IDataObject *pDataObject, - TS_TEXTCHANGE *pChange) -{ - // embedded objects are not supported - return E_NOTIMPL; -} - -STDMETHODIMP -nsTextStore::RequestSupportedAttrs(DWORD dwFlags, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs) -{ - // no attributes defined - return S_OK; -} - -STDMETHODIMP -nsTextStore::RequestAttrsAtPosition(LONG acpPos, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs, - DWORD dwFlags) -{ - // no per character attributes defined - return S_OK; -} - -STDMETHODIMP -nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttr, - DWORD dwFlags) -{ - // no per character attributes defined - return S_OK; -} - -STDMETHODIMP -nsTextStore::FindNextAttrTransition(LONG acpStart, - LONG acpHalt, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs, - DWORD dwFlags, - LONG *pacpNext, - BOOL *pfFound, - LONG *plFoundOffset) -{ - NS_ENSURE_TRUE(pacpNext && pfFound && plFoundOffset, E_INVALIDARG); - // no per character attributes defined - *pacpNext = *plFoundOffset = acpHalt; - *pfFound = FALSE; - return S_OK; -} - -STDMETHODIMP -nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, - TS_ATTRVAL *paAttrVals, - ULONG *pcFetched) -{ - NS_ENSURE_TRUE(pcFetched && ulCount && paAttrVals, E_INVALIDARG); - // no attributes defined - *pcFetched = 0; - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetEndACP(LONG *pacp) -{ - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(pacp, E_INVALIDARG); - // Flattened text is retrieved and its length returned - nsQueryContentEvent event(PR_TRUE, NS_QUERY_TEXT_CONTENT, mWindow); - mWindow->InitEvent(event); - // Return entire text - event.InitForQueryTextContent(0, PR_INT32_MAX); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); - *pacp = LONG(event.mReply.mString.Length()); - return S_OK; -} - -#define TEXTSTORE_DEFAULT_VIEW (1) - -STDMETHODIMP -nsTextStore::GetActiveView(TsViewCookie *pvcView) -{ - NS_ENSURE_TRUE(pvcView, E_INVALIDARG); - *pvcView = TEXTSTORE_DEFAULT_VIEW; - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetACPFromPoint(TsViewCookie vcView, - const POINT *pt, - DWORD dwFlags, - LONG *pacp) -{ - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView, E_INVALIDARG); - // not supported for now - return E_NOTIMPL; -} - -STDMETHODIMP -nsTextStore::GetTextExt(TsViewCookie vcView, - LONG acpStart, - LONG acpEnd, - RECT *prc, - BOOL *pfClipped) -{ - NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK); - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc && pfClipped, - E_INVALIDARG); - NS_ENSURE_TRUE(acpStart >= 0 && acpEnd >= acpStart, TS_E_INVALIDPOS); - - // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates - nsQueryContentEvent event(PR_TRUE, NS_QUERY_TEXT_RECT, mWindow); - mWindow->InitEvent(event); - event.InitForQueryTextRect(acpStart, acpEnd - acpStart); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, TS_E_INVALIDPOS); - // IMEs don't like empty rects, fix here - if (event.mReply.mRect.width <= 0) - event.mReply.mRect.width = 1; - if (event.mReply.mRect.height <= 0) - event.mReply.mRect.height = 1; - - // convert to unclipped screen rect - nsWindow* refWindow = static_cast( - event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); - // Result rect is in top level widget coordinates - refWindow = refWindow->GetTopLevelWindow(PR_FALSE); - NS_ENSURE_TRUE(refWindow, E_FAIL); - - nsresult rv = refWindow->WidgetToScreen(event.mReply.mRect, - event.mReply.mRect); - NS_ENSURE_SUCCESS(rv, E_FAIL); - - // get bounding screen rect to test for clipping - HRESULT hr = GetScreenExt(vcView, prc); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - // clip text rect to bounding rect - RECT textRect; - ::SetRect(&textRect, event.mReply.mRect.x, event.mReply.mRect.y, - event.mReply.mRect.XMost(), event.mReply.mRect.YMost()); - if (!::IntersectRect(prc, prc, &textRect)) - // Text is not visible - ::SetRectEmpty(prc); - - // not equal if text rect was clipped - *pfClipped = !::EqualRect(prc, &textRect); - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetScreenExt(TsViewCookie vcView, - RECT *prc) -{ - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc, E_INVALIDARG); - // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates - nsQueryContentEvent event(PR_TRUE, NS_QUERY_EDITOR_RECT, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); - NS_ENSURE_TRUE(event.mSucceeded, E_FAIL); - - nsWindow* refWindow = static_cast( - event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); - // Result rect is in top level widget coordinates - refWindow = refWindow->GetTopLevelWindow(PR_FALSE); - NS_ENSURE_TRUE(refWindow, E_FAIL); - - nsIntRect boundRect; - nsresult rv = refWindow->GetClientBounds(boundRect); - NS_ENSURE_SUCCESS(rv, E_FAIL); - - // Clip frame rect to window rect - boundRect.IntersectRect(event.mReply.mRect, boundRect); - rv = refWindow->WidgetToScreen(boundRect, boundRect); - NS_ENSURE_SUCCESS(rv, E_FAIL); - - if (!boundRect.IsEmpty()) { - ::SetRect(prc, boundRect.x, boundRect.y, - boundRect.XMost(), boundRect.YMost()); - } else { - ::SetRectEmpty(prc); - } - return S_OK; -} - -STDMETHODIMP -nsTextStore::GetWnd(TsViewCookie vcView, - HWND *phwnd) -{ - NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && phwnd, E_INVALIDARG); - *phwnd = mWindow->GetWindowHandle(); - return S_OK; -} - -STDMETHODIMP -nsTextStore::InsertTextAtSelection(DWORD dwFlags, - const WCHAR *pchText, - ULONG cch, - LONG *pacpStart, - LONG *pacpEnd, - TS_TEXTCHANGE *pChange) -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection, cch=%lu\n", cch)); - NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK); - NS_ENSURE_TRUE(!cch || pchText, E_INVALIDARG); - - // Get selection first - TS_SELECTION_ACP sel; - ULONG selFetched; - NS_ENSURE_TRUE(SUCCEEDED(GetSelection( - TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL); - if (TS_IAS_QUERYONLY == dwFlags) { - NS_ENSURE_TRUE(pacpStart && pacpEnd, E_INVALIDARG); - // Simulate text insertion - *pacpStart = sel.acpStart; - *pacpEnd = sel.acpEnd; - if (pChange) { - pChange->acpStart = sel.acpStart; - pChange->acpOldEnd = sel.acpEnd; - pChange->acpNewEnd = sel.acpStart + cch; - } - } else { - NS_ENSURE_TRUE(pChange, E_INVALIDARG); - NS_ENSURE_TRUE(TS_IAS_NOQUERY == dwFlags || (pacpStart && pacpEnd), - E_INVALIDARG); - if (mCompositionView) { - // Emulate text insertion during compositions, because during a - // composition, editor expects the whole composition string to - // be sent in NS_TEXT_TEXT, not just the inserted part. - // The actual NS_TEXT_TEXT is sent in OnUpdateComposition, which - // should get called by TSF after this returns - mCompositionString.Replace(PRUint32(sel.acpStart - mCompositionStart), - sel.acpEnd - sel.acpStart, pchText, cch); - - mCompositionSelection.acpStart += cch; - mCompositionSelection.acpEnd = mCompositionSelection.acpStart; - mCompositionSelection.style.ase = TS_AE_END; - // OnUpdateComposition is not called here because it will - // result in fun visual artifacts - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection, replaced=%lu-%lu\n", - sel.acpStart - mCompositionStart, - sel.acpEnd - mCompositionStart)); - } else { - // Use a temporary composition to contain the text - nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_START, mWindow); - mWindow->InitEvent(compEvent); - mWindow->DispatchWindowEvent(&compEvent); - nsTextEvent event(PR_TRUE, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(event); - if (!cch) { - // XXX See OnEndComposition comment on inserting empty strings - event.theText = NS_LITERAL_STRING(" "); - mWindow->DispatchWindowEvent(&event); - } - event.theText.Assign(pchText, cch); - event.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), - NS_LITERAL_STRING("\n")); - mWindow->DispatchWindowEvent(&event); - compEvent.message = NS_COMPOSITION_END; - mWindow->DispatchWindowEvent(&compEvent); - } - pChange->acpStart = sel.acpStart; - pChange->acpOldEnd = sel.acpEnd; - // Get new selection - NS_ENSURE_TRUE(SUCCEEDED(GetSelection( - TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL); - pChange->acpNewEnd = sel.acpEnd; - if (TS_IAS_NOQUERY != dwFlags) { - *pacpStart = pChange->acpStart; - *pacpEnd = pChange->acpNewEnd; - } - } - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: InsertTextAtSelection SUCCEEDED\n")); - return S_OK; -} - -STDMETHODIMP -nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, - IDataObject *pDataObject, - LONG *pacpStart, - LONG *pacpEnd, - TS_TEXTCHANGE *pChange) -{ - // embedded objects are not supported - return E_NOTIMPL; -} - -static HRESULT -GetRangeExtent(ITfRange* aRange, LONG* aStart, LONG* aLength) -{ - nsRefPtr rangeACP; - aRange->QueryInterface(IID_ITfRangeACP, getter_AddRefs(rangeACP)); - NS_ENSURE_TRUE(rangeACP, E_FAIL); - return rangeACP->GetExtent(aStart, aLength); -} - -HRESULT -nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, - ITfRange* aRange, - PRBool aPreserveSelection) -{ - mCompositionView = pComposition; - HRESULT hr = GetRangeExtent(aRange, &mCompositionStart, &mCompositionLength); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnStartComposition, range=%ld-%ld\n", mCompositionStart, - mCompositionStart + mCompositionLength)); - - // Select composition range so the new composition replaces the range - nsSelectionEvent selEvent(PR_TRUE, NS_SELECTION_SET, mWindow); - mWindow->InitEvent(selEvent); - selEvent.mOffset = PRUint32(mCompositionStart); - selEvent.mLength = PRUint32(mCompositionLength); - selEvent.mReversed = PR_FALSE; - mWindow->DispatchWindowEvent(&selEvent); - NS_ENSURE_TRUE(selEvent.mSucceeded, E_FAIL); - - // Set up composition - nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_SELECTED_TEXT, mWindow); - mWindow->InitEvent(queryEvent); - mWindow->DispatchWindowEvent(&queryEvent); - NS_ENSURE_TRUE(queryEvent.mSucceeded, E_FAIL); - mCompositionString = queryEvent.mReply.mString; - if (!aPreserveSelection) { - mCompositionSelection.acpStart = mCompositionStart; - mCompositionSelection.acpEnd = mCompositionStart + mCompositionLength; - mCompositionSelection.style.ase = TS_AE_END; - mCompositionSelection.style.fInterimChar = FALSE; - } - nsCompositionEvent event(PR_TRUE, NS_COMPOSITION_START, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); - return S_OK; -} - -STDMETHODIMP -nsTextStore::OnStartComposition(ITfCompositionView* pComposition, - BOOL* pfOk) -{ - *pfOk = FALSE; - - // Only one composition at a time - if (mCompositionView) - return S_OK; - - nsRefPtr range; - HRESULT hr = pComposition->GetRange(getter_AddRefs(range)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - hr = OnStartCompositionInternal(pComposition, range, PR_FALSE); - if (SUCCEEDED(hr)) - *pfOk = TRUE; - return hr; -} - -STDMETHODIMP -nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, - ITfRange* pRangeNew) -{ - NS_ENSURE_TRUE(mCompositionView && - mCompositionView == pComposition && - mDocumentMgr && mContext, E_UNEXPECTED); - - // Getting display attributes is *really* complicated! - // We first get the context and the property objects to query for - // attributes, but since a big range can have a variety of values for - // the attribute, we have to find out all the ranges that have distinct - // attribute values. Then we query for what the value represents through - // the display attribute manager and translate that to nsTextRange to be - // sent in NS_TEXT_TEXT - if (!pRangeNew) // pRangeNew is null when the update is not complete - return S_OK; - - // Get starting offset of the composition - LONG compStart = 0, compLength = 0; - HRESULT hr = GetRangeExtent(pRangeNew, &compStart, &compLength); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - if (mCompositionStart != compStart || - mCompositionString.Length() != compLength) { - // If the queried composition length is different from the length - // of our composition string, OnUpdateComposition is being called - // because a part of the original composition was committed. - // Reflect that by committing existing composition and starting - // a new one. OnEndComposition followed by OnStartComposition - // will accomplish this automagically. - OnEndComposition(pComposition); - OnStartCompositionInternal(pComposition, pRangeNew, PR_TRUE); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnUpdateComposition, (reset) range=%ld-%ld\n", - compStart, compStart + compLength)); - } else { - mCompositionLength = compLength; - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnUpdateComposition, range=%ld-%ld\n", - compStart, compStart + compLength)); - } - - nsRefPtr prop; - hr = mContext->GetProperty(GUID_PROP_ATTRIBUTE, getter_AddRefs(prop)); - NS_ENSURE_TRUE(SUCCEEDED(hr) && prop, hr); - hr = LoadManagers(); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - // Use NS_TEXT_TEXT to set composition string - nsTextEvent event(PR_TRUE, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(event); - - VARIANT propValue; - ::VariantInit(&propValue); - nsRefPtr range; - nsRefPtr enumRanges; - hr = prop->EnumRanges(TfEditCookie(mEditCookie), - getter_AddRefs(enumRanges), pRangeNew); - NS_ENSURE_TRUE(SUCCEEDED(hr) && enumRanges, hr); - - nsAutoTArray textRanges; - nsTextRange newRange; - newRange.mStartOffset = PRUint32(mCompositionSelection.acpStart - compStart); - newRange.mEndOffset = PRUint32(mCompositionSelection.acpEnd - compStart); - newRange.mRangeType = NS_TEXTRANGE_CARETPOSITION; - textRanges.AppendElement(newRange); - // No matter if we have display attribute info or not, - // we always pass in at least one range to NS_TEXT_TEXT - newRange.mStartOffset = 0; - newRange.mEndOffset = mCompositionString.Length(); - newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; - textRanges.AppendElement(newRange); - - while (S_OK == enumRanges->Next(1, getter_AddRefs(range), NULL) && range) { - - LONG start = 0, length = 0; - if (FAILED(GetRangeExtent(range, &start, &length))) continue; - - newRange.mStartOffset = PRUint32(start - compStart); - // The end of the last range in the array is - // always kept at the end of composition - newRange.mEndOffset = mCompositionString.Length(); - - // Who came up with this convoluted way that we have to follow? - ::VariantClear(&propValue); - hr = prop->GetValue(TfEditCookie(mEditCookie), range, &propValue); - if (FAILED(hr) || VT_I4 != propValue.vt) continue; - - GUID guid; - hr = mCatMgr->GetGUID(DWORD(propValue.lVal), &guid); - if (FAILED(hr)) continue; - - nsRefPtr info; - hr = mDAMgr->GetDisplayAttributeInfo( - guid, getter_AddRefs(info), NULL); - if (FAILED(hr) || !info) continue; - - TF_DISPLAYATTRIBUTE attr; - hr = info->GetAttributeInfo(&attr); - if (FAILED(hr)) continue; - - switch (attr.bAttr) { - case TF_ATTR_TARGET_CONVERTED: - newRange.mRangeType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT; - break; - case TF_ATTR_CONVERTED: - newRange.mRangeType = NS_TEXTRANGE_CONVERTEDTEXT; - break; - case TF_ATTR_TARGET_NOTCONVERTED: - newRange.mRangeType = NS_TEXTRANGE_SELECTEDRAWTEXT; - break; - default: - newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; - break; - } - - nsTextRange& lastRange = textRanges[textRanges.Length() - 1]; - if (lastRange.mStartOffset == newRange.mStartOffset) { - // Replace range if last range is the same as this one - // So that ranges don't overlap and confuse the editor - lastRange = newRange; - } else { - lastRange.mEndOffset = newRange.mStartOffset; - textRanges.AppendElement(newRange); - } - } - - event.theText = mCompositionString; - event.rangeArray = textRanges.Elements(); - event.rangeCount = textRanges.Length(); - mWindow->DispatchWindowEvent(&event); - ::VariantClear(&propValue); - return S_OK; -} - -STDMETHODIMP -nsTextStore::OnEndComposition(ITfCompositionView* pComposition) -{ - NS_ENSURE_TRUE(mCompositionView && - mCompositionView == pComposition, E_UNEXPECTED); - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: OnEndComposition\n")); - - // Use NS_TEXT_TEXT to commit composition string - nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(textEvent); - if (!mCompositionString.Length()) { - // XXX HACK! HACK! NS_TEXT_TEXT handler specifically rejects - // first-time empty strings as workaround for another IME bug - // and our request will be rejected if this is the first time - // we are sending NS_TEXT_TEXT. The workaround is to send it a - // non-empty dummy string first. - textEvent.theText = NS_LITERAL_STRING(" "); - mWindow->DispatchWindowEvent(&textEvent); - } - textEvent.theText = mCompositionString; - textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), - NS_LITERAL_STRING("\n")); - mWindow->DispatchWindowEvent(&textEvent); - - nsCompositionEvent event(PR_TRUE, NS_COMPOSITION_END, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); - - mCompositionView = NULL; - mCompositionString.Truncate(0); - // Maintain selection - SetSelectionInternal(&mCompositionSelection); - return S_OK; -} - -nsresult -nsTextStore::OnFocusChange(PRBool aFocus, - nsWindow* aWindow, - PRUint32 aIMEEnabled) -{ - // no change notifications if TSF is disabled - if (!sTsfThreadMgr || !sTsfTextStore) - return NS_ERROR_NOT_AVAILABLE; - - if (aFocus) { - if (sTsfTextStore->Create(aWindow, aIMEEnabled)) - sTsfTextStore->Focus(); - } else { - sTsfTextStore->Destroy(); - } - return NS_OK; -} - -nsresult -nsTextStore::OnTextChangeInternal(PRUint32 aStart, - PRUint32 aOldEnd, - PRUint32 aNewEnd) -{ - if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE)) { - mTextChange.acpStart = PR_MIN(mTextChange.acpStart, LONG(aStart)); - mTextChange.acpOldEnd = PR_MAX(mTextChange.acpOldEnd, LONG(aOldEnd)); - mTextChange.acpNewEnd = PR_MAX(mTextChange.acpNewEnd, LONG(aNewEnd)); - ::PostMessageW(mWindow->GetWindowHandle(), - WM_USER_TSF_TEXTCHANGE, 0, NULL); - } - return NS_OK; -} - -void -nsTextStore::OnTextChangeMsgInternal(void) -{ - if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE) && - PR_INT32_MAX > mTextChange.acpStart) { - mSink->OnTextChange(0, &mTextChange); - mTextChange.acpStart = PR_INT32_MAX; - mTextChange.acpOldEnd = mTextChange.acpNewEnd = 0; - } -} - -nsresult -nsTextStore::OnSelectionChangeInternal(void) -{ - if (!mLock && mSink && 0 != (mSinkMask & TS_AS_SEL_CHANGE)) { - mSink->OnSelectionChange(); - } - return NS_OK; -} - -void -nsTextStore::CommitCompositionInternal(PRBool aDiscard) -{ - if (mCompositionView && aDiscard) { - mCompositionString.Truncate(0); - if (mSink && !mLock) { - TS_TEXTCHANGE textChange; - textChange.acpStart = mCompositionStart; - textChange.acpOldEnd = mCompositionStart + mCompositionLength; - textChange.acpNewEnd = mCompositionStart; - mSink->OnTextChange(0, &textChange); - } - } - // Terminate two contexts, the base context (mContext) and the top - // if the top context is not the same as the base context - nsRefPtr context = mContext; - do { - if (context) { - nsRefPtr services; - context->QueryInterface(IID_ITfContextOwnerCompositionServices, - getter_AddRefs(services)); - if (services) - services->TerminateComposition(NULL); - } - if (context != mContext) - break; - if (mDocumentMgr) - mDocumentMgr->GetTop(getter_AddRefs(context)); - } while (context != mContext); -} - -static -PRBool -GetCompartment(IUnknown* pUnk, - const GUID& aID, - ITfCompartment** aCompartment) -{ - if (!pUnk) return PR_FALSE; - - nsRefPtr compMgr; - pUnk->QueryInterface(IID_ITfCompartmentMgr, getter_AddRefs(compMgr)); - if (!compMgr) return PR_FALSE; - - return SUCCEEDED(compMgr->GetCompartment(aID, aCompartment)) && - (*aCompartment) != NULL; -} - -void -nsTextStore::SetIMEOpenState(PRBool aState) -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetIMEOpenState, state=%lu\n", aState)); - - nsRefPtr comp; - if (!GetCompartment(sTsfThreadMgr, - GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, - getter_AddRefs(comp))) - return; - - VARIANT variant; - variant.vt = VT_I4; - variant.lVal = aState; - comp->SetValue(sTsfClientId, &variant); -} - -PRBool -nsTextStore::GetIMEOpenState(void) -{ - nsRefPtr comp; - if (!GetCompartment(sTsfThreadMgr, - GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, - getter_AddRefs(comp))) - return PR_FALSE; - - VARIANT variant; - ::VariantInit(&variant); - if (SUCCEEDED(comp->GetValue(&variant)) && variant.vt == VT_I4) - return variant.lVal != 0; - - ::VariantClear(&variant); // clear up in case variant.vt != VT_I4 - return PR_FALSE; -} - -void -nsTextStore::SetIMEEnabledInternal(PRUint32 aState) -{ - PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: SetIMEEnabled, state=%lu\n", aState)); - - VARIANT variant; - variant.vt = VT_I4; - variant.lVal = aState != nsIWidget::IME_STATUS_ENABLED; - - // Set two contexts, the base context (mContext) and the top - // if the top context is not the same as the base context - nsRefPtr context = mContext; - nsRefPtr comp; - do { - if (GetCompartment(context, GUID_COMPARTMENT_KEYBOARD_DISABLED, - getter_AddRefs(comp))) - comp->SetValue(sTsfClientId, &variant); - - if (context != mContext) - break; - if (mDocumentMgr) - mDocumentMgr->GetTop(getter_AddRefs(context)); - } while (context != mContext); -} - -HRESULT -nsTextStore::LoadManagers(void) -{ - HRESULT hr; - if (!mDAMgr) { - hr = ::CoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, - CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeMgr, - getter_AddRefs(mDAMgr)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - } - if (!mCatMgr) { - hr = ::CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, - IID_ITfCategoryMgr, getter_AddRefs(mCatMgr)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - } - return S_OK; -} - -void -nsTextStore::Initialize(void) -{ -#ifdef PR_LOGGING - if (!sTextStoreLog) - sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets"); -#endif - if (!sTsfThreadMgr) { - PRBool enableTsf = PR_TRUE; - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - nsCOMPtr prefBranch; - prefs->GetBranch(nsnull, getter_AddRefs(prefBranch)); - if (prefBranch && NS_FAILED(prefBranch->GetBoolPref( - "config.windows.use_tsf", &enableTsf))) - enableTsf = PR_TRUE; - } - if (enableTsf) { - if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, - CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, - reinterpret_cast(&sTsfThreadMgr)))) { - if (FAILED(sTsfThreadMgr->Activate(&sTsfClientId))) { - NS_RELEASE(sTsfThreadMgr); - NS_WARNING("failed to activate TSF\n"); - } - } else - // TSF not installed? - NS_WARNING("failed to create TSF manager\n"); - } - } - if (sTsfThreadMgr && !sTsfTextStore) { - sTsfTextStore = new nsTextStore(); - if (!sTsfTextStore) - NS_ERROR("failed to create text store\n"); - } - if (sTsfThreadMgr && !sFlushTIPInputMessage) { - sFlushTIPInputMessage = ::RegisterWindowMessageW( - NS_LITERAL_STRING("Flush TIP Input Message").get()); - } -} - -void -nsTextStore::Terminate(void) -{ - NS_IF_RELEASE(sTsfTextStore); - if (sTsfThreadMgr) { - sTsfThreadMgr->Deactivate(); - NS_RELEASE(sTsfThreadMgr); - } -} diff --git a/widget/src/windows/nsTextStore.h b/widget/src/windows/nsTextStore.h deleted file mode 100644 index cedc90feaa6d..000000000000 --- a/widget/src/windows/nsTextStore.h +++ /dev/null @@ -1,232 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ningjie Chen - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef NSTEXTSTORE_H_ -#define NSTEXTSTORE_H_ - -#include "nsAutoPtr.h" -#include "nsString.h" - -#include -#include - -struct ITfThreadMgr; -struct ITfDocumentMgr; -class nsWindow; - -// It doesn't work well when we notify TSF of text change -// during a mutation observer call because things get broken. -// So we post a message and notify TSF when we get it later. -#define WM_USER_TSF_TEXTCHANGE (WM_USER + 0x100) - -/* - * Text Services Framework text store - */ - -class nsTextStore : public ITextStoreACP, - public ITfContextOwnerCompositionSink -{ -public: /*IUnknown*/ - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP QueryInterface(REFIID, void**); - STDMETHODIMP_(ULONG) Release(void); - -public: /*ITextStoreACP*/ - STDMETHODIMP AdviseSink(REFIID, IUnknown*, DWORD); - STDMETHODIMP UnadviseSink(IUnknown*); - STDMETHODIMP RequestLock(DWORD, HRESULT*); - STDMETHODIMP GetStatus(TS_STATUS*); - STDMETHODIMP QueryInsert(LONG, LONG, ULONG, LONG*, LONG*); - STDMETHODIMP GetSelection(ULONG, ULONG, TS_SELECTION_ACP*, ULONG*); - STDMETHODIMP SetSelection(ULONG, const TS_SELECTION_ACP*); - STDMETHODIMP GetText(LONG, LONG, WCHAR*, ULONG, ULONG*, TS_RUNINFO*, ULONG, - ULONG*, LONG*); - STDMETHODIMP SetText(DWORD, LONG, LONG, const WCHAR*, ULONG, TS_TEXTCHANGE*); - STDMETHODIMP GetFormattedText(LONG, LONG, IDataObject**); - STDMETHODIMP GetEmbedded(LONG, REFGUID, REFIID, IUnknown**); - STDMETHODIMP QueryInsertEmbedded(const GUID*, const FORMATETC*, BOOL*); - STDMETHODIMP InsertEmbedded(DWORD, LONG, LONG, IDataObject*, TS_TEXTCHANGE*); - STDMETHODIMP RequestSupportedAttrs(DWORD, ULONG, const TS_ATTRID*); - STDMETHODIMP RequestAttrsAtPosition(LONG, ULONG, const TS_ATTRID*, DWORD); - STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG, ULONG, - const TS_ATTRID*, DWORD); - STDMETHODIMP FindNextAttrTransition(LONG, LONG, ULONG, const TS_ATTRID*, - DWORD, LONG*, BOOL*, LONG*); - STDMETHODIMP RetrieveRequestedAttrs(ULONG, TS_ATTRVAL*, ULONG*); - STDMETHODIMP GetEndACP(LONG*); - STDMETHODIMP GetActiveView(TsViewCookie*); - STDMETHODIMP GetACPFromPoint(TsViewCookie, const POINT*, DWORD, LONG*); - STDMETHODIMP GetTextExt(TsViewCookie, LONG, LONG, RECT*, BOOL*); - STDMETHODIMP GetScreenExt(TsViewCookie, RECT*); - STDMETHODIMP GetWnd(TsViewCookie, HWND*); - STDMETHODIMP InsertTextAtSelection(DWORD, const WCHAR*, ULONG, LONG*, LONG*, - TS_TEXTCHANGE*); - STDMETHODIMP InsertEmbeddedAtSelection(DWORD, IDataObject*, LONG*, LONG*, - TS_TEXTCHANGE*); - -public: /*ITfContextOwnerCompositionSink*/ - STDMETHODIMP OnStartComposition(ITfCompositionView*, BOOL*); - STDMETHODIMP OnUpdateComposition(ITfCompositionView*, ITfRange*); - STDMETHODIMP OnEndComposition(ITfCompositionView*); - -public: - static void Initialize(void); - static void Terminate(void); - static void SetIMEOpenState(PRBool); - static PRBool GetIMEOpenState(void); - - static void CommitComposition(PRBool aDiscard) - { - if (!sTsfTextStore) return; - sTsfTextStore->CommitCompositionInternal(aDiscard); - } - - static void SetIMEEnabled(PRUint32 aState) - { - if (!sTsfTextStore) return; - sTsfTextStore->SetIMEEnabledInternal(aState); - } - - static nsresult OnFocusChange(PRBool, nsWindow*, PRUint32); - - static nsresult OnTextChange(PRUint32 aStart, - PRUint32 aOldEnd, - PRUint32 aNewEnd) - { - if (!sTsfTextStore) return NS_OK; - return sTsfTextStore->OnTextChangeInternal(aStart, aOldEnd, aNewEnd); - } - - static void OnTextChangeMsg(void) - { - if (!sTsfTextStore) return; - // Notify TSF text change - // (see comments on WM_USER_TSF_TEXTCHANGE in nsTextStore.h) - sTsfTextStore->OnTextChangeMsgInternal(); - } - - static nsresult OnSelectionChange(void) - { - if (!sTsfTextStore) return NS_OK; - return sTsfTextStore->OnSelectionChangeInternal(); - } - - static void* GetNativeData(void) - { - // Returns the address of the pointer so that the TSF automatic test can - // replace the system object with a custom implementation for testing. - return (void*) & sTsfThreadMgr; - } - -protected: - nsTextStore(); - ~nsTextStore(); - - PRBool Create(nsWindow*, PRUint32); - PRBool Destroy(void); - PRBool Focus(void); - PRBool Blur(void); - - HRESULT LoadManagers(void); - HRESULT SetSelectionInternal(const TS_SELECTION_ACP*); - HRESULT OnStartCompositionInternal(ITfCompositionView*, ITfRange*, PRBool); - void CommitCompositionInternal(PRBool); - void SetIMEEnabledInternal(PRUint32 aState); - nsresult OnTextChangeInternal(PRUint32, PRUint32, PRUint32); - void OnTextChangeMsgInternal(void); - nsresult OnSelectionChangeInternal(void); - - // TSF display attribute manager, loaded by LoadManagers - nsRefPtr mDAMgr; - // TSF category manager, loaded by LoadManagers - nsRefPtr mCatMgr; - - // Document manager for the currently focused editor - nsRefPtr mDocumentMgr; - // Edit cookie associated with the current editing context - DWORD mEditCookie; - // Editing context at the bottom of mDocumentMgr's context stack - nsRefPtr mContext; - // Currently installed notification sink - nsRefPtr mSink; - // TS_AS_* mask of what events to notify - DWORD mSinkMask; - // Window containing the focused editor - nsWindow* mWindow; - // 0 if not locked, otherwise TS_LF_* indicating the current lock - DWORD mLock; - // 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock - DWORD mLockQueued; - // Cumulative text change offsets since the last notification - TS_TEXTCHANGE mTextChange; - // NULL if no composition is active, otherwise the current composition - nsRefPtr mCompositionView; - // Current copy of the active composition string. Only mCompositionString is - // changed during a InsertTextAtSelection call if we have a composition. - // mCompositionString acts as a buffer until OnUpdateComposition is called - // and mCompositionString is flushed to editor through NS_TEXT_TEXT. This - // way all changes are updated in batches to avoid inconsistencies/artifacts. - nsString mCompositionString; - // "Current selection" during a composition, in ACP offsets. - // We use a fake selection during a composition because editor code doesn't - // like us accessing the actual selection during a composition. So we leave - // the actual selection alone and get/set mCompositionSelection instead - // during GetSelection/SetSelection calls. - TS_SELECTION_ACP mCompositionSelection; - // The start and length of the current active composition, in ACP offsets - LONG mCompositionStart; - LONG mCompositionLength; - - // TSF thread manager object for the current application - static ITfThreadMgr* sTsfThreadMgr; - // TSF client ID for the current application - static DWORD sTsfClientId; - // Current text store. Currently only ONE nsTextStore instance is ever used, - // although Create is called when an editor is focused and Destroy called - // when the focused editor is blurred. - static nsTextStore* sTsfTextStore; - - // Message the Tablet Input Panel uses to flush text during blurring. - // See comments in Destroy - static UINT sFlushTIPInputMessage; - -private: - ULONG mRefCnt; -}; - -#endif /*NSTEXTSTORE_H_*/ diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 1f953645bb63..f49fa63ebc63 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -34,7 +34,6 @@ * Dainis Jonitis * Christian Biesinger * Mats Palmgren - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -150,9 +149,7 @@ #include "prprf.h" #include "prmem.h" -#ifdef NS_ENABLE_TSF -#include "nsTextStore.h" -#endif //NS_ENABLE_TSF + #ifdef WINCE @@ -749,18 +746,14 @@ nsWindow::nsWindow() : nsBaseWidget() mIsTopWidgetWindow = PR_FALSE; mLastKeyboardLayout = 0; -#ifdef NS_ENABLE_TSF - if (!sInstanceCount) - nsTextStore::Initialize(); -#endif //NS_ENABLE_TSF - #ifndef WINCE if (!sInstanceCount && SUCCEEDED(::OleInitialize(NULL))) { sIsOleInitialized = TRUE; } NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n"); -#endif + sInstanceCount++; +#endif } //------------------------------------------------------------------------- @@ -795,17 +788,11 @@ nsWindow::~nsWindow() SetCursor(eCursor_standard); } - sInstanceCount--; - -#ifdef NS_ENABLE_TSF - if (!sInstanceCount) - nsTextStore::Terminate(); -#endif //NS_ENABLE_TSF - #ifndef WINCE // // delete any of the IME structures that we allocated // + sInstanceCount--; if (sInstanceCount == 0) { if (sIMECompUnicode) delete sIMECompUnicode; @@ -2829,12 +2816,6 @@ void* nsWindow::GetNativeData(PRUint32 aDataType) #else return (void*)::GetDC(mWnd); #endif - -#ifdef NS_ENABLE_TSF - case NS_NATIVE_TSF_POINTER: - return nsTextStore::GetNativeData(); -#endif //NS_ENABLE_TSF - case NS_NATIVE_COLORMAP: default: break; @@ -5328,12 +5309,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT } #endif // WINCE -#ifdef NS_ENABLE_TSF - else if (msg == WM_USER_TSF_TEXTCHANGE) { - nsTextStore::OnTextChangeMsg(); - } -#endif //NS_ENABLE_TSF - } break; #ifndef WINCE @@ -7458,8 +7433,8 @@ PRBool nsWindow::OnIMEQueryCharPosition(LPARAM aData, LRESULT *oResult) nsIntRect r; if (!useCaretRect) { - nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, this); - charRect.InitForQueryTextRect(offset, 1); + nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_CHARACTER_RECT, this); + charRect.InitForQueryCharacterRect(offset); InitEvent(charRect, &point); DispatchWindowEvent(&charRect); if (charRect.mSucceeded) @@ -7567,11 +7542,6 @@ NS_IMETHODIMP nsWindow::ResetInputState() #ifdef DEBUG_KBSTATE printf("ResetInputState\n"); #endif - -#ifdef NS_ENABLE_TSF - nsTextStore::CommitComposition(PR_FALSE); -#endif //NS_ENABLE_TSF - HIMC hIMC = ::ImmGetContext(mWnd); if (hIMC) { BOOL ret = FALSE; @@ -7589,11 +7559,6 @@ NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState) #ifdef DEBUG_KBSTATE printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close")); #endif - -#ifdef NS_ENABLE_TSF - nsTextStore::SetIMEOpenState(aState); -#endif //NS_ENABLE_TSF - HIMC hIMC = ::ImmGetContext(mWnd); if (hIMC) { ::ImmSetOpenStatus(hIMC, aState ? TRUE : FALSE); @@ -7612,21 +7577,12 @@ NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState) ::ImmReleaseContext(mWnd, hIMC); } else *aState = PR_FALSE; - -#ifdef NS_ENABLE_TSF - *aState |= nsTextStore::GetIMEOpenState(); -#endif //NS_ENABLE_TSF - return NS_OK; } //========================================================================== NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState) { -#ifdef NS_ENABLE_TSF - nsTextStore::SetIMEEnabled(aState); -#endif //NS_ENABLE_TSF - if (sIMEIsComposing) ResetInputState(); mIMEEnabled = aState; @@ -7653,11 +7609,6 @@ NS_IMETHODIMP nsWindow::CancelIMEComposition() #ifdef DEBUG_KBSTATE printf("CancelIMEComposition\n"); #endif - -#ifdef NS_ENABLE_TSF - nsTextStore::CommitComposition(PR_TRUE); -#endif //NS_ENABLE_TSF - HIMC hIMC = ::ImmGetContext(mWnd); if (hIMC) { BOOL ret = FALSE; @@ -7863,30 +7814,6 @@ static VOID CALLBACK nsGetAttentionTimerFunc(HWND hwnd, UINT uMsg, UINT idEvent, gAttentionTimerMonitor->KillTimer(hwnd); } - -#ifdef NS_ENABLE_TSF -NS_IMETHODIMP -nsWindow::OnIMEFocusChange(PRBool aFocus) -{ - return nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled); -} - -NS_IMETHODIMP -nsWindow::OnIMETextChange(PRUint32 aStart, - PRUint32 aOldEnd, - PRUint32 aNewEnd) -{ - return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd); -} - -NS_IMETHODIMP -nsWindow::OnIMESelectionChange(void) -{ - return nsTextStore::OnSelectionChange(); -} -#endif //NS_ENABLE_TSF - - // Draw user's attention to this window until it comes to foreground. NS_IMETHODIMP nsWindow::GetAttention(PRInt32 aCycleCount) diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index a58fd8cc12d2..5eed7a2d229e 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -25,7 +25,6 @@ * Makoto Kato * Dainis Jonitis * Masayuki Nakano - * Ningjie Chen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -74,11 +73,6 @@ struct nsFakeCharMessage; #include "gfxWindowsSurface.h" -// Text Services Framework support -#ifndef WINCE -#define NS_ENABLE_TSF -#endif //WINCE - #define IME_MAX_CHAR_POS 64 #define NSRGB_2_COLOREF(color) \ @@ -241,12 +235,6 @@ public: NS_IMETHOD CancelIMEComposition(); NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState); -#ifdef NS_ENABLE_TSF - NS_IMETHOD OnIMEFocusChange(PRBool aFocus); - NS_IMETHOD OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd); - NS_IMETHOD OnIMESelectionChange(void); -#endif //NS_ENABLE_TSF - PRBool IMEMouseHandling(PRInt32 aAction, LPARAM lParam); PRBool IMECompositionHitTest(POINT * ptPos); PRBool HandleMouseActionOfIME(PRInt32 aAction, POINT* ptPos); @@ -262,8 +250,6 @@ public: LPARAM lParam, PRBool aIsContextMenuKey = PR_FALSE, PRInt16 aButton = nsMouseEvent::eLeftButton); - virtual PRBool DispatchWindowEvent(nsGUIEvent* event); - virtual PRBool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus); #ifdef ACCESSIBILITY virtual PRBool DispatchAccessibleEvent(PRUint32 aEventType, nsIAccessible** aAccessible, nsIntPoint* aPoint = nsnull); already_AddRefed GetRootAccessible(); @@ -317,6 +303,8 @@ protected: LRESULT ProcessKeyDownMessage(const MSG &aMsg, PRBool *aEventDispatched); + virtual PRBool DispatchWindowEvent(nsGUIEvent* event); + virtual PRBool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus); // Allow Derived classes to modify the height that is passed // when the window is created or resized. diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index b3da4b2c2c3b..b875c0005afd 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -139,16 +139,13 @@ public: NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical); virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD ResetInputState() { return NS_OK; } + NS_IMETHOD ResetInputState() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD SetIMEOpenState(PRBool aState) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD GetIMEOpenState(PRBool* aState) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD SetIMEEnabled(PRUint32 aState) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD GetIMEEnabled(PRUint32* aState) { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD CancelIMEComposition() { return NS_OK; } + NS_IMETHOD CancelIMEComposition() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD OnIMEFocusChange(PRBool aFocus) { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd) { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD OnIMESelectionChange(void) { return NS_ERROR_NOT_IMPLEMENTED; } protected: diff --git a/widget/tests/Makefile.in b/widget/tests/Makefile.in index 347c4c70d317..698e28cbef96 100644 --- a/widget/tests/Makefile.in +++ b/widget/tests/Makefile.in @@ -39,40 +39,9 @@ DEPTH = ../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ -relativesrcdir = widget/tests +relativesrcdir = widget/test include $(DEPTH)/config/autoconf.mk - -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -ifneq ($(OS_ARCH), WINCE) -ifndef MOZ_ENABLE_LIBXUL -MOZILLA_INTERNAL_API = 1 -else -LIBS += $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \ - $(NULL) -endif - -CPP_UNIT_TESTS += TestWinTSF.cpp \ - $(NULL) - -LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/tests - -CPPSRCS += $(CPP_UNIT_TESTS) - -SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX)) - -REQUIRES += appshell content docshell \ - dom embed_base gfx layout locale \ - necko string thebes uriloader view \ - webbrwsr widget xpcom \ - $(NULL) - -LIBS += $(XPCOM_LIBS) \ - $(NSPR_LIBS) \ - $(NULL) -endif -endif - include $(topsrcdir)/config/rules.mk _TEST_FILES = test_bug343416.xul \ @@ -91,13 +60,3 @@ endif libs:: $(_TEST_FILES) $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir) - -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -ifneq ($(OS_ARCH), WINCE) -check:: - @$(EXIT_ON_ERROR) \ - for f in $(subst .cpp,,$(CPP_UNIT_TESTS)); do \ - XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \ - done -endif -endif diff --git a/widget/tests/TestWinTSF.cpp b/widget/tests/TestWinTSF.cpp deleted file mode 100644 index 4ee5e15e582b..000000000000 --- a/widget/tests/TestWinTSF.cpp +++ /dev/null @@ -1,1822 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ningjie Chen - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -/* This tests Mozilla's Text Services Framework implementation (bug #88831) - * - * The Mozilla implementation interacts with the TSF system through a - * system-provided COM interface, ITfThreadMgr. This tests works by swapping - * the system version of the interface with a custom version implemented in - * here. This way the Mozilla implementation thinks it's interacting with the - * system but in fact is interacting with this test program. This allows the - * test program to access and test every aspect of the Mozilla implementation. - */ - -#include -#include - -#include "TestHarness.h" - -#define WM_USER_TSF_TEXTCHANGE (WM_USER + 0x100) - -#ifndef MOZILLA_INTERNAL_API -// some of the includes make use of internal string types -#define nsAString_h___ -#define nsString_h___ -class nsAFlatString; -class nsAFlatCString; -#endif - -#include "nsWeakReference.h" -#include "nsIAppShell.h" -#include "nsWidgetsCID.h" -#include "nsIAppShellService.h" -#include "nsAppShellCID.h" -#include "nsNetUtil.h" -#include "nsIWebBrowserChrome.h" -#include "nsIXULWindow.h" -#include "nsIBaseWindow.h" -#include "nsIDOMWindowInternal.h" -#include "nsIDocShell.h" -#include "nsIWidget.h" -#include "nsIPresShell.h" -#include "nsPresContext.h" -#include "nsIFrame.h" -#include "nsIWebProgress.h" -#include "nsIWebProgressListener.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIDOMHTMLBodyElement.h" -#include "nsIDOMHTMLElement.h" -#include "nsIDOMHTMLInputElement.h" -#include "nsIDOMHTMLTextAreaElement.h" -#include "nsISelectionController.h" -#include "nsIViewManager.h" - -#ifndef MOZILLA_INTERNAL_API -#undef nsString_h___ -#undef nsAString_h___ -#endif - -static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); - -class TSFImpl; - -class TestApp : public nsIWebProgressListener, public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIWEBPROGRESSLISTENER - - TestApp() : mFailed(PR_FALSE) {} - ~TestApp() {} - - nsresult Run(void); - PRBool CheckFailed(void); - - typedef PRBool (TestApp::*test_type)(void); - -protected: - nsresult Init(void); - nsresult Term(void); - PRBool RunTest(test_type aTest, PRBool aLock = PR_TRUE); - - PRBool TestFocus(void); - PRBool TestClustering(void); - PRBool TestSelection(void); - PRBool TestText(void); - PRBool TestExtents(void); - PRBool TestComposition(void); - PRBool TestNotification(void); - - PRBool TestApp::TestSelectionInternal(char* aTestName, - LONG aStart, - LONG aEnd, - TsActiveSelEnd aSelEnd); - PRBool TestCompositionSelectionAndText(char* aTestName, - LONG aExpectedSelStart, - LONG aExpectedSelEnd, - nsString& aReferenceString); - PRBool TestNotificationTextChange(nsIWidget* aWidget, - PRUint32 aCode, - const nsAString& aCharacter, - LONG aStart, - LONG aOldEnd, - LONG aNewEnd); - nsresult GetSelCon(nsISelectionController** aSelCon); - - PRBool mFailed; - nsString mTestString; - nsRefPtr mImpl; - nsCOMPtr mAppShell; - nsCOMPtr mWindow; - nsCOMPtr mCurrentNode; - nsCOMPtr mInput; - nsCOMPtr mTextArea; - nsCOMPtr mButton; -}; - -NS_IMETHODIMP -TestApp::OnProgressChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - PRInt32 aCurSelfProgress, - PRInt32 aMaxSelfProgress, - PRInt32 aCurTotalProgress, - PRInt32 aMaxTotalProgress) -{ - return NS_OK; -} - -NS_IMETHODIMP -TestApp::OnLocationChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - nsIURI *aLocation) -{ - return NS_OK; -} - -NS_IMETHODIMP -TestApp::OnStatusChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - nsresult aStatus, - const PRUnichar *aMessage) -{ - return NS_OK; -} - -NS_IMETHODIMP -TestApp::OnSecurityChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - PRUint32 aState) -{ - return NS_OK; -} - -// Simple TSF manager implementation for testing -// Most methods are not implemented, but the ones used by Mozilla are -// -// XXX Implement appropriate methods here as the Mozilla TSF code changes -// -class TSFImpl : public ITfThreadMgr, public ITfDocumentMgr, public ITfContext, - public ITfRangeACP, public ITfCompositionView, - public ITextStoreACPSink -{ -private: - ULONG mRefCnt; - nsRefPtr mTestApp; - -public: - TestApp::test_type mTest; - TestApp::test_type mOnFocus; - TestApp::test_type mOnBlur; - nsRefPtr mStore; - PRBool mFocused; - PRBool mContextPushed; - PRBool mDeactivated; - PRUint32 mFocusCount; - PRUint32 mBlurCount; - PRUint32 mRangeStart; - PRUint32 mRangeLength; - PRBool mTextChanged; - PRBool mSelChanged; - TS_TEXTCHANGE mTextChangeData; - -public: - TSFImpl(TestApp* test) : mTestApp(test), mTest(nsnull), - mRefCnt(0), mFocused(PR_FALSE), mDeactivated(PR_FALSE), - mFocusCount(0), mBlurCount(0), mRangeStart(0), mRangeLength(0), - mContextPushed(PR_FALSE), mOnFocus(nsnull), mOnBlur(nsnull), - mTextChanged(PR_FALSE), mSelChanged(PR_FALSE) - { - } - - ~TSFImpl() - { - } - -public: // IUnknown - - STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) - { - *ppUnk = NULL; - if (IID_IUnknown == riid || IID_ITfThreadMgr == riid) - *ppUnk = static_cast(this); - else if (IID_ITfDocumentMgr == riid) - *ppUnk = static_cast(this); - else if (IID_ITfContext == riid) - *ppUnk = static_cast(this); - else if (IID_ITfRange == riid || IID_ITfRangeACP == riid) - *ppUnk = static_cast(this); - else if (IID_ITextStoreACPSink == riid) - *ppUnk = static_cast(this); - if (*ppUnk) - AddRef(); - return *ppUnk ? S_OK : E_NOINTERFACE; - } - - STDMETHODIMP_(ULONG) AddRef(void) - { - return ++mRefCnt; - } - - STDMETHODIMP_(ULONG) Release(void) - { - if (--mRefCnt) return mRefCnt; - delete this; - return 0; - } - -public: // ITfThreadMgr - - STDMETHODIMP Activate(TfClientId *ptid) - { - *ptid = 1; - return S_OK; - } - - STDMETHODIMP Deactivate(void) - { - SetFocus(NULL); - mDeactivated = PR_TRUE; - return S_OK; - } - - STDMETHODIMP CreateDocumentMgr(ITfDocumentMgr **ppdim) - { - (*ppdim) = this; - (*ppdim)->AddRef(); - return S_OK; - } - - STDMETHODIMP EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum) - { - NS_NOTREACHED("ITfThreadMgr::EnumDocumentMgrs"); - return E_NOTIMPL; - } - - STDMETHODIMP GetFocus(ITfDocumentMgr **ppdimFocus) - { - (*ppdimFocus) = mFocused ? this : NULL; - if (*ppdimFocus) (*ppdimFocus)->AddRef(); - return S_OK; - } - - STDMETHODIMP SetFocus(ITfDocumentMgr *pdimFocus) - { - mFocused = pdimFocus != NULL; - if (mFocused) { - ++mFocusCount; - if (mOnFocus) (mTestApp->*mOnFocus)(); - } else { - ++mBlurCount; - if (mOnBlur) (mTestApp->*mOnBlur)(); - } - return S_OK; - } - - STDMETHODIMP AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew, - ITfDocumentMgr **ppdimPrev) - { - NS_NOTREACHED("ITfThreadMgr::AssociateFocus"); - return E_NOTIMPL; - } - - STDMETHODIMP IsThreadFocus(BOOL *pfThreadFocus) - { - *pfThreadFocus = TRUE; - return S_OK; - } - - STDMETHODIMP GetFunctionProvider(REFCLSID clsid, - ITfFunctionProvider **ppFuncProv) - { - NS_NOTREACHED("ITfThreadMgr::GetFunctionProvider"); - return E_NOTIMPL; - } - - STDMETHODIMP EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum) - { - NS_NOTREACHED("ITfThreadMgr::EnumFunctionProviders"); - return E_NOTIMPL; - } - - STDMETHODIMP GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr) - { - NS_NOTREACHED("ITfThreadMgr::GetGlobalCompartment"); - return E_NOTIMPL; - } - -public: // ITfDocumentMgr - - STDMETHODIMP CreateContext(TfClientId tidOwner, DWORD dwFlags, - IUnknown *punk, ITfContext **ppic, - TfEditCookie *pecTextStore) - { - punk->QueryInterface(IID_ITextStoreACP, getter_AddRefs(mStore)); - NS_ENSURE_TRUE(mStore, E_FAIL); - HRESULT hr = mStore->AdviseSink(IID_ITextStoreACPSink, - static_cast(this), - TS_AS_ALL_SINKS); - if (FAILED(hr)) mStore = NULL; - NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); - (*ppic) = this; - (*ppic)->AddRef(); - *pecTextStore = 1; - return S_OK; - } - - STDMETHODIMP Push(ITfContext *pic) - { - mContextPushed = PR_TRUE; - return S_OK; - } - - STDMETHODIMP Pop(DWORD dwFlags) - { - if (!mStore || dwFlags != TF_POPF_ALL) return E_FAIL; - mStore->UnadviseSink(static_cast(this)); - mStore = NULL; - mContextPushed = PR_FALSE; - return S_OK; - } - - STDMETHODIMP GetTop(ITfContext **ppic) - { - (*ppic) = mContextPushed ? this : NULL; - if (*ppic) (*ppic)->AddRef(); - return S_OK; - } - - STDMETHODIMP GetBase(ITfContext **ppic) - { - (*ppic) = mContextPushed ? this : NULL; - if (*ppic) (*ppic)->AddRef(); - return S_OK; - } - - STDMETHODIMP EnumContexts(IEnumTfContexts **ppEnum) - { - NS_NOTREACHED("ITfDocumentMgr::EnumContexts"); - return E_NOTIMPL; - } - -public: // ITfContext - - STDMETHODIMP RequestEditSession(TfClientId tid, ITfEditSession *pes, - DWORD dwFlags, HRESULT *phrSession) - { - NS_NOTREACHED("ITfContext::RequestEditSession"); - return E_NOTIMPL; - } - - STDMETHODIMP InWriteSession(TfClientId tid, BOOL *pfWriteSession) - { - NS_NOTREACHED("ITfContext::InWriteSession"); - return E_NOTIMPL; - } - - STDMETHODIMP GetSelection(TfEditCookie ec, ULONG ulIndex, ULONG ulCount, - TF_SELECTION *pSelection, ULONG *pcFetched) - { - NS_NOTREACHED("ITfContext::GetSelection"); - return E_NOTIMPL; - } - - STDMETHODIMP SetSelection(TfEditCookie ec, ULONG ulCount, - const TF_SELECTION *pSelection) - { - NS_NOTREACHED("ITfContext::SetSelection"); - return E_NOTIMPL; - } - - STDMETHODIMP GetStart(TfEditCookie ec, ITfRange **ppStart) - { - NS_NOTREACHED("ITfContext::GetStart"); - return E_NOTIMPL; - } - - STDMETHODIMP GetEnd(TfEditCookie ec, ITfRange **ppEnd) - { - NS_NOTREACHED("ITfContext::GetEnd"); - return E_NOTIMPL; - } - - STDMETHODIMP GetActiveView(ITfContextView **ppView) - { - NS_NOTREACHED("ITfContext::GetActiveView"); - return E_NOTIMPL; - } - - STDMETHODIMP EnumViews(IEnumTfContextViews **ppEnum) - { - NS_NOTREACHED("ITfContext::EnumViews"); - return E_NOTIMPL; - } - - STDMETHODIMP GetStatus(TF_STATUS *pdcs) - { - NS_NOTREACHED("ITfContext::GetStatus"); - return E_NOTIMPL; - } - - STDMETHODIMP GetProperty(REFGUID guidProp, ITfProperty **ppProp) - { - NS_NOTREACHED("ITfContext::GetProperty"); - return E_NOTIMPL; - } - - STDMETHODIMP GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp) - { - NS_NOTREACHED("ITfContext::GetAppProperty"); - return E_NOTIMPL; - } - - STDMETHODIMP TrackProperties(const GUID **prgProp, ULONG cProp, - const GUID **prgAppProp, ULONG cAppProp, - ITfReadOnlyProperty **ppProperty) - { - NS_NOTREACHED("ITfContext::TrackProperties"); - return E_NOTIMPL; - } - - STDMETHODIMP EnumProperties(IEnumTfProperties **ppEnum) - { - NS_NOTREACHED("ITfContext::EnumProperties"); - return E_NOTIMPL; - } - - STDMETHODIMP GetDocumentMgr(ITfDocumentMgr **ppDm) - { - NS_NOTREACHED("ITfContext::GetDocumentMgr"); - return E_NOTIMPL; - } - - STDMETHODIMP CreateRangeBackup(TfEditCookie ec, ITfRange *pRange, - ITfRangeBackup **ppBackup) - { - NS_NOTREACHED("ITfContext::CreateRangeBackup"); - return E_NOTIMPL; - } - -public: // ITfRangeACP - - STDMETHODIMP GetText(TfEditCookie ec, DWORD dwFlags, WCHAR *pchText, - ULONG cchMax, ULONG *pcch) - { - NS_NOTREACHED("ITfRangeACP::GetText"); - return E_NOTIMPL; - } - - STDMETHODIMP SetText(TfEditCookie ec, DWORD dwFlags, const WCHAR *pchText, - LONG cch) - { - NS_NOTREACHED("ITfRangeACP::SetText"); - return E_NOTIMPL; - } - - STDMETHODIMP GetFormattedText(TfEditCookie ec, IDataObject **ppDataObject) - { - NS_NOTREACHED("ITfRangeACP::GetFormattedText"); - return E_NOTIMPL; - } - - STDMETHODIMP GetEmbedded(TfEditCookie ec, REFGUID rguidService, REFIID riid, - IUnknown **ppunk) - { - NS_NOTREACHED("ITfRangeACP::GetEmbedded"); - return E_NOTIMPL; - } - - STDMETHODIMP InsertEmbedded(TfEditCookie ec, DWORD dwFlags, - IDataObject *pDataObject) - { - NS_NOTREACHED("ITfRangeACP::InsertEmbedded"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftStart(TfEditCookie ec, LONG cchReq, LONG *pcch, - const TF_HALTCOND *pHalt) - { - NS_NOTREACHED("ITfRangeACP::ShiftStart"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftEnd(TfEditCookie ec, LONG cchReq, LONG *pcch, - const TF_HALTCOND *pHalt) - { - NS_NOTREACHED("ITfRangeACP::ShiftEnd"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftStartToRange(TfEditCookie ec, ITfRange *pRange, - TfAnchor aPos) - { - NS_NOTREACHED("ITfRangeACP::ShiftStartToRange"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftEndToRange(TfEditCookie ec, ITfRange *pRange, - TfAnchor aPos) - { - NS_NOTREACHED("ITfRangeACP::ShiftEndToRange"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftStartRegion(TfEditCookie ec, TfShiftDir dir, - BOOL *pfNoRegion) - { - NS_NOTREACHED("ITfRangeACP::ShiftStartRegion"); - return E_NOTIMPL; - } - - STDMETHODIMP ShiftEndRegion(TfEditCookie ec, TfShiftDir dir, - BOOL *pfNoRegion) - { - NS_NOTREACHED("ITfRangeACP::ShiftEndRegion"); - return E_NOTIMPL; - } - - STDMETHODIMP IsEmpty(TfEditCookie ec, BOOL *pfEmpty) - { - NS_NOTREACHED("ITfRangeACP::IsEmpty"); - return E_NOTIMPL; - } - - STDMETHODIMP Collapse(TfEditCookie ec, TfAnchor aPos) - { - NS_NOTREACHED("ITfRangeACP::Collapse"); - return E_NOTIMPL; - } - - STDMETHODIMP IsEqualStart(TfEditCookie ec, ITfRange *pWith, - TfAnchor aPos, BOOL *pfEqual) - { - NS_NOTREACHED("ITfRangeACP::IsEqualStart"); - return E_NOTIMPL; - } - - STDMETHODIMP IsEqualEnd(TfEditCookie ec, ITfRange *pWith, - TfAnchor aPos, BOOL *pfEqual) - { - NS_NOTREACHED("ITfRangeACP::IsEqualEnd"); - return E_NOTIMPL; - } - - STDMETHODIMP CompareStart(TfEditCookie ec, ITfRange *pWith, - TfAnchor aPos, LONG *plResult) - { - NS_NOTREACHED("ITfRangeACP::CompareStart"); - return E_NOTIMPL; - } - - STDMETHODIMP CompareEnd(TfEditCookie ec, ITfRange *pWith, - TfAnchor aPos, LONG *plResult) - { - NS_NOTREACHED("ITfRangeACP::CompareEnd"); - return E_NOTIMPL; - } - - STDMETHODIMP AdjustForInsert(TfEditCookie ec, ULONG cchInsert, - BOOL *pfInsertOk) - { - NS_NOTREACHED("ITfRangeACP::AdjustForInsert"); - return E_NOTIMPL; - } - - STDMETHODIMP GetGravity(TfGravity *pgStart, TfGravity *pgEnd) - { - NS_NOTREACHED("ITfRangeACP::GetGravity"); - return E_NOTIMPL; - } - - STDMETHODIMP SetGravity(TfEditCookie ec, TfGravity gStart, TfGravity gEnd) - { - NS_NOTREACHED("ITfRangeACP::SetGravity"); - return E_NOTIMPL; - } - - STDMETHODIMP Clone(ITfRange **ppClone) - { - NS_NOTREACHED("ITfRangeACP::Clone"); - return E_NOTIMPL; - } - - STDMETHODIMP GetContext(ITfContext **ppContext) - { - NS_NOTREACHED("ITfRangeACP::GetContext"); - return E_NOTIMPL; - } - - STDMETHODIMP GetExtent(LONG *pacpAnchor, LONG *pcch) - { - *pacpAnchor = LONG(mRangeStart); - *pcch = LONG(mRangeLength); - return S_OK; - } - - STDMETHODIMP SetExtent(LONG acpAnchor, LONG cch) - { - mRangeStart = PRUint32(acpAnchor); - mRangeLength = PRUint32(cch); - return S_OK; - } - -public: // ITfCompositionView - - STDMETHODIMP GetOwnerClsid(CLSID* pclsid) - { - NS_NOTREACHED("ITfCompositionView::GetOwnerClsid"); - return E_NOTIMPL; - } - - STDMETHODIMP GetRange(ITfRange** ppRange) - { - (*ppRange) = this; - (*ppRange)->AddRef(); - return S_OK; - } - -public: // ITextStoreACPSink - - STDMETHODIMP OnTextChange(DWORD dwFlags, const TS_TEXTCHANGE *pChange) - { - mTextChanged = PR_TRUE; - mTextChangeData = *pChange; - return S_OK; - } - - STDMETHODIMP OnSelectionChange(void) - { - mSelChanged = PR_TRUE; - return S_OK; - } - - STDMETHODIMP OnLayoutChange(TsLayoutCode lcode, TsViewCookie vcView) - { - return S_OK; - } - - STDMETHODIMP OnStatusChange(DWORD dwFlags) - { - return S_OK; - } - - STDMETHODIMP OnAttrsChange(LONG acpStart, LONG acpEnd, ULONG cAttrs, - const TS_ATTRID *paAttrs) - { - return S_OK; - } - - STDMETHODIMP OnLockGranted(DWORD dwLockFlags) - { - // If we have a test, run it - if (mTest && !(mTestApp->*mTest)()) - return S_FALSE; - return S_OK; - } - - STDMETHODIMP OnStartEditTransaction(void) - { - return S_OK; - } - - STDMETHODIMP OnEndEditTransaction(void) - { - return S_OK; - } -}; - -NS_IMPL_ISUPPORTS2(TestApp, nsIWebProgressListener, - nsISupportsWeakReference) - -nsresult -TestApp::Run(void) -{ - // Create a test window - // We need a full-fledged window to test for TSF functionality - nsresult rv; - mAppShell = do_GetService(kAppShellCID); - NS_ENSURE_TRUE(mAppShell, NS_ERROR_UNEXPECTED); - - nsCOMPtr appShellService( - do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); - NS_ENSURE_TRUE(appShellService, NS_ERROR_UNEXPECTED); - - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), "about:blank", nsnull); - NS_ENSURE_SUCCESS(rv, rv); - - rv = appShellService->CreateTopLevelWindow(nsnull, uri, - nsIWebBrowserChrome::CHROME_DEFAULT, - 800 /*nsIAppShellService::SIZE_TO_CONTENT*/, - 600 /*nsIAppShellService::SIZE_TO_CONTENT*/, - mAppShell, getter_AddRefs(mWindow)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr docShell; - rv = mWindow->GetDocShell(getter_AddRefs(docShell)); - NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED); - nsCOMPtr progress(do_GetInterface(docShell)); - NS_ENSURE_TRUE(progress, NS_ERROR_UNEXPECTED); - rv = progress->AddProgressListener(this, - nsIWebProgress::NOTIFY_STATE_WINDOW | - nsIWebProgress::NOTIFY_STATUS); - NS_ENSURE_SUCCESS(rv, rv); - - mAppShell->Run(); - return NS_OK; -} - -PRBool -TestApp::CheckFailed(void) -{ - // All windows should be closed by now - if (mImpl && !mImpl->mDeactivated) { - fail("TSF not terminated properly"); - mFailed = PR_TRUE; - } - mImpl = nsnull; - return mFailed; -} - -nsresult -TestApp::Init(void) -{ - // Replace TSF manager pointer - nsCOMPtr baseWindow(do_QueryInterface(mWindow)); - NS_ENSURE_TRUE(baseWindow, NS_ERROR_UNEXPECTED); - nsCOMPtr widget; - nsresult rv = baseWindow->GetMainWidget(getter_AddRefs(widget)); - NS_ENSURE_TRUE(widget, NS_ERROR_UNEXPECTED); - - ITfThreadMgr **mgr = reinterpret_cast( - widget->GetNativeData(NS_NATIVE_TSF_POINTER)); - if (!mgr) { - fail("nsIWidget::GetNativeData(NS_NATIVE_TSF_POINTER) not supported"); - return E_FAIL; - } - if (*mgr) { - (*mgr)->Deactivate(); - (*mgr)->Release(); - (*mgr) = NULL; - } else - printf("TSF not initialized properly (TSF is not enabled/installed?)"); - mImpl = new TSFImpl(this); - if (!mImpl) - return E_OUTOFMEMORY; - (*mgr) = mImpl; - (*mgr)->AddRef(); - - // Create a couple of text boxes for testing - nsCOMPtr win(do_GetInterface(mWindow)); - NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED); - nsCOMPtr document; - rv = win->GetDocument(getter_AddRefs(document)); - NS_ENSURE_TRUE(document, NS_ERROR_UNEXPECTED); - nsCOMPtr htmlDoc(do_QueryInterface(document)); - NS_ENSURE_TRUE(htmlDoc, NS_ERROR_UNEXPECTED); - nsCOMPtr htmlBody; - rv = htmlDoc->GetBody(getter_AddRefs(htmlBody)); - NS_ENSURE_TRUE(htmlBody, NS_ERROR_UNEXPECTED); - - nsCOMPtr form; - rv = htmlDoc->CreateElementNS( - NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), - NS_LITERAL_STRING("form"), - getter_AddRefs(form)); - nsCOMPtr elem; - rv = htmlDoc->CreateElementNS( - NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), - NS_LITERAL_STRING("input"), - getter_AddRefs(elem)); - NS_ENSURE_SUCCESS(rv, rv); - elem->SetAttribute(NS_LITERAL_STRING("type"), - NS_LITERAL_STRING("text")); - mInput = do_QueryInterface(elem); - NS_ENSURE_TRUE(mInput, NS_ERROR_UNEXPECTED); - rv = htmlDoc->CreateElementNS( - NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), - NS_LITERAL_STRING("textarea"), - getter_AddRefs(elem)); - NS_ENSURE_SUCCESS(rv, rv); - mTextArea = do_QueryInterface(elem); - NS_ENSURE_TRUE(mTextArea, NS_ERROR_UNEXPECTED); - rv = htmlDoc->CreateElementNS( - NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"), - NS_LITERAL_STRING("input"), - getter_AddRefs(elem)); - NS_ENSURE_SUCCESS(rv, rv); - elem->SetAttribute(NS_LITERAL_STRING("type"), - NS_LITERAL_STRING("button")); - mButton = do_QueryInterface(elem); - NS_ENSURE_TRUE(mButton, NS_ERROR_UNEXPECTED); - - nsCOMPtr node; - rv = form->AppendChild(mInput, getter_AddRefs(node)); - NS_ENSURE_SUCCESS(rv, rv); - rv = form->AppendChild(mTextArea, getter_AddRefs(node)); - NS_ENSURE_SUCCESS(rv, rv); - rv = form->AppendChild(mButton, getter_AddRefs(node)); - NS_ENSURE_SUCCESS(rv, rv); - rv = htmlBody->AppendChild(form, getter_AddRefs(node)); - NS_ENSURE_SUCCESS(rv, rv); - - // set a background color manually, - // otherwise the window might be transparent - nsCOMPtr(do_QueryInterface(htmlBody))-> - SetBgColor(NS_LITERAL_STRING("white")); - - widget->Show(PR_TRUE); - widget->SetFocus(); - return NS_OK; -} - -nsresult -TestApp::Term(void) -{ - mCurrentNode = nsnull; - mInput = nsnull; - mTextArea = nsnull; - mButton = nsnull; - - nsCOMPtr win(do_GetInterface(mWindow)); - if (win) - win->Close(); - win = nsnull; - mWindow = nsnull; - - if (mAppShell) - mAppShell->Exit(); - mAppShell = nsnull; - return NS_OK; -} - -PRBool -TestApp::RunTest(test_type aTest, PRBool aLock) -{ - PRBool succeeded; - if (aLock && mImpl->mStore) { - mImpl->mTest = aTest; - HRESULT hr = E_FAIL; - mImpl->mStore->RequestLock(TS_LF_READWRITE | TS_LF_SYNC, &hr); - succeeded = hr == S_OK; - } else { - succeeded = (this->*aTest)(); - } - mFailed |= !succeeded; - return succeeded; -} - -NS_IMETHODIMP -TestApp::OnStateChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, - PRUint32 aStateFlags, - nsresult aStatus) -{ - NS_ASSERTION(aStateFlags & nsIWebProgressListener::STATE_IS_WINDOW && - aStateFlags & nsIWebProgressListener::STATE_STOP, "wrong state"); - if (NS_SUCCEEDED(Init())) { - if (RunTest(&TestApp::TestFocus, PR_FALSE)) - passed("TestFocus"); - - mCurrentNode = mInput; - mInput->Focus(); - if (mImpl->mStore) { - if (RunTest(&TestApp::TestClustering)) - passed("TestClustering"); - } else { - fail("no text store (clustering)"); - mFailed = PR_TRUE; - } - - printf("Testing TSF support in text input element...\n"); - mCurrentNode = mInput; - mTestString = NS_LITERAL_STRING( - "This is a test of the Text Services Framework implementation."); - mInput->SetValue(mTestString); - mInput->Focus(); - if (mImpl->mStore) { - if (RunTest(&TestApp::TestSelection)) - passed("TestSelection (input)"); - if (RunTest(&TestApp::TestText)) - passed("TestText (input)"); - if (RunTest(&TestApp::TestExtents)) - passed("TestExtents (input)"); - if (RunTest(&TestApp::TestComposition)) - passed("TestComposition (input)"); - if (RunTest(&TestApp::TestNotification, PR_FALSE)) - passed("TestNotification (input)"); - } else { - fail("no text store (input)"); - mFailed = PR_TRUE; - } - - printf("Testing TSF support in textarea element...\n"); - mCurrentNode = mTextArea; - mTestString = NS_LITERAL_STRING( - "This is a test of the\r\nText Services Framework\r\nimplementation."); - mTextArea->SetValue(mTestString); - mTextArea->Focus(); - if (mImpl->mStore) { - if (RunTest(&TestApp::TestSelection)) - passed("TestSelection (textarea)"); - if (RunTest(&TestApp::TestText)) - passed("TestText (textarea)"); - if (RunTest(&TestApp::TestExtents)) - passed("TestExtents (textarea)"); - if (RunTest(&TestApp::TestComposition)) - passed("TestComposition (textarea)"); - if (RunTest(&TestApp::TestNotification, PR_FALSE)) - passed("TestNotification (textarea)"); - } else { - fail("no text store (textarea)"); - mFailed = PR_TRUE; - } - } else { - fail("initialization"); - mFailed = PR_TRUE; - } - Term(); - return NS_OK; -} - -PRBool -TestApp::TestFocus(void) -{ - PRUint32 focus = mImpl->mFocusCount, blur = mImpl->mBlurCount; - nsresult rv; - - /* If these fail the cause is probably one or more of: - * - nsIMEStateManager::OnTextStateFocus not called by nsEventStateManager - * - nsIMEStateManager::OnTextStateBlur not called by nsEventStateManager - * - nsWindow::OnIMEFocusChange (nsIWidget) not called by nsIMEStateManager - * - nsTextStore::Create/Focus/Destroy not called by nsWindow - * - ITfThreadMgr::CreateDocumentMgr/SetFocus not called by nsTextStore - * - ITfDocumentMgr::CreateContext/Push not called by nsTextStore - */ - - rv = mInput->Focus(); - if (!(NS_SUCCEEDED(rv) && - mImpl->mFocused && - mImpl->mStore && - mImpl->mFocusCount - focus == 1 && - mImpl->mBlurCount - blur == 0 && - mImpl->mStore)) { - fail("TestFocus: document focus was not set"); - return PR_FALSE; - } - - rv = mTextArea->Focus(); - if (!(NS_SUCCEEDED(rv) && - mImpl->mFocused && - mImpl->mStore && - mImpl->mFocusCount - focus == 2 && - mImpl->mBlurCount - blur == 1 && - mImpl->mStore)) { - fail("TestFocus: document focus was not changed"); - return PR_FALSE; - } - - rv = mButton->Focus(); - if (!(NS_SUCCEEDED(rv) && - !mImpl->mFocused && - !mImpl->mStore && - mImpl->mFocusCount - focus == 2 && - mImpl->mBlurCount - blur == 2 && - !mImpl->mStore)) { - fail("TestFocus: document was not blurred"); - return PR_FALSE; - } - return PR_TRUE; -} - -PRBool -TestApp::TestClustering(void) -{ - // Text for testing - const PRUint32 STRING_LENGTH = 2; - PRUnichar string[3]; - string[0] = 'e'; - string[1] = 0x0301; // U+0301 'acute accent' - string[2] = nsnull; - - // Replace entire string with our string - TS_TEXTCHANGE textChange; - HRESULT hr = mImpl->mStore->SetText(0, 0, -1, string, STRING_LENGTH, - &textChange); - if (!(SUCCEEDED(hr) && - 0 == textChange.acpStart && - STRING_LENGTH == textChange.acpNewEnd)) { - fail("TestClustering: SetText"); - return PR_FALSE; - } - - TsViewCookie view; - RECT rectLetter, rectAccent, rectWhole, rectCombined; - BOOL clipped, nonEmpty; - - hr = mImpl->mStore->GetActiveView(&view); - if (!(SUCCEEDED(hr))) { - fail("TestClustering: GetActiveView"); - return PR_FALSE; - } - - // Get rect of first char (the letter) - hr = mImpl->mStore->GetTextExt(view, 0, STRING_LENGTH / 2, - &rectLetter, &clipped); - if (!(SUCCEEDED(hr))) { - fail("TestClustering: GetTextExt (letter)"); - return PR_FALSE; - } - - // Get rect of second char (the accent) - hr = mImpl->mStore->GetTextExt(view, STRING_LENGTH / 2, STRING_LENGTH, - &rectAccent, &clipped); - if (!(SUCCEEDED(hr))) { - fail("TestClustering: GetTextExt (accent)"); - return PR_FALSE; - } - - // Get rect of combined char - hr = mImpl->mStore->GetTextExt(view, 0, STRING_LENGTH, - &rectWhole, &clipped); - if (!(SUCCEEDED(hr))) { - fail("TestClustering: GetTextExt (whole)"); - return PR_FALSE; - } - - nonEmpty = ::UnionRect(&rectCombined, &rectLetter, &rectAccent); - if (!(nonEmpty && - ::EqualRect(&rectCombined, &rectWhole))) { - fail("TestClustering: unexpected combined rect"); - return PR_FALSE; - } - return PR_TRUE; -} - -PRBool -TestApp::TestSelectionInternal(char* aTestName, - LONG aStart, - LONG aEnd, - TsActiveSelEnd aSelEnd) -{ - PRBool succeeded = PR_TRUE, continueTest = PR_TRUE; - TS_SELECTION_ACP sel, testSel; - ULONG selFetched; - - sel.acpStart = aStart; - sel.acpEnd = aEnd; - sel.style.ase = aSelEnd; - sel.style.fInterimChar = FALSE; - HRESULT hr = mImpl->mStore->SetSelection(1, &sel); - if (!(SUCCEEDED(hr))) { - fail("TestSelection: SetSelection (%s)", aTestName); - continueTest = succeeded = PR_FALSE; - } - - if (continueTest) { - hr = mImpl->mStore->GetSelection(TS_DEFAULT_SELECTION, 1, - &testSel, &selFetched); - if (!(SUCCEEDED(hr) && - selFetched == 1 && - !memcmp(&sel, &testSel, sizeof(sel)))) { - fail("TestSelection: unexpected GetSelection result (%s)", aTestName); - succeeded = PR_FALSE; - } - } - return succeeded; -} - -PRBool -TestApp::TestSelection(void) -{ - PRBool succeeded = PR_TRUE; - - /* If these fail the cause is probably one or more of: - * nsTextStore::GetSelection not sending NS_QUERY_SELECTED_TEXT - * NS_QUERY_SELECTED_TEXT not handled by nsContentEventHandler - * Bug in NS_QUERY_SELECTED_TEXT handler - * nsTextStore::SetSelection not sending NS_SELECTION_SET - * NS_SELECTION_SET not handled by nsContentEventHandler - * Bug in NS_SELECTION_SET handler - */ - - TS_SELECTION_ACP testSel; - ULONG selFetched; - - HRESULT hr = mImpl->mStore->GetSelection(0, 1, &testSel, &selFetched); - if (!(SUCCEEDED(hr) && - selFetched == 1)) { - fail("TestSelection: GetSelection"); - succeeded = PR_FALSE; - } - - const LONG SELECTION1_START = 0; - const LONG SELECTION1_END = mTestString.Length(); - const TsActiveSelEnd SELECTION1_SELEND = TS_AE_END; - - if (!TestSelectionInternal("normal", - SELECTION1_START, - SELECTION1_END, - SELECTION1_SELEND)) { - succeeded = PR_FALSE; - } - - const LONG SELECTION2_START = mTestString.Length() / 2; - const LONG SELECTION2_END = SELECTION2_START; - const TsActiveSelEnd SELECTION2_SELEND = TS_AE_END; - - if (!TestSelectionInternal("collapsed", - SELECTION2_START, - SELECTION2_END, - SELECTION2_SELEND)) { - succeeded = PR_FALSE; - } - - const LONG SELECTION3_START = 12; - const LONG SELECTION3_END = mTestString.Length() - 20; - const TsActiveSelEnd SELECTION3_SELEND = TS_AE_START; - - if (!TestSelectionInternal("reversed", - SELECTION3_START, - SELECTION3_END, - SELECTION3_SELEND)) { - succeeded = PR_FALSE; - } - return succeeded; -} - -PRBool -TestApp::TestText(void) -{ - const PRUint32 BUFFER_SIZE = (0x100); - const PRUint32 RUNINFO_SIZE = (0x10); - - PRBool succeeded = PR_TRUE, continueTest; - PRUnichar buffer[BUFFER_SIZE]; - TS_RUNINFO runInfo[RUNINFO_SIZE]; - ULONG bufferRet, runInfoRet; - LONG acpRet, acpCurrent; - TS_TEXTCHANGE textChange; - HRESULT hr; - - /* If these fail the cause is probably one or more of: - * nsTextStore::GetText not sending NS_QUERY_TEXT_CONTENT - * NS_QUERY_TEXT_CONTENT not handled by nsContentEventHandler - * Bug in NS_QUERY_TEXT_CONTENT handler - * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection - * Bug in SetSelection or InsertTextAtSelection - * NS_SELECTION_SET bug or NS_COMPOSITION_* / NS_TEXT_TEXT bug - */ - - // Get all text - hr = mImpl->mStore->GetText(0, -1, buffer, BUFFER_SIZE, &bufferRet, - runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet); - if (!(SUCCEEDED(hr) && - bufferRet <= mTestString.Length() && - !wcsncmp(mTestString.get(), buffer, bufferRet) && - acpRet == LONG(bufferRet) && - runInfoRet > 0)) { - fail("TestText: GetText 1"); - succeeded = PR_FALSE; - } - - - // Get text from GETTEXT2_START to GETTEXT2_END - const PRUint32 GETTEXT2_START = (18); - const PRUint32 GETTEXT2_END = (mTestString.Length() - 16); - const PRUint32 GETTEXT2_BUFFER_SIZE = (0x10); - - hr = mImpl->mStore->GetText(GETTEXT2_START, GETTEXT2_END, - buffer, GETTEXT2_BUFFER_SIZE, &bufferRet, - runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet); - if (!(SUCCEEDED(hr) && - bufferRet <= GETTEXT2_BUFFER_SIZE && - !wcsncmp(mTestString.get() + GETTEXT2_START, buffer, bufferRet) && - acpRet == LONG(bufferRet) + GETTEXT2_START && - runInfoRet > 0)) { - fail("TestText: GetText 2"); - succeeded = PR_FALSE; - } - - - // Replace text from SETTEXT1_START to SETTEXT1_END with insertString - const PRUint32 SETTEXT1_START = (8); - const PRUint32 SETTEXT1_TAIL_LENGTH = (40); - const PRUint32 SETTEXT1_END = (mTestString.Length() - - SETTEXT1_TAIL_LENGTH); - NS_NAMED_LITERAL_STRING(insertString, "(Inserted string)"); - - continueTest = PR_TRUE; - hr = mImpl->mStore->SetText(0, SETTEXT1_START, SETTEXT1_END, - insertString.get(), insertString.Length(), &textChange); - if (!(SUCCEEDED(hr) && - textChange.acpStart == SETTEXT1_START && - textChange.acpOldEnd == LONG(SETTEXT1_END) && - textChange.acpNewEnd == LONG(SETTEXT1_START + - insertString.Length()))) { - fail("TestText: SetText 1"); - continueTest = succeeded = PR_FALSE; - } - - const PRUint32 SETTEXT1_FINAL_LENGTH = (SETTEXT1_START + - SETTEXT1_TAIL_LENGTH + - insertString.Length()); - - if (continueTest) { - acpCurrent = 0; - while (acpCurrent < LONG(SETTEXT1_FINAL_LENGTH)) { - hr = mImpl->mStore->GetText(acpCurrent, -1, &buffer[acpCurrent], - BUFFER_SIZE, &bufferRet, runInfo, - RUNINFO_SIZE, &runInfoRet, &acpRet); - if (!(SUCCEEDED(hr) && - acpRet > acpCurrent && - bufferRet <= SETTEXT1_FINAL_LENGTH && - runInfoRet > 0)) { - fail("TestText: GetText failed after SetTest 1"); - continueTest = succeeded = PR_FALSE; - break; - } - acpCurrent = acpRet; - } - } - - if (continueTest) { - if (!(acpCurrent == LONG(SETTEXT1_FINAL_LENGTH) && - !wcsncmp(buffer, mTestString.get(), SETTEXT1_START) && - !wcsncmp(&buffer[SETTEXT1_START], insertString.get(), - insertString.Length()) && - !wcsncmp(&buffer[SETTEXT1_START + insertString.Length()], - mTestString.get() + SETTEXT1_END, SETTEXT1_TAIL_LENGTH))) { - fail("TestText: unexpected GetText result after SetText 1"); - succeeded = PR_FALSE; - } - } - - - // Restore entire text to original text (mTestString) - continueTest = PR_TRUE; - hr = mImpl->mStore->SetText(0, 0, -1, mTestString.get(), - mTestString.Length(), &textChange); - if (!(SUCCEEDED(hr) && - textChange.acpStart == 0 && - textChange.acpOldEnd == LONG(SETTEXT1_FINAL_LENGTH) && - textChange.acpNewEnd == LONG(mTestString.Length()))) { - fail("TestText: SetText 2"); - continueTest = succeeded = PR_FALSE; - } - - if (continueTest) { - acpCurrent = 0; - while (acpCurrent < LONG(mTestString.Length())) { - hr = mImpl->mStore->GetText(acpCurrent, -1, &buffer[acpCurrent], - BUFFER_SIZE, &bufferRet, runInfo, RUNINFO_SIZE, &runInfoRet, &acpRet); - if (!(SUCCEEDED(hr) && - acpRet > acpCurrent && - bufferRet <= mTestString.Length() && - runInfoRet > 0)) { - fail("TestText: GetText failed after SetText 2"); - continueTest = succeeded = PR_FALSE; - break; - } - acpCurrent = acpRet; - } - } - - if (continueTest) { - if (!(acpCurrent == LONG(mTestString.Length()) && - !wcsncmp(buffer, mTestString.get(), mTestString.Length()))) { - fail("TestText: unexpected GetText result after SetText 2"); - succeeded = PR_FALSE; - } - } - return succeeded; -} - -PRBool -TestApp::TestExtents(void) -{ - TS_SELECTION_ACP sel; - sel.acpStart = 0; - sel.acpEnd = 0; - sel.style.ase = TS_AE_END; - sel.style.fInterimChar = FALSE; - mImpl->mStore->SetSelection(1, &sel); - - nsCOMPtr selCon; - if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) { - fail("TestExtents: get nsISelectionController"); - return PR_FALSE; - } - selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, - nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE); - - nsCOMPtr window(do_GetInterface(mWindow)); - if (!window) { - fail("TestExtents: get nsIDOMWindowInternal"); - return PR_FALSE; - } - RECT windowRect, screenRect, textRect1, textRect2; - BOOL clipped; - PRInt32 val; - TsViewCookie view; - HRESULT hr; - - nsresult nsr = window->GetScreenX(&val); - windowRect.left = val; - nsr |= window->GetScreenY(&val); - windowRect.top = val; - nsr |= window->GetOuterWidth(&val); - windowRect.right = windowRect.left + val; - nsr |= window->GetOuterHeight(&val); - windowRect.bottom = windowRect.top + val; - if (!(NS_SUCCEEDED(nsr))) { - fail("TestExtents: get window rect failed"); - return PR_FALSE; - } - - hr = mImpl->mStore->GetActiveView(&view); - if (!(SUCCEEDED(hr))) { - fail("TestExtents: GetActiveView"); - return PR_FALSE; - } - - PRBool succeeded = PR_TRUE; - HWND hwnd; - hr = mImpl->mStore->GetWnd(view, &hwnd); - if (!(SUCCEEDED(hr) && - ::IsWindow(hwnd))) { - fail("TestExtents: GetWnd"); - succeeded = PR_FALSE; - } - - ::SetRectEmpty(&screenRect); - hr = mImpl->mStore->GetScreenExt(view, &screenRect); - if (!(SUCCEEDED(hr) && - screenRect.left > windowRect.left && - screenRect.top > windowRect.top && - screenRect.right > screenRect.left && - screenRect.bottom > screenRect.top && - screenRect.right < windowRect.right && - screenRect.bottom < windowRect.bottom)) { - fail("TestExtents: GetScreenExt"); - succeeded = PR_FALSE; - } - - const LONG GETTEXTEXT1_START = 0; - const LONG GETTEXTEXT1_END = 0; - - ::SetRectEmpty(&textRect1); - hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT1_START, GETTEXTEXT1_END, - &textRect1, &clipped); - if (!(SUCCEEDED(hr) && - textRect1.left >= screenRect.left && - textRect1.top >= screenRect.top && - textRect1.right < screenRect.right && - textRect1.bottom <= screenRect.bottom && - textRect1.right >= textRect1.left && - textRect1.bottom > textRect1.top)) { - fail("TestExtents: GetTextExt (offset %ld to %ld)", - GETTEXTEXT1_START, GETTEXTEXT1_END); - succeeded = PR_FALSE; - } - - const LONG GETTEXTEXT2_START = 10; - const LONG GETTEXTEXT2_END = 25; - - ::SetRectEmpty(&textRect2); - hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT2_START, GETTEXTEXT2_END, - &textRect2, &clipped); - if (!(SUCCEEDED(hr) && - textRect2.left >= screenRect.left && - textRect2.top >= screenRect.top && - textRect2.right <= screenRect.right && - textRect2.bottom <= screenRect.bottom && - textRect2.right > textRect2.left && - textRect2.bottom > textRect2.top)) { - fail("TestExtents: GetTextExt (offset %ld to %ld)", - GETTEXTEXT2_START, GETTEXTEXT2_END); - succeeded = PR_FALSE; - } - - // Offsets must be between GETTEXTEXT2_START and GETTEXTEXT2_END - const LONG GETTEXTEXT3_START = 23; - const LONG GETTEXTEXT3_END = 23; - - ::SetRectEmpty(&textRect1); - hr = mImpl->mStore->GetTextExt(view, GETTEXTEXT3_START, GETTEXTEXT3_END, - &textRect1, &clipped); - // Rectangle must be entirely inside the previous rectangle, - // since GETTEXTEXT3_START and GETTEXTEXT3_END are between - // GETTEXTEXT2_START and GETTEXTEXT2_START - if (!(SUCCEEDED(hr) && ::IsRectEmpty(&textRect1) || - (textRect1.left >= textRect2.left && - textRect1.top >= textRect2.top && - textRect1.right <= textRect2.right && - textRect1.bottom <= textRect2.bottom && - textRect1.right >= textRect1.left && - textRect1.bottom > textRect1.top))) { - fail("TestExtents: GetTextExt (offset %ld to %ld)", - GETTEXTEXT3_START, GETTEXTEXT3_END); - succeeded = PR_FALSE; - } - return succeeded; -} - -PRBool -TestApp::TestCompositionSelectionAndText(char* aTestName, - LONG aExpectedSelStart, - LONG aExpectedSelEnd, - nsString& aReferenceString) -{ - TS_SELECTION_ACP currentSel; - ULONG selFetched = 0; - HRESULT hr = mImpl->mStore->GetSelection(TF_DEFAULT_SELECTION, 1, - ¤tSel, &selFetched); - if (!(SUCCEEDED(hr) && - 1 == selFetched && - currentSel.acpStart == aExpectedSelStart && - currentSel.acpEnd == aExpectedSelEnd)) { - fail("TestComposition: GetSelection (%s)", aTestName); - return PR_FALSE; - } - - const PRUint32 bufferSize = 0x100, runInfoSize = 0x10; - PRUnichar buffer[bufferSize]; - TS_RUNINFO runInfo[runInfoSize]; - ULONG bufferRet, runInfoRet; - LONG acpRet, acpCurrent = 0; - while (acpCurrent < LONG(aReferenceString.Length())) { - hr = mImpl->mStore->GetText(acpCurrent, aReferenceString.Length(), - &buffer[acpCurrent], bufferSize, &bufferRet, runInfo, runInfoSize, - &runInfoRet, &acpRet); - if (!(SUCCEEDED(hr) && - acpRet > acpCurrent && - bufferRet <= aReferenceString.Length() && - runInfoRet > 0)) { - fail("TestComposition: GetText (%s)", aTestName); - return PR_FALSE; - } - acpCurrent = acpRet; - } - if (!(acpCurrent == aReferenceString.Length() && - !wcsncmp(buffer, aReferenceString.get(), aReferenceString.Length()))) { - fail("TestComposition: unexpected GetText result (%s)", aTestName); - return PR_FALSE; - } - return PR_TRUE; -} - -PRBool -TestApp::TestComposition(void) -{ - nsRefPtr sink; - HRESULT hr = mImpl->mStore->QueryInterface( - IID_ITfContextOwnerCompositionSink, - getter_AddRefs(sink)); - if (!(SUCCEEDED(hr))) { - fail("TestComposition: QueryInterface"); - return PR_FALSE; - } - - const LONG PRECOMPOSITION_SEL_START = 2; - const LONG PRECOMPOSITION_SEL_END = PRECOMPOSITION_SEL_START; - const TsActiveSelEnd PRECOMPOSITION_SEL_SELEND = TS_AE_END; - - TS_SELECTION_ACP sel; - sel.acpStart = PRECOMPOSITION_SEL_START; - sel.acpEnd = PRECOMPOSITION_SEL_END; - sel.style.ase = PRECOMPOSITION_SEL_SELEND; - sel.style.fInterimChar = FALSE; - hr = mImpl->mStore->SetSelection(1, &sel); - if (!(SUCCEEDED(hr))) { - fail("TestComposition: SetSelection (pre-composition)"); - return PR_FALSE; - } - - - TS_TEXTCHANGE textChange; - NS_NAMED_LITERAL_STRING(insertString1, "Compo1"); - hr = mImpl->mStore->InsertTextAtSelection(TF_IAS_NOQUERY, - insertString1.get(), - insertString1.Length(), - NULL, NULL, &textChange); - if (!(SUCCEEDED(hr) && - sel.acpEnd == textChange.acpStart && - sel.acpEnd == textChange.acpOldEnd && - sel.acpEnd + insertString1.Length() == textChange.acpNewEnd)) { - fail("TestComposition: InsertTextAtSelection"); - return PR_FALSE; - } - sel.acpEnd = textChange.acpNewEnd; - - mImpl->mRangeStart = textChange.acpStart; - mImpl->mRangeLength = textChange.acpNewEnd - textChange.acpOldEnd; - BOOL okay = FALSE; - hr = sink->OnStartComposition(mImpl, &okay); - if (!(SUCCEEDED(hr) && - okay)) { - fail("TestComposition: OnStartComposition"); - return PR_FALSE; - } - - - NS_NAMED_LITERAL_STRING(insertString2, "Composition2"); - hr = mImpl->mStore->SetText(0, mImpl->mRangeStart + mImpl->mRangeLength, - mImpl->mRangeStart + mImpl->mRangeLength, - insertString2.get(), insertString2.Length(), - &textChange); - if (!(SUCCEEDED(hr) && - sel.acpEnd == textChange.acpStart && - sel.acpEnd == textChange.acpOldEnd && - sel.acpEnd + insertString2.Length() == textChange.acpNewEnd)) { - fail("TestComposition: SetText 1"); - return PR_FALSE; - } - sel.acpEnd = textChange.acpNewEnd; - mImpl->mRangeLength += textChange.acpNewEnd - textChange.acpOldEnd; - - - const LONG COMPOSITION3_TEXT_START_OFFSET = -8; // offset 8 from the end - const LONG COMPOSITION3_TEXT_END_OFFSET = 4; - - const LONG COMPOSITION3_TEXT_START = mImpl->mRangeStart + - mImpl->mRangeLength + - COMPOSITION3_TEXT_START_OFFSET; - const LONG COMPOSITION3_TEXT_END = COMPOSITION3_TEXT_START + - COMPOSITION3_TEXT_END_OFFSET; - - NS_NAMED_LITERAL_STRING(insertString3, "Compo3"); - hr = mImpl->mStore->SetText(0, COMPOSITION3_TEXT_START, - COMPOSITION3_TEXT_END, - insertString3.get(), insertString3.Length(), - &textChange); - if (!(SUCCEEDED(hr) && - sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET == textChange.acpStart && - sel.acpEnd + COMPOSITION3_TEXT_START_OFFSET + - COMPOSITION3_TEXT_END_OFFSET == textChange.acpOldEnd && - sel.acpEnd + insertString3.Length() + COMPOSITION3_TEXT_START_OFFSET == - textChange.acpNewEnd)) { - fail("TestComposition: SetText 2"); - return PR_FALSE; - } - sel.acpEnd = textChange.acpNewEnd; - mImpl->mRangeLength += textChange.acpNewEnd - textChange.acpOldEnd; - - - nsString referenceString; - referenceString.Append(mTestString.get(), sel.acpStart); - referenceString.Append(insertString1); - referenceString.Append(insertString2.get(), - insertString2.Length() + COMPOSITION3_TEXT_START_OFFSET); - referenceString.Append(insertString3); - referenceString.Append(insertString2.get() + insertString2.Length() - - COMPOSITION3_TEXT_END_OFFSET, COMPOSITION3_TEXT_END_OFFSET); - referenceString.Append(mTestString.get() + sel.acpStart, - COMPOSITION3_TEXT_END_OFFSET); - - if (!TestCompositionSelectionAndText("composition", - sel.acpEnd, sel.acpEnd, - referenceString)) - return PR_FALSE; - - - const LONG POSTCOMPOSITION_SEL_START = sel.acpEnd - 8; - const LONG POSTCOMPOSITION_SEL_END = POSTCOMPOSITION_SEL_START + 2; - - sel.acpStart = POSTCOMPOSITION_SEL_START; - sel.acpEnd = POSTCOMPOSITION_SEL_END; - hr = mImpl->mStore->SetSelection(1, &sel); - if (!(SUCCEEDED(hr))) { - fail("TestComposition: SetSelection (composition)"); - return PR_FALSE; - } - - hr = sink->OnEndComposition(mImpl); - if (!(SUCCEEDED(hr))) { - fail("TestComposition: OnEndComposition"); - return PR_FALSE; - } - - if (!TestCompositionSelectionAndText("post-composition", - sel.acpStart, sel.acpEnd, - referenceString)) - return PR_FALSE; - - - const LONG EMPTYCOMPOSITION_START = mImpl->mRangeStart + 2; - const LONG EMPTYCOMPOSITION_LENGTH = mImpl->mRangeLength - 4; - - mImpl->mRangeStart = EMPTYCOMPOSITION_START; - mImpl->mRangeLength = EMPTYCOMPOSITION_LENGTH; - okay = FALSE; - hr = sink->OnStartComposition(mImpl, &okay); - if (!(SUCCEEDED(hr) && - okay)) { - fail("TestComposition: OnStartComposition (empty composition)"); - return PR_FALSE; - } - - hr = sink->OnEndComposition(mImpl); - if (!(SUCCEEDED(hr))) { - fail("TestComposition: OnEndComposition (empty composition)"); - return PR_FALSE; - } - - if (!TestCompositionSelectionAndText("empty composition", - mImpl->mRangeStart, - mImpl->mRangeStart + mImpl->mRangeLength, - referenceString)) - return PR_FALSE; - - return PR_TRUE; -} - -PRBool -TestApp::TestNotificationTextChange(nsIWidget* aWidget, - PRUint32 aCode, - const nsAString& aCharacter, - LONG aStart, - LONG aOldEnd, - LONG aNewEnd) -{ - MSG msg; - if (::PeekMessageW(&msg, NULL, WM_USER_TSF_TEXTCHANGE, - WM_USER_TSF_TEXTCHANGE, PM_REMOVE)) - ::DispatchMessageW(&msg); - mImpl->mTextChanged = PR_FALSE; - nsresult nsr = aWidget->SynthesizeNativeKeyEvent(0, aCode, 0, - aCharacter, aCharacter); - if (::PeekMessageW(&msg, NULL, WM_USER_TSF_TEXTCHANGE, - WM_USER_TSF_TEXTCHANGE, PM_REMOVE)) - ::DispatchMessageW(&msg); - return NS_SUCCEEDED(nsr) && - mImpl->mTextChanged && - aStart == mImpl->mTextChangeData.acpStart && - aOldEnd == mImpl->mTextChangeData.acpOldEnd && - aNewEnd == mImpl->mTextChangeData.acpNewEnd; -} - -PRBool -TestApp::TestNotification(void) -{ - nsresult nsr; - // get selection to test notification support - nsCOMPtr selCon; - if (!(NS_SUCCEEDED(GetSelCon(getter_AddRefs(selCon))) && selCon)) { - fail("TestNotification: get nsISelectionController"); - return PR_FALSE; - } - - nsr = selCon->CompleteMove(PR_FALSE, PR_FALSE); - if (!(NS_SUCCEEDED(nsr))) { - fail("TestNotification: CompleteMove"); - return PR_FALSE; - } - - mImpl->mSelChanged = PR_FALSE; - nsr = selCon->CharacterMove(PR_TRUE, PR_FALSE); - if (!(NS_SUCCEEDED(nsr) && - mImpl->mSelChanged)) { - fail("TestNotification: CharacterMove"); - return PR_FALSE; - } - - mImpl->mSelChanged = PR_FALSE; - nsr = selCon->CharacterMove(PR_TRUE, PR_TRUE); - if (!(NS_SUCCEEDED(nsr) && - mImpl->mSelChanged)) { - fail("TestNotification: CharacterMove (extend)"); - return PR_FALSE; - } - - nsCOMPtr widget; - nsCOMPtr docShell; - nsr = mWindow->GetDocShell(getter_AddRefs(docShell)); - if (NS_SUCCEEDED(nsr) && docShell) { - nsCOMPtr presShell; - nsr = docShell->GetPresShell(getter_AddRefs(presShell)); - if (NS_SUCCEEDED(nsr) && presShell) { - nsCOMPtr viewManager = presShell->GetViewManager(); - if (viewManager) { - nsr = viewManager->GetWidget(getter_AddRefs(widget)); - } - } - } - if (!(NS_SUCCEEDED(nsr) && widget)) { - fail("TestNotification: get nsIWidget"); - return PR_FALSE; - } - - NS_NAMED_LITERAL_STRING(character, ""); - NS_NAMED_LITERAL_STRING(characterA, "A"); - - // The selection test code above placed the selection at offset 1 to 2 - const LONG TEXTCHANGE1_START = 1; - const LONG TEXTCHANGE1_OLDEND = 2; - const LONG TEXTCHANGE1_NEWEND = 2; - - // replace single selected character with 'A' - if (!TestNotificationTextChange(widget, 'A', characterA, - TEXTCHANGE1_START, TEXTCHANGE1_OLDEND, TEXTCHANGE1_NEWEND)) { - fail("TestNotification: text change 1"); - return PR_FALSE; - } - - const LONG TEXTCHANGE2_START = TEXTCHANGE1_NEWEND; - const LONG TEXTCHANGE2_OLDEND = TEXTCHANGE1_NEWEND; - const LONG TEXTCHANGE2_NEWEND = TEXTCHANGE1_NEWEND + 1; - - // insert 'A' - if (!TestNotificationTextChange(widget, 'A', characterA, - TEXTCHANGE2_START, TEXTCHANGE2_OLDEND, TEXTCHANGE2_NEWEND)) { - fail("TestNotification: text change 2"); - return PR_FALSE; - } - - const LONG TEXTCHANGE3_START = TEXTCHANGE2_NEWEND - 1; - const LONG TEXTCHANGE3_OLDEND = TEXTCHANGE2_NEWEND; - const LONG TEXTCHANGE3_NEWEND = TEXTCHANGE2_NEWEND - 1; - - // backspace - if (!TestNotificationTextChange(widget, '\b', character, - TEXTCHANGE3_START, TEXTCHANGE3_OLDEND, TEXTCHANGE3_NEWEND)) { - fail("TestNotification: text change 3"); - return PR_FALSE; - } - return PR_TRUE; -} - -nsresult -TestApp::GetSelCon(nsISelectionController** aSelCon) -{ - nsCOMPtr docShell; - nsresult nsr = mWindow->GetDocShell(getter_AddRefs(docShell)); - if (NS_SUCCEEDED(nsr) && docShell) { - nsCOMPtr presShell; - nsr = docShell->GetPresShell(getter_AddRefs(presShell)); - if (NS_SUCCEEDED(nsr) && presShell) { - nsIFrame* frame = presShell->GetPrimaryFrameFor( - nsCOMPtr(do_QueryInterface(mCurrentNode))); - if (frame) { - nsPresContext* presContext = presShell->GetPresContext(); - if (presContext) { - nsr = frame->GetSelectionController(presContext, aSelCon); - } - } - } - } - return nsr; -} - -int main(int argc, char** argv) -{ - ScopedXPCOM xpcom("TestWinTSF (bug #88831)"); - if (xpcom.failed()) - return 1; - - nsRefPtr tests = new TestApp(); - if (!tests) - return 1; - - if (NS_FAILED(tests->Run())) { - fail("run failed"); - return 1; - } - return int(tests->CheckFailed()); -}