From 3f0a190da83d6fc9eea45ef4d584a2ddebe775b7 Mon Sep 17 00:00:00 2001 From: "rods%netscape.com" Date: Tue, 10 Dec 2002 15:03:04 +0000 Subject: [PATCH] Implement filters for spellchecker, so we can skip certain nodes (like Block Quote "cite") for mail Bug 173046 r=jfrancis sr=kin a=asa git-svn-id: svn://10.0.0.236/trunk@135030 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/composer/src/Makefile.in | 1 + .../composer/src/nsComposeTxtSrvFilter.cpp | 90 ++++ .../composer/src/nsComposeTxtSrvFilter.h | 91 ++++ .../composer/src/nsComposerRegistration.cpp | 98 +++- .../composer/src/nsEditorSpellCheck.cpp | 15 +- .../editor/composer/src/nsEditorSpellCheck.h | 4 + mozilla/editor/idl/nsIEditorSpellCheck.idl | 2 + mozilla/editor/libeditor/base/Makefile.in | 1 + mozilla/editor/macbuild/composer.xml | 30 ++ mozilla/editor/txtsvc/macbuild/txtsvc.xml | 30 ++ mozilla/editor/txtsvc/public/MANIFEST_IDL | 1 + mozilla/editor/txtsvc/public/Makefile.in | 4 + .../txtsvc/public/nsITextServicesDocument.h | 7 + .../txtsvc/public/nsITextServicesFilter.idl | 55 ++ mozilla/editor/txtsvc/src/Makefile.in | 1 + .../txtsvc/src/nsFilteredContentIterator.cpp | 480 ++++++++++++++++++ .../txtsvc/src/nsFilteredContentIterator.h | 104 ++++ .../txtsvc/src/nsTextServicesDocument.cpp | 74 ++- .../txtsvc/src/nsTextServicesDocument.h | 15 +- .../editor/ui/dialogs/content/EdSpellCheck.js | 13 +- 20 files changed, 1074 insertions(+), 42 deletions(-) create mode 100644 mozilla/editor/composer/src/nsComposeTxtSrvFilter.cpp create mode 100644 mozilla/editor/composer/src/nsComposeTxtSrvFilter.h create mode 100644 mozilla/editor/txtsvc/public/MANIFEST_IDL create mode 100644 mozilla/editor/txtsvc/public/nsITextServicesFilter.idl create mode 100644 mozilla/editor/txtsvc/src/nsFilteredContentIterator.cpp create mode 100644 mozilla/editor/txtsvc/src/nsFilteredContentIterator.h diff --git a/mozilla/editor/composer/src/Makefile.in b/mozilla/editor/composer/src/Makefile.in index 17673233e4c..c46ce47b1e1 100644 --- a/mozilla/editor/composer/src/Makefile.in +++ b/mozilla/editor/composer/src/Makefile.in @@ -61,6 +61,7 @@ REQUIRES = xpcom \ $(NULL) CPPSRCS = \ + nsComposeTxtSrvFilter.cpp \ nsEditorParserObserver.cpp \ nsComposerController.cpp \ nsComposerCommands.cpp \ diff --git a/mozilla/editor/composer/src/nsComposeTxtSrvFilter.cpp b/mozilla/editor/composer/src/nsComposeTxtSrvFilter.cpp new file mode 100644 index 00000000000..d4ed9b3e31a --- /dev/null +++ b/mozilla/editor/composer/src/nsComposeTxtSrvFilter.cpp @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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): + * + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsComposeTxtSrvFilter.h" +#include "nsIContent.h" +#include "nsIDOMNode.h" +#include "nsString.h" +#include "nsINameSpaceManager.h" + +nsComposeTxtSrvFilter::nsComposeTxtSrvFilter() : + mIsForMail(PR_FALSE) +{ + NS_INIT_ISUPPORTS(); + + mBlockQuoteAtom = getter_AddRefs(do_GetAtom("blockquote")); + mTypeAtom = getter_AddRefs(do_GetAtom("type")); + mScriptAtom = getter_AddRefs(do_GetAtom("script")); + mTextAreaAtom = getter_AddRefs(do_GetAtom("textarea")); + mSelectAreaAtom = getter_AddRefs(do_GetAtom("select")); + mMapAtom = getter_AddRefs(do_GetAtom("map")); +} + +NS_IMPL_ISUPPORTS1(nsComposeTxtSrvFilter, nsITextServicesFilter); + +NS_IMETHODIMP +nsComposeTxtSrvFilter::Skip(nsIDOMNode* aNode, PRBool *_retval) +{ + *_retval = PR_FALSE; + + // Check to see if we can skip this node + // For nodes that are blockquotes, we must make sure + // their type is "cite" + nsCOMPtr content(do_QueryInterface(aNode)); + if (content) { + nsCOMPtr tag; + content->GetTag(*getter_AddRefs(tag)); + if (tag) { + if (tag == mBlockQuoteAtom) { + if (mIsForMail) { + nsAutoString cite; + if (NS_SUCCEEDED(content->GetAttr(kNameSpaceID_None, mTypeAtom, cite))) { + *_retval = cite.EqualsIgnoreCase("cite"); + } + } + } else if (tag == mScriptAtom || + tag == mTextAreaAtom || + tag == mSelectAreaAtom || + tag == mMapAtom) { + *_retval = PR_TRUE; + } + } + } + + return NS_OK; +} diff --git a/mozilla/editor/composer/src/nsComposeTxtSrvFilter.h b/mozilla/editor/composer/src/nsComposeTxtSrvFilter.h new file mode 100644 index 00000000000..717d2e3aa72 --- /dev/null +++ b/mozilla/editor/composer/src/nsComposeTxtSrvFilter.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsComposeTxtSrvFilter_h__ +#define nsComposeTxtSrvFilter_h__ + +#include "nsITextServicesFilter.h" +#include "nsIAtom.h" + +class nsIContent; + +/** + * This class implements a filter interface, that enables + * those usnig it to ski;p over certain nodes when traversing content + * + * This filter is used to skip over various form control nodes and + * mail's cite nodes + */ +class nsComposeTxtSrvFilter : public nsITextServicesFilter +{ +public: + nsComposeTxtSrvFilter(); + virtual ~nsComposeTxtSrvFilter() {}; + + // nsISupports interface... + NS_DECL_ISUPPORTS + + // nsITextServicesFilter + NS_DECL_NSITEXTSERVICESFILTER + + // Helper - Intializer + void Init(PRBool aIsForMail) { mIsForMail = aIsForMail; } + +protected: + PRBool mIsForMail; + nsCOMPtr mBlockQuoteAtom; + nsCOMPtr mTypeAtom; + nsCOMPtr mScriptAtom; + nsCOMPtr mTextAreaAtom; + nsCOMPtr mSelectAreaAtom; + nsCOMPtr mMapAtom; + +}; + +#define NS_COMPOSERTXTSRVFILTER_CID \ +{/* {171E72DB-0F8A-412a-8461-E4C927A3A2AC}*/ \ +0x171e72db, 0xf8a, 0x412a, \ +{ 0x84, 0x61, 0xe4, 0xc9, 0x27, 0xa3, 0xa2, 0xac} } + +// Generic for the editor +#define COMPOSER_TXTSRVFILTER_CONTRACTID "@mozilla.org/editor/txtsrvfilter;1" + +// This is the same but includes "cite" typed blocked quotes +#define COMPOSER_TXTSRVFILTERMAIL_CONTRACTID "@mozilla.org/editor/txtsrvfiltermail;1" + +#endif diff --git a/mozilla/editor/composer/src/nsComposerRegistration.cpp b/mozilla/editor/composer/src/nsComposerRegistration.cpp index 1639254d21c..411ece9193e 100644 --- a/mozilla/editor/composer/src/nsComposerRegistration.cpp +++ b/mozilla/editor/composer/src/nsComposerRegistration.cpp @@ -44,6 +44,7 @@ #include "nsComposerController.h" // for the CID #include "nsEditorSpellCheck.h" // for the CID #include "nsEditorService.h" +#include "nsComposeTxtSrvFilter.h" #include "nsIControllerContext.h" //////////////////////////////////////////////////////////////////////// @@ -56,39 +57,82 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditingSession) NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsEditorSpellCheck) +// There are no macros that enable us to have 2 constructors +// for the same object +// +// Here we are creating the same object with two different contract IDs +// and then initializing it different. +// Basically, we need to tell the filter whether it is doing mail or not +static nsresult +nsComposeTxtSrvFilterConstructor(nsISupports *aOuter, REFNSIID aIID, + void **aResult, PRBool aIsForMail) +{ + *aResult = NULL; + if (NULL != aOuter) + { + return NS_ERROR_NO_AGGREGATION; + } + nsComposeTxtSrvFilter * inst; + NS_NEWXPCOM(inst, nsComposeTxtSrvFilter); + if (NULL == inst) + { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(inst); + inst->Init(aIsForMail); + nsresult rv = inst->QueryInterface(aIID, aResult); + NS_RELEASE(inst); + return rv; +} + +static NS_IMETHODIMP +nsComposeTxtSrvFilterConstructorForComposer(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + return nsComposeTxtSrvFilterConstructor(aOuter, aIID, aResult, PR_TRUE); +} + +static NS_IMETHODIMP +nsComposeTxtSrvFilterConstructorForMail(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + return nsComposeTxtSrvFilterConstructor(aOuter, aIID, aResult, PR_FALSE); +} NS_IMETHODIMP nsEditorDocStateControllerConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) { - static PRBool sDocStateCommandsRegistered = PR_FALSE; + static PRBool sDocStateCommandsRegistered = PR_FALSE; - nsresult rv; - nsCOMPtr context = - do_CreateInstance("@mozilla.org/embedcomp/base-command-controller;1", &rv); - if (NS_FAILED(rv)) - return rv; - if (!context) - return NS_ERROR_FAILURE; - - nsCOMPtr composerCommandManager( - do_GetService(NS_COMPOSERSCONTROLLERCOMMANDMANAGER_CONTRACTID, &rv)); - - if (NS_FAILED(rv)) - return rv; - if (!composerCommandManager) - return NS_ERROR_OUT_OF_MEMORY; - if (!sDocStateCommandsRegistered) - { - rv = nsComposerController::RegisterEditorDocStateCommands(composerCommandManager); + nsresult rv; + nsCOMPtr context = + do_CreateInstance("@mozilla.org/embedcomp/base-command-controller;1", &rv); if (NS_FAILED(rv)) + return rv; + if (!context) + return NS_ERROR_FAILURE; + + nsCOMPtr composerCommandManager( + do_GetService(NS_COMPOSERSCONTROLLERCOMMANDMANAGER_CONTRACTID, &rv)); + + if (NS_FAILED(rv)) + return rv; + if (!composerCommandManager) + return NS_ERROR_OUT_OF_MEMORY; + if (!sDocStateCommandsRegistered) { - return rv; + rv = nsComposerController::RegisterEditorDocStateCommands(composerCommandManager); + if (NS_FAILED(rv)) + { + return rv; + } + sDocStateCommandsRegistered = PR_TRUE; } - sDocStateCommandsRegistered = PR_TRUE; - } - context->SetControllerCommandManager(composerCommandManager); - return context->QueryInterface(aIID, aResult); + context->SetControllerCommandManager(composerCommandManager); + return context->QueryInterface(aIID, aResult); } NS_IMETHODIMP nsHTMLEditorControllerConstructor(nsISupports *aOuter, REFNSIID aIID, @@ -151,6 +195,12 @@ static const nsModuleComponentInfo components[] = { { "Edit Startup Handler", NS_EDITORSERVICE_CID, "@mozilla.org/commandlinehandler/general-startup;1?type=edit", nsEditorServiceConstructor, }, + { "TxtSrv Filter", NS_COMPOSERTXTSRVFILTER_CID, + COMPOSER_TXTSRVFILTER_CONTRACTID, + nsComposeTxtSrvFilterConstructorForComposer, }, + { "TxtSrv Filter For Mail", NS_COMPOSERTXTSRVFILTER_CID, + COMPOSER_TXTSRVFILTERMAIL_CONTRACTID, + nsComposeTxtSrvFilterConstructorForMail, }, }; //////////////////////////////////////////////////////////////////////// diff --git a/mozilla/editor/composer/src/nsEditorSpellCheck.cpp b/mozilla/editor/composer/src/nsEditorSpellCheck.cpp index d714d92a649..34b43ae63a4 100644 --- a/mozilla/editor/composer/src/nsEditorSpellCheck.cpp +++ b/mozilla/editor/composer/src/nsEditorSpellCheck.cpp @@ -53,6 +53,7 @@ #include "nsIChromeRegistry.h" #include "nsString.h" #include "nsReadableUtils.h" +#include "nsComposeTxtSrvFilter.h" static NS_DEFINE_CID(kCTextServicesDocumentCID, NS_TEXTSERVICESDOCUMENT_CID); @@ -88,6 +89,8 @@ nsEditorSpellCheck::InitSpellChecker(nsIEditor* editor) if (!tsDoc) return NS_ERROR_NULL_POINTER; + tsDoc->SetFilter(mTxtSrvFilter); + // Pass the editor to the text services document rv = tsDoc->InitWithEditor(editor); NS_ENSURE_SUCCESS(rv, rv); @@ -401,6 +404,14 @@ nsEditorSpellCheck::UninitSpellChecker() return NS_OK; } +/* void setFilter (in nsITextServicesFilter filter); */ +NS_IMETHODIMP +nsEditorSpellCheck::SetFilter(nsITextServicesFilter *filter) +{ + mTxtSrvFilter = filter; + return NS_OK; +} + nsresult nsEditorSpellCheck::DeleteSuggestedWordList() { @@ -408,7 +419,3 @@ nsEditorSpellCheck::DeleteSuggestedWordList() mSuggestedWordIndex = 0; return NS_OK; } - - - - diff --git a/mozilla/editor/composer/src/nsEditorSpellCheck.h b/mozilla/editor/composer/src/nsEditorSpellCheck.h index 28a9a8d023d..5fc529cf969 100644 --- a/mozilla/editor/composer/src/nsEditorSpellCheck.h +++ b/mozilla/editor/composer/src/nsEditorSpellCheck.h @@ -46,6 +46,8 @@ #include "nsVoidArray.h" #include "nsCOMPtr.h" +#include "nsComposeTxtSrvFilter.h" + #define NS_EDITORSPELLCHECK_CID \ { /* {75656ad9-bd13-4c5d-939a-ec6351eea0cc} */ \ 0x75656ad9, 0xbd13, 0x4c5d, \ @@ -73,6 +75,8 @@ protected: PRInt32 mDictionaryIndex; nsresult DeleteSuggestedWordList(); + + nsCOMPtr mTxtSrvFilter; }; #endif // nsEditorSpellCheck_h___ diff --git a/mozilla/editor/idl/nsIEditorSpellCheck.idl b/mozilla/editor/idl/nsIEditorSpellCheck.idl index 9dee62e0cef..38a61a2ef29 100644 --- a/mozilla/editor/idl/nsIEditorSpellCheck.idl +++ b/mozilla/editor/idl/nsIEditorSpellCheck.idl @@ -39,6 +39,7 @@ #include "nsISupports.idl" interface nsIEditor; +interface nsITextServicesFilter; [scriptable, uuid(87ce8b81-1cf2-11d3-9ce4-c60a16061e7c)] interface nsIEditorSpellCheck : nsISupports @@ -58,5 +59,6 @@ interface nsIEditorSpellCheck : nsISupports wstring GetCurrentDictionary(); void SetCurrentDictionary(in wstring dictionary); void UninitSpellChecker(); + void setFilter(in nsITextServicesFilter filter); }; diff --git a/mozilla/editor/libeditor/base/Makefile.in b/mozilla/editor/libeditor/base/Makefile.in index 658091e41c3..000c43fc12b 100644 --- a/mozilla/editor/libeditor/base/Makefile.in +++ b/mozilla/editor/libeditor/base/Makefile.in @@ -36,6 +36,7 @@ REQUIRES = xpcom \ layout \ content \ txmgr \ + txtsvc \ htmlparser \ necko \ pref \ diff --git a/mozilla/editor/macbuild/composer.xml b/mozilla/editor/macbuild/composer.xml index 9953703567c..27d28310f02 100644 --- a/mozilla/editor/macbuild/composer.xml +++ b/mozilla/editor/macbuild/composer.xml @@ -1000,6 +1000,13 @@ Text Debug + + Name + nsComposeTxtSrvFilter.cpp + MacOS + Text + Debug + Name nsComposerController.cpp @@ -1094,6 +1101,11 @@ nsComposerCommands.cpp MacOS + + Name + nsComposeTxtSrvFilter.cpp + MacOS + Name JavaScriptDebug.shlb @@ -2073,6 +2085,13 @@ Text Debug + + Name + nsComposeTxtSrvFilter.cpp + MacOS + Text + Debug + Name nsComposerController.cpp @@ -2167,6 +2186,11 @@ nsComposerCommands.cpp MacOS + + Name + nsComposeTxtSrvFilter.cpp + MacOS + Name JavaScript.shlb @@ -2214,6 +2238,12 @@ nsComposerCommands.cpp MacOS + + ComposerDebug.shlb + Name + nsComposeTxtSrvFilter.cpp + MacOS + ComposerDebug.shlb Name diff --git a/mozilla/editor/txtsvc/macbuild/txtsvc.xml b/mozilla/editor/txtsvc/macbuild/txtsvc.xml index 3aa86df6ced..617b8054e95 100644 --- a/mozilla/editor/txtsvc/macbuild/txtsvc.xml +++ b/mozilla/editor/txtsvc/macbuild/txtsvc.xml @@ -981,6 +981,13 @@ Text Debug + + Name + nsFilteredContentIterator.cpp + MacOS + Text + Debug + Name NSRuntime.shlb @@ -1057,6 +1064,11 @@ nsTextServicesDocument.cpp MacOS + + Name + nsFilteredContentIterator.cpp + MacOS + Name NSRuntime.shlb @@ -2012,6 +2024,13 @@ Text Debug + + Name + nsFilteredContentIterator.cpp + MacOS + Text + Debug + Name NSStdLibDebug.shlb @@ -2088,6 +2107,11 @@ nsTextServicesDocument.cpp MacOS + + Name + nsFilteredContentIterator.cpp + MacOS + Name NSStdLibDebug.shlb @@ -2130,6 +2154,12 @@ nsTextServicesDocument.cpp MacOS + + TextServices.shlb + Name + nsFilteredContentIterator.cpp + MacOS + TextServices.shlb Name diff --git a/mozilla/editor/txtsvc/public/MANIFEST_IDL b/mozilla/editor/txtsvc/public/MANIFEST_IDL new file mode 100644 index 00000000000..38637fa1ec5 --- /dev/null +++ b/mozilla/editor/txtsvc/public/MANIFEST_IDL @@ -0,0 +1 @@ +nsITextServicesFilter.idl diff --git a/mozilla/editor/txtsvc/public/Makefile.in b/mozilla/editor/txtsvc/public/Makefile.in index 970fd2318db..11a4277af50 100644 --- a/mozilla/editor/txtsvc/public/Makefile.in +++ b/mozilla/editor/txtsvc/public/Makefile.in @@ -35,5 +35,9 @@ EXPORTS = \ nsTextServicesCID.h \ $(NULL) +XPIDLSRCS = \ + nsITextServicesFilter.idl \ + $(NULL) + include $(topsrcdir)/config/rules.mk diff --git a/mozilla/editor/txtsvc/public/nsITextServicesDocument.h b/mozilla/editor/txtsvc/public/nsITextServicesDocument.h index 23a98fcd0b8..99c2cfe1932 100644 --- a/mozilla/editor/txtsvc/public/nsITextServicesDocument.h +++ b/mozilla/editor/txtsvc/public/nsITextServicesDocument.h @@ -45,6 +45,7 @@ class nsIDOMDocument; class nsIPresShell; class nsIEditor; class nsString; +class nsITextServicesFilter; /* TextServicesDocument interface to outside world @@ -94,6 +95,12 @@ public: */ NS_IMETHOD InitWithEditor(nsIEditor *aEditor) = 0; + /** + * Sets the filter to be used while iterating over content. + * @param aFilter filter to be used while iterating over content. + */ + NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter) = 0; + /** * Returns true if the document can be modified with calls * to DeleteSelection() and InsertText(). diff --git a/mozilla/editor/txtsvc/public/nsITextServicesFilter.idl b/mozilla/editor/txtsvc/public/nsITextServicesFilter.idl new file mode 100644 index 00000000000..96bd01f4408 --- /dev/null +++ b/mozilla/editor/txtsvc/public/nsITextServicesFilter.idl @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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): + * Rod Spears + * + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIDOMNode; + +[scriptable, uuid(5BEC321F-59AC-413a-A4AD-8A8D7C50A0D0)] +interface nsITextServicesFilter : nsISupports +{ + + /** + * Indicates whether the content node should be skipped by the iterator + * @param aNode - node to skip + */ + boolean skip(in nsIDOMNode aNode); + +}; + diff --git a/mozilla/editor/txtsvc/src/Makefile.in b/mozilla/editor/txtsvc/src/Makefile.in index 3fcc9ca1ff5..dad37558279 100644 --- a/mozilla/editor/txtsvc/src/Makefile.in +++ b/mozilla/editor/txtsvc/src/Makefile.in @@ -43,6 +43,7 @@ REQUIRES = xpcom \ $(NULL) CPPSRCS = \ + nsFilteredContentIterator.cpp \ nsTextServicesDocument.cpp \ nsTSDNotifier.cpp \ $(NULL) diff --git a/mozilla/editor/txtsvc/src/nsFilteredContentIterator.cpp b/mozilla/editor/txtsvc/src/nsFilteredContentIterator.cpp new file mode 100644 index 00000000000..a790b994a6b --- /dev/null +++ b/mozilla/editor/txtsvc/src/nsFilteredContentIterator.cpp @@ -0,0 +1,480 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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): + * + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsFilteredContentIterator.h" +#include "nsIContentIterator.h" +#include "nsContentCID.h" +#include "nsIContent.h" +#include "nsString.h" +#include "nsIEnumerator.h" + +#include "nsTextServicesDocument.h" + +#include "nsIDOMNode.h" +#include "nsIDOMRange.h" + +static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); +static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID); +static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID); + +//------------------------------------------------------------ +nsFilteredContentIterator::nsFilteredContentIterator(nsITextServicesFilter* aFilter) : + mFilter(aFilter), + mDidSkip(PR_FALSE), + mIsOutOfRange(PR_FALSE), + mDirection(eDirNotSet) +{ + NS_INIT_ISUPPORTS(); + + nsComponentManager::CreateInstance(kCContentIteratorCID, + nsnull, + NS_GET_IID(nsIContentIterator), + getter_AddRefs(mIterator)); + + nsComponentManager::CreateInstance(kCPreContentIteratorCID, + nsnull, + NS_GET_IID(nsIContentIterator), + getter_AddRefs(mPreIterator)); + +} + +//------------------------------------------------------------ +nsFilteredContentIterator::~nsFilteredContentIterator() +{ + mIterator = nsnull; +} + +//------------------------------------------------------------ +NS_IMPL_ISUPPORTS1(nsFilteredContentIterator, nsIContentIterator); + +//------------------------------------------------------------ +NS_IMETHODIMP +nsFilteredContentIterator::Init(nsIContent* aRoot) +{ + NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE); + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); + mIsOutOfRange = PR_FALSE; + mDirection = eForward; + mCurrentIterator = mPreIterator; + + nsresult rv = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull, + NS_GET_IID(nsIDOMRange), + getter_AddRefs(mRange)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr domRange(do_QueryInterface(mRange)); + nsCOMPtr domNode(do_QueryInterface(aRoot)); + if (domRange && domNode) { + domRange->SelectNode(domNode); + } + + rv = mPreIterator->Init(domRange); + NS_ENSURE_SUCCESS(rv, rv); + return mIterator->Init(domRange); +} + +//------------------------------------------------------------ +NS_IMETHODIMP +nsFilteredContentIterator::Init(nsIDOMRange* aRange) +{ + NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE); + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); + NS_ENSURE_ARG_POINTER(aRange); + mIsOutOfRange = PR_FALSE; + mDirection = eForward; + mCurrentIterator = mPreIterator; + + nsCOMPtr domRange; + nsresult rv = aRange->CloneRange(getter_AddRefs(domRange)); + NS_ENSURE_SUCCESS(rv, rv); + mRange = do_QueryInterface(domRange); + + rv = mPreIterator->Init(domRange); + NS_ENSURE_SUCCESS(rv, rv); + return mIterator->Init(domRange); +} + +//------------------------------------------------------------ +nsresult +nsFilteredContentIterator::SwitchDirections(PRPackedBool aChangeToForward) +{ + nsCOMPtr node; + mCurrentIterator->CurrentNode(getter_AddRefs(node)); + + if (aChangeToForward) { + mCurrentIterator = mPreIterator; + mDirection = eForward; + } else { + mCurrentIterator = mIterator; + mDirection = eBackward; + } + + if (node) { + nsresult rv = mCurrentIterator->PositionAt(node); + if (NS_FAILED(rv)) { + mIsOutOfRange = PR_TRUE; + return rv; + } + } + return NS_OK; +} + +//------------------------------------------------------------ +NS_IMETHODIMP +nsFilteredContentIterator::First() +{ + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + + // If we are switching directions then + // we need to switch how we process the nodes + if (mDirection != eForward) { + mCurrentIterator = mPreIterator; + mDirection = eForward; + mIsOutOfRange = PR_FALSE; + } + + nsresult rv = mCurrentIterator->First(); + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_ENUMERATOR_FALSE != mCurrentIterator->IsDone()) { + return NS_OK; + } + + nsCOMPtr currentContent; + rv = mCurrentIterator->CurrentNode(getter_AddRefs(currentContent)); + nsCOMPtr node(do_QueryInterface(currentContent)); + + PRPackedBool didCross; + CheckAdvNode(node, didCross, eForward); + + return NS_OK; +} + +//------------------------------------------------------------ +NS_IMETHODIMP +nsFilteredContentIterator::Last() +{ + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + + // If we are switching directions then + // we need to switch how we process the nodes + if (mDirection != eBackward) { + mCurrentIterator = mIterator; + mDirection = eBackward; + mIsOutOfRange = PR_FALSE; + } + + nsresult rv = mCurrentIterator->Last(); + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_ENUMERATOR_FALSE != mCurrentIterator->IsDone()) { + return NS_OK; + } + + nsCOMPtr currentContent; + rv = mCurrentIterator->CurrentNode(getter_AddRefs(currentContent)); + nsCOMPtr node(do_QueryInterface(currentContent)); + + PRPackedBool didCross; + CheckAdvNode(node, didCross, eBackward); + + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////// +// ContentToParentOffset: returns the content node's parent and offset. +// +static void +ContentToParentOffset(nsIContent *aContent, nsIDOMNode **aParent, PRInt32 *aOffset) +{ + if (!aParent || !aOffset) + return; + + *aParent = nsnull; + *aOffset = 0; + + if (!aContent) + return; + + nsCOMPtr parent; + nsresult rv = aContent->GetParent(*getter_AddRefs(parent)); + + if (NS_FAILED(rv) || !parent) + return; + + rv = parent->IndexOf(aContent, *aOffset); + + if (NS_FAILED(rv)) + return; + + CallQueryInterface(parent, aParent); +} + +/////////////////////////////////////////////////////////////////////////// +// ContentIsInTraversalRange: returns true if content is visited during +// the traversal of the range in the specified mode. +// +static PRBool +ContentIsInTraversalRange(nsIContent *aContent, PRBool aIsPreMode, + nsIDOMNode *aStartNode, PRInt32 aStartOffset, + nsIDOMNode *aEndNode, PRInt32 aEndOffset) +{ + if (!aStartNode || !aEndNode || !aContent) + return PR_FALSE; + + nsCOMPtr parentNode; + PRInt32 indx = 0; + + ContentToParentOffset(aContent, getter_AddRefs(parentNode), &indx); + + if (!parentNode) + return PR_FALSE; + + if (!aIsPreMode) + ++indx; + + PRInt32 startRes; + PRInt32 endRes; + nsresult rv = nsTextServicesDocument::ComparePoints(aStartNode, aStartOffset, parentNode, indx, &startRes); + if (NS_FAILED(rv)) return PR_FALSE; + + rv = nsTextServicesDocument::ComparePoints(aEndNode, aEndOffset, parentNode, indx, &endRes); + if (NS_FAILED(rv)) return PR_FALSE; + + return (startRes <= 0) && (endRes >= 0); +} + +static PRBool +ContentIsInTraversalRange(nsIDOMNSRange *aRange, nsIDOMNode* aNextNode, PRBool aIsPreMode) +{ + nsCOMPtr content(do_QueryInterface(aNextNode)); + nsCOMPtr range(do_QueryInterface(aRange)); + if (!content || !range) + return PR_FALSE; + + + + nsCOMPtr sNode; + nsCOMPtr eNode; + PRInt32 sOffset; + PRInt32 eOffset; + range->GetStartContainer(getter_AddRefs(sNode)); + range->GetStartOffset(&sOffset); + range->GetEndContainer(getter_AddRefs(eNode)); + range->GetEndOffset(&eOffset); + return ContentIsInTraversalRange(content, aIsPreMode, sNode, sOffset, eNode, eOffset); +} + +//------------------------------------------------------------ +// Helper function to advance to the next or previous node +nsresult +nsFilteredContentIterator::AdvanceNode(nsIDOMNode* aNode, nsIDOMNode*& aNewNode, eDirectionType aDir) +{ + nsCOMPtr nextNode; + if (aDir == eForward) { + aNode->GetNextSibling(getter_AddRefs(nextNode)); + } else { + aNode->GetPreviousSibling(getter_AddRefs(nextNode)); + } + + if (nextNode) { + // If we got here, that means we found the nxt/prv node + // make sure it is in our DOMRange + PRBool intersects = ContentIsInTraversalRange(mRange, nextNode, aDir == eForward); + if (intersects) { + aNewNode = nextNode; + NS_ADDREF(aNewNode); + return NS_OK; + } + } else { + // The next node was null so we need to walk up the parent(s) + nsCOMPtr parent; + aNode->GetParentNode(getter_AddRefs(parent)); + NS_ASSERTION(parent, "parent can't be NULL"); + + // Make sure the parent is in the DOMRange before going further + PRBool intersects = ContentIsInTraversalRange(mRange, nextNode, aDir == eForward); + if (intersects) { + // Now find the nxt/prv node after/before this node + nsresult rv = AdvanceNode(parent, aNewNode, aDir); + if (NS_SUCCEEDED(rv) && aNewNode) { + return NS_OK; + } + } + } + + // if we get here it pretty much means + // we went out of the DOM Range + mIsOutOfRange = PR_TRUE; + + return NS_ERROR_FAILURE; +} + +//------------------------------------------------------------ +// Helper function to see if the next/prev node should be skipped +void +nsFilteredContentIterator::CheckAdvNode(nsIDOMNode* aNode, PRPackedBool& aDidSkip, eDirectionType aDir) +{ + aDidSkip = PR_FALSE; + mIsOutOfRange = PR_FALSE; + + if (aNode && mFilter) { + nsCOMPtr currentNode = aNode; + PRBool skipIt; + while (1) { + nsresult rv = mFilter->Skip(aNode, &skipIt); + if (NS_SUCCEEDED(rv) && skipIt) { + aDidSkip = PR_TRUE; + // Get the next/prev node and then + // see if we should skip that + nsCOMPtr advNode; + rv = AdvanceNode(aNode, *getter_AddRefs(advNode), aDir); + if (NS_SUCCEEDED(rv) && advNode) { + aNode = advNode; + } else { + return; // fell out of range + } + } else { + if (aNode != currentNode) { + nsCOMPtr content(do_QueryInterface(aNode)); + mCurrentIterator->PositionAt(content); + } + return; // found something + } + } + } +} + +NS_IMETHODIMP +nsFilteredContentIterator::Next() +{ + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + + if (mIsOutOfRange) { + return NS_OK; + } + // If we are switching directions then + // we need to switch how we process the nodes + if (mDirection != eForward) { + nsresult rv = SwitchDirections(PR_TRUE); + if (NS_FAILED(rv)) { + return NS_OK; + } + } + + nsresult rv = mCurrentIterator->Next(); + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_ENUMERATOR_FALSE != mCurrentIterator->IsDone()) { + return NS_OK; + } + + // If we can't get the current node then + // don't check to see if we can skip it + nsCOMPtr currentContent; + rv = mCurrentIterator->CurrentNode(getter_AddRefs(currentContent)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr node(do_QueryInterface(currentContent)); + CheckAdvNode(node, mDidSkip, eForward); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFilteredContentIterator::Prev() +{ + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + + if (mIsOutOfRange) { + return NS_OK; + } + // If we are switching directions then + // we need to switch how we process the nodes + if (mDirection != eBackward) { + nsresult rv = SwitchDirections(PR_FALSE); + if (NS_FAILED(rv)) { + return NS_OK; + } + } + + nsresult rv = mCurrentIterator->Prev(); + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_ENUMERATOR_FALSE != mCurrentIterator->IsDone()) { + return NS_OK; + } + + // If we can't get the current node then + // don't check to see if we can skip it + nsCOMPtr currentContent; + rv = mCurrentIterator->CurrentNode(getter_AddRefs(currentContent)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr node(do_QueryInterface(currentContent)); + CheckAdvNode(node, mDidSkip, eBackward); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFilteredContentIterator::CurrentNode(nsIContent **aNode) +{ + if (mIsOutOfRange) { + return NS_ERROR_FAILURE; + } + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + return mCurrentIterator->CurrentNode(aNode); +} + +NS_IMETHODIMP +nsFilteredContentIterator::IsDone() +{ + if (mIsOutOfRange) { + return NS_OK; + } + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + return mCurrentIterator->IsDone(); +} + +NS_IMETHODIMP +nsFilteredContentIterator::PositionAt(nsIContent* aCurNode) +{ + NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE); + mIsOutOfRange = PR_FALSE; + return mCurrentIterator->PositionAt(aCurNode); +} diff --git a/mozilla/editor/txtsvc/src/nsFilteredContentIterator.h b/mozilla/editor/txtsvc/src/nsFilteredContentIterator.h new file mode 100644 index 00000000000..a839bfcb89f --- /dev/null +++ b/mozilla/editor/txtsvc/src/nsFilteredContentIterator.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsFilteredContentIterator_h__ +#define nsFilteredContentIterator_h__ + +#include "nsIContentIterator.h" +#include "nsCOMPtr.h" +#include "nsIAtom.h" +#include "nsITextServicesFilter.h" +#include "nsIDOMNSRange.h" +#include "nsIRangeUtils.h" + +/** + * + */ +class nsFilteredContentIterator : public nsIContentIterator +{ +public: + + // nsISupports interface... + NS_DECL_ISUPPORTS + + nsFilteredContentIterator(nsITextServicesFilter* aFilter); + + virtual ~nsFilteredContentIterator(); + + /* nsIContentIterator */ + NS_IMETHOD Init(nsIContent* aRoot); + NS_IMETHOD Init(nsIDOMRange* aRange); + NS_IMETHOD First(); + NS_IMETHOD Last(); + NS_IMETHOD Next(); + NS_IMETHOD Prev(); + NS_IMETHOD CurrentNode(nsIContent **aNode); + NS_IMETHOD IsDone(); + NS_IMETHOD PositionAt(nsIContent* aCurNode); + + /* Helpers */ + PRPackedBool DidSkip() { return mDidSkip; } + void ClearDidSkip() { mDidSkip = PR_FALSE; } + +protected: + nsFilteredContentIterator() { } + + // enum to give us the direction + typedef enum {eDirNotSet, eForward, eBackward} eDirectionType; + nsresult AdvanceNode(nsIDOMNode* aNode, nsIDOMNode*& aNewNode, eDirectionType aDir); + void CheckAdvNode(nsIDOMNode* aNode, PRPackedBool& aDidSkip, eDirectionType aDir); + nsresult SwitchDirections(PRPackedBool aChangeToForward); + + nsCOMPtr mCurrentIterator; + nsCOMPtr mIterator; + nsCOMPtr mPreIterator; + + nsCOMPtr mBlockQuoteAtom; + nsCOMPtr mScriptAtom; + nsCOMPtr mTextAreaAtom; + nsCOMPtr mSelectAreaAtom; + nsCOMPtr mMapAtom; + + nsCOMPtr mFilter; + nsCOMPtr mRange; + PRPackedBool mDidSkip; + PRPackedBool mIsOutOfRange; + eDirectionType mDirection; +}; + +#endif diff --git a/mozilla/editor/txtsvc/src/nsTextServicesDocument.cpp b/mozilla/editor/txtsvc/src/nsTextServicesDocument.cpp index ad483d87f32..4a6218f04de 100644 --- a/mozilla/editor/txtsvc/src/nsTextServicesDocument.cpp +++ b/mozilla/editor/txtsvc/src/nsTextServicesDocument.cpp @@ -49,6 +49,7 @@ #include "nsISelection.h" #include "nsIPlaintextEditor.h" #include "nsTextServicesDocument.h" +#include "nsFilteredContentIterator.h" #include "nsIDOMElement.h" #include "nsIDOMHTMLElement.h" @@ -390,6 +391,15 @@ nsTextServicesDocument::InitWithEditor(nsIEditor *aEditor) return result; } +NS_IMETHODIMP +nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter) +{ + // Hang on to the filter so we can set it into the filtered iterator. + mTxtSvcFilter = aFilter; + + return NS_OK; +} + NS_IMETHODIMP nsTextServicesDocument::CanEdit(PRBool *aCanEdit) { @@ -2580,12 +2590,19 @@ nsTextServicesDocument::CreateContentIterator(nsIDOMRange *aRange, nsIContentIte *aIterator = 0; - result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, - NS_GET_IID(nsIContentIterator), - (void **)aIterator); - - if (NS_FAILED(result)) - return result; + // Create a nsFilteredContentIterator + // This class wraps the ContentIterator in order to give itself a chance + // to filter out certain content nodes + nsFilteredContentIterator* filter = new nsFilteredContentIterator(mTxtSvcFilter); + *aIterator = NS_STATIC_CAST(nsIContentIterator *, filter); + if (*aIterator) { + NS_IF_ADDREF(*aIterator); + result = filter ? NS_OK : NS_ERROR_FAILURE; + } else { + delete filter; + result = NS_ERROR_FAILURE; + } + NS_ENSURE_SUCCESS(result, result); if (!*aIterator) return NS_ERROR_NULL_POINTER; @@ -2928,6 +2945,33 @@ nsTextServicesDocument::AdjustContentIterator() return NS_OK; } +PRBool +nsTextServicesDocument::DidSkip(nsIContentIterator* aFilteredIter) +{ + // We can assume here that the Iterator is a nsFilteredContentIterator because + // all the iterator are created in CreateContentIterator which create a + // nsFilteredContentIterator + // So if the iterator bailed on one of the "filtered" content nodes then we + // consider that to be a block and bail with PR_TRUE + if (aFilteredIter) { + nsFilteredContentIterator* filter = NS_STATIC_CAST(nsFilteredContentIterator *, aFilteredIter); + if (filter && filter->DidSkip()) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void +nsTextServicesDocument::ClearDidSkip(nsIContentIterator* aFilteredIter) +{ + // Clear filter's skip flag + if (aFilteredIter) { + nsFilteredContentIterator* filter = NS_STATIC_CAST(nsFilteredContentIterator *, aFilteredIter); + filter->ClearDidSkip(); + } +} + PRBool nsTextServicesDocument::IsBlockNode(nsIContent *aContent) { @@ -4024,6 +4068,8 @@ nsTextServicesDocument::FirstTextNodeInCurrentBlock(nsIContentIterator *iter) if (!iter) return NS_ERROR_NULL_POINTER; + ClearDidSkip(iter); + nsCOMPtr content; nsCOMPtr last; @@ -4055,6 +4101,9 @@ nsTextServicesDocument::FirstTextNodeInCurrentBlock(nsIContentIterator *iter) if (NS_FAILED(result)) return result; + + if (DidSkip(iter)) + break; } if (last) @@ -4107,6 +4156,8 @@ nsTextServicesDocument::FirstTextNodeInNextBlock(nsIContentIterator *aIterator) if (!aIterator) return NS_ERROR_NULL_POINTER; + ClearDidSkip(aIterator); + while (NS_ENUMERATOR_FALSE == aIterator->IsDone()) { result = aIterator->CurrentNode(getter_AddRefs(content)); @@ -4122,15 +4173,17 @@ nsTextServicesDocument::FirstTextNodeInNextBlock(nsIContentIterator *aIterator) prev = content; else break; - } - else if (IsBlockNode(content)) + else if (!crossedBlockBoundary && IsBlockNode(content)) crossedBlockBoundary = PR_TRUE; result = aIterator->Next(); if (NS_FAILED(result)) return result; + + if (!crossedBlockBoundary && DidSkip(aIterator)) + crossedBlockBoundary = PR_TRUE; } return NS_OK; @@ -4255,6 +4308,8 @@ nsTextServicesDocument::CreateOffsetTable(nsString *aStr) PRInt32 offset = 0; + ClearDidSkip(mIterator); + while (NS_ENUMERATOR_FALSE == mIterator->IsDone()) { result = mIterator->CurrentNode(getter_AddRefs(content)); @@ -4318,6 +4373,9 @@ nsTextServicesDocument::CreateOffsetTable(nsString *aStr) if (NS_FAILED(result)) return result; + + if (DidSkip(mIterator)) + break; } if (first) diff --git a/mozilla/editor/txtsvc/src/nsTextServicesDocument.h b/mozilla/editor/txtsvc/src/nsTextServicesDocument.h index 0309bec60a0..bc765be3d8e 100644 --- a/mozilla/editor/txtsvc/src/nsTextServicesDocument.h +++ b/mozilla/editor/txtsvc/src/nsTextServicesDocument.h @@ -51,6 +51,7 @@ #include "nsVoidArray.h" #include "nsTSDNotifier.h" #include "nsISelectionController.h" +#include "nsITextServicesFilter.h" /** implementation of a text services object. * @@ -109,6 +110,8 @@ private: PRInt32 mSelEndIndex; PRInt32 mSelEndOffset; + nsCOMPtr mTxtSvcFilter; + public: /** The default constructor. @@ -125,6 +128,7 @@ public: /* nsITextServicesDocument method implementations. */ NS_IMETHOD InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell); NS_IMETHOD InitWithEditor(nsIEditor *aEditor); + NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter); NS_IMETHOD CanEdit(PRBool *aCanEdit); NS_IMETHOD GetCurrentTextBlock(nsString *aStr); NS_IMETHOD FirstBlock(); @@ -152,6 +156,11 @@ public: nsIDOMNode *aRightNode, nsIDOMNode *aParent); + /* Helper functions */ + static nsresult ComparePoints(nsIDOMNode *aParent1, PRInt32 aOffset1, nsIDOMNode *aParent2, PRInt32 aOffset2, PRInt32 *aResult); + static nsresult GetRangeEndPoints(nsIDOMRange *aRange, nsIDOMNode **aParent1, PRInt32 *aOffset1, nsIDOMNode **aParent2, PRInt32 *aOffset2); + static nsresult CreateRange(nsIDOMNode *aStartParent, PRInt32 aStartOffset, nsIDOMNode *aEndParent, PRInt32 aEndOffset, nsIDOMRange **aRange); + private: /* nsTextServicesDocument private methods. */ @@ -174,6 +183,8 @@ private: PRBool IsBlockNode(nsIContent *aContent); PRBool IsTextNode(nsIContent *aContent); PRBool IsTextNode(nsIDOMNode *aNode); + PRBool DidSkip(nsIContentIterator* aFilteredIter); + void ClearDidSkip(nsIContentIterator* aFilteredIter); PRBool HasSameBlockNodeParent(nsIContent *aContent1, nsIContent *aContent2); @@ -185,10 +196,6 @@ private: PRBool SelectionIsCollapsed(); PRBool SelectionIsValid(); - nsresult ComparePoints(nsIDOMNode *aParent1, PRInt32 aOffset1, nsIDOMNode *aParent2, PRInt32 aOffset2, PRInt32 *aResult); - nsresult GetRangeEndPoints(nsIDOMRange *aRange, nsIDOMNode **aParent1, PRInt32 *aOffset1, nsIDOMNode **aParent2, PRInt32 *aOffset2); - nsresult CreateRange(nsIDOMNode *aStartParent, PRInt32 aStartOffset, nsIDOMNode *aEndParent, PRInt32 aEndOffset, nsIDOMRange **aRange); - nsresult RemoveInvalidOffsetEntries(); nsresult CreateOffsetTable(nsString *aStr=0); nsresult ClearOffsetTable(); diff --git a/mozilla/editor/ui/dialogs/content/EdSpellCheck.js b/mozilla/editor/ui/dialogs/content/EdSpellCheck.js index dc01da11518..200d4337145 100644 --- a/mozilla/editor/ui/dialogs/content/EdSpellCheck.js +++ b/mozilla/editor/ui/dialogs/content/EdSpellCheck.js @@ -37,6 +37,7 @@ function Startup() window.close(); return; } + // Get the spellChecker shell gSpellChecker = Components.classes['@mozilla.org/editor/editorspellchecker;1'].createInstance(Components.interfaces.nsIEditorSpellCheck); if (!gSpellChecker) @@ -48,7 +49,16 @@ function Startup() // Start the spell checker module. try { - gSpellChecker.InitSpellChecker(GetCurrentEditor()); + // TxtSrv Filter Contract Id + var filterContractId; + gSendMailMessageMode = window.arguments[0]; + if (gSendMailMessageMode) + filterContractId = "@mozilla.org/editor/txtsrvfiltermail;1"; + else + filterContractId = "@mozilla.org/editor/txtsrvfilter;1"; + + gSpellChecker.setFilter(Components.classes[filterContractId].createInstance(Components.interfaces.nsITextServicesFilter)); + gSpellChecker.InitSpellChecker(GetCurrentEditor()); // XXX: We need to read in a pref here so we can set the // default language for the spellchecker! @@ -88,7 +98,6 @@ function Startup() // When startup param is true, setup different UI when spell checking // just before sending mail message - gSendMailMessageMode = window.arguments[0]; if (gSendMailMessageMode) { // If no misspelled words found, simply close dialog and send message