1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/templates/src/nsRDFBinding.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,271 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsXULTemplateQueryProcessorRDF.h" 1.10 +#include "nsXULTemplateResultRDF.h" 1.11 +#include "nsRDFBinding.h" 1.12 + 1.13 +#ifdef DEBUG 1.14 +#include "nsXULContentUtils.h" 1.15 +#endif 1.16 + 1.17 +RDFBindingSet::~RDFBindingSet() 1.18 +{ 1.19 + while (mFirst) { 1.20 + RDFBinding* doomed = mFirst; 1.21 + mFirst = mFirst->mNext; 1.22 + delete doomed; 1.23 + } 1.24 + 1.25 + MOZ_COUNT_DTOR(RDFBindingSet); 1.26 +} 1.27 + 1.28 +nsresult 1.29 +RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate) 1.30 +{ 1.31 + RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar); 1.32 + if (! newbinding) 1.33 + return NS_ERROR_OUT_OF_MEMORY; 1.34 + 1.35 + if (mFirst) { 1.36 + RDFBinding* binding = mFirst; 1.37 + 1.38 + while (binding) { 1.39 + // the binding is dependant on the calculation of a previous binding 1.40 + if (binding->mSubjectVariable == aVar) 1.41 + newbinding->mHasDependency = true; 1.42 + 1.43 + // if the target variable is already used in a binding, ignore it 1.44 + // since it won't be useful for anything 1.45 + if (binding->mTargetVariable == aVar) { 1.46 + delete newbinding; 1.47 + return NS_OK; 1.48 + } 1.49 + 1.50 + // add the binding at the end of the list 1.51 + if (! binding->mNext) { 1.52 + binding->mNext = newbinding; 1.53 + break; 1.54 + } 1.55 + 1.56 + binding = binding->mNext; 1.57 + } 1.58 + } 1.59 + else { 1.60 + mFirst = newbinding; 1.61 + } 1.62 + 1.63 + mCount++; 1.64 + 1.65 + return NS_OK; 1.66 +} 1.67 + 1.68 +bool 1.69 +RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject, 1.70 + nsIRDFResource* aPredicate, 1.71 + nsIRDFNode* aTarget, 1.72 + nsIAtom* aMemberVariable, 1.73 + nsXULTemplateResultRDF* aResult, 1.74 + nsBindingValues& aBindingValues) 1.75 +{ 1.76 + NS_ASSERTION(aBindingValues.GetBindingSet() == this, 1.77 + "nsBindingValues not for this RDFBindingSet"); 1.78 + NS_PRECONDITION(aResult, "Must have result"); 1.79 + 1.80 + bool needSync = false; 1.81 + nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray(); 1.82 + if (!valuesArray) 1.83 + return false; 1.84 + 1.85 + RDFBinding* binding = mFirst; 1.86 + int32_t count = 0; 1.87 + 1.88 + // QI for proper comparisons just to be safe 1.89 + nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject); 1.90 + 1.91 + // iterate through the bindings looking for ones that would match the RDF 1.92 + // nodes that were involved in a change 1.93 + nsCOMPtr<nsIRDFNode> value; 1.94 + while (binding) { 1.95 + if (aPredicate == binding->mPredicate) { 1.96 + // if the source of the binding is the member variable, optimize 1.97 + if (binding->mSubjectVariable == aMemberVariable) { 1.98 + valuesArray[count] = aTarget; 1.99 + needSync = true; 1.100 + } 1.101 + else { 1.102 + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); 1.103 + if (value == subjectnode) { 1.104 + valuesArray[count] = aTarget; 1.105 + needSync = true; 1.106 + } 1.107 + } 1.108 + } 1.109 + 1.110 + binding = binding->mNext; 1.111 + count++; 1.112 + } 1.113 + 1.114 + return needSync; 1.115 +} 1.116 + 1.117 +void 1.118 +RDFBindingSet::AddDependencies(nsIRDFResource* aSubject, 1.119 + nsXULTemplateResultRDF* aResult) 1.120 +{ 1.121 + NS_PRECONDITION(aResult, "Must have result"); 1.122 + 1.123 + // iterate through the bindings and add binding dependencies to the 1.124 + // processor 1.125 + 1.126 + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); 1.127 + if (! processor) 1.128 + return; 1.129 + 1.130 + nsCOMPtr<nsIRDFNode> value; 1.131 + 1.132 + RDFBinding* binding = mFirst; 1.133 + while (binding) { 1.134 + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); 1.135 + 1.136 + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); 1.137 + if (valueres) 1.138 + processor->AddBindingDependency(aResult, valueres); 1.139 + 1.140 + binding = binding->mNext; 1.141 + } 1.142 +} 1.143 + 1.144 +void 1.145 +RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject, 1.146 + nsXULTemplateResultRDF* aResult) 1.147 +{ 1.148 + NS_PRECONDITION(aResult, "Must have result"); 1.149 + 1.150 + // iterate through the bindings and remove binding dependencies from the 1.151 + // processor 1.152 + 1.153 + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); 1.154 + if (! processor) 1.155 + return; 1.156 + 1.157 + nsCOMPtr<nsIRDFNode> value; 1.158 + 1.159 + RDFBinding* binding = mFirst; 1.160 + while (binding) { 1.161 + aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); 1.162 + 1.163 + nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value); 1.164 + if (valueres) 1.165 + processor->RemoveBindingDependency(aResult, valueres); 1.166 + 1.167 + binding = binding->mNext; 1.168 + } 1.169 +} 1.170 + 1.171 +int32_t 1.172 +RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding) 1.173 +{ 1.174 + int32_t idx = 0; 1.175 + RDFBinding* binding = mFirst; 1.176 + 1.177 + while (binding) { 1.178 + if (binding->mTargetVariable == aTargetVariable) { 1.179 + *aBinding = binding; 1.180 + return idx; 1.181 + } 1.182 + idx++; 1.183 + binding = binding->mNext; 1.184 + } 1.185 + 1.186 + return -1; 1.187 +} 1.188 + 1.189 +nsBindingValues::~nsBindingValues() 1.190 +{ 1.191 + ClearBindingSet(); 1.192 + MOZ_COUNT_DTOR(nsBindingValues); 1.193 +} 1.194 + 1.195 +void 1.196 +nsBindingValues::ClearBindingSet() 1.197 +{ 1.198 + if (mBindings && mValues) { 1.199 + delete [] mValues; 1.200 + mValues = nullptr; 1.201 + } 1.202 + 1.203 + mBindings = nullptr; 1.204 +} 1.205 + 1.206 +nsresult 1.207 +nsBindingValues::SetBindingSet(RDFBindingSet* aBindings) 1.208 +{ 1.209 + ClearBindingSet(); 1.210 + 1.211 + int32_t count = aBindings->Count(); 1.212 + if (count) { 1.213 + mValues = new nsCOMPtr<nsIRDFNode>[count]; 1.214 + if (!mValues) 1.215 + return NS_ERROR_OUT_OF_MEMORY; 1.216 + 1.217 + mBindings = aBindings; 1.218 + } 1.219 + else { 1.220 + mValues = nullptr; 1.221 + } 1.222 + 1.223 + return NS_OK; 1.224 +} 1.225 + 1.226 +void 1.227 +nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult, 1.228 + nsIAtom* aVar, 1.229 + nsIRDFNode** aValue) 1.230 +{ 1.231 + *aValue = nullptr; 1.232 + 1.233 + // assignments are calculated lazily when asked for. The only issue is 1.234 + // when a binding has no value in the RDF graph, it will be checked again 1.235 + // every time. 1.236 + 1.237 + if (mBindings && mValues) { 1.238 + RDFBinding* binding; 1.239 + int32_t idx = mBindings->LookupTargetIndex(aVar, &binding); 1.240 + if (idx >= 0) { 1.241 + *aValue = mValues[idx]; 1.242 + if (*aValue) { 1.243 + NS_ADDREF(*aValue); 1.244 + } 1.245 + else { 1.246 + nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); 1.247 + if (! processor) 1.248 + return; 1.249 + 1.250 + nsIRDFDataSource* ds = processor->GetDataSource(); 1.251 + if (! ds) 1.252 + return; 1.253 + 1.254 + nsCOMPtr<nsIRDFNode> subjectValue; 1.255 + aResult->GetAssignment(binding->mSubjectVariable, 1.256 + getter_AddRefs(subjectValue)); 1.257 + if (subjectValue) { 1.258 + nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue); 1.259 + ds->GetTarget(subject, binding->mPredicate, true, aValue); 1.260 + if (*aValue) 1.261 + mValues[idx] = *aValue; 1.262 + } 1.263 + } 1.264 + } 1.265 + } 1.266 +} 1.267 + 1.268 +void 1.269 +nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject, 1.270 + nsXULTemplateResultRDF* aResult) 1.271 +{ 1.272 + if (mBindings) 1.273 + mBindings->RemoveDependencies(aSubject, aResult); 1.274 +}