diff --git a/mozilla/content/base/public/nsContentCID.h b/mozilla/content/base/public/nsContentCID.h index c97a0dfd1d1..a0f6f5d5742 100644 --- a/mozilla/content/base/public/nsContentCID.h +++ b/mozilla/content/base/public/nsContentCID.h @@ -200,6 +200,10 @@ #define NS_DOMEVENTGROUP_CID \ { 0x66856477, 0x6596, 0x40eb, { 0xbb, 0x87, 0x59, 0xca, 0x2d, 0xab, 0xb6, 0xf7 } } +// {EA713261-ECE7-4134-A3FA-E138724C99EE} +#define NS_XPOINTERRESULT_CID \ +{ 0xea713261, 0xece7, 0x4134, { 0xa3, 0xfa, 0xe1, 0x38, 0x72, 0x4c, 0x99, 0xee } } + // {64F300A1-C88C-11d3-97FB-00400553EEF0} #define NS_XBLSERVICE_CID \ { 0x64f300a1, 0xc88c, 0x11d3, { 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } } diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index eeddd85f8b2..4b7762e1df9 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -111,6 +111,7 @@ #include "nsContentUtils.h" #include "nsNodeInfoManager.h" #include "nsIXBLService.h" +#include "nsIXPointer.h" #include "nsNetUtil.h" // for NS_MakeAbsoluteURI @@ -2452,6 +2453,15 @@ nsDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange) return NS_OK; } +NS_IMETHODIMP +nsDocument::EvaluateXPointer(const nsAString& aExpression, + nsIXPointerResult **aResult) +{ + NS_ERROR("nsDocument::EvaluateXPointer() should be overriden by subclass!"); + + return NS_OK; +} + NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) { diff --git a/mozilla/content/xml/document/public/Makefile.in b/mozilla/content/xml/document/public/Makefile.in index cc447e88fc9..cf8e2568a22 100644 --- a/mozilla/content/xml/document/public/Makefile.in +++ b/mozilla/content/xml/document/public/Makefile.in @@ -28,6 +28,11 @@ include $(DEPTH)/config/autoconf.mk MODULE = content +XPIDLSRCS = \ + nsIXPointer.idl \ + nsIModifyableXPointer.idl \ + $(NULL) + EXPORTS = \ nsIXMLContentSink.h \ nsIXMLDocument.h \ diff --git a/mozilla/content/xml/document/public/nsIModifyableXPointer.idl b/mozilla/content/xml/document/public/nsIModifyableXPointer.idl new file mode 100755 index 00000000000..ebd98368b49 --- /dev/null +++ b/mozilla/content/xml/document/public/nsIModifyableXPointer.idl @@ -0,0 +1,55 @@ +/* -*- Mode: IDL; 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) 2003 + * 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 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 ***** */ + +/** + * Modifyable interfaces for XPointer. + * + */ + +#include "nsIXPointer.idl" + +interface nsIDOMRange; + +/** + * Helper interface that can assist in creating an nsIXPointerResult. + */ +[uuid(2DC3BE2E-642D-4d7e-B3C5-F3DAC51AFBEE)] +interface nsIModifyableXPointerResult : nsIXPointerResult +{ + void appendRange(in nsIDOMRange aRange); +}; diff --git a/mozilla/content/xml/document/public/nsIXPointer.idl b/mozilla/content/xml/document/public/nsIXPointer.idl new file mode 100755 index 00000000000..e50c9edc7f6 --- /dev/null +++ b/mozilla/content/xml/document/public/nsIXPointer.idl @@ -0,0 +1,99 @@ +/* -*- Mode: IDL; 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) 2003 + * 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 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 "nsISupports.idl" + +interface nsIDOMRange; +interface nsIDOMDocument; + +/** + * XXX A good XPointerResult would probably mimic XPathresult, + * this range list is just the minimum that will be able to represent + * all return values, although it would be more user friendly to return + * nodes and node lists when they are possible. + */ +[scriptable, uuid(D3992637-F474-4b65-83ED-323FE69C60D2)] +interface nsIXPointerResult : nsISupports +{ + nsIDOMRange item(in unsigned long index); + readonly attribute unsigned long length; +}; + + +/** + * Scheme context for nsIXPointerSchemeProcessor. The context consists of + * all the scheme/data pairs that precede the scheme/data that the + * nsIXPointerSchemeProcessor is currently evaluating. + */ +[uuid(781F4AA1-EBB3-4667-B1C2-2B35E94C4281)] +interface nsIXPointerSchemeContext : nsISupports +{ + readonly attribute unsigned long count; + void getSchemeData(in unsigned long index, + out DOMString scheme, + out DOMString data); +}; + +%{C++ +/** + * nsIXPointerSchemeProcessor implementations must be registered with the below + * progid, appended with the scheme name that the processor implements. + */ +#define NS_XPOINTER_SCHEME_PROCESSOR_BASE "@mozilla.org/xml/xpointer;1?scheme=" +%} + +/** + * nsIXPointerSchemeProcessors will be called by the XPointer Processor that + * implements the XPointer Framework. This is done for each scheme the + * XPointer Processor finds, in left-to-right order. + */ +[uuid(093D3559-B56B-44d0-8764-C25815715080)] +interface nsIXPointerSchemeProcessor : nsISupports +{ + /** + * Evaluate. + * + * @param aDocument The document in which to resolve the XPointer. + * @param aContext The XPointer context in which to process aData. + * @param aData The data in the scheme that needs to be resolved. + * @return The result of the evaluation. + */ + nsIXPointerResult evaluate(in nsIDOMDocument aDocument, + in nsIXPointerSchemeContext aContext, + in DOMString aData); +}; diff --git a/mozilla/content/xml/document/src/Makefile.in b/mozilla/content/xml/document/src/Makefile.in index efe90a06c58..7ed95b830c0 100644 --- a/mozilla/content/xml/document/src/Makefile.in +++ b/mozilla/content/xml/document/src/Makefile.in @@ -59,6 +59,7 @@ CPPSRCS = \ nsXMLDocument.cpp \ nsXMLPrettyPrinter.cpp \ nsFIXptr.cpp \ + nsXPointer.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff --git a/mozilla/content/xml/document/src/nsXMLDocument.cpp b/mozilla/content/xml/document/src/nsXMLDocument.cpp index 968748cc94e..af6e76ca4b1 100644 --- a/mozilla/content/xml/document/src/nsXMLDocument.cpp +++ b/mozilla/content/xml/document/src/nsXMLDocument.cpp @@ -83,6 +83,7 @@ #include "nsDOMAttribute.h" #include "nsGUIEvent.h" #include "nsFIXptr.h" +#include "nsXPointer.h" #include "nsCExternalHandlerService.h" #include "nsIMIMEService.h" #include "nsNetUtil.h" @@ -201,7 +202,7 @@ nsXMLDocument::~nsXMLDocument() } -// QueryInterface implementation for nsHTMLAnchorElement +// QueryInterface implementation for nsXMLDocument NS_INTERFACE_MAP_BEGIN(nsXMLDocument) NS_INTERFACE_MAP_ENTRY(nsIXMLDocument) NS_INTERFACE_MAP_ENTRY(nsIHTMLContentContainer) @@ -333,6 +334,15 @@ nsXMLDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange return nsFIXptr::Evaluate(this, aExpression, aRange); } +NS_IMETHODIMP +nsXMLDocument::EvaluateXPointer(const nsAString& aExpression, + nsIXPointerResult **aResult) +{ + return nsXPointer::Evaluate(this, aExpression, aResult); +} + + + NS_IMETHODIMP nsXMLDocument::Load(const nsAString& aUrl) { diff --git a/mozilla/content/xml/document/src/nsXPointer.cpp b/mozilla/content/xml/document/src/nsXPointer.cpp new file mode 100755 index 00000000000..646efc14210 --- /dev/null +++ b/mozilla/content/xml/document/src/nsXPointer.cpp @@ -0,0 +1,418 @@ +/* -*- 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) 2003 + * 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 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 ***** */ + +/** + * Implementation for the XPointer family of specifications, practically the + * XPointer Processor. The processor can call optional modules that implement + * some XPointer schemes that were not implemented in this file. Please note + * that implementation of the xmlns scheme is left to the optional scheme + * implementations - all the information they need will be passed in. + * + * The framework: + * http://www.w3.org/TR/xptr-framework/ + * The element scheme: + * http://www.w3.org/TR/xptr-element/ + * + * Additionally this module implements 'fixptr' scheme for the FIXptr + * W3C proposal: + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + */ + +// TODO: +// - xpointer scheme + + +#include "nsIDOMNode.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMRange.h" +#include "nsIDOMElement.h" +#include "nsIDOMDocument.h" +#include "nsCOMPtr.h" +#include "nsXPointer.h" +#include "nsIModifyableXPointer.h" +#include "nsISupports.h" +#include "nsISupportsUtils.h" +#include "nsIXPointer.h" +#include "nsFIXptr.h" +#include "nsCOMArray.h" +#include "nsIServiceManager.h" +#include "nsContentUtils.h" + +#include "nsContentCID.h" +static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); + +class nsXPointerResult : public nsIModifyableXPointerResult { +public: + nsXPointerResult(); + virtual ~nsXPointerResult(); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIXPOINTERRESULT + NS_DECL_NSIMODIFYABLEXPOINTERRESULT + +private: + nsCOMArray mArray; +}; + +nsXPointerResult::nsXPointerResult() +{ +} + +nsXPointerResult::~nsXPointerResult() +{ +} + +NS_INTERFACE_MAP_BEGIN(nsXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsIXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsIModifyableXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XPointerResult) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPointerResult) +NS_IMPL_RELEASE(nsXPointerResult) + +NS_IMETHODIMP +nsXPointerResult::AppendRange(nsIDOMRange* aRange) +{ + NS_ENSURE_ARG(aRange); + + if (!mArray.AppendObject(aRange)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerResult::Item(PRUint32 aIndex, nsIDOMRange** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + + if (aIndex >= mArray.Count()) { + return NS_ERROR_FAILURE; + } + + *aReturn = mArray.ObjectAt(aIndex); + NS_IF_ADDREF(*aReturn); + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerResult::GetLength(PRUint32* aLength) +{ + NS_ENSURE_ARG_POINTER(aLength); + + *aLength = mArray.Count(); + + return NS_OK; +} + +nsresult NS_NewXPointerResult(nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = new nsXPointerResult(); + if (!*aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult); + + return NS_OK; +} + +static nsresult NS_NewXPointerResult(nsIDOMRange *aRange, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG(aRange); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr result(new nsXPointerResult()); + if (!result) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = result->AppendRange(aRange); + if (NS_FAILED(rv)) { + return rv; + } + + *aResult = result.get(); + NS_ADDREF(*aResult); + + return NS_OK; +} + +static nsresult NS_NewXPointerResult(nsIDOMNode *aNode, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG(aNode); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = range->SelectNode(aNode); + if (NS_FAILED(rv)) { + return rv; + } + + return NS_NewXPointerResult(range, aResult); +} + + +// nsXPointerSchemeContext + +class nsXPointerSchemeContext : public nsIXPointerSchemeContext +{ +public: + nsXPointerSchemeContext() {}; + virtual ~nsXPointerSchemeContext() {}; + + NS_DECL_ISUPPORTS + NS_DECL_NSIXPOINTERSCHEMECONTEXT + + nsresult Append(const nsAString &aScheme, const nsAString &aData); + +private: + nsStringArray mSchemes; + nsStringArray mDatas; +}; + +NS_IMPL_ISUPPORTS1(nsXPointerSchemeContext, nsIXPointerSchemeContext) + +NS_IMETHODIMP +nsXPointerSchemeContext::GetCount(PRUint32 *aCount) +{ + NS_ENSURE_ARG_POINTER(aCount); + + *aCount = mSchemes.Count(); + + return NS_OK; +} + + +nsresult +nsXPointerSchemeContext::Append(const nsAString &aScheme, + const nsAString &aData) +{ + if (!mSchemes.AppendString(aScheme)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!mDatas.AppendString(aData)) { + // Keep mDatas and mSchemes in sync + mSchemes.RemoveStringAt(mSchemes.Count() - 1); + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerSchemeContext::GetSchemeData(PRUint32 aIndex, + nsAString &aScheme, + nsAString &aData) +{ + if (aIndex >= mSchemes.Count()) { + aScheme.Truncate(); + aData.Truncate(); + + return NS_ERROR_FAILURE; + } + + mSchemes.StringAt(aIndex, aScheme); + mDatas.StringAt(aIndex, aData); + + return NS_OK; +} + +// XPointer + +nsXPointer::nsXPointer() +{ +} + +nsXPointer::~nsXPointer() +{ +} + +static nsresult GetNextSchemeNameAndData(nsString& aExpression, + nsString &aScheme, + nsString& aData) +{ + aScheme.Truncate(); + aData.Truncate(); + + PRInt32 lp = aExpression.FindChar('('); + if (lp < 1) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + PRInt32 i = lp + 1, len = aExpression.Length(); + if (i >= len) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + aScheme = Substring(aExpression, 0, lp); + aScheme.CompressWhitespace(PR_TRUE, PR_FALSE); + if (aScheme.FindCharInSet(" \t\r\n") > 0) { + return NS_ERROR_FAILURE; // scheme name can't contain ws (we'd really need to check a lot more...) + } + + // XXX perf: Switch to string iterators + PRBool escapeOn = PR_FALSE; + PRInt32 balance = 1; + for (; i < len; ++i) { + // Circumflex is the escape character that can precede ^, ( and ) only + if (aExpression[i] == '^') { + if (!escapeOn) { + escapeOn = PR_TRUE; + continue; + } + } else if (escapeOn) { + if ((aExpression[i] != '(') && (aExpression[i] != ')')) { + return NS_ERROR_FAILURE; // illegal use of ^ + } + } else if (aExpression[i] == '(') { + ++balance; + } else if (aExpression[i] == ')') { + if (--balance == 0) { + aExpression.Cut(0, i + 1); + break; + } + } + + aData.Append(aExpression[i]); + escapeOn = PR_FALSE; + } + + if (balance != 0) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + return NS_OK; +} + + +nsresult +nsXPointer::Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG_POINTER(aDocument); + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + + nsresult rv = NS_OK; + + if (aExpression.FindChar('(') < 0) { + // Must be shorthand, i.e. plain id + nsCOMPtr element; + aDocument->GetElementById(aExpression, getter_AddRefs(element)); + if (element) { + rv = NS_NewXPointerResult(element, aResult); + } + return rv; + } + + nsAutoString expression(aExpression), scheme, data; + + NS_NAMED_LITERAL_STRING(element, "element"); + NS_NAMED_LITERAL_STRING(fixptr, "fixptr"); + NS_NAMED_LITERAL_CSTRING(baseSchemeProgID, NS_XPOINTER_SCHEME_PROCESSOR_BASE); + nsCOMPtr contextSchemeDataArray(new nsXPointerSchemeContext()); + if (!contextSchemeDataArray) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // Keep trying the schemes from left to right until one finds a subresource + while (!expression.IsEmpty()) { + rv = GetNextSchemeNameAndData(expression, scheme, data); + if (NS_FAILED(rv)) + break; + + // Built in schemes + if (scheme.Equals(element)) { + // We implement element scheme by using the FIXptr processor. + // Check there are no parenthesis (legal in FIXptr data). + if (data.FindChar('(') < 0) { + nsCOMPtr range; + rv = nsFIXptr::Evaluate(aDocument, data, getter_AddRefs(range)); + if (NS_FAILED(rv)) + break; + if (range) { + return NS_NewXPointerResult(range, aResult); + } + } + } else if (scheme.Equals(fixptr)) { + nsCOMPtr range; + rv = nsFIXptr::Evaluate(aDocument, data, getter_AddRefs(range)); + if (NS_FAILED(rv)) + break; + if (range) { + return NS_NewXPointerResult(range, aResult); + } + } else { + // Add-on schemes + nsCAutoString progid(baseSchemeProgID + NS_ConvertUCS2toUTF8(scheme)); + nsCOMPtr p(do_CreateInstance(progid.get())); + if (p) { + rv = p->Evaluate(aDocument, contextSchemeDataArray, data, aResult); + if (NS_FAILED(rv)) + break; + if (*aResult) + return NS_OK; + } + } + + rv = contextSchemeDataArray->Append(scheme, data); + if (NS_FAILED(rv)) + break; + + } + + return rv; +} + diff --git a/mozilla/content/xml/document/src/nsXPointer.h b/mozilla/content/xml/document/src/nsXPointer.h new file mode 100755 index 00000000000..2df971cac29 --- /dev/null +++ b/mozilla/content/xml/document/src/nsXPointer.h @@ -0,0 +1,63 @@ +/* -*- 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) 2003 + * 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 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 nsXPointer_h__ +#define nsXPointer_h__ + +#include "nsAString.h" +#include "nsIXPointer.h" + +class nsXPointer { + nsXPointer(); + ~nsXPointer(); +public: + /** + * Evaluate an XPointer expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The XPointer expression string to evaluate. + * @param aResult The result. + */ + static nsresult Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIXPointerResult **aResult); + +}; + +#endif diff --git a/mozilla/content/xml/tests/xpointer/xpointer.xml b/mozilla/content/xml/tests/xpointer/xpointer.xml new file mode 100755 index 00000000000..baf8b5495a4 --- /dev/null +++ b/mozilla/content/xml/tests/xpointer/xpointer.xml @@ -0,0 +1,79 @@ + + + + +]> + + + div {display: block; padding-left: +1em;} + p {display: block; padding-left: +1em;} + mylink1 {display: inline; color:blue; padding-left: +1em;} + + +
+

First para in div="id1"

+
+

First para in div with no id

+

Second para in div with id=id2

+
+

Second para in div="id1"

+

Third para in div="id1", the ID of this element is id3.

+ XHTML h2 element + XHTML h3 element +

Foobar

+ XHTML h3 element too +
+ id1 - div=id1JS + element(id2) - Second paraJS + element(id1/2/1) - First para in second divJS + element(/1/2) - div=id1JS + xpath1(id("id3")) - p=id3JS + foobar(id("id3")) - ???JS + element(nothere) - ???JS + xmlns(foo=http://www.w3.org/1999/xhtml) xpath1(//foo:h2//foo:span) - span inside h2JS + xmlns(foo=http://www.w3.org/1999/xhtml) xpath1(//foo:h3) - h3 elementsJS + xpath1(//html:h2) - ???JS + foobar(^^foo^)) - ???JS + foobar(^foo) - ??? [error]JS + foobar() - ???JS + foo bar(foo) - ??? [error]JS + foobar((foo) - ??? [error]JS + foobar)(foo - ??? [error]JS + xpath1(//foo:h3) - ???JS + + + + +
diff --git a/mozilla/dom/public/idl/core/nsIDOMXMLDocument.idl b/mozilla/dom/public/idl/core/nsIDOMXMLDocument.idl index 0b6d8411621..9a3c459bca1 100644 --- a/mozilla/dom/public/idl/core/nsIDOMXMLDocument.idl +++ b/mozilla/dom/public/idl/core/nsIDOMXMLDocument.idl @@ -39,6 +39,8 @@ #include "nsIDOMDocument.idl" +interface nsIXPointerResult; + [scriptable, uuid(8816d003-e7c8-4065-8827-829b8d07b6e0)] interface nsIDOMXMLDocument : nsIDOMDocument { @@ -53,4 +55,9 @@ interface nsIDOMXMLDocument : nsIDOMDocument * @return The range object that results from evaluation */ nsIDOMRange evaluateFIXptr(in DOMString expression); + + /** + * Evaluate XPointer expression. + */ + nsIXPointerResult evaluateXPointer(in DOMString expression); }; diff --git a/mozilla/dom/public/nsIDOMClassInfo.h b/mozilla/dom/public/nsIDOMClassInfo.h index aceef81d244..bc7add558c2 100644 --- a/mozilla/dom/public/nsIDOMClassInfo.h +++ b/mozilla/dom/public/nsIDOMClassInfo.h @@ -266,6 +266,9 @@ enum nsDOMClassInfoID { eDOMClassInfo_ImageDocument_id, + // XPointer evaluation result + eDOMClassInfo_XPointerResult_id, + // This one better be the last one in this list eDOMClassInfoIDCount }; diff --git a/mozilla/dom/src/base/nsDOMClassInfo.cpp b/mozilla/dom/src/base/nsDOMClassInfo.cpp index 323ff52447b..67eacae23a5 100644 --- a/mozilla/dom/src/base/nsDOMClassInfo.cpp +++ b/mozilla/dom/src/base/nsDOMClassInfo.cpp @@ -313,6 +313,8 @@ #include "nsIImageDocument.h" +#include "nsIXPointer.h" + static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); @@ -811,6 +813,10 @@ static nsDOMClassInfoData sClassInfoData[] = { NS_DEFINE_CLASSINFO_DATA(ImageDocument, nsHTMLDocumentSH, DOCUMENT_SCRIPTABLE_FLAGS | nsIXPCScriptable::WANT_ENUMERATE) + + + NS_DEFINE_CLASSINFO_DATA(XPointerResult, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) }; nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull; @@ -2184,6 +2190,10 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCollection) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XPointerResult, nsIXPointerResult) + DOM_CLASSINFO_MAP_ENTRY(nsIXPointerResult) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(ImageDocument, nsIImageDocument) DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument) DOM_CLASSINFO_MAP_ENTRY(nsIImageDocument) diff --git a/mozilla/extensions/transformiix/build/Makefile.in b/mozilla/extensions/transformiix/build/Makefile.in index e1268d5afb7..3c99c886559 100644 --- a/mozilla/extensions/transformiix/build/Makefile.in +++ b/mozilla/extensions/transformiix/build/Makefile.in @@ -84,6 +84,7 @@ LOBJS = ../source/base/Double.$(OBJ_SUFFIX) \ ../source/xpath/nsXPathExpression.$(OBJ_SUFFIX) \ ../source/xpath/nsXPathNSResolver.$(OBJ_SUFFIX) \ ../source/xpath/nsXPathResult.$(OBJ_SUFFIX) \ + ../source/xpath/nsXPath1Scheme.$(OBJ_SUFFIX) \ ../source/xpath/NumberExpr.$(OBJ_SUFFIX) \ ../source/xpath/NumberFunctionCall.$(OBJ_SUFFIX) \ ../source/xpath/NumberResult.$(OBJ_SUFFIX) \ diff --git a/mozilla/extensions/transformiix/build/XSLTProcessorModule.cpp b/mozilla/extensions/transformiix/build/XSLTProcessorModule.cpp index bbb0e67c523..141ea75d0ee 100755 --- a/mozilla/extensions/transformiix/build/XSLTProcessorModule.cpp +++ b/mozilla/extensions/transformiix/build/XSLTProcessorModule.cpp @@ -42,11 +42,18 @@ #include "nsCRT.h" #include "nsIScriptSecurityManager.h" #include "txURIUtils.h" +#include "nsXPath1Scheme.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPath1SchemeProcessor) /* 1c1a3c01-14f6-11d6-a7f2-ea502af815dc */ #define TRANSFORMIIX_DOMCI_EXTENSION_CID \ { 0x1c1a3c01, 0x14f6, 0x11d6, {0xa7, 0xf2, 0xea, 0x50, 0x2a, 0xf8, 0x15, 0xdc} } +/* {0C351177-0159-4500-86B0-A219DFDE4258} */ +#define TRANSFORMIIX_XPATH1_SCHEME_CID \ +{ 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } } + #define TRANSFORMIIX_DOMCI_EXTENSION_CONTRACTID \ "@mozilla.org/transformiix-domci-extender;1" @@ -264,7 +271,11 @@ static const nsModuleComponentInfo gComponents[] = { { "Transformiix DOMCI Extender", TRANSFORMIIX_DOMCI_EXTENSION_CID, TRANSFORMIIX_DOMCI_EXTENSION_CONTRACTID, - NS_DOMCI_EXTENSION_CONSTRUCTOR(Transformiix) } + NS_DOMCI_EXTENSION_CONSTRUCTOR(Transformiix) }, + { "XPath1 XPointer Scheme Processor", + TRANSFORMIIX_XPATH1_SCHEME_CID, + NS_XPOINTER_SCHEME_PROCESSOR_BASE "xpath1", + nsXPath1SchemeProcessorConstructor } }; NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(TransformiixModule, gComponents, diff --git a/mozilla/extensions/transformiix/source/xpath/Makefile.in b/mozilla/extensions/transformiix/source/xpath/Makefile.in index 5b0bff14d94..839faac6f8a 100644 --- a/mozilla/extensions/transformiix/source/xpath/Makefile.in +++ b/mozilla/extensions/transformiix/source/xpath/Makefile.in @@ -77,7 +77,8 @@ CPPSRCS += nsXPathEvaluator.cpp \ nsXPathException.cpp \ nsXPathExpression.cpp \ nsXPathNSResolver.cpp \ - nsXPathResult.cpp + nsXPathResult.cpp \ + nsXPath1Scheme.cpp endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.cpp b/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.cpp new file mode 100755 index 00000000000..c2ebb9c3cf8 --- /dev/null +++ b/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.cpp @@ -0,0 +1,228 @@ +/* -*- 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) 2003 + * 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 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 file implements the xpath1 XPointer scheme, and the xmlns scheme + * as well but only for xpath1. + */ + +#include "nsXPath1Scheme.h" +#include "nsXPathEvaluator.h" +#include "nsXPathException.h" +#include "nsDOMError.h" +#include "nsXPathResult.h" +#include "nsIDOMNode.h" +#include "nsIDOMDocument.h" +#include "nsIDOMXPathNSResolver.h" +#include "nsIDOMRange.h" +#include "nsIModifyableXPointer.h" +#include "nsAutoPtr.h" + +#include "nsContentCID.h" +static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); +static NS_DEFINE_IID(kXPointerResultCID, NS_XPOINTERRESULT_CID); + +/** + * nsXPath1SchemeNSResolver + * + * This will effectively give us xmlns scheme support. + */ +class nsXPath1SchemeNSResolver : public nsIDOMXPathNSResolver +{ +public: + nsXPath1SchemeNSResolver(nsIXPointerSchemeContext *aContext) + : mContext(aContext) + { + } + + virtual ~nsXPath1SchemeNSResolver() + { + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMXPATHNSRESOLVER + +private: + nsCOMPtr mContext; +}; + +NS_IMPL_ISUPPORTS1(nsXPath1SchemeNSResolver, nsIDOMXPathNSResolver) + +//DOMString lookupNamespaceURI(in DOMString prefix); +NS_IMETHODIMP +nsXPath1SchemeNSResolver::LookupNamespaceURI(const nsAString &aPrefix, + nsAString &aURI) +{ + aURI.Truncate(); + + // This method will be called each time the XPath engine encounters + // a prefix. + + // We could cache the extracted prefix + URI pairs in a hash table, + // and do a lookup from that first. But typical XPointers only have + // a few scheme + data pairs (and only some of those will be xmlns + // schemes), and typical XPath expressions only have a few prefixes + // as well, so we'll see if we can manage without... + + if (!mContext) { + return NS_OK; + } + + NS_NAMED_LITERAL_STRING(xmlns, "xmlns"); + + PRUint32 count; + mContext->GetCount(&count); + PRUint32 i; + for (i = 0; i < count; ++i) { + nsAutoString scheme, data; + mContext->GetSchemeData(i, scheme, data); + if (scheme.Equals(xmlns)) { + PRInt32 sep = data.FindChar('='); + if (sep > 0 && aPrefix.Equals(Substring(data, 0, sep))) { + aURI.Assign(Substring(data, sep + 1, data.Length() - sep - 1)); + return NS_OK; + } + } + } + + return NS_OK; +} + +// nsXPath1SchemeProcessor +nsXPath1SchemeProcessor::nsXPath1SchemeProcessor() +{ +} + +nsXPath1SchemeProcessor::~nsXPath1SchemeProcessor() +{ +} + +NS_IMPL_ISUPPORTS1(nsXPath1SchemeProcessor, nsIXPointerSchemeProcessor) + +/** + * Evaluate. + * + * @param aDocument The document in which to resolve the XPointer. + * @param aContext The XPointer context in which to process aData. + * @param aData The data in the scheme that needs to be resolved. + * @return The result of the evaluation. + */ +NS_IMETHODIMP +nsXPath1SchemeProcessor::Evaluate(nsIDOMDocument *aDocument, + nsIXPointerSchemeContext *aContext, + const nsAString &aData, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG_POINTER(aDocument); + NS_ENSURE_ARG_POINTER(aContext); + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + + // Resolve expression + nsCOMPtr nsresolver(new nsXPath1SchemeNSResolver(aContext)); + if (!nsresolver) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsRefPtr e(new nsXPathEvaluator()); + if (!e) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsCOMPtr result; + nsresult rv = e->Evaluate(aData, + aDocument, + nsresolver, + nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE, + nsnull, + getter_AddRefs(result)); + if (NS_FAILED(rv)) { + if ((rv == NS_ERROR_DOM_INVALID_EXPRESSION_ERR) || + (rv == NS_ERROR_DOM_NAMESPACE_ERR) || + (rv == NS_ERROR_DOM_TYPE_ERR)) { + // These errors are benign, change them to NS_OK so that + // we will not terminate the processor. + rv = NS_OK; + } + return rv; + } + + // Create return result + // XXX perf: just store the XPathResult and resolve as XPointerResult on demand + nsCOMPtr xpointerResult(do_CreateInstance(kXPointerResultCID, &rv)); + if (NS_FAILED(rv)) { + return rv; + } + + nsCOMPtr privatePointerResult(do_QueryInterface(xpointerResult)); + if (!privatePointerResult) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr node; + rv = result->IterateNext(getter_AddRefs(node)); + if (NS_FAILED(rv)) { + return rv; + } + + // Fill in return result + while (node) { + nsCOMPtr range(do_CreateInstance(kRangeCID, &rv)); + if (NS_FAILED(rv)) + break; + + rv = range->SelectNode(node); + if (NS_FAILED(rv)) + break; + + rv = privatePointerResult->AppendRange(range); + if (NS_FAILED(rv)) + break; + + rv = result->IterateNext(getter_AddRefs(node)); + if (NS_FAILED(rv)) + break; + } + + PRUint32 count; + xpointerResult->GetLength(&count); + if (NS_SUCCEEDED(rv) && (count > 0)) { + *aResult = xpointerResult; + NS_ADDREF(*aResult); + } + + return rv; +} diff --git a/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.h b/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.h new file mode 100755 index 00000000000..7b5ff150785 --- /dev/null +++ b/mozilla/extensions/transformiix/source/xpath/nsXPath1Scheme.h @@ -0,0 +1,59 @@ +/* -*- 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) 2003 + * 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 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 file implements the xpath1 XPointer scheme. + */ + +#ifndef __nsXPath1Scheme_h__ +#define __nsXPath1Scheme_h__ + +#include "nsIXPointer.h" + +class nsXPath1SchemeProcessor : public nsIXPointerSchemeProcessor +{ +public: + nsXPath1SchemeProcessor(); + virtual ~nsXPath1SchemeProcessor(); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIXPOINTERSCHEMEPROCESSOR +}; + +#endif diff --git a/mozilla/extensions/xmlextras/pointers/src/nsXPointer.cpp b/mozilla/extensions/xmlextras/pointers/src/nsXPointer.cpp new file mode 100755 index 00000000000..646efc14210 --- /dev/null +++ b/mozilla/extensions/xmlextras/pointers/src/nsXPointer.cpp @@ -0,0 +1,418 @@ +/* -*- 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) 2003 + * 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 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 ***** */ + +/** + * Implementation for the XPointer family of specifications, practically the + * XPointer Processor. The processor can call optional modules that implement + * some XPointer schemes that were not implemented in this file. Please note + * that implementation of the xmlns scheme is left to the optional scheme + * implementations - all the information they need will be passed in. + * + * The framework: + * http://www.w3.org/TR/xptr-framework/ + * The element scheme: + * http://www.w3.org/TR/xptr-element/ + * + * Additionally this module implements 'fixptr' scheme for the FIXptr + * W3C proposal: + * http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm + */ + +// TODO: +// - xpointer scheme + + +#include "nsIDOMNode.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMRange.h" +#include "nsIDOMElement.h" +#include "nsIDOMDocument.h" +#include "nsCOMPtr.h" +#include "nsXPointer.h" +#include "nsIModifyableXPointer.h" +#include "nsISupports.h" +#include "nsISupportsUtils.h" +#include "nsIXPointer.h" +#include "nsFIXptr.h" +#include "nsCOMArray.h" +#include "nsIServiceManager.h" +#include "nsContentUtils.h" + +#include "nsContentCID.h" +static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); + +class nsXPointerResult : public nsIModifyableXPointerResult { +public: + nsXPointerResult(); + virtual ~nsXPointerResult(); + + NS_DECL_ISUPPORTS + + NS_DECL_NSIXPOINTERRESULT + NS_DECL_NSIMODIFYABLEXPOINTERRESULT + +private: + nsCOMArray mArray; +}; + +nsXPointerResult::nsXPointerResult() +{ +} + +nsXPointerResult::~nsXPointerResult() +{ +} + +NS_INTERFACE_MAP_BEGIN(nsXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsIXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsIModifyableXPointerResult) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XPointerResult) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPointerResult) +NS_IMPL_RELEASE(nsXPointerResult) + +NS_IMETHODIMP +nsXPointerResult::AppendRange(nsIDOMRange* aRange) +{ + NS_ENSURE_ARG(aRange); + + if (!mArray.AppendObject(aRange)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerResult::Item(PRUint32 aIndex, nsIDOMRange** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + + if (aIndex >= mArray.Count()) { + return NS_ERROR_FAILURE; + } + + *aReturn = mArray.ObjectAt(aIndex); + NS_IF_ADDREF(*aReturn); + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerResult::GetLength(PRUint32* aLength) +{ + NS_ENSURE_ARG_POINTER(aLength); + + *aLength = mArray.Count(); + + return NS_OK; +} + +nsresult NS_NewXPointerResult(nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = new nsXPointerResult(); + if (!*aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult); + + return NS_OK; +} + +static nsresult NS_NewXPointerResult(nsIDOMRange *aRange, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG(aRange); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr result(new nsXPointerResult()); + if (!result) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = result->AppendRange(aRange); + if (NS_FAILED(rv)) { + return rv; + } + + *aResult = result.get(); + NS_ADDREF(*aResult); + + return NS_OK; +} + +static nsresult NS_NewXPointerResult(nsIDOMNode *aNode, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG(aNode); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr range(do_CreateInstance(kRangeCID)); + if (!range) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = range->SelectNode(aNode); + if (NS_FAILED(rv)) { + return rv; + } + + return NS_NewXPointerResult(range, aResult); +} + + +// nsXPointerSchemeContext + +class nsXPointerSchemeContext : public nsIXPointerSchemeContext +{ +public: + nsXPointerSchemeContext() {}; + virtual ~nsXPointerSchemeContext() {}; + + NS_DECL_ISUPPORTS + NS_DECL_NSIXPOINTERSCHEMECONTEXT + + nsresult Append(const nsAString &aScheme, const nsAString &aData); + +private: + nsStringArray mSchemes; + nsStringArray mDatas; +}; + +NS_IMPL_ISUPPORTS1(nsXPointerSchemeContext, nsIXPointerSchemeContext) + +NS_IMETHODIMP +nsXPointerSchemeContext::GetCount(PRUint32 *aCount) +{ + NS_ENSURE_ARG_POINTER(aCount); + + *aCount = mSchemes.Count(); + + return NS_OK; +} + + +nsresult +nsXPointerSchemeContext::Append(const nsAString &aScheme, + const nsAString &aData) +{ + if (!mSchemes.AppendString(aScheme)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!mDatas.AppendString(aData)) { + // Keep mDatas and mSchemes in sync + mSchemes.RemoveStringAt(mSchemes.Count() - 1); + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPointerSchemeContext::GetSchemeData(PRUint32 aIndex, + nsAString &aScheme, + nsAString &aData) +{ + if (aIndex >= mSchemes.Count()) { + aScheme.Truncate(); + aData.Truncate(); + + return NS_ERROR_FAILURE; + } + + mSchemes.StringAt(aIndex, aScheme); + mDatas.StringAt(aIndex, aData); + + return NS_OK; +} + +// XPointer + +nsXPointer::nsXPointer() +{ +} + +nsXPointer::~nsXPointer() +{ +} + +static nsresult GetNextSchemeNameAndData(nsString& aExpression, + nsString &aScheme, + nsString& aData) +{ + aScheme.Truncate(); + aData.Truncate(); + + PRInt32 lp = aExpression.FindChar('('); + if (lp < 1) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + PRInt32 i = lp + 1, len = aExpression.Length(); + if (i >= len) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + aScheme = Substring(aExpression, 0, lp); + aScheme.CompressWhitespace(PR_TRUE, PR_FALSE); + if (aScheme.FindCharInSet(" \t\r\n") > 0) { + return NS_ERROR_FAILURE; // scheme name can't contain ws (we'd really need to check a lot more...) + } + + // XXX perf: Switch to string iterators + PRBool escapeOn = PR_FALSE; + PRInt32 balance = 1; + for (; i < len; ++i) { + // Circumflex is the escape character that can precede ^, ( and ) only + if (aExpression[i] == '^') { + if (!escapeOn) { + escapeOn = PR_TRUE; + continue; + } + } else if (escapeOn) { + if ((aExpression[i] != '(') && (aExpression[i] != ')')) { + return NS_ERROR_FAILURE; // illegal use of ^ + } + } else if (aExpression[i] == '(') { + ++balance; + } else if (aExpression[i] == ')') { + if (--balance == 0) { + aExpression.Cut(0, i + 1); + break; + } + } + + aData.Append(aExpression[i]); + escapeOn = PR_FALSE; + } + + if (balance != 0) { + return NS_ERROR_FAILURE; // format |scheme + '(' [ + data + ] + ')'| required + } + + return NS_OK; +} + + +nsresult +nsXPointer::Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIXPointerResult **aResult) +{ + NS_ENSURE_ARG_POINTER(aDocument); + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + + nsresult rv = NS_OK; + + if (aExpression.FindChar('(') < 0) { + // Must be shorthand, i.e. plain id + nsCOMPtr element; + aDocument->GetElementById(aExpression, getter_AddRefs(element)); + if (element) { + rv = NS_NewXPointerResult(element, aResult); + } + return rv; + } + + nsAutoString expression(aExpression), scheme, data; + + NS_NAMED_LITERAL_STRING(element, "element"); + NS_NAMED_LITERAL_STRING(fixptr, "fixptr"); + NS_NAMED_LITERAL_CSTRING(baseSchemeProgID, NS_XPOINTER_SCHEME_PROCESSOR_BASE); + nsCOMPtr contextSchemeDataArray(new nsXPointerSchemeContext()); + if (!contextSchemeDataArray) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // Keep trying the schemes from left to right until one finds a subresource + while (!expression.IsEmpty()) { + rv = GetNextSchemeNameAndData(expression, scheme, data); + if (NS_FAILED(rv)) + break; + + // Built in schemes + if (scheme.Equals(element)) { + // We implement element scheme by using the FIXptr processor. + // Check there are no parenthesis (legal in FIXptr data). + if (data.FindChar('(') < 0) { + nsCOMPtr range; + rv = nsFIXptr::Evaluate(aDocument, data, getter_AddRefs(range)); + if (NS_FAILED(rv)) + break; + if (range) { + return NS_NewXPointerResult(range, aResult); + } + } + } else if (scheme.Equals(fixptr)) { + nsCOMPtr range; + rv = nsFIXptr::Evaluate(aDocument, data, getter_AddRefs(range)); + if (NS_FAILED(rv)) + break; + if (range) { + return NS_NewXPointerResult(range, aResult); + } + } else { + // Add-on schemes + nsCAutoString progid(baseSchemeProgID + NS_ConvertUCS2toUTF8(scheme)); + nsCOMPtr p(do_CreateInstance(progid.get())); + if (p) { + rv = p->Evaluate(aDocument, contextSchemeDataArray, data, aResult); + if (NS_FAILED(rv)) + break; + if (*aResult) + return NS_OK; + } + } + + rv = contextSchemeDataArray->Append(scheme, data); + if (NS_FAILED(rv)) + break; + + } + + return rv; +} + diff --git a/mozilla/extensions/xmlextras/pointers/src/nsXPointer.h b/mozilla/extensions/xmlextras/pointers/src/nsXPointer.h new file mode 100755 index 00000000000..2df971cac29 --- /dev/null +++ b/mozilla/extensions/xmlextras/pointers/src/nsXPointer.h @@ -0,0 +1,63 @@ +/* -*- 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) 2003 + * 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 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 nsXPointer_h__ +#define nsXPointer_h__ + +#include "nsAString.h" +#include "nsIXPointer.h" + +class nsXPointer { + nsXPointer(); + ~nsXPointer(); +public: + /** + * Evaluate an XPointer expression. + * + * @param aDocument The document in which to evaluate. + * @param aExpression The XPointer expression string to evaluate. + * @param aResult The result. + */ + static nsresult Evaluate(nsIDOMDocument *aDocument, + const nsAString& aExpression, + nsIXPointerResult **aResult); + +}; + +#endif diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index e63348eabb0..5b94f37f6b8 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -87,6 +87,7 @@ #include "nsIPageSequenceFrame.h" #include "nsICaret.h" #include "nsIDOMHTMLDocument.h" +#include "nsIXPointer.h" #include "nsIXMLDocument.h" #include "nsIDOMXMLDocument.h" #include "nsIScrollableView.h" @@ -1285,8 +1286,6 @@ protected: nsresult SetPrefLinkRules(void); nsresult SetPrefFocusRules(void); - 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 // pointers for weak (ie, non owning) references. If you add any members to this @@ -4044,8 +4043,31 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) } } - // Finally try FIXptr + // Try XPointer nsCOMPtr jumpToRange; + nsCOMPtr xpointerResult; + if (!content) { + nsCOMPtr xmldoc = do_QueryInterface(mDocument); + if (xmldoc) { + xmldoc->EvaluateXPointer(aAnchorName, getter_AddRefs(xpointerResult)); + if (xpointerResult) { + xpointerResult->Item(0, getter_AddRefs(jumpToRange)); + if (!jumpToRange) { + // We know it was an XPointer, so there is no point in + // trying any other pointer types, let's just return + // an error. + return NS_ERROR_FAILURE; + } + nsCOMPtr node; + jumpToRange->GetStartContainer(getter_AddRefs(node)); + if (node) { + content = do_QueryInterface(node); + } + } + } + } + + // Finally try FIXptr if (!content) { nsCOMPtr xmldoc = do_QueryInterface(mDocument); if (xmldoc) { @@ -4054,7 +4076,7 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) nsCOMPtr node; jumpToRange->GetStartContainer(getter_AddRefs(node)); if (node) { - node->QueryInterface(NS_GET_IID(nsIContent),getter_AddRefs(content)); + content = do_QueryInterface(node); } } } @@ -4092,7 +4114,26 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) if (jumpToRange) { if (!selectAnchor) jumpToRange->Collapse(PR_TRUE); - SelectRange(jumpToRange); + + nsCOMPtr sel; + if (NS_SUCCEEDED( + GetSelection(nsISelectionController::SELECTION_NORMAL, + getter_AddRefs(sel))) && + sel) { + sel->RemoveAllRanges(); + sel->AddRange(jumpToRange); + } + + if (selectAnchor && xpointerResult) { + // Select the rest (if any) of the ranges in XPointerResult + PRUint32 count, i; + xpointerResult->GetLength(&count); + for (i = 1; i < count; i++) { // jumpToRange is i = 0 + nsCOMPtr range; + xpointerResult->Item(i, getter_AddRefs(range)); + sel->AddRange(range); + } + } } if (esm) { @@ -4129,19 +4170,6 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) return rv; } -nsresult -PresShell::SelectRange(nsIDOMRange *aRange) -{ - nsCOMPtr sel; - nsresult rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); - if (NS_SUCCEEDED(rv) && sel) { - sel->RemoveAllRanges(); - sel->AddRange(aRange); - } - - return rv; -} - /** * This function takes a scrolling view, a rect, and a scroll position and * attempts to scroll that rect to that position in that view. The rect diff --git a/mozilla/layout/build/nsLayoutModule.cpp b/mozilla/layout/build/nsLayoutModule.cpp index 5717a2db44f..f18436738fc 100644 --- a/mozilla/layout/build/nsLayoutModule.cpp +++ b/mozilla/layout/build/nsLayoutModule.cpp @@ -128,6 +128,7 @@ #include "nsIAutoCopy.h" #include "nsIPrintPreviewContext.h" #include "nsCSSLoader.h" +#include "nsIModifyableXPointer.h" #include "nsXULAtoms.h" #include "nsLayoutCID.h" @@ -368,6 +369,7 @@ nsresult NS_NewContentPolicy(nsIContentPolicy** aResult); nsresult NS_NewFrameLoader(nsIFrameLoader** aResult); nsresult NS_NewSyncLoadDOMService(nsISyncLoadDOMService** aResult); nsresult NS_NewDOMEventGroup(nsIDOMEventGroup** aResult); +nsresult NS_NewXPointerResult(nsIXPointerResult **aResult); nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult); nsresult NS_CreateCSSFrameConstructor(nsICSSFrameConstructor** aResult); @@ -455,6 +457,7 @@ MAKE_CTOR(CreateNewAutoCopyService, nsIAutoCopyService, NS_NewAutoCopySe MAKE_CTOR(CreateSelectionImageService, nsISelectionImageService,NS_NewSelectionImageService) MAKE_CTOR(CreateCaret, nsICaret, NS_NewCaret) +MAKE_CTOR(CreateXPointerResult, nsIXPointerResult, NS_NewXPointerResult) MAKE_CTOR(CreateNameSpaceManager, nsINameSpaceManager, NS_GetNameSpaceManager) MAKE_CTOR(CreateEventListenerManager, nsIEventListenerManager, NS_NewEventListenerManager) MAKE_CTOR(CreateEventStateManager, nsIEventStateManager, NS_NewEventStateManager) @@ -798,6 +801,11 @@ static const nsModuleComponentInfo gComponents[] = { nsnull, CreateDOMEventGroup }, + { "XPointer Result", + NS_XPOINTERRESULT_CID, + nsnull, + CreateXPointerResult }, + { "Document Viewer", NS_DOCUMENT_VIEWER_CID, nsnull, diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index e63348eabb0..5b94f37f6b8 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -87,6 +87,7 @@ #include "nsIPageSequenceFrame.h" #include "nsICaret.h" #include "nsIDOMHTMLDocument.h" +#include "nsIXPointer.h" #include "nsIXMLDocument.h" #include "nsIDOMXMLDocument.h" #include "nsIScrollableView.h" @@ -1285,8 +1286,6 @@ protected: nsresult SetPrefLinkRules(void); nsresult SetPrefFocusRules(void); - 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 // pointers for weak (ie, non owning) references. If you add any members to this @@ -4044,8 +4043,31 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) } } - // Finally try FIXptr + // Try XPointer nsCOMPtr jumpToRange; + nsCOMPtr xpointerResult; + if (!content) { + nsCOMPtr xmldoc = do_QueryInterface(mDocument); + if (xmldoc) { + xmldoc->EvaluateXPointer(aAnchorName, getter_AddRefs(xpointerResult)); + if (xpointerResult) { + xpointerResult->Item(0, getter_AddRefs(jumpToRange)); + if (!jumpToRange) { + // We know it was an XPointer, so there is no point in + // trying any other pointer types, let's just return + // an error. + return NS_ERROR_FAILURE; + } + nsCOMPtr node; + jumpToRange->GetStartContainer(getter_AddRefs(node)); + if (node) { + content = do_QueryInterface(node); + } + } + } + } + + // Finally try FIXptr if (!content) { nsCOMPtr xmldoc = do_QueryInterface(mDocument); if (xmldoc) { @@ -4054,7 +4076,7 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) nsCOMPtr node; jumpToRange->GetStartContainer(getter_AddRefs(node)); if (node) { - node->QueryInterface(NS_GET_IID(nsIContent),getter_AddRefs(content)); + content = do_QueryInterface(node); } } } @@ -4092,7 +4114,26 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) if (jumpToRange) { if (!selectAnchor) jumpToRange->Collapse(PR_TRUE); - SelectRange(jumpToRange); + + nsCOMPtr sel; + if (NS_SUCCEEDED( + GetSelection(nsISelectionController::SELECTION_NORMAL, + getter_AddRefs(sel))) && + sel) { + sel->RemoveAllRanges(); + sel->AddRange(jumpToRange); + } + + if (selectAnchor && xpointerResult) { + // Select the rest (if any) of the ranges in XPointerResult + PRUint32 count, i; + xpointerResult->GetLength(&count); + for (i = 1; i < count; i++) { // jumpToRange is i = 0 + nsCOMPtr range; + xpointerResult->Item(i, getter_AddRefs(range)); + sel->AddRange(range); + } + } } if (esm) { @@ -4129,19 +4170,6 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll) return rv; } -nsresult -PresShell::SelectRange(nsIDOMRange *aRange) -{ - nsCOMPtr sel; - nsresult rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel)); - if (NS_SUCCEEDED(rv) && sel) { - sel->RemoveAllRanges(); - sel->AddRange(aRange); - } - - return rv; -} - /** * This function takes a scrolling view, a rect, and a scroll position and * attempts to scroll that rect to that position in that view. The rect