From db89a9ce2198de317046682c7664397ca10bcf98 Mon Sep 17 00:00:00 2001 From: "heikki%netscape.com" Date: Thu, 20 Dec 2001 05:15:52 +0000 Subject: [PATCH] Bug 74800, implemented FIXptr. r=harishd, sr=vidur. --- content/base/src/nsDocument.cpp | 8 + content/macbuild/content.xml | 30 ++ content/xml/document/src/Makefile.in | 1 + content/xml/document/src/makefile.win | 1 + content/xml/document/src/nsFIXptr.cpp | 333 ++++++++++++++++++ content/xml/document/src/nsFIXptr.h | 73 ++++ content/xml/document/src/nsXMLDocument.cpp | 8 +- dom/public/idl/core/nsIDOMXMLDocument.idl | 10 + .../xmlextras/pointers/src/nsFIXptr.cpp | 333 ++++++++++++++++++ extensions/xmlextras/pointers/src/nsFIXptr.h | 73 ++++ layout/base/nsPresShell.cpp | 50 ++- layout/html/base/src/nsPresShell.cpp | 50 ++- 12 files changed, 935 insertions(+), 35 deletions(-) create mode 100644 content/xml/document/src/nsFIXptr.cpp create mode 100644 content/xml/document/src/nsFIXptr.h create mode 100644 extensions/xmlextras/pointers/src/nsFIXptr.cpp create mode 100644 extensions/xmlextras/pointers/src/nsFIXptr.h diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index ad62b1d856e4..aea95acfae00 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2119,6 +2119,14 @@ nsDocument::Load(const nsAReadableString& aUrl) return NS_OK; } + +NS_IMETHODIMP +nsDocument::EvaluateFIXptr(const nsAReadableString& aExpression, nsIDOMRange **aRange) +{ + NS_ERROR("nsDocument::EvaluateFIXptr() should be overriden by subclass!"); + + return NS_OK; +} NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) diff --git a/content/macbuild/content.xml b/content/macbuild/content.xml index e2f799e7b15d..584de9b08c55 100644 --- a/content/macbuild/content.xml +++ b/content/macbuild/content.xml @@ -2373,6 +2373,13 @@ Library Debug + + Name + nsFIXptr.cpp + MacOS + Text + Debug + @@ -3420,6 +3427,11 @@ contentSVG.o MacOS + + Name + nsFIXptr.cpp + MacOS + @@ -5742,6 +5754,13 @@ Library Debug + + Name + nsFIXptr.cpp + MacOS + Text + Debug + @@ -6789,6 +6808,11 @@ contentSVGDebug.o MacOS + + Name + nsFIXptr.cpp + MacOS + @@ -7770,6 +7794,12 @@ nsXMLDocument.cpp MacOS + + content.shlb + Name + nsFIXptr.cpp + MacOS + xsl diff --git a/content/xml/document/src/Makefile.in b/content/xml/document/src/Makefile.in index e25b7b24995b..8fe229fd0fdd 100644 --- a/content/xml/document/src/Makefile.in +++ b/content/xml/document/src/Makefile.in @@ -55,6 +55,7 @@ REQUIRES = xpcom \ CPPSRCS = \ nsXMLContentSink.cpp \ nsXMLDocument.cpp \ + nsFIXptr.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff --git a/content/xml/document/src/makefile.win b/content/xml/document/src/makefile.win index 8510158fc15a..3ad6434dd860 100644 --- a/content/xml/document/src/makefile.win +++ b/content/xml/document/src/makefile.win @@ -52,6 +52,7 @@ DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN CPP_OBJS= \ .\$(OBJDIR)\nsXMLContentSink.obj \ .\$(OBJDIR)\nsXMLDocument.obj \ + .\$(OBJDIR)\nsFIXptr.obj \ $(NULL) EXPORTS = \ diff --git a/content/xml/document/src/nsFIXptr.cpp b/content/xml/document/src/nsFIXptr.cpp new file mode 100644 index 000000000000..8962b5c2f191 --- /dev/null +++ b/content/xml/document/src/nsFIXptr.cpp @@ -0,0 +1,333 @@ +/* -*- 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) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Heikki Toivonen (original author) + * + * 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 ***** */ + +/** + * Implementation for FIXptr, a W3C NOTE. + * + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + * + */ +#include "nsIDOMDocument.h" +#include "nsIContent.h" +#include "nsIDOMRange.h" +#include "nsISelection.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" +#include "nsIDOMNodeList.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsFIXptr.h" + +#include "nsContentCID.h" +static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); + +// Get nth child element +static nsresult GetChild(nsIDOMNode *aParent, PRInt32 aChildNum, nsIDOMNode **aChild) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aChild); + + *aChild = nsnull; + nsCOMPtr list; + aParent->GetChildNodes(getter_AddRefs(list)); + if (!list) + return NS_OK; + + PRUint32 count; + list->GetLength(&count); + PRUint32 i; + PRInt32 curChildNum = 0; + for (i = 0; i < count; i++) { + nsCOMPtr node; + list->Item(i, getter_AddRefs(node)); + if (!node) + break; + PRUint16 nodeType; + node->GetNodeType(&nodeType); + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + curChildNum++; + } + if (curChildNum == aChildNum) { + *aChild = node; + NS_ADDREF(*aChild); + break; + } + } + return NS_OK; +} + +// Get range for char index +static nsresult GetCharRange(nsIDOMNode *aParent, PRInt32 aCharNum, nsIDOMRange **aRange) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aRange); + + *aRange = nsnull; + nsCOMPtr list; + aParent->GetChildNodes(getter_AddRefs(list)); + if (!list) + return NS_OK; + + PRUint32 count; + list->GetLength(&count); + PRUint32 i; + PRInt32 maxCharNum = 0; + PRInt32 prevCharNum = 0; + for (i = 0; i < count; i++) { + nsCOMPtr node; + list->Item(i, getter_AddRefs(node)); + if (!node) + break; + PRUint16 nodeType; + node->GetNodeType(&nodeType); + if (nodeType & (nsIDOMNode::TEXT_NODE | nsIDOMNode::CDATA_SECTION_NODE)) { + nsAutoString value; + node->GetNodeValue(value); + maxCharNum += value.Length(); + } + if (maxCharNum >= aCharNum) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) + return NS_ERROR_OUT_OF_MEMORY; + range->SetStart(node, aCharNum - prevCharNum); + range->SetEnd(node, aCharNum - prevCharNum + 1); + *aRange = range.get(); + NS_ADDREF(*aRange); + break; + } + prevCharNum = maxCharNum; + } + return NS_OK; +} + +// Get node by tumbler +static nsresult GetTumblerNode(nsIDOMNode *aParent, const nsString &aTumbler, nsIDOMNode **aNode) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aNode); + + *aNode = nsnull; + nsAutoString tumbler(aTumbler); + if (tumbler[0] == '/') + tumbler.Cut(0, 1); + nsCOMPtr node(aParent); + while (!tumbler.IsEmpty() && node) { + PRInt32 sep = tumbler.FindChar('/'); + if (sep > 0) { + nsAutoString num; + tumbler.Left(num, sep); + PRInt32 error; + PRInt32 n = num.ToInteger(&error); + if (n <= 0) { + node = nsnull; + break; + } + nsCOMPtr child; + GetChild(node, n, getter_AddRefs(child)); + node = child; + } else { + // Last + PRInt32 error; + PRInt32 n = tumbler.ToInteger(&error); + if (n <= 0) { + node = nsnull; + break; + } + nsCOMPtr child; + GetChild(node, n, getter_AddRefs(child)); + node = child; + break; + } + tumbler.Cut(0, sep + 1); + } + *aNode = node.get(); + NS_IF_ADDREF(*aNode); + return NS_OK; +} + +static nsresult GetRange( + nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange) +{ + nsresult rv = NS_OK; + nsCOMPtr node; + if (nsString::IsAlpha(aExpression.First())) { + // name + nsAutoString id; + const nsAutoString expression(aExpression); + PRInt32 sep = expression.FindCharInSet("/("); + if (sep > 0) { + expression.Left(id,sep); + nsCOMPtr element; + aDocument->GetElementById(id, getter_AddRefs(element)); + node = do_QueryInterface(element); + if (node) { + if (expression[sep] == '/') { + // tumbler + nsAutoString tumbler; + expression.Mid(tumbler, sep, expression.Length()); + sep = tumbler.FindChar('('); + if (sep > 0) + tumbler.Truncate(sep); + nsCOMPtr child; + GetTumblerNode(node, tumbler, getter_AddRefs(child)); + node = child; + } + // char + sep = expression.FindChar('('); + if (sep > 0) { + nsAutoString charNum(aExpression); + if (charNum[charNum.Length() -1] == ')') { + charNum.Truncate(charNum.Length() - 1); + charNum.Cut(0, sep + 1); + PRInt32 error; + PRInt32 n = charNum.ToInteger(&error); + if (n < 1) + return NS_OK; + rv = GetCharRange(node, n - 1, aRange); + if (!*aRange) { + node = nsnull; + } + } + } + } + } else { + // just name + nsCOMPtr element; + aDocument->GetElementById(expression, getter_AddRefs(element)); + node = do_QueryInterface(element); + } + } else if (aExpression.First() == '/') { + // Starts with tumbler + node = do_QueryInterface(aDocument); + nsCOMPtr child; + nsAutoString tumbler(aExpression); + PRInt32 sep = tumbler.FindChar('('); + if (sep > 0) + tumbler.Truncate(sep); + GetTumblerNode(node, tumbler, getter_AddRefs(child)); + node = child; + // char + sep = aExpression.FindChar('('); + if (sep > 0) { + nsAutoString charNum(aExpression); + if (charNum[charNum.Length() -1] == ')') { + charNum.Truncate(charNum.Length() - 1); + charNum.Cut(0, sep + 1); + PRInt32 error; + PRInt32 n = charNum.ToInteger(&error); + if (n < 1) + return NS_OK; + rv = GetCharRange(node, n - 1, aRange); + if (!*aRange) { + node = nsnull; + } + } + } + } else { + // Not FIXptr + } + + if (NS_SUCCEEDED(rv) && !*aRange && node) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) + return NS_ERROR_OUT_OF_MEMORY; + range->SelectNode(node); + *aRange = range.get(); + NS_ADDREF(*aRange); + } + + return rv; +} + +/** + * Evaluate a FIXptr expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The FIXptr expression string to evaluate. + * @param aRange The resulting range. + */ +nsresult +nsFIXptr::Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange) +{ + NS_ENSURE_ARG_POINTER(aDocument); + NS_ENSURE_ARG_POINTER(aRange); + *aRange = nsnull; + + nsresult rv; + + PRInt32 split = aExpression.FindChar(','); + if (split >= 0) { + nsAutoString expr1, expr2; + nsCOMPtr range1, range2; + + aExpression.Left(expr1, split); + aExpression.Mid(expr2, split + 1, aExpression.Length()); + + rv = GetRange(aDocument, expr1, getter_AddRefs(range1)); + if (!range1) + return rv; + rv = GetRange(aDocument, expr2, getter_AddRefs(range2)); + if (!range2) + return rv; + + nsCOMPtr begin, end; + PRInt32 beginOffset, endOffset; + range1->GetStartContainer(getter_AddRefs(begin)); + range1->GetStartOffset(&beginOffset); + range2->GetEndContainer(getter_AddRefs(end)); + range2->GetEndOffset(&endOffset); + + nsCOMPtr range(do_CreateInstance(kRangeCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + range->SetStart(begin, beginOffset); + range->SetEnd(end, endOffset); + *aRange = range.get(); + NS_ADDREF(*aRange); + } else { + rv = GetRange(aDocument, aExpression, aRange); + } + + return rv; +} diff --git a/content/xml/document/src/nsFIXptr.h b/content/xml/document/src/nsFIXptr.h new file mode 100644 index 000000000000..307038e240db --- /dev/null +++ b/content/xml/document/src/nsFIXptr.h @@ -0,0 +1,73 @@ +/* -*- 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) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Heikki Toivonen (original author) + * + * 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 ***** */ + + +/** + * Implementation for FIXptr, a W3C NOTE. + * + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + * + */ +#ifndef nsFIXptr_h__ +#define nsFIXptr_h__ + +class nsIDOMDocument; +class nsIDOMRange; +class nsISelection; + +#include "nsString.h" + +class nsFIXptr { + nsFIXptr(); // Use the static members for now + ~nsFIXptr(); + +public: + /** + * Evaluate a FIXptr expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The FIXptr expression string to evaluate. + * @param aRange The range. + */ + static nsresult Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange); +}; + +#endif diff --git a/content/xml/document/src/nsXMLDocument.cpp b/content/xml/document/src/nsXMLDocument.cpp index 4e25954fe72d..18708f2e40f9 100644 --- a/content/xml/document/src/nsXMLDocument.cpp +++ b/content/xml/document/src/nsXMLDocument.cpp @@ -91,7 +91,7 @@ #include "nsContentCID.h" #include "nsDOMAttribute.h" #include "nsGUIEvent.h" - +#include "nsFIXptr.h" #include "nsCExternalHandlerService.h" #include "nsIMIMEService.h" #include "nsNetUtil.h" @@ -310,6 +310,12 @@ nsXMLDocument::OnRedirect(nsIHttpChannel *aHttpChannel, nsIChannel *aNewChannel) return rv; } +NS_IMETHODIMP +nsXMLDocument::EvaluateFIXptr(const nsAReadableString& aExpression, nsIDOMRange **aRange) +{ + return nsFIXptr::Evaluate(this, aExpression, aRange); +} + NS_IMETHODIMP nsXMLDocument::Load(const nsAReadableString& aUrl) { diff --git a/dom/public/idl/core/nsIDOMXMLDocument.idl b/dom/public/idl/core/nsIDOMXMLDocument.idl index adcdc2894a64..0b6d84116212 100644 --- a/dom/public/idl/core/nsIDOMXMLDocument.idl +++ b/dom/public/idl/core/nsIDOMXMLDocument.idl @@ -43,4 +43,14 @@ interface nsIDOMXMLDocument : nsIDOMDocument { void load(in DOMString url); + + /** + * Evaluate FIXptr expression. FIXptr is a W3C NOTE, see + * + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + * + * @param expression FIXptr string. + * @return The range object that results from evaluation + */ + nsIDOMRange evaluateFIXptr(in DOMString expression); }; diff --git a/extensions/xmlextras/pointers/src/nsFIXptr.cpp b/extensions/xmlextras/pointers/src/nsFIXptr.cpp new file mode 100644 index 000000000000..8962b5c2f191 --- /dev/null +++ b/extensions/xmlextras/pointers/src/nsFIXptr.cpp @@ -0,0 +1,333 @@ +/* -*- 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) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Heikki Toivonen (original author) + * + * 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 ***** */ + +/** + * Implementation for FIXptr, a W3C NOTE. + * + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + * + */ +#include "nsIDOMDocument.h" +#include "nsIContent.h" +#include "nsIDOMRange.h" +#include "nsISelection.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" +#include "nsIDOMNodeList.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsFIXptr.h" + +#include "nsContentCID.h" +static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); + +// Get nth child element +static nsresult GetChild(nsIDOMNode *aParent, PRInt32 aChildNum, nsIDOMNode **aChild) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aChild); + + *aChild = nsnull; + nsCOMPtr list; + aParent->GetChildNodes(getter_AddRefs(list)); + if (!list) + return NS_OK; + + PRUint32 count; + list->GetLength(&count); + PRUint32 i; + PRInt32 curChildNum = 0; + for (i = 0; i < count; i++) { + nsCOMPtr node; + list->Item(i, getter_AddRefs(node)); + if (!node) + break; + PRUint16 nodeType; + node->GetNodeType(&nodeType); + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + curChildNum++; + } + if (curChildNum == aChildNum) { + *aChild = node; + NS_ADDREF(*aChild); + break; + } + } + return NS_OK; +} + +// Get range for char index +static nsresult GetCharRange(nsIDOMNode *aParent, PRInt32 aCharNum, nsIDOMRange **aRange) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aRange); + + *aRange = nsnull; + nsCOMPtr list; + aParent->GetChildNodes(getter_AddRefs(list)); + if (!list) + return NS_OK; + + PRUint32 count; + list->GetLength(&count); + PRUint32 i; + PRInt32 maxCharNum = 0; + PRInt32 prevCharNum = 0; + for (i = 0; i < count; i++) { + nsCOMPtr node; + list->Item(i, getter_AddRefs(node)); + if (!node) + break; + PRUint16 nodeType; + node->GetNodeType(&nodeType); + if (nodeType & (nsIDOMNode::TEXT_NODE | nsIDOMNode::CDATA_SECTION_NODE)) { + nsAutoString value; + node->GetNodeValue(value); + maxCharNum += value.Length(); + } + if (maxCharNum >= aCharNum) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) + return NS_ERROR_OUT_OF_MEMORY; + range->SetStart(node, aCharNum - prevCharNum); + range->SetEnd(node, aCharNum - prevCharNum + 1); + *aRange = range.get(); + NS_ADDREF(*aRange); + break; + } + prevCharNum = maxCharNum; + } + return NS_OK; +} + +// Get node by tumbler +static nsresult GetTumblerNode(nsIDOMNode *aParent, const nsString &aTumbler, nsIDOMNode **aNode) +{ + NS_ENSURE_ARG_POINTER(aParent); + NS_ENSURE_ARG_POINTER(aNode); + + *aNode = nsnull; + nsAutoString tumbler(aTumbler); + if (tumbler[0] == '/') + tumbler.Cut(0, 1); + nsCOMPtr node(aParent); + while (!tumbler.IsEmpty() && node) { + PRInt32 sep = tumbler.FindChar('/'); + if (sep > 0) { + nsAutoString num; + tumbler.Left(num, sep); + PRInt32 error; + PRInt32 n = num.ToInteger(&error); + if (n <= 0) { + node = nsnull; + break; + } + nsCOMPtr child; + GetChild(node, n, getter_AddRefs(child)); + node = child; + } else { + // Last + PRInt32 error; + PRInt32 n = tumbler.ToInteger(&error); + if (n <= 0) { + node = nsnull; + break; + } + nsCOMPtr child; + GetChild(node, n, getter_AddRefs(child)); + node = child; + break; + } + tumbler.Cut(0, sep + 1); + } + *aNode = node.get(); + NS_IF_ADDREF(*aNode); + return NS_OK; +} + +static nsresult GetRange( + nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange) +{ + nsresult rv = NS_OK; + nsCOMPtr node; + if (nsString::IsAlpha(aExpression.First())) { + // name + nsAutoString id; + const nsAutoString expression(aExpression); + PRInt32 sep = expression.FindCharInSet("/("); + if (sep > 0) { + expression.Left(id,sep); + nsCOMPtr element; + aDocument->GetElementById(id, getter_AddRefs(element)); + node = do_QueryInterface(element); + if (node) { + if (expression[sep] == '/') { + // tumbler + nsAutoString tumbler; + expression.Mid(tumbler, sep, expression.Length()); + sep = tumbler.FindChar('('); + if (sep > 0) + tumbler.Truncate(sep); + nsCOMPtr child; + GetTumblerNode(node, tumbler, getter_AddRefs(child)); + node = child; + } + // char + sep = expression.FindChar('('); + if (sep > 0) { + nsAutoString charNum(aExpression); + if (charNum[charNum.Length() -1] == ')') { + charNum.Truncate(charNum.Length() - 1); + charNum.Cut(0, sep + 1); + PRInt32 error; + PRInt32 n = charNum.ToInteger(&error); + if (n < 1) + return NS_OK; + rv = GetCharRange(node, n - 1, aRange); + if (!*aRange) { + node = nsnull; + } + } + } + } + } else { + // just name + nsCOMPtr element; + aDocument->GetElementById(expression, getter_AddRefs(element)); + node = do_QueryInterface(element); + } + } else if (aExpression.First() == '/') { + // Starts with tumbler + node = do_QueryInterface(aDocument); + nsCOMPtr child; + nsAutoString tumbler(aExpression); + PRInt32 sep = tumbler.FindChar('('); + if (sep > 0) + tumbler.Truncate(sep); + GetTumblerNode(node, tumbler, getter_AddRefs(child)); + node = child; + // char + sep = aExpression.FindChar('('); + if (sep > 0) { + nsAutoString charNum(aExpression); + if (charNum[charNum.Length() -1] == ')') { + charNum.Truncate(charNum.Length() - 1); + charNum.Cut(0, sep + 1); + PRInt32 error; + PRInt32 n = charNum.ToInteger(&error); + if (n < 1) + return NS_OK; + rv = GetCharRange(node, n - 1, aRange); + if (!*aRange) { + node = nsnull; + } + } + } + } else { + // Not FIXptr + } + + if (NS_SUCCEEDED(rv) && !*aRange && node) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) + return NS_ERROR_OUT_OF_MEMORY; + range->SelectNode(node); + *aRange = range.get(); + NS_ADDREF(*aRange); + } + + return rv; +} + +/** + * Evaluate a FIXptr expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The FIXptr expression string to evaluate. + * @param aRange The resulting range. + */ +nsresult +nsFIXptr::Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange) +{ + NS_ENSURE_ARG_POINTER(aDocument); + NS_ENSURE_ARG_POINTER(aRange); + *aRange = nsnull; + + nsresult rv; + + PRInt32 split = aExpression.FindChar(','); + if (split >= 0) { + nsAutoString expr1, expr2; + nsCOMPtr range1, range2; + + aExpression.Left(expr1, split); + aExpression.Mid(expr2, split + 1, aExpression.Length()); + + rv = GetRange(aDocument, expr1, getter_AddRefs(range1)); + if (!range1) + return rv; + rv = GetRange(aDocument, expr2, getter_AddRefs(range2)); + if (!range2) + return rv; + + nsCOMPtr begin, end; + PRInt32 beginOffset, endOffset; + range1->GetStartContainer(getter_AddRefs(begin)); + range1->GetStartOffset(&beginOffset); + range2->GetEndContainer(getter_AddRefs(end)); + range2->GetEndOffset(&endOffset); + + nsCOMPtr range(do_CreateInstance(kRangeCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + range->SetStart(begin, beginOffset); + range->SetEnd(end, endOffset); + *aRange = range.get(); + NS_ADDREF(*aRange); + } else { + rv = GetRange(aDocument, aExpression, aRange); + } + + return rv; +} diff --git a/extensions/xmlextras/pointers/src/nsFIXptr.h b/extensions/xmlextras/pointers/src/nsFIXptr.h new file mode 100644 index 000000000000..307038e240db --- /dev/null +++ b/extensions/xmlextras/pointers/src/nsFIXptr.h @@ -0,0 +1,73 @@ +/* -*- 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) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Heikki Toivonen (original author) + * + * 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 ***** */ + + +/** + * Implementation for FIXptr, a W3C NOTE. + * + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + * + */ +#ifndef nsFIXptr_h__ +#define nsFIXptr_h__ + +class nsIDOMDocument; +class nsIDOMRange; +class nsISelection; + +#include "nsString.h" + +class nsFIXptr { + nsFIXptr(); // Use the static members for now + ~nsFIXptr(); + +public: + /** + * Evaluate a FIXptr expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The FIXptr expression string to evaluate. + * @param aRange The range. + */ + static nsresult Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIDOMRange **aRange); +}; + +#endif diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 75070fc483c5..06191abbda00 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -84,6 +84,7 @@ #include "nsICaret.h" #include "nsIDOMHTMLDocument.h" #include "nsIXMLDocument.h" +#include "nsIDOMXMLDocument.h" #include "nsIScrollableView.h" #include "nsIParser.h" #include "nsParserCIID.h" @@ -1157,7 +1158,7 @@ protected: nsresult SetPrefLinkRules(void); nsresult SetPrefFocusRules(void); - nsresult SelectContent(nsIContent *aContent); + nsresult SelectRange(nsIDOMRange *aRange); // IMPORTANT: The ownership implicit in the following member variables has been // explicitly checked and set using nsCOMPtr for owning pointers and raw COM interface @@ -3931,7 +3932,22 @@ PresShell::GoToAnchor(const nsString& aAnchorName) } } - + // Finally try FIXptr + nsCOMPtr fixPtrRange; + if (!content) { + nsCOMPtr xmldoc = do_QueryInterface(mDocument); + if (xmldoc) { + xmldoc->EvaluateFIXptr(aAnchorName,getter_AddRefs(fixPtrRange)); + if (fixPtrRange) { + nsCOMPtr node; + fixPtrRange->GetStartContainer(getter_AddRefs(node)); + if (node) { + node->QueryInterface(NS_GET_IID(nsIContent),getter_AddRefs(content)); + } + } + } + } + if (content) { nsIFrame* frame; @@ -3946,10 +3962,18 @@ PresShell::GoToAnchor(const nsString& aAnchorName) nsCOMPtr prefs(do_GetService(kPrefServiceCID,&rv)); if (NS_SUCCEEDED(rv) && prefs) { PRBool selectAnchor; - nsresult rvPref; - rvPref = prefs->GetBoolPref("layout.selectanchor",&selectAnchor); + nsresult rvPref = prefs->GetBoolPref("layout.selectanchor",&selectAnchor); if (NS_SUCCEEDED(rvPref) && selectAnchor) { - rv = SelectContent(content); + if (!fixPtrRange) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + nsCOMPtr node(do_QueryInterface(content)); + if (range && node) { + range->SelectNode(node); + SelectRange(range); + } + } else { + SelectRange(fixPtrRange); + } } } } @@ -3980,21 +4004,13 @@ PresShell::GoToAnchor(const nsString& aAnchorName) } nsresult -PresShell::SelectContent(nsIContent *aContent) +PresShell::SelectRange(nsIDOMRange *aRange) { - nsresult rv; nsCOMPtr sel; - rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); + nsresult rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); if (NS_SUCCEEDED(rv) && sel) { - nsCOMPtr range(do_CreateInstance(kRangeCID,&rv)); - nsCOMPtr node(do_QueryInterface(aContent)); - if (NS_SUCCEEDED(rv) && node) { - rv = range->SelectNode(node); - if (NS_SUCCEEDED(rv)) { - sel->RemoveAllRanges(); - rv = sel->AddRange(range); - } - } + sel->RemoveAllRanges(); + sel->AddRange(aRange); } return rv; diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index 75070fc483c5..06191abbda00 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -84,6 +84,7 @@ #include "nsICaret.h" #include "nsIDOMHTMLDocument.h" #include "nsIXMLDocument.h" +#include "nsIDOMXMLDocument.h" #include "nsIScrollableView.h" #include "nsIParser.h" #include "nsParserCIID.h" @@ -1157,7 +1158,7 @@ protected: nsresult SetPrefLinkRules(void); nsresult SetPrefFocusRules(void); - nsresult SelectContent(nsIContent *aContent); + nsresult SelectRange(nsIDOMRange *aRange); // IMPORTANT: The ownership implicit in the following member variables has been // explicitly checked and set using nsCOMPtr for owning pointers and raw COM interface @@ -3931,7 +3932,22 @@ PresShell::GoToAnchor(const nsString& aAnchorName) } } - + // Finally try FIXptr + nsCOMPtr fixPtrRange; + if (!content) { + nsCOMPtr xmldoc = do_QueryInterface(mDocument); + if (xmldoc) { + xmldoc->EvaluateFIXptr(aAnchorName,getter_AddRefs(fixPtrRange)); + if (fixPtrRange) { + nsCOMPtr node; + fixPtrRange->GetStartContainer(getter_AddRefs(node)); + if (node) { + node->QueryInterface(NS_GET_IID(nsIContent),getter_AddRefs(content)); + } + } + } + } + if (content) { nsIFrame* frame; @@ -3946,10 +3962,18 @@ PresShell::GoToAnchor(const nsString& aAnchorName) nsCOMPtr prefs(do_GetService(kPrefServiceCID,&rv)); if (NS_SUCCEEDED(rv) && prefs) { PRBool selectAnchor; - nsresult rvPref; - rvPref = prefs->GetBoolPref("layout.selectanchor",&selectAnchor); + nsresult rvPref = prefs->GetBoolPref("layout.selectanchor",&selectAnchor); if (NS_SUCCEEDED(rvPref) && selectAnchor) { - rv = SelectContent(content); + if (!fixPtrRange) { + nsCOMPtr range(do_CreateInstance(kRangeCID)); + nsCOMPtr node(do_QueryInterface(content)); + if (range && node) { + range->SelectNode(node); + SelectRange(range); + } + } else { + SelectRange(fixPtrRange); + } } } } @@ -3980,21 +4004,13 @@ PresShell::GoToAnchor(const nsString& aAnchorName) } nsresult -PresShell::SelectContent(nsIContent *aContent) +PresShell::SelectRange(nsIDOMRange *aRange) { - nsresult rv; nsCOMPtr sel; - rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); + nsresult rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); if (NS_SUCCEEDED(rv) && sel) { - nsCOMPtr range(do_CreateInstance(kRangeCID,&rv)); - nsCOMPtr node(do_QueryInterface(aContent)); - if (NS_SUCCEEDED(rv) && node) { - rv = range->SelectNode(node); - if (NS_SUCCEEDED(rv)) { - sel->RemoveAllRanges(); - rv = sel->AddRange(range); - } - } + sel->RemoveAllRanges(); + sel->AddRange(aRange); } return rv;