зеркало из https://github.com/mozilla/gecko-dev.git
188 строки
6.0 KiB
C++
188 строки
6.0 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/dom/XPathEvaluator.h"
|
|
#include "mozilla/Move.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsAtom.h"
|
|
#include "mozilla/dom/XPathExpression.h"
|
|
#include "XPathResult.h"
|
|
#include "nsContentCID.h"
|
|
#include "txExpr.h"
|
|
#include "txExprParser.h"
|
|
#include "nsError.h"
|
|
#include "txURIUtils.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "nsDOMString.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "nsContentUtils.h"
|
|
#include "txIXPathContext.h"
|
|
#include "mozilla/dom/XPathEvaluatorBinding.h"
|
|
#include "mozilla/dom/BindingUtils.h"
|
|
#include "mozilla/dom/XPathNSResolverBinding.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
// txIParseContext implementation
|
|
class XPathEvaluatorParseContext : public txIParseContext {
|
|
public:
|
|
XPathEvaluatorParseContext(XPathNSResolver* aResolver, bool aIsCaseSensitive)
|
|
: mResolver(aResolver),
|
|
mResolverNode(nullptr),
|
|
mLastError(NS_OK),
|
|
mIsCaseSensitive(aIsCaseSensitive) {}
|
|
XPathEvaluatorParseContext(nsINode* aResolver, bool aIsCaseSensitive)
|
|
: mResolver(nullptr),
|
|
mResolverNode(aResolver),
|
|
mLastError(NS_OK),
|
|
mIsCaseSensitive(aIsCaseSensitive) {}
|
|
|
|
nsresult getError() { return mLastError; }
|
|
|
|
nsresult resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) override;
|
|
nsresult resolveFunctionCall(nsAtom* aName, int32_t aID,
|
|
FunctionCall** aFunction) override;
|
|
bool caseInsensitiveNameTests() override;
|
|
void SetErrorOffset(uint32_t aOffset) override;
|
|
|
|
private:
|
|
XPathNSResolver* mResolver;
|
|
nsINode* mResolverNode;
|
|
nsresult mLastError;
|
|
bool mIsCaseSensitive;
|
|
};
|
|
|
|
XPathEvaluator::XPathEvaluator(Document* aDocument)
|
|
: mDocument(do_GetWeakReference(aDocument)) {}
|
|
|
|
XPathEvaluator::~XPathEvaluator() {}
|
|
|
|
XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression,
|
|
XPathNSResolver* aResolver,
|
|
ErrorResult& aRv) {
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
|
|
XPathEvaluatorParseContext pContext(aResolver,
|
|
!(doc && doc->IsHTMLDocument()));
|
|
return CreateExpression(aExpression, &pContext, doc, aRv);
|
|
}
|
|
|
|
XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression,
|
|
nsINode* aResolver,
|
|
ErrorResult& aRv) {
|
|
nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
|
|
XPathEvaluatorParseContext pContext(aResolver,
|
|
!(doc && doc->IsHTMLDocument()));
|
|
return CreateExpression(aExpression, &pContext, doc, aRv);
|
|
}
|
|
|
|
XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression,
|
|
txIParseContext* aContext,
|
|
Document* aDocument,
|
|
ErrorResult& aRv) {
|
|
if (!mRecycler) {
|
|
mRecycler = new txResultRecycler;
|
|
}
|
|
|
|
nsAutoPtr<Expr> expression;
|
|
aRv = txExprParser::createExpr(PromiseFlatString(aExpression), aContext,
|
|
getter_Transfers(expression));
|
|
if (aRv.Failed()) {
|
|
if (!aRv.ErrorCodeIs(NS_ERROR_DOM_NAMESPACE_ERR)) {
|
|
aRv.SuppressException();
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_EXPRESSION_ERR);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
return new XPathExpression(std::move(expression), mRecycler, aDocument);
|
|
}
|
|
|
|
bool XPathEvaluator::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto,
|
|
JS::MutableHandle<JSObject*> aReflector) {
|
|
return dom::XPathEvaluator_Binding::Wrap(aCx, this, aGivenProto, aReflector);
|
|
}
|
|
|
|
/* static */ XPathEvaluator* XPathEvaluator::Constructor(
|
|
const GlobalObject& aGlobal, ErrorResult& rv) {
|
|
return new XPathEvaluator(nullptr);
|
|
}
|
|
|
|
already_AddRefed<XPathResult> XPathEvaluator::Evaluate(
|
|
JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode,
|
|
XPathNSResolver* aResolver, uint16_t aType, JS::Handle<JSObject*> aResult,
|
|
ErrorResult& rv) {
|
|
nsAutoPtr<XPathExpression> expression(
|
|
CreateExpression(aExpression, aResolver, rv));
|
|
if (rv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
return expression->Evaluate(aCx, aContextNode, aType, aResult, rv);
|
|
}
|
|
|
|
/*
|
|
* Implementation of txIParseContext private to XPathEvaluator, based on a
|
|
* XPathNSResolver
|
|
*/
|
|
|
|
nsresult XPathEvaluatorParseContext::resolveNamespacePrefix(nsAtom* aPrefix,
|
|
int32_t& aID) {
|
|
aID = kNameSpaceID_Unknown;
|
|
|
|
if (!mResolver && !mResolverNode) {
|
|
return NS_ERROR_DOM_NAMESPACE_ERR;
|
|
}
|
|
|
|
nsAutoString prefix;
|
|
if (aPrefix) {
|
|
aPrefix->ToString(prefix);
|
|
}
|
|
|
|
nsAutoString ns;
|
|
if (mResolver) {
|
|
ErrorResult rv;
|
|
mResolver->LookupNamespaceURI(prefix, ns, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
} else {
|
|
if (aPrefix == nsGkAtoms::xml) {
|
|
ns.AssignLiteral("http://www.w3.org/XML/1998/namespace");
|
|
} else {
|
|
mResolverNode->LookupNamespaceURI(prefix, ns);
|
|
}
|
|
}
|
|
|
|
if (DOMStringIsNull(ns)) {
|
|
return NS_ERROR_DOM_NAMESPACE_ERR;
|
|
}
|
|
|
|
if (ns.IsEmpty()) {
|
|
aID = kNameSpaceID_None;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// get the namespaceID for the URI
|
|
return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
|
|
}
|
|
|
|
nsresult XPathEvaluatorParseContext::resolveFunctionCall(nsAtom* aName,
|
|
int32_t aID,
|
|
FunctionCall** aFn) {
|
|
return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
|
|
}
|
|
|
|
bool XPathEvaluatorParseContext::caseInsensitiveNameTests() {
|
|
return !mIsCaseSensitive;
|
|
}
|
|
|
|
void XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset) {}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|