summaryrefslogtreecommitdiffstats
path: root/dom/xul/templates/nsRDFBinding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xul/templates/nsRDFBinding.cpp')
-rw-r--r--dom/xul/templates/nsRDFBinding.cpp265
1 files changed, 265 insertions, 0 deletions
diff --git a/dom/xul/templates/nsRDFBinding.cpp b/dom/xul/templates/nsRDFBinding.cpp
new file mode 100644
index 000000000..120adfa79
--- /dev/null
+++ b/dom/xul/templates/nsRDFBinding.cpp
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsXULTemplateQueryProcessorRDF.h"
+#include "nsXULTemplateResultRDF.h"
+#include "nsRDFBinding.h"
+
+#ifdef DEBUG
+#include "nsXULContentUtils.h"
+#endif
+
+RDFBindingSet::~RDFBindingSet()
+{
+ while (mFirst) {
+ RDFBinding* doomed = mFirst;
+ mFirst = mFirst->mNext;
+ delete doomed;
+ }
+
+ MOZ_COUNT_DTOR(RDFBindingSet);
+}
+
+nsresult
+RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate)
+{
+ RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar);
+ if (mFirst) {
+ RDFBinding* binding = mFirst;
+
+ while (binding) {
+ // the binding is dependant on the calculation of a previous binding
+ if (binding->mSubjectVariable == aVar)
+ newbinding->mHasDependency = true;
+
+ // if the target variable is already used in a binding, ignore it
+ // since it won't be useful for anything
+ if (binding->mTargetVariable == aVar) {
+ delete newbinding;
+ return NS_OK;
+ }
+
+ // add the binding at the end of the list
+ if (! binding->mNext) {
+ binding->mNext = newbinding;
+ break;
+ }
+
+ binding = binding->mNext;
+ }
+ }
+ else {
+ mFirst = newbinding;
+ }
+
+ mCount++;
+
+ return NS_OK;
+}
+
+bool
+RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject,
+ nsIRDFResource* aPredicate,
+ nsIRDFNode* aTarget,
+ nsIAtom* aMemberVariable,
+ nsXULTemplateResultRDF* aResult,
+ nsBindingValues& aBindingValues)
+{
+ NS_ASSERTION(aBindingValues.GetBindingSet() == this,
+ "nsBindingValues not for this RDFBindingSet");
+ NS_PRECONDITION(aResult, "Must have result");
+
+ bool needSync = false;
+ nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray();
+ if (!valuesArray)
+ return false;
+
+ RDFBinding* binding = mFirst;
+ int32_t count = 0;
+
+ // QI for proper comparisons just to be safe
+ nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject);
+
+ // iterate through the bindings looking for ones that would match the RDF
+ // nodes that were involved in a change
+ nsCOMPtr<nsIRDFNode> value;
+ while (binding) {
+ if (aPredicate == binding->mPredicate) {
+ // if the source of the binding is the member variable, optimize
+ if (binding->mSubjectVariable == aMemberVariable) {
+ valuesArray[count] = aTarget;
+ needSync = true;
+ }
+ else {
+ aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
+ if (value == subjectnode) {
+ valuesArray[count] = aTarget;
+ needSync = true;
+ }
+ }
+ }
+
+ binding = binding->mNext;
+ count++;
+ }
+
+ return needSync;
+}
+
+void
+RDFBindingSet::AddDependencies(nsIRDFResource* aSubject,
+ nsXULTemplateResultRDF* aResult)
+{
+ NS_PRECONDITION(aResult, "Must have result");
+
+ // iterate through the bindings and add binding dependencies to the
+ // processor
+
+ nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
+ if (! processor)
+ return;
+
+ nsCOMPtr<nsIRDFNode> value;
+
+ RDFBinding* binding = mFirst;
+ while (binding) {
+ aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
+
+ nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
+ if (valueres)
+ processor->AddBindingDependency(aResult, valueres);
+
+ binding = binding->mNext;
+ }
+}
+
+void
+RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject,
+ nsXULTemplateResultRDF* aResult)
+{
+ NS_PRECONDITION(aResult, "Must have result");
+
+ // iterate through the bindings and remove binding dependencies from the
+ // processor
+
+ nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
+ if (! processor)
+ return;
+
+ nsCOMPtr<nsIRDFNode> value;
+
+ RDFBinding* binding = mFirst;
+ while (binding) {
+ aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
+
+ nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
+ if (valueres)
+ processor->RemoveBindingDependency(aResult, valueres);
+
+ binding = binding->mNext;
+ }
+}
+
+int32_t
+RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding)
+{
+ int32_t idx = 0;
+ RDFBinding* binding = mFirst;
+
+ while (binding) {
+ if (binding->mTargetVariable == aTargetVariable) {
+ *aBinding = binding;
+ return idx;
+ }
+ idx++;
+ binding = binding->mNext;
+ }
+
+ return -1;
+}
+
+nsBindingValues::~nsBindingValues()
+{
+ ClearBindingSet();
+ MOZ_COUNT_DTOR(nsBindingValues);
+}
+
+void
+nsBindingValues::ClearBindingSet()
+{
+ if (mBindings && mValues) {
+ delete [] mValues;
+ mValues = nullptr;
+ }
+
+ mBindings = nullptr;
+}
+
+nsresult
+nsBindingValues::SetBindingSet(RDFBindingSet* aBindings)
+{
+ ClearBindingSet();
+
+ int32_t count = aBindings->Count();
+ if (count) {
+ mValues = new nsCOMPtr<nsIRDFNode>[count];
+ mBindings = aBindings;
+ }
+ else {
+ mValues = nullptr;
+ }
+
+ return NS_OK;
+}
+
+void
+nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult,
+ nsIAtom* aVar,
+ nsIRDFNode** aValue)
+{
+ *aValue = nullptr;
+
+ // assignments are calculated lazily when asked for. The only issue is
+ // when a binding has no value in the RDF graph, it will be checked again
+ // every time.
+
+ if (mBindings && mValues) {
+ RDFBinding* binding;
+ int32_t idx = mBindings->LookupTargetIndex(aVar, &binding);
+ if (idx >= 0) {
+ *aValue = mValues[idx];
+ if (*aValue) {
+ NS_ADDREF(*aValue);
+ }
+ else {
+ nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
+ if (! processor)
+ return;
+
+ nsIRDFDataSource* ds = processor->GetDataSource();
+ if (! ds)
+ return;
+
+ nsCOMPtr<nsIRDFNode> subjectValue;
+ aResult->GetAssignment(binding->mSubjectVariable,
+ getter_AddRefs(subjectValue));
+ if (subjectValue) {
+ nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue);
+ ds->GetTarget(subject, binding->mPredicate, true, aValue);
+ if (*aValue)
+ mValues[idx] = *aValue;
+ }
+ }
+ }
+ }
+}
+
+void
+nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject,
+ nsXULTemplateResultRDF* aResult)
+{
+ if (mBindings)
+ mBindings->RemoveDependencies(aSubject, aResult);
+}