LCOV - code coverage report
Current view: top level - dom/xul/templates - nsXULTemplateQueryProcessorRDF.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 857 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 46 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsCOMPtr.h"
       7             : #include "nsICollation.h"
       8             : #include "nsIDOMNode.h"
       9             : #include "nsIRDFNode.h"
      10             : #include "nsIRDFObserver.h"
      11             : #include "nsIRDFRemoteDataSource.h"
      12             : #include "nsIRDFInferDataSource.h"
      13             : #include "nsIRDFService.h"
      14             : #include "nsRDFCID.h"
      15             : #include "nsIServiceManager.h"
      16             : #include "nsNameSpaceManager.h"
      17             : #include "nsGkAtoms.h"
      18             : #include "nsIDOMDocument.h"
      19             : #include "nsAttrName.h"
      20             : #include "rdf.h"
      21             : #include "nsArrayUtils.h"
      22             : #include "nsIURI.h"
      23             : 
      24             : #include "nsContentTestNode.h"
      25             : #include "nsRDFConInstanceTestNode.h"
      26             : #include "nsRDFConMemberTestNode.h"
      27             : #include "nsRDFPropertyTestNode.h"
      28             : #include "nsInstantiationNode.h"
      29             : #include "nsRDFTestNode.h"
      30             : #include "nsXULContentUtils.h"
      31             : #include "nsXULTemplateBuilder.h"
      32             : #include "nsXULTemplateResultRDF.h"
      33             : #include "nsXULTemplateResultSetRDF.h"
      34             : #include "nsXULTemplateQueryProcessorRDF.h"
      35             : #include "nsXULSortService.h"
      36             : #include "nsIDocument.h"
      37             : #include "nsIRDFCompositeDataSource.h"
      38             : 
      39             : //----------------------------------------------------------------------
      40             : 
      41             : #define PARSE_TYPE_INTEGER  "Integer"
      42             : 
      43             : nsrefcnt                  nsXULTemplateQueryProcessorRDF::gRefCnt = 0;
      44             : nsIRDFService*            nsXULTemplateQueryProcessorRDF::gRDFService;
      45             : nsIRDFContainerUtils*     nsXULTemplateQueryProcessorRDF::gRDFContainerUtils;
      46             : nsIRDFResource*           nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator;
      47             : nsIRDFResource*           nsXULTemplateQueryProcessorRDF::kRDF_type;
      48             : 
      49             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorRDF)
      50             : 
      51           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorRDF)
      52           0 :     tmp->Done();
      53           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      54             : 
      55           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorRDF)
      56           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDB)
      57           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastRef)
      58             : 
      59           0 :     for (auto it = tmp->mBindingDependencies.Iter(); !it.Done(); it.Next()) {
      60           0 :         nsXULTemplateQueryProcessorRDF::ResultArray* array = it.UserData();
      61           0 :         int32_t count = array->Length();
      62           0 :         for (int32_t i = 0; i < count; ++i) {
      63           0 :             cb.NoteXPCOMChild(array->ElementAt(i));
      64             :         }
      65             :     }
      66             : 
      67           0 :     for (auto it = tmp->mMemoryElementToResultMap.Iter();
      68           0 :          !it.Done();
      69           0 :          it.Next()) {
      70           0 :         nsCOMArray<nsXULTemplateResultRDF>* array = it.UserData();
      71           0 :         int32_t count = array->Count();
      72           0 :         for (int32_t i = 0; i < count; ++i) {
      73           0 :             cb.NoteXPCOMChild(array->ObjectAt(i));
      74             :         }
      75             :     }
      76             : 
      77           0 :     for (auto it = tmp->mRuleToBindingsMap.Iter(); !it.Done(); it.Next()) {
      78           0 :         cb.NoteXPCOMChild(it.Key());
      79             :     }
      80             : 
      81           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueries)
      82           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      83             : 
      84           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorRDF)
      85           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorRDF)
      86           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorRDF)
      87           0 :     NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor)
      88           0 :     NS_INTERFACE_MAP_ENTRY(nsIRDFObserver)
      89           0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor)
      90           0 : NS_INTERFACE_MAP_END
      91             : 
      92           0 : nsXULTemplateQueryProcessorRDF::nsXULTemplateQueryProcessorRDF(void)
      93             :     : mDB(nullptr),
      94             :       mBuilder(nullptr),
      95             :       mQueryProcessorRDFInited(false),
      96             :       mGenerationStarted(false),
      97             :       mUpdateBatchNest(0),
      98           0 :       mSimpleRuleMemberTest(nullptr)
      99             : {
     100           0 :     gRefCnt++;
     101           0 : }
     102             : 
     103           0 : nsXULTemplateQueryProcessorRDF::~nsXULTemplateQueryProcessorRDF(void)
     104             : {
     105           0 :     if (--gRefCnt == 0) {
     106           0 :         NS_IF_RELEASE(gRDFService);
     107           0 :         NS_IF_RELEASE(gRDFContainerUtils);
     108           0 :         NS_IF_RELEASE(kNC_BookmarkSeparator);
     109           0 :         NS_IF_RELEASE(kRDF_type);
     110             :     }
     111           0 : }
     112             : 
     113             : nsresult
     114           0 : nsXULTemplateQueryProcessorRDF::InitGlobals()
     115             : {
     116             :     nsresult rv;
     117             : 
     118             :     // Initialize the global shared reference to the service
     119             :     // manager and get some shared resource objects.
     120           0 :     if (!gRDFService) {
     121           0 :         NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
     122           0 :         rv = CallGetService(kRDFServiceCID, &gRDFService);
     123           0 :         if (NS_FAILED(rv))
     124           0 :             return rv;
     125             :     }
     126             : 
     127           0 :     if (!gRDFContainerUtils) {
     128           0 :         NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
     129           0 :         rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
     130           0 :         if (NS_FAILED(rv))
     131           0 :             return rv;
     132             :     }
     133             : 
     134           0 :     if (!kNC_BookmarkSeparator) {
     135           0 :         gRDFService->GetResource(
     136           0 :           NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
     137           0 :                              &kNC_BookmarkSeparator);
     138             :     }
     139             : 
     140           0 :     if (!kRDF_type) {
     141           0 :         gRDFService->GetResource(
     142           0 :           NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
     143           0 :                              &kRDF_type);
     144             :     }
     145             : 
     146           0 :     return NS_OK;
     147             : }
     148             : 
     149             : //----------------------------------------------------------------------
     150             : //
     151             : // nsIXULTemplateQueryProcessor interface
     152             : //
     153             : 
     154             : NS_IMETHODIMP
     155           0 : nsXULTemplateQueryProcessorRDF::GetDatasource(nsIArray* aDataSources,
     156             :                                               nsIDOMNode* aRootNode,
     157             :                                               bool aIsTrusted,
     158             :                                               nsIXULTemplateBuilder* aBuilder,
     159             :                                               bool* aShouldDelayBuilding,
     160             :                                               nsISupports** aResult)
     161             : {
     162           0 :     nsCOMPtr<nsIRDFCompositeDataSource> compDB;
     163           0 :     nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode);
     164             :     nsresult rv;
     165             : 
     166           0 :     *aResult = nullptr;
     167           0 :     *aShouldDelayBuilding = false;
     168             : 
     169           0 :     NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
     170             : 
     171             :     // make sure the RDF service is set up
     172           0 :     rv = InitGlobals();
     173           0 :     NS_ENSURE_SUCCESS(rv, rv);
     174             : 
     175             :     // create a database for the builder
     176           0 :     compDB = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX
     177           0 :                                "composite-datasource");
     178           0 :     if (!compDB) {
     179           0 :         NS_ERROR("unable to construct new composite data source");
     180           0 :         return NS_ERROR_UNEXPECTED;
     181             :     }
     182             : 
     183             :     // check for magical attributes. XXX move to ``flags''?
     184           0 :     if (root->AttrValueIs(kNameSpaceID_None,
     185             :                           nsGkAtoms::coalesceduplicatearcs,
     186             :                           nsGkAtoms::_false, eCaseMatters))
     187           0 :         compDB->SetCoalesceDuplicateArcs(false);
     188             : 
     189           0 :     if (root->AttrValueIs(kNameSpaceID_None,
     190             :                           nsGkAtoms::allownegativeassertions,
     191             :                           nsGkAtoms::_false, eCaseMatters))
     192           0 :         compDB->SetAllowNegativeAssertions(false);
     193             : 
     194           0 :     if (aIsTrusted) {
     195             :         // If we're a privileged (e.g., chrome) document, then add the
     196             :         // local store as the first data source in the db. Note that
     197             :         // we _might_ not be able to get a local store if we haven't
     198             :         // got a profile to read from yet.
     199           0 :         nsCOMPtr<nsIRDFDataSource> localstore;
     200           0 :         rv = gRDFService->GetDataSource("rdf:local-store",
     201           0 :                                         getter_AddRefs(localstore));
     202           0 :         NS_ENSURE_SUCCESS(rv, rv);
     203             : 
     204           0 :         rv = compDB->AddDataSource(localstore);
     205           0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add local store to db");
     206           0 :         NS_ENSURE_SUCCESS(rv, rv);
     207             :     }
     208             : 
     209             :     uint32_t length, index;
     210           0 :     rv = aDataSources->GetLength(&length);
     211           0 :     NS_ENSURE_SUCCESS(rv,rv);
     212             : 
     213           0 :     for (index = 0; index < length; index++) {
     214             : 
     215           0 :         nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, index);
     216           0 :         if (!uri) // we ignore other datasources than uri
     217           0 :             continue;
     218             : 
     219           0 :         nsCOMPtr<nsIRDFDataSource> ds;
     220           0 :         nsAutoCString uristrC;
     221           0 :         uri->GetSpec(uristrC);
     222             : 
     223           0 :         rv = gRDFService->GetDataSource(uristrC.get(), getter_AddRefs(ds));
     224             : 
     225           0 :         if (NS_FAILED(rv)) {
     226             :             // This is only a warning because the data source may not
     227             :             // be accessible for any number of reasons, including
     228             :             // security, a bad URL, etc.
     229             :   #ifdef DEBUG
     230           0 :             nsAutoCString msg;
     231           0 :             msg.AppendLiteral("unable to load datasource '");
     232           0 :             msg.Append(uristrC);
     233           0 :             msg.Append('\'');
     234           0 :             NS_WARNING(msg.get());
     235             :   #endif
     236           0 :             continue;
     237             :         }
     238             : 
     239           0 :         compDB->AddDataSource(ds);
     240             :     }
     241             : 
     242             : 
     243             :     // check if we were given an inference engine type
     244           0 :     nsAutoString infer;
     245           0 :     nsCOMPtr<nsIRDFDataSource> db;
     246           0 :     root->GetAttr(kNameSpaceID_None, nsGkAtoms::infer, infer);
     247           0 :     if (!infer.IsEmpty()) {
     248           0 :         nsCString inferCID(NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX);
     249           0 :         AppendUTF16toUTF8(infer, inferCID);
     250             :         nsCOMPtr<nsIRDFInferDataSource> inferDB =
     251           0 :             do_CreateInstance(inferCID.get());
     252             : 
     253           0 :         if (inferDB) {
     254           0 :             inferDB->SetBaseDataSource(compDB);
     255           0 :             db = do_QueryInterface(inferDB);
     256             :         }
     257             :         else {
     258           0 :             NS_WARNING("failed to construct inference engine specified on template");
     259             :         }
     260             :     }
     261             : 
     262           0 :     if (!db)
     263           0 :         db = compDB;
     264             : 
     265           0 :     return CallQueryInterface(db, aResult);
     266             : }
     267             : 
     268             : NS_IMETHODIMP
     269           0 : nsXULTemplateQueryProcessorRDF::InitializeForBuilding(nsISupports* aDatasource,
     270             :                                                       nsIXULTemplateBuilder* aBuilder,
     271             :                                                       nsIDOMNode* aRootNode)
     272             : {
     273           0 :     if (!mQueryProcessorRDFInited) {
     274           0 :         nsresult rv = InitGlobals();
     275           0 :         if (NS_FAILED(rv))
     276           0 :             return rv;
     277             : 
     278           0 :         mQueryProcessorRDFInited = true;
     279             :     }
     280             : 
     281             :     // don't do anything if generation has already been done
     282           0 :     if (mGenerationStarted)
     283           0 :         return NS_ERROR_UNEXPECTED;
     284             : 
     285           0 :     mDB = do_QueryInterface(aDatasource);
     286           0 :     mBuilder = aBuilder;
     287             : 
     288           0 :     ComputeContainmentProperties(aRootNode);
     289             : 
     290             :     // Add ourselves as a datasource observer
     291           0 :     if (mDB)
     292           0 :         mDB->AddObserver(this);
     293             : 
     294           0 :     return NS_OK;
     295             : }
     296             : 
     297             : NS_IMETHODIMP
     298           0 : nsXULTemplateQueryProcessorRDF::Done()
     299             : {
     300           0 :     if (!mQueryProcessorRDFInited)
     301           0 :         return NS_OK;
     302             : 
     303           0 :     if (mDB)
     304           0 :         mDB->RemoveObserver(this);
     305             : 
     306           0 :     mDB = nullptr;
     307           0 :     mBuilder = nullptr;
     308           0 :     mRefVariable = nullptr;
     309           0 :     mLastRef = nullptr;
     310             : 
     311           0 :     mGenerationStarted = false;
     312           0 :     mUpdateBatchNest = 0;
     313             : 
     314           0 :     mContainmentProperties.Clear();
     315             : 
     316           0 :     for (ReteNodeSet::Iterator node = mAllTests.First();
     317           0 :          node != mAllTests.Last(); ++node)
     318           0 :         delete *node;
     319             : 
     320           0 :     mAllTests.Clear();
     321           0 :     mRDFTests.Clear();
     322           0 :     mQueries.Clear();
     323             : 
     324           0 :     mSimpleRuleMemberTest = nullptr;
     325             : 
     326           0 :     mBindingDependencies.Clear();
     327             : 
     328           0 :     mMemoryElementToResultMap.Clear();
     329             : 
     330           0 :     mRuleToBindingsMap.Clear();
     331             : 
     332           0 :     return NS_OK;
     333             : }
     334             : 
     335             : NS_IMETHODIMP
     336           0 : nsXULTemplateQueryProcessorRDF::CompileQuery(nsIXULTemplateBuilder* aBuilder,
     337             :                                              nsIDOMNode* aQueryNode,
     338             :                                              nsIAtom* aRefVariable,
     339             :                                              nsIAtom* aMemberVariable,
     340             :                                              nsISupports** _retval)
     341             : {
     342           0 :     RefPtr<nsRDFQuery> query = new nsRDFQuery(this);
     343           0 :     if (!query)
     344           0 :         return NS_ERROR_OUT_OF_MEMORY;
     345             : 
     346           0 :     query->mRefVariable = aRefVariable;
     347           0 :     if (!mRefVariable)
     348           0 :       mRefVariable = aRefVariable;
     349             : 
     350           0 :     if (!aMemberVariable)
     351           0 :         query->mMemberVariable = NS_Atomize("?");
     352             :     else
     353           0 :         query->mMemberVariable = aMemberVariable;
     354             : 
     355             :     nsresult rv;
     356           0 :     TestNode *lastnode = nullptr;
     357             : 
     358           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
     359             : 
     360           0 :     if (content->NodeInfo()->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
     361             :         // simplified syntax with no rules
     362             : 
     363           0 :         query->SetSimple();
     364           0 :         NS_ASSERTION(!mSimpleRuleMemberTest,
     365             :                      "CompileQuery called twice with the same template");
     366           0 :         if (!mSimpleRuleMemberTest)
     367           0 :             rv = CompileSimpleQuery(query, content, &lastnode);
     368             :         else
     369           0 :             rv = NS_ERROR_FAILURE;
     370             :     }
     371           0 :     else if (content->NodeInfo()->Equals(nsGkAtoms::rule, kNameSpaceID_XUL)) {
     372             :         // simplified syntax with at least one rule
     373           0 :         query->SetSimple();
     374           0 :         rv = CompileSimpleQuery(query, content, &lastnode);
     375             :     }
     376             :     else {
     377           0 :         rv = CompileExtendedQuery(query, content, &lastnode);
     378             :     }
     379             : 
     380           0 :     if (NS_FAILED(rv))
     381           0 :         return rv;
     382             : 
     383           0 :     query->SetQueryNode(aQueryNode);
     384             : 
     385           0 :     nsInstantiationNode* instnode = new nsInstantiationNode(this, query);
     386             : 
     387             :     // this and other functions always add nodes to mAllTests first. That
     388             :     // way if something fails, the node will just sit harmlessly in mAllTests
     389             :     // where it can be deleted later.
     390           0 :     rv = mAllTests.Add(instnode);
     391           0 :     if (NS_FAILED(rv)) {
     392           0 :         delete instnode;
     393           0 :         return rv;
     394             :     }
     395             : 
     396           0 :     rv = lastnode->AddChild(instnode);
     397           0 :     if (NS_FAILED(rv))
     398           0 :         return rv;
     399             : 
     400           0 :     mQueries.AppendElement(query);
     401             : 
     402           0 :     query.forget(_retval);
     403             : 
     404           0 :     return NS_OK;
     405             : }
     406             : 
     407             : NS_IMETHODIMP
     408           0 : nsXULTemplateQueryProcessorRDF::GenerateResults(nsISupports* aDatasource,
     409             :                                                 nsIXULTemplateResult* aRef,
     410             :                                                 nsISupports* aQuery,
     411             :                                                 nsISimpleEnumerator** aResults)
     412             : {
     413           0 :     nsCOMPtr<nsITemplateRDFQuery> rdfquery = do_QueryInterface(aQuery);
     414           0 :     if (! rdfquery)
     415           0 :         return NS_ERROR_INVALID_ARG;
     416             : 
     417           0 :     mGenerationStarted = true;
     418             : 
     419             :     // should be safe to cast here since the query is a
     420             :     // non-scriptable nsITemplateRDFQuery
     421           0 :     nsRDFQuery* query = static_cast<nsRDFQuery *>(aQuery);
     422             : 
     423           0 :     *aResults = nullptr;
     424             : 
     425           0 :     nsCOMPtr<nsISimpleEnumerator> results;
     426             : 
     427           0 :     if (aRef) {
     428             :         // make sure that cached results were generated for this ref, and if not,
     429             :         // regenerate them. Otherwise, things will go wrong for templates bound to
     430             :         // an HTML element as they are not generated lazily.
     431           0 :         if (aRef == mLastRef) {
     432           0 :             query->UseCachedResults(getter_AddRefs(results));
     433             :         }
     434             :         else {
     435             :             // clear the cached results
     436           0 :             int32_t count = mQueries.Length();
     437           0 :             for (int32_t r = 0; r < count; r++) {
     438           0 :                 mQueries[r]->ClearCachedResults();
     439             :             }
     440             :         }
     441             : 
     442           0 :         if (! results) {
     443           0 :             if (! query->mRefVariable)
     444           0 :                 query->mRefVariable = NS_Atomize("?uri");
     445             : 
     446           0 :             nsCOMPtr<nsIRDFResource> refResource;
     447           0 :             aRef->GetResource(getter_AddRefs(refResource));
     448           0 :             if (! refResource)
     449           0 :                 return NS_ERROR_FAILURE;
     450             : 
     451             :             // Propagate the assignments through the network
     452           0 :             TestNode* root = query->GetRoot();
     453             : 
     454           0 :             if (query->IsSimple() && mSimpleRuleMemberTest) {
     455             :                 // get the top node in the simple rule tree
     456           0 :                 root = mSimpleRuleMemberTest->GetParent();
     457           0 :                 mLastRef = aRef;
     458             :             }
     459             : 
     460           0 :             if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     461           0 :                 nsAutoString id;
     462           0 :                 aRef->GetId(id);
     463             : 
     464           0 :                 nsAutoString rvar;
     465           0 :                 query->mRefVariable->ToString(rvar);
     466           0 :                 nsAutoString mvar;
     467           0 :                 query->mMemberVariable->ToString(mvar);
     468             : 
     469           0 :                 MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     470             :                        ("QueryProcessor::GenerateResults using ref %s and vars [ ref: %s  member: %s]",
     471             :                        NS_ConvertUTF16toUTF8(id).get(),
     472             :                        NS_ConvertUTF16toUTF8(rvar).get(),
     473             :                        NS_ConvertUTF16toUTF8(mvar).get()));
     474             :             }
     475             : 
     476           0 :             if (root) {
     477             :                 // the seed is the initial instantiation, which has a single
     478             :                 // assignment holding the reference point
     479           0 :                 Instantiation seed;
     480           0 :                 seed.AddAssignment(query->mRefVariable, refResource);
     481             : 
     482           0 :                 InstantiationSet* instantiations = new InstantiationSet();
     483           0 :                 instantiations->Append(seed);
     484             : 
     485             :                 // if the propagation caused a match, then the results will be
     486             :                 // cached in the query, retrieved below by calling
     487             :                 // UseCachedResults. The matching result set owns the
     488             :                 // instantiations and will delete them when results have been
     489             :                 // iterated over. If the propagation did not match, the
     490             :                 // instantiations need to be deleted.
     491           0 :                 bool owned = false;
     492           0 :                 nsresult rv = root->Propagate(*instantiations, false, owned);
     493           0 :                 if (! owned)
     494           0 :                     delete instantiations;
     495           0 :                 if (NS_FAILED(rv))
     496           0 :                     return rv;
     497             : 
     498           0 :                 query->UseCachedResults(getter_AddRefs(results));
     499             :             }
     500             :         }
     501             :     }
     502             : 
     503           0 :     if (! results) {
     504             :         // no results were found so create an empty set
     505           0 :         results = new nsXULTemplateResultSetRDF(this, query, nullptr);
     506             :     }
     507             : 
     508           0 :     results.swap(*aResults);
     509             : 
     510           0 :     return NS_OK;
     511             : }
     512             : 
     513             : NS_IMETHODIMP
     514           0 : nsXULTemplateQueryProcessorRDF::AddBinding(nsIDOMNode* aRuleNode,
     515             :                                            nsIAtom* aVar,
     516             :                                            nsIAtom* aRef,
     517             :                                            const nsAString& aExpr)
     518             : {
     519             :     // add a <binding> to a rule. When a result is matched, the bindings are
     520             :     // examined to add additional variable assignments
     521             : 
     522             :     // bindings can't be added once result generation has started, otherwise
     523             :     // the array sizes will get out of sync
     524           0 :     if (mGenerationStarted)
     525           0 :         return NS_ERROR_UNEXPECTED;
     526             : 
     527           0 :     nsCOMPtr<nsIRDFResource> property;
     528           0 :     nsresult rv = gRDFService->GetUnicodeResource(aExpr, getter_AddRefs(property));
     529           0 :     if (NS_FAILED(rv))
     530           0 :         return rv;
     531             : 
     532           0 :     RefPtr<RDFBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
     533           0 :     if (!bindings) {
     534           0 :         bindings = new RDFBindingSet();
     535           0 :         mRuleToBindingsMap.Put(aRuleNode, bindings);
     536             :     }
     537             : 
     538           0 :     return bindings->AddBinding(aVar, aRef, property);
     539             : }
     540             : 
     541             : NS_IMETHODIMP
     542           0 : nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
     543             :                                                            const nsAString& aRefString,
     544             :                                                            nsIXULTemplateResult** aRef)
     545             : {
     546             :     // make sure the RDF service is set up
     547           0 :     nsresult rv = InitGlobals();
     548           0 :     if (NS_FAILED(rv))
     549           0 :         return rv;
     550             : 
     551           0 :     nsCOMPtr<nsIRDFResource> uri;
     552           0 :     gRDFService->GetUnicodeResource(aRefString, getter_AddRefs(uri));
     553             : 
     554           0 :     RefPtr<nsXULTemplateResultRDF> refresult = new nsXULTemplateResultRDF(uri);
     555           0 :     if (! refresult)
     556           0 :         return NS_ERROR_OUT_OF_MEMORY;
     557             : 
     558           0 :     refresult.forget(aRef);
     559             : 
     560           0 :     return NS_OK;
     561             : }
     562             : 
     563             : NS_IMETHODIMP
     564           0 : nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
     565             :                                                nsIXULTemplateResult* aRight,
     566             :                                                nsIAtom* aVar,
     567             :                                                uint32_t aSortHints,
     568             :                                                int32_t* aResult)
     569             : {
     570           0 :     NS_ENSURE_ARG_POINTER(aLeft);
     571           0 :     NS_ENSURE_ARG_POINTER(aRight);
     572             : 
     573           0 :     *aResult = 0;
     574             : 
     575             :     // for natural order sorting, use the index in the RDF container for the
     576             :     // order. If there is no container, just sort them arbitrarily.
     577           0 :     if (!aVar) {
     578             :         // if a result has a negative index, just sort it first
     579           0 :         int32_t leftindex = GetContainerIndexOf(aLeft);
     580           0 :         int32_t rightindex = GetContainerIndexOf(aRight);
     581           0 :         *aResult = leftindex == rightindex ? 0 :
     582           0 :                    leftindex > rightindex ? 1 :
     583             :                    -1;
     584           0 :         return NS_OK;
     585             :     }
     586             : 
     587           0 :     nsDependentAtomString sortkey(aVar);
     588             : 
     589           0 :     nsCOMPtr<nsISupports> leftNode, rightNode;
     590             : 
     591           0 :     if (!sortkey.IsEmpty() && sortkey[0] != '?' &&
     592           0 :         !StringBeginsWith(sortkey, NS_LITERAL_STRING("rdf:")) &&
     593           0 :         mDB) {
     594             :         // if the sort key is not a template variable, it should be an RDF
     595             :         // predicate. Get the targets and compare those instead.
     596           0 :         nsCOMPtr<nsIRDFResource> predicate;
     597           0 :         nsresult rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(predicate));
     598           0 :         NS_ENSURE_SUCCESS(rv, rv);
     599             : 
     600             :         // create a predicate with '?sort=true' appended. This special
     601             :         // predicate may be used to have a different sort value than the
     602             :         // displayed value
     603           0 :         sortkey.AppendLiteral("?sort=true");
     604             : 
     605           0 :         nsCOMPtr<nsIRDFResource> sortPredicate;
     606           0 :         rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(sortPredicate));
     607           0 :         NS_ENSURE_SUCCESS(rv, rv);
     608             : 
     609           0 :         rv = GetSortValue(aLeft, predicate, sortPredicate, getter_AddRefs(leftNode));
     610           0 :         NS_ENSURE_SUCCESS(rv, rv);
     611             : 
     612           0 :         rv = GetSortValue(aRight, predicate, sortPredicate, getter_AddRefs(rightNode));
     613           0 :         NS_ENSURE_SUCCESS(rv, rv);
     614             :     }
     615             :     else {
     616             :         // get the values for the sort key from the results
     617           0 :         aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode));
     618           0 :         aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightNode));
     619             :     }
     620             : 
     621             :     {
     622             :         // Literals?
     623           0 :         nsCOMPtr<nsIRDFLiteral> l = do_QueryInterface(leftNode);
     624           0 :         if (l) {
     625           0 :             nsCOMPtr<nsIRDFLiteral> r = do_QueryInterface(rightNode);
     626           0 :             if (r) {
     627             :                 const char16_t *lstr, *rstr;
     628           0 :                 l->GetValueConst(&lstr);
     629           0 :                 r->GetValueConst(&rstr);
     630             : 
     631           0 :                 *aResult = XULSortServiceImpl::CompareValues(
     632           0 :                                nsDependentString(lstr),
     633           0 :                                nsDependentString(rstr), aSortHints);
     634             :             }
     635             : 
     636           0 :             return NS_OK;
     637             :         }
     638             :     }
     639             : 
     640             :     {
     641             :         // Dates?
     642           0 :         nsCOMPtr<nsIRDFDate> l = do_QueryInterface(leftNode);
     643           0 :         if (l) {
     644           0 :             nsCOMPtr<nsIRDFDate> r = do_QueryInterface(rightNode);
     645           0 :             if (r) {
     646             :                 PRTime ldate, rdate;
     647           0 :                 l->GetValue(&ldate);
     648           0 :                 r->GetValue(&rdate);
     649             : 
     650           0 :                 int64_t delta = ldate - rdate;
     651           0 :                 if (delta == 0)
     652           0 :                     *aResult = 0;
     653           0 :                 else if (delta >= 0)
     654           0 :                     *aResult = 1;
     655             :                 else
     656           0 :                     *aResult = -1;
     657             :             }
     658             : 
     659           0 :             return NS_OK;
     660             :         }
     661             :     }
     662             : 
     663             :     {
     664             :         // Integers?
     665           0 :         nsCOMPtr<nsIRDFInt> l = do_QueryInterface(leftNode);
     666           0 :         if (l) {
     667           0 :             nsCOMPtr<nsIRDFInt> r = do_QueryInterface(rightNode);
     668           0 :             if (r) {
     669             :                 int32_t lval, rval;
     670           0 :                 l->GetValue(&lval);
     671           0 :                 r->GetValue(&rval);
     672             : 
     673           0 :                 *aResult = lval - rval;
     674             :             }
     675             : 
     676           0 :             return NS_OK;
     677             :         }
     678             :     }
     679             : 
     680           0 :     nsICollation* collation = nsXULContentUtils::GetCollation();
     681           0 :     if (collation) {
     682             :         // Blobs? (We can only compare these reasonably if we have a
     683             :         // collation object.)
     684           0 :         nsCOMPtr<nsIRDFBlob> l = do_QueryInterface(leftNode);
     685           0 :         if (l) {
     686           0 :             nsCOMPtr<nsIRDFBlob> r = do_QueryInterface(rightNode);
     687           0 :             if (r) {
     688             :                 const uint8_t *lval, *rval;
     689             :                 int32_t llen, rlen;
     690           0 :                 l->GetValue(&lval);
     691           0 :                 l->GetLength(&llen);
     692           0 :                 r->GetValue(&rval);
     693           0 :                 r->GetLength(&rlen);
     694             : 
     695           0 :                 collation->CompareRawSortKey(lval, llen, rval, rlen, aResult);
     696             :             }
     697             :         }
     698             :     }
     699             : 
     700             :     // if the results are none of the above, just pretend that they are equal
     701           0 :     return NS_OK;
     702             : }
     703             : 
     704             : //----------------------------------------------------------------------
     705             : //
     706             : // nsIRDFObserver interface
     707             : //
     708             : 
     709             : 
     710             : NS_IMETHODIMP
     711           0 : nsXULTemplateQueryProcessorRDF::OnAssert(nsIRDFDataSource* aDataSource,
     712             :                                          nsIRDFResource* aSource,
     713             :                                          nsIRDFResource* aProperty,
     714             :                                          nsIRDFNode* aTarget)
     715             : {
     716             :     // Ignore updates if we're batching
     717           0 :     if (mUpdateBatchNest)
     718           0 :         return(NS_OK);
     719             : 
     720           0 :     if (! mBuilder)
     721           0 :         return NS_OK;
     722             : 
     723           0 :     LOG("onassert", aSource, aProperty, aTarget);
     724             : 
     725           0 :     Propagate(aSource, aProperty, aTarget);
     726           0 :     SynchronizeAll(aSource, aProperty, nullptr, aTarget);
     727           0 :     return NS_OK;
     728             : }
     729             : 
     730             : 
     731             : 
     732             : NS_IMETHODIMP
     733           0 : nsXULTemplateQueryProcessorRDF::OnUnassert(nsIRDFDataSource* aDataSource,
     734             :                                            nsIRDFResource* aSource,
     735             :                                            nsIRDFResource* aProperty,
     736             :                                            nsIRDFNode* aTarget)
     737             : {
     738             :     // Ignore updates if we're batching
     739           0 :     if (mUpdateBatchNest)
     740           0 :         return NS_OK;
     741             : 
     742           0 :     if (! mBuilder)
     743           0 :         return NS_OK;
     744             : 
     745           0 :     LOG("onunassert", aSource, aProperty, aTarget);
     746             : 
     747           0 :     Retract(aSource, aProperty, aTarget);
     748           0 :     SynchronizeAll(aSource, aProperty, aTarget, nullptr);
     749           0 :     return NS_OK;
     750             : }
     751             : 
     752             : 
     753             : NS_IMETHODIMP
     754           0 : nsXULTemplateQueryProcessorRDF::OnChange(nsIRDFDataSource* aDataSource,
     755             :                                          nsIRDFResource* aSource,
     756             :                                          nsIRDFResource* aProperty,
     757             :                                          nsIRDFNode* aOldTarget,
     758             :                                          nsIRDFNode* aNewTarget)
     759             : {
     760             :     // Ignore updates if we're batching
     761           0 :     if (mUpdateBatchNest)
     762           0 :         return NS_OK;
     763             : 
     764           0 :     if (! mBuilder)
     765           0 :         return NS_OK;
     766             : 
     767           0 :     LOG("onchange", aSource, aProperty, aNewTarget);
     768             : 
     769           0 :     if (aOldTarget) {
     770             :         // Pull any old results that were relying on aOldTarget
     771           0 :         Retract(aSource, aProperty, aOldTarget);
     772             :     }
     773             : 
     774           0 :     if (aNewTarget) {
     775             :         // Fire any new results that are activated by aNewTarget
     776           0 :         Propagate(aSource, aProperty, aNewTarget);
     777             :     }
     778             : 
     779             :     // Synchronize any of the content model that may have changed.
     780           0 :     SynchronizeAll(aSource, aProperty, aOldTarget, aNewTarget);
     781           0 :     return NS_OK;
     782             : }
     783             : 
     784             : 
     785             : NS_IMETHODIMP
     786           0 : nsXULTemplateQueryProcessorRDF::OnMove(nsIRDFDataSource* aDataSource,
     787             :                                        nsIRDFResource* aOldSource,
     788             :                                        nsIRDFResource* aNewSource,
     789             :                                        nsIRDFResource* aProperty,
     790             :                                        nsIRDFNode* aTarget)
     791             : {
     792             :     // Ignore updates if we're batching
     793           0 :     if (mUpdateBatchNest)
     794           0 :         return NS_OK;
     795             : 
     796           0 :     NS_NOTYETIMPLEMENTED("write me");
     797           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     798             : }
     799             : 
     800             : 
     801             : NS_IMETHODIMP
     802           0 : nsXULTemplateQueryProcessorRDF::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
     803             : {
     804           0 :     mUpdateBatchNest++;
     805           0 :     return NS_OK;
     806             : }
     807             : 
     808             : 
     809             : NS_IMETHODIMP
     810           0 : nsXULTemplateQueryProcessorRDF::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
     811             : {
     812           0 :     NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
     813           0 :     if (--mUpdateBatchNest <= 0) {
     814           0 :         mUpdateBatchNest = 0;
     815             : 
     816           0 :         if (mBuilder)
     817           0 :             mBuilder->Rebuild();
     818             :     }
     819             : 
     820           0 :     return NS_OK;
     821             : }
     822             : 
     823             : nsresult
     824           0 : nsXULTemplateQueryProcessorRDF::Propagate(nsIRDFResource* aSource,
     825             :                                           nsIRDFResource* aProperty,
     826             :                                           nsIRDFNode* aTarget)
     827             : {
     828             :     // When a new assertion is added to the graph, determine any new matches
     829             :     // that must be added to the template builder. First, iterate through all
     830             :     // the RDF tests (<member> and <triple> tests), and find the topmost test
     831             :     // that would be affected by the new assertion.
     832             :     nsresult rv;
     833             : 
     834           0 :     ReteNodeSet livenodes;
     835             : 
     836           0 :     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     837             :         const char* sourceStr;
     838           0 :         aSource->GetValueConst(&sourceStr);
     839             :         const char* propertyStr;
     840           0 :         aProperty->GetValueConst(&propertyStr);
     841           0 :         nsAutoString targetStr;
     842           0 :         nsXULContentUtils::GetTextForNode(aTarget, targetStr);
     843             : 
     844           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     845             :                ("nsXULTemplateQueryProcessorRDF::Propagate: [%s] -> [%s] -> [%s]\n",
     846             :                sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get()));
     847             :     }
     848             : 
     849             :     {
     850           0 :         ReteNodeSet::Iterator last = mRDFTests.Last();
     851           0 :         for (ReteNodeSet::Iterator i = mRDFTests.First(); i != last; ++i) {
     852           0 :             nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i);
     853             : 
     854           0 :             Instantiation seed;
     855           0 :             if (rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed)) {
     856           0 :                 rv = livenodes.Add(rdftestnode);
     857           0 :                 if (NS_FAILED(rv))
     858           0 :                     return rv;
     859             :             }
     860             :         }
     861             :     }
     862             : 
     863             :     // Now, we'll go through each, and any that aren't dominated by
     864             :     // another live node will be used to propagate the assertion
     865             :     // through the rule network
     866             :     {
     867           0 :         ReteNodeSet::Iterator last = livenodes.Last();
     868           0 :         for (ReteNodeSet::Iterator i = livenodes.First(); i != last; ++i) {
     869           0 :             nsRDFTestNode* rdftestnode = static_cast<nsRDFTestNode*>(*i);
     870             : 
     871             :             // What happens here is we create an instantiation as if we were
     872             :             // at the found test in the rule network. For example, if the
     873             :             // found test was a member test (parent => child), the parent
     874             :             // and child variables are assigned the values provided by the new
     875             :             // RDF assertion in the graph. The Constrain call is used to go
     876             :             // up to earlier RDF tests, filling in variables as it goes.
     877             :             // Constrain will eventually get up to the top node, an
     878             :             // nsContentTestNode, which takes the value of the reference
     879             :             // variable and calls the template builder to see if a result has
     880             :             // been generated already for the reference value. If it hasn't,
     881             :             // the new assertion couldn't cause a new match. If the result
     882             :             // exists, call Propagate to continue to the later RDF tests to
     883             :             // fill in the rest of the variable assignments.
     884             : 
     885             :             // Bogus, to get the seed instantiation
     886           0 :             Instantiation seed;
     887           0 :             rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed);
     888             : 
     889           0 :             InstantiationSet* instantiations = new InstantiationSet();
     890           0 :             instantiations->Append(seed);
     891             : 
     892           0 :             rv = rdftestnode->Constrain(*instantiations);
     893           0 :             if (NS_FAILED(rv)) {
     894           0 :                 delete instantiations;
     895           0 :                 return rv;
     896             :             }
     897             : 
     898           0 :             bool owned = false;
     899           0 :             if (!instantiations->Empty())
     900           0 :                 rv = rdftestnode->Propagate(*instantiations, true, owned);
     901             : 
     902             :             // owned should always be false in update mode, but check just
     903             :             // to be sure
     904           0 :             if (!owned)
     905           0 :                 delete instantiations;
     906           0 :             if (NS_FAILED(rv))
     907           0 :                 return rv;
     908             :         }
     909             :     }
     910             : 
     911           0 :     return NS_OK;
     912             : }
     913             : 
     914             : 
     915             : nsresult
     916           0 : nsXULTemplateQueryProcessorRDF::Retract(nsIRDFResource* aSource,
     917             :                                         nsIRDFResource* aProperty,
     918             :                                         nsIRDFNode* aTarget)
     919             : {
     920             : 
     921           0 :     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     922             :         const char* sourceStr;
     923           0 :         aSource->GetValueConst(&sourceStr);
     924             :         const char* propertyStr;
     925           0 :         aProperty->GetValueConst(&propertyStr);
     926           0 :         nsAutoString targetStr;
     927           0 :         nsXULContentUtils::GetTextForNode(aTarget, targetStr);
     928             : 
     929           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     930             :                ("nsXULTemplateQueryProcessorRDF::Retract: [%s] -> [%s] -> [%s]\n",
     931             :                sourceStr, propertyStr, NS_ConvertUTF16toUTF8(targetStr).get()));
     932             :     }
     933             : 
     934             :     // Retract any currently active rules that will no longer be matched.
     935           0 :     ReteNodeSet::ConstIterator lastnode = mRDFTests.Last();
     936           0 :     for (ReteNodeSet::ConstIterator node = mRDFTests.First(); node != lastnode; ++node) {
     937           0 :         const nsRDFTestNode* rdftestnode = static_cast<const nsRDFTestNode*>(*node);
     938             : 
     939           0 :         rdftestnode->Retract(aSource, aProperty, aTarget);
     940             : 
     941             :         // Now fire any newly revealed rules
     942             :         // XXXwaterson yo. write me.
     943             :         // The intent here is to handle any rules that might be
     944             :         // "revealed" by the removal of an assertion from the datasource.
     945             :         // Waterson doesn't think we support negated conditions in a rule.
     946             :         // Nor is he sure that this is currently useful.
     947             :     }
     948             : 
     949           0 :     return NS_OK;
     950             : }
     951             : 
     952             : nsresult
     953           0 : nsXULTemplateQueryProcessorRDF::SynchronizeAll(nsIRDFResource* aSource,
     954             :                                                nsIRDFResource* aProperty,
     955             :                                                nsIRDFNode* aOldTarget,
     956             :                                                nsIRDFNode* aNewTarget)
     957             : {
     958             :     // Update each match that contains <aSource, aProperty, aOldTarget>.
     959             : 
     960             :     // Get all the matches whose assignments are currently supported
     961             :     // by aSource and aProperty: we'll need to recompute them.
     962             :     ResultArray* results;
     963           0 :     if (!mBindingDependencies.Get(aSource, &results) || !mBuilder)
     964           0 :         return NS_OK;
     965             : 
     966           0 :     uint32_t length = results->Length();
     967             : 
     968           0 :     for (uint32_t r = 0; r < length; r++) {
     969           0 :         nsXULTemplateResultRDF* result = (*results)[r];
     970           0 :         if (result) {
     971             :             // synchronize the result's bindings and then update the builder
     972             :             // so that content can be updated
     973           0 :             if (result->SyncAssignments(aSource, aProperty, aNewTarget)) {
     974           0 :                 nsITemplateRDFQuery* query = result->Query();
     975           0 :                 if (query) {
     976           0 :                     nsCOMPtr<nsIDOMNode> querynode;
     977           0 :                     query->GetQueryNode(getter_AddRefs(querynode));
     978             : 
     979           0 :                     mBuilder->ResultBindingChanged(result);
     980             :                 }
     981             :             }
     982             :         }
     983             :     }
     984             : 
     985           0 :     return NS_OK;
     986             : }
     987             : 
     988             : nsresult
     989           0 : nsXULTemplateQueryProcessorRDF::Log(const char* aOperation,
     990             :                                     nsIRDFResource* aSource,
     991             :                                     nsIRDFResource* aProperty,
     992             :                                     nsIRDFNode* aTarget)
     993             : {
     994           0 :     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     995             :         nsresult rv;
     996             : 
     997             :         const char* sourceStr;
     998           0 :         rv = aSource->GetValueConst(&sourceStr);
     999           0 :         if (NS_FAILED(rv))
    1000           0 :             return rv;
    1001             : 
    1002           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
    1003             :                ("xultemplate[%p] %8s [%s]--", this, aOperation, sourceStr));
    1004             : 
    1005             :         const char* propertyStr;
    1006           0 :         rv = aProperty->GetValueConst(&propertyStr);
    1007           0 :         if (NS_FAILED(rv))
    1008           0 :             return rv;
    1009             : 
    1010           0 :         nsAutoString targetStr;
    1011           0 :         rv = nsXULContentUtils::GetTextForNode(aTarget, targetStr);
    1012           0 :         if (NS_FAILED(rv))
    1013           0 :             return rv;
    1014             : 
    1015           0 :         nsAutoCString targetstrC;
    1016           0 :         targetstrC.AssignWithConversion(targetStr);
    1017           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
    1018             :                ("                        --[%s]-->[%s]",
    1019             :                 propertyStr,
    1020             :                 targetstrC.get()));
    1021             :     }
    1022           0 :     return NS_OK;
    1023             : }
    1024             : 
    1025             : nsresult
    1026           0 : nsXULTemplateQueryProcessorRDF::CheckContainer(nsIRDFResource* aResource,
    1027             :                                                bool* aIsContainer)
    1028             : {
    1029           0 :     NS_ENSURE_ARG_POINTER(aIsContainer);
    1030           0 :     NS_ENSURE_STATE(mDB);
    1031             : 
    1032             :     // We have to look at all of the arcs extending out of the
    1033             :     // resource: if any of them are that "containment" property, then
    1034             :     // we know we'll have children.
    1035           0 :     bool isContainer = false;
    1036             : 
    1037           0 :     for (nsResourceSet::ConstIterator property = mContainmentProperties.First();
    1038           0 :          property != mContainmentProperties.Last();
    1039             :          property++) {
    1040           0 :         bool hasArc = false;
    1041           0 :         mDB->HasArcOut(aResource, *property, &hasArc);
    1042             : 
    1043           0 :         if (hasArc) {
    1044             :             // Well, it's a container...
    1045           0 :             isContainer = true;
    1046           0 :             break;
    1047             :         }
    1048             :     }
    1049             : 
    1050             :     // If we get here, and we're still not sure if it's a container,
    1051             :     // then see if it's an RDF container
    1052           0 :     if (! isContainer) {
    1053           0 :         gRDFContainerUtils->IsContainer(mDB, aResource, &isContainer);
    1054             :     }
    1055             : 
    1056           0 :     *aIsContainer = isContainer;
    1057             : 
    1058           0 :     return NS_OK;
    1059             : }
    1060             : 
    1061             : nsresult
    1062           0 : nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource,
    1063             :                                            bool* aIsEmpty)
    1064             : {
    1065           0 :     NS_ENSURE_STATE(mDB);
    1066           0 :     *aIsEmpty = true;
    1067             : 
    1068           0 :     for (nsResourceSet::ConstIterator property = mContainmentProperties.First();
    1069           0 :          property != mContainmentProperties.Last();
    1070             :          property++) {
    1071             : 
    1072           0 :         nsCOMPtr<nsIRDFNode> dummy;
    1073           0 :         mDB->GetTarget(aResource, *property, true, getter_AddRefs(dummy));
    1074             : 
    1075           0 :         if (dummy) {
    1076           0 :             *aIsEmpty = false;
    1077           0 :             break;
    1078             :         }
    1079             :     }
    1080             : 
    1081           0 :     if (*aIsEmpty){
    1082             :         return nsXULTemplateQueryProcessorRDF::gRDFContainerUtils->
    1083           0 :                    IsEmpty(mDB, aResource, aIsEmpty);
    1084             :     }
    1085             : 
    1086           0 :     return NS_OK;
    1087             : }
    1088             : 
    1089             : nsresult
    1090           0 : nsXULTemplateQueryProcessorRDF::CheckIsSeparator(nsIRDFResource* aResource,
    1091             :                                                  bool* aIsSeparator)
    1092             : {
    1093           0 :     NS_ENSURE_STATE(mDB);
    1094           0 :     return mDB->HasAssertion(aResource, kRDF_type, kNC_BookmarkSeparator,
    1095           0 :                              true, aIsSeparator);
    1096             : }
    1097             : 
    1098             : //----------------------------------------------------------------------
    1099             : 
    1100             : nsresult
    1101           0 : nsXULTemplateQueryProcessorRDF::ComputeContainmentProperties(nsIDOMNode* aRootNode)
    1102             : {
    1103             :     // The 'containment' attribute on the root node is a
    1104             :     // whitespace-separated list that tells us which properties we
    1105             :     // should use to test for containment.
    1106             :     nsresult rv;
    1107             : 
    1108           0 :     mContainmentProperties.Clear();
    1109             : 
    1110           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aRootNode);
    1111             : 
    1112           0 :     nsAutoString containment;
    1113           0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::containment, containment);
    1114             : 
    1115           0 :     uint32_t len = containment.Length();
    1116           0 :     uint32_t offset = 0;
    1117           0 :     while (offset < len) {
    1118           0 :         while (offset < len && nsCRT::IsAsciiSpace(containment[offset]))
    1119           0 :             ++offset;
    1120             : 
    1121           0 :         if (offset >= len)
    1122           0 :             break;
    1123             : 
    1124           0 :         uint32_t end = offset;
    1125           0 :         while (end < len && !nsCRT::IsAsciiSpace(containment[end]))
    1126           0 :             ++end;
    1127             : 
    1128           0 :         nsAutoString propertyStr;
    1129           0 :         containment.Mid(propertyStr, offset, end - offset);
    1130             : 
    1131           0 :         nsCOMPtr<nsIRDFResource> property;
    1132           0 :         rv = gRDFService->GetUnicodeResource(propertyStr, getter_AddRefs(property));
    1133           0 :         if (NS_FAILED(rv))
    1134           0 :             return rv;
    1135             : 
    1136           0 :         rv = mContainmentProperties.Add(property);
    1137           0 :         if (NS_FAILED(rv))
    1138           0 :             return rv;
    1139             : 
    1140           0 :         offset = end;
    1141             :     }
    1142             : 
    1143             : #define TREE_PROPERTY_HACK 1
    1144             : #if defined(TREE_PROPERTY_HACK)
    1145           0 :     if (! len) {
    1146             :         // Some ever-present membership tests.
    1147           0 :         mContainmentProperties.Add(nsXULContentUtils::NC_child);
    1148           0 :         mContainmentProperties.Add(nsXULContentUtils::NC_Folder);
    1149             :     }
    1150             : #endif
    1151             : 
    1152           0 :     return NS_OK;
    1153             : }
    1154             : 
    1155             : nsresult
    1156           0 : nsXULTemplateQueryProcessorRDF::CompileExtendedQuery(nsRDFQuery* aQuery,
    1157             :                                                      nsIContent* aConditions,
    1158             :                                                      TestNode** aLastNode)
    1159             : {
    1160             :     // Compile an extended query's children
    1161             :     nsContentTestNode* idnode =
    1162           0 :         new nsContentTestNode(this, aQuery->mRefVariable);
    1163             : 
    1164           0 :     aQuery->SetRoot(idnode);
    1165           0 :     nsresult rv = mAllTests.Add(idnode);
    1166           0 :     if (NS_FAILED(rv)) {
    1167           0 :         delete idnode;
    1168           0 :         return rv;
    1169             :     }
    1170             : 
    1171           0 :     TestNode* prevnode = idnode;
    1172             : 
    1173           0 :     for (nsIContent* condition = aConditions->GetFirstChild();
    1174           0 :          condition;
    1175           0 :          condition = condition->GetNextSibling()) {
    1176             : 
    1177             :         // the <content> condition should always be the first child
    1178           0 :         if (condition->IsXULElement(nsGkAtoms::content)) {
    1179           0 :             if (condition != aConditions->GetFirstChild()) {
    1180           0 :                 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_CONTENT_NOT_FIRST);
    1181           0 :                 continue;
    1182             :             }
    1183             : 
    1184             :             // check for <content tag='tag'/> which indicates that matches
    1185             :             // should only be generated for items inside content with that tag
    1186           0 :             nsAutoString tagstr;
    1187           0 :             condition->GetAttr(kNameSpaceID_None, nsGkAtoms::tag, tagstr);
    1188             : 
    1189           0 :             nsCOMPtr<nsIAtom> tag;
    1190           0 :             if (! tagstr.IsEmpty()) {
    1191           0 :                 tag = NS_Atomize(tagstr);
    1192             :             }
    1193             : 
    1194           0 :             nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(condition->GetComposedDoc());
    1195           0 :             if (! doc)
    1196           0 :                 return NS_ERROR_FAILURE;
    1197             : 
    1198           0 :             idnode->SetTag(tag, doc);
    1199           0 :             continue;
    1200             :         }
    1201             : 
    1202           0 :         TestNode* testnode = nullptr;
    1203           0 :         nsresult rv = CompileQueryChild(condition->NodeInfo()->NameAtom(),
    1204           0 :                                         aQuery, condition, prevnode, &testnode);
    1205           0 :         if (NS_FAILED(rv))
    1206           0 :             return rv;
    1207             : 
    1208           0 :         if (testnode) {
    1209           0 :             rv = prevnode->AddChild(testnode);
    1210           0 :             if (NS_FAILED(rv))
    1211           0 :                 return rv;
    1212             : 
    1213           0 :             prevnode = testnode;
    1214             :         }
    1215             :     }
    1216             : 
    1217           0 :     *aLastNode = prevnode;
    1218             : 
    1219           0 :     return NS_OK;
    1220             : }
    1221             : 
    1222             : nsresult
    1223           0 : nsXULTemplateQueryProcessorRDF::CompileQueryChild(nsIAtom* aTag,
    1224             :                                                   nsRDFQuery* aQuery,
    1225             :                                                   nsIContent* aCondition,
    1226             :                                                   TestNode* aParentNode,
    1227             :                                                   TestNode** aResult)
    1228             : {
    1229           0 :     nsresult rv = NS_OK;
    1230             : 
    1231           0 :     if (aTag == nsGkAtoms::triple) {
    1232           0 :         rv = CompileTripleCondition(aQuery, aCondition, aParentNode, aResult);
    1233             :     }
    1234           0 :     else if (aTag == nsGkAtoms::member) {
    1235           0 :         rv = CompileMemberCondition(aQuery, aCondition, aParentNode, aResult);
    1236             :     }
    1237           0 :     else if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Info)) {
    1238           0 :         nsAutoString tagstr;
    1239           0 :         aTag->ToString(tagstr);
    1240             : 
    1241           0 :         nsAutoCString tagstrC;
    1242           0 :         tagstrC.AssignWithConversion(tagstr);
    1243           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Info,
    1244             :                ("xultemplate[%p] unrecognized condition test <%s>",
    1245             :                 this, tagstrC.get()));
    1246             :     }
    1247             : 
    1248           0 :     return rv;
    1249             : }
    1250             : 
    1251             : nsresult
    1252           0 : nsXULTemplateQueryProcessorRDF::ParseLiteral(const nsString& aParseType,
    1253             :                                              const nsString& aValue,
    1254             :                                              nsIRDFNode** aResult)
    1255             : {
    1256           0 :     nsresult rv = NS_OK;
    1257           0 :     *aResult = nullptr;
    1258             : 
    1259           0 :     if (aParseType.EqualsLiteral(PARSE_TYPE_INTEGER)) {
    1260           0 :         nsCOMPtr<nsIRDFInt> intLiteral;
    1261             :         nsresult errorCode;
    1262           0 :         int32_t intValue = aValue.ToInteger(&errorCode);
    1263           0 :         if (NS_FAILED(errorCode))
    1264           0 :             return NS_ERROR_FAILURE;
    1265           0 :         rv = gRDFService->GetIntLiteral(intValue, getter_AddRefs(intLiteral));
    1266           0 :         if (NS_FAILED(rv))
    1267           0 :             return rv;
    1268           0 :         intLiteral.forget(aResult);
    1269             :     }
    1270             :     else {
    1271           0 :         nsCOMPtr<nsIRDFLiteral> literal;
    1272           0 :         rv = gRDFService->GetLiteral(aValue.get(), getter_AddRefs(literal));
    1273           0 :         if (NS_FAILED(rv))
    1274           0 :             return rv;
    1275           0 :         literal.forget(aResult);
    1276             :     }
    1277           0 :     return rv;
    1278             : }
    1279             : 
    1280             : nsresult
    1281           0 : nsXULTemplateQueryProcessorRDF::CompileTripleCondition(nsRDFQuery* aQuery,
    1282             :                                                        nsIContent* aCondition,
    1283             :                                                        TestNode* aParentNode,
    1284             :                                                        TestNode** aResult)
    1285             : {
    1286             :     // Compile a <triple> condition, which must be of the form:
    1287             :     //
    1288             :     //   <triple subject="?var1|resource"
    1289             :     //           predicate="resource"
    1290             :     //           object="?var2|resource|literal" />
    1291             :     //
    1292             :     // XXXwaterson Some day it would be cool to allow the 'predicate'
    1293             :     // to be bound to a variable.
    1294             : 
    1295             :     // subject
    1296           0 :     nsAutoString subject;
    1297           0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::subject, subject);
    1298             : 
    1299           0 :     nsCOMPtr<nsIAtom> svar;
    1300           0 :     nsCOMPtr<nsIRDFResource> sres;
    1301           0 :     if (subject.IsEmpty()) {
    1302           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_SUBJECT);
    1303           0 :         return NS_OK;
    1304             :     }
    1305           0 :     if (subject[0] == char16_t('?'))
    1306           0 :         svar = NS_Atomize(subject);
    1307             :     else
    1308           0 :         gRDFService->GetUnicodeResource(subject, getter_AddRefs(sres));
    1309             : 
    1310             :     // predicate
    1311           0 :     nsAutoString predicate;
    1312           0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::predicate, predicate);
    1313             : 
    1314           0 :     nsCOMPtr<nsIRDFResource> pres;
    1315           0 :     if (predicate.IsEmpty() || predicate[0] == char16_t('?')) {
    1316           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_PREDICATE);
    1317           0 :         return NS_OK;
    1318             :     }
    1319           0 :     gRDFService->GetUnicodeResource(predicate, getter_AddRefs(pres));
    1320             : 
    1321             :     // object
    1322           0 :     nsAutoString object;
    1323           0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::object, object);
    1324             : 
    1325           0 :     nsCOMPtr<nsIAtom> ovar;
    1326           0 :     nsCOMPtr<nsIRDFNode> onode;
    1327           0 :     if (object.IsEmpty()) {
    1328           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_BAD_OBJECT);
    1329           0 :         return NS_OK;
    1330             :     }
    1331             : 
    1332           0 :     if (object[0] == char16_t('?')) {
    1333           0 :         ovar = NS_Atomize(object);
    1334             :     }
    1335           0 :     else if (object.FindChar(':') != -1) { // XXXwaterson evil.
    1336             :         // treat as resource
    1337           0 :         nsCOMPtr<nsIRDFResource> resource;
    1338           0 :         gRDFService->GetUnicodeResource(object, getter_AddRefs(resource));
    1339           0 :         onode = do_QueryInterface(resource);
    1340             :     }
    1341             :     else {
    1342           0 :         nsAutoString parseType;
    1343           0 :         aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType);
    1344           0 :         nsresult rv = ParseLiteral(parseType, object, getter_AddRefs(onode));
    1345           0 :         if (NS_FAILED(rv))
    1346           0 :             return rv;
    1347             :     }
    1348             : 
    1349           0 :     nsRDFPropertyTestNode* testnode = nullptr;
    1350             : 
    1351           0 :     if (svar && ovar) {
    1352           0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, ovar);
    1353             :     }
    1354           0 :     else if (svar) {
    1355           0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, svar, pres, onode);
    1356             :     }
    1357           0 :     else if (ovar) {
    1358           0 :         testnode = new nsRDFPropertyTestNode(aParentNode, this, sres, pres, ovar);
    1359             :     }
    1360             :     else {
    1361           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_TRIPLE_NO_VAR);
    1362           0 :         return NS_OK;
    1363             :     }
    1364             : 
    1365             :     // add testnode to mAllTests first. If adding to mRDFTests fails, just
    1366             :     // leave it in the list so that it can be deleted later.
    1367           0 :     MOZ_ASSERT(testnode);
    1368           0 :     nsresult rv = mAllTests.Add(testnode);
    1369           0 :     if (NS_FAILED(rv)) {
    1370           0 :         delete testnode;
    1371           0 :         return rv;
    1372             :     }
    1373             : 
    1374           0 :     rv = mRDFTests.Add(testnode);
    1375           0 :     if (NS_FAILED(rv))
    1376           0 :         return rv;
    1377             : 
    1378           0 :     *aResult = testnode;
    1379           0 :     return NS_OK;
    1380             : }
    1381             : 
    1382             : nsresult
    1383           0 : nsXULTemplateQueryProcessorRDF::CompileMemberCondition(nsRDFQuery* aQuery,
    1384             :                                                        nsIContent* aCondition,
    1385             :                                                        TestNode* aParentNode,
    1386             :                                                        TestNode** aResult)
    1387             : {
    1388             :     // Compile a <member> condition, which must be of the form:
    1389             :     //
    1390             :     //   <member container="?var1" child="?var2" />
    1391             :     //
    1392             : 
    1393             :     // container
    1394           0 :     nsAutoString container;
    1395           0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::container, container);
    1396             : 
    1397           0 :     if (!container.IsEmpty() && container[0] != char16_t('?')) {
    1398           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCONTAINERVAR);
    1399           0 :         return NS_OK;
    1400             :     }
    1401             : 
    1402           0 :     nsCOMPtr<nsIAtom> containervar = NS_Atomize(container);
    1403             : 
    1404             :     // child
    1405           0 :     nsAutoString child;
    1406           0 :     aCondition->GetAttr(kNameSpaceID_None, nsGkAtoms::child, child);
    1407             : 
    1408           0 :     if (!child.IsEmpty() && child[0] != char16_t('?')) {
    1409           0 :         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_MEMBER_NOCHILDVAR);
    1410           0 :         return NS_OK;
    1411             :     }
    1412             : 
    1413           0 :     nsCOMPtr<nsIAtom> childvar = NS_Atomize(child);
    1414             : 
    1415             :     TestNode* testnode =
    1416             :         new nsRDFConMemberTestNode(aParentNode,
    1417             :                                    this,
    1418             :                                    containervar,
    1419           0 :                                    childvar);
    1420             : 
    1421             :     // add testnode to mAllTests first. If adding to mRDFTests fails, just
    1422             :     // leave it in the list so that it can be deleted later.
    1423           0 :     nsresult rv = mAllTests.Add(testnode);
    1424           0 :     if (NS_FAILED(rv)) {
    1425           0 :         delete testnode;
    1426           0 :         return rv;
    1427             :     }
    1428             : 
    1429           0 :     rv = mRDFTests.Add(testnode);
    1430           0 :     if (NS_FAILED(rv))
    1431           0 :         return rv;
    1432             : 
    1433           0 :     *aResult = testnode;
    1434           0 :     return NS_OK;
    1435             : }
    1436             : 
    1437             : nsresult
    1438           0 : nsXULTemplateQueryProcessorRDF::AddDefaultSimpleRules(nsRDFQuery* aQuery,
    1439             :                                                       TestNode** aChildNode)
    1440             : {
    1441             :     // XXXndeakin should check for tag in query processor instead of builder?
    1442             :     nsContentTestNode* idnode =
    1443             :         new nsContentTestNode(this,
    1444           0 :                               aQuery->mRefVariable);
    1445             : 
    1446             :     // Create (?container ^member ?member)
    1447             :     nsRDFConMemberTestNode* membernode =
    1448             :         new nsRDFConMemberTestNode(idnode,
    1449             :                                    this,
    1450             :                                    aQuery->mRefVariable,
    1451           0 :                                    aQuery->mMemberVariable);
    1452             : 
    1453             :     // add nodes to mAllTests first. If later calls fail, just leave them in
    1454             :     // the list so that they can be deleted later.
    1455           0 :     nsresult rv = mAllTests.Add(idnode);
    1456           0 :     if (NS_FAILED(rv)) {
    1457           0 :         delete idnode;
    1458           0 :         delete membernode;
    1459           0 :         return rv;
    1460             :     }
    1461             : 
    1462           0 :     rv = mAllTests.Add(membernode);
    1463           0 :     if (NS_FAILED(rv)) {
    1464           0 :         delete membernode;
    1465           0 :         return rv;
    1466             :     }
    1467             : 
    1468           0 :     rv = mRDFTests.Add(membernode);
    1469           0 :     if (NS_FAILED(rv))
    1470           0 :         return rv;
    1471             : 
    1472           0 :     rv = idnode->AddChild(membernode);
    1473           0 :     if (NS_FAILED(rv))
    1474           0 :         return rv;
    1475             : 
    1476           0 :     mSimpleRuleMemberTest = membernode;
    1477           0 :     *aChildNode = membernode;
    1478             : 
    1479           0 :     return NS_OK;
    1480             : }
    1481             : 
    1482             : nsresult
    1483           0 : nsXULTemplateQueryProcessorRDF::CompileSimpleQuery(nsRDFQuery* aQuery,
    1484             :                                                    nsIContent* aQueryElement,
    1485             :                                                    TestNode** aLastNode)
    1486             : {
    1487             :     // Compile a "simple" (or old-school style) <template> query.
    1488             :     nsresult rv;
    1489             : 
    1490             :     TestNode* parentNode;
    1491             : 
    1492           0 :     if (! mSimpleRuleMemberTest) {
    1493           0 :         rv = AddDefaultSimpleRules(aQuery, &parentNode);
    1494           0 :         if (NS_FAILED(rv))
    1495           0 :             return rv;
    1496             :     }
    1497             : 
    1498           0 :     bool hasContainerTest = false;
    1499             : 
    1500           0 :     TestNode* prevnode = mSimpleRuleMemberTest;
    1501             : 
    1502             :     // Add constraints for the LHS
    1503             :     const nsAttrName* name;
    1504           0 :     for (uint32_t i = 0; (name = aQueryElement->GetAttrNameAt(i)); ++i) {
    1505             :         // Note: some attributes must be skipped on XUL template query subtree
    1506             : 
    1507             :         // never compare against rdf:property, rdf:instanceOf, {}:id or {}:parsetype attribute
    1508           0 :         if (name->Equals(nsGkAtoms::property, kNameSpaceID_RDF) ||
    1509           0 :             name->Equals(nsGkAtoms::instanceOf, kNameSpaceID_RDF) ||
    1510           0 :             name->Equals(nsGkAtoms::id, kNameSpaceID_None) ||
    1511           0 :             name->Equals(nsGkAtoms::parsetype, kNameSpaceID_None)) {
    1512           0 :             continue;
    1513             :         }
    1514             : 
    1515           0 :         int32_t attrNameSpaceID = name->NamespaceID();
    1516           0 :         if (attrNameSpaceID == kNameSpaceID_XMLNS)
    1517           0 :           continue;
    1518           0 :         nsIAtom* attr = name->LocalName();
    1519             : 
    1520           0 :         nsAutoString value;
    1521           0 :         aQueryElement->GetAttr(attrNameSpaceID, attr, value);
    1522             : 
    1523           0 :         TestNode* testnode = nullptr;
    1524             : 
    1525           0 :         if (name->Equals(nsGkAtoms::iscontainer, kNameSpaceID_None) ||
    1526           0 :             name->Equals(nsGkAtoms::isempty, kNameSpaceID_None)) {
    1527             :             // Tests about containerhood and emptiness. These can be
    1528             :             // globbed together, mostly. Check to see if we've already
    1529             :             // added a container test: we only need one.
    1530           0 :             if (hasContainerTest)
    1531           0 :                 continue;
    1532             : 
    1533             :             nsRDFConInstanceTestNode::Test iscontainer =
    1534           0 :                 nsRDFConInstanceTestNode::eDontCare;
    1535             : 
    1536             :             static nsIContent::AttrValuesArray strings[] =
    1537             :               {&nsGkAtoms::_true, &nsGkAtoms::_false, nullptr};
    1538           0 :             switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None,
    1539             :                                                    nsGkAtoms::iscontainer,
    1540           0 :                                                    strings, eCaseMatters)) {
    1541           0 :                 case 0: iscontainer = nsRDFConInstanceTestNode::eTrue; break;
    1542           0 :                 case 1: iscontainer = nsRDFConInstanceTestNode::eFalse; break;
    1543             :             }
    1544             : 
    1545             :             nsRDFConInstanceTestNode::Test isempty =
    1546           0 :                 nsRDFConInstanceTestNode::eDontCare;
    1547             : 
    1548           0 :             switch (aQueryElement->FindAttrValueIn(kNameSpaceID_None,
    1549             :                                                    nsGkAtoms::isempty,
    1550           0 :                                                    strings, eCaseMatters)) {
    1551           0 :                 case 0: isempty = nsRDFConInstanceTestNode::eTrue; break;
    1552           0 :                 case 1: isempty = nsRDFConInstanceTestNode::eFalse; break;
    1553             :             }
    1554             : 
    1555           0 :             testnode = new nsRDFConInstanceTestNode(prevnode,
    1556             :                                                     this,
    1557             :                                                     aQuery->mMemberVariable,
    1558             :                                                     iscontainer,
    1559           0 :                                                     isempty);
    1560             : 
    1561           0 :             rv = mAllTests.Add(testnode);
    1562           0 :             if (NS_FAILED(rv)) {
    1563           0 :                 delete testnode;
    1564           0 :                 return rv;
    1565             :             }
    1566             : 
    1567           0 :             rv = mRDFTests.Add(testnode);
    1568           0 :             if (NS_FAILED(rv))
    1569           0 :                 return rv;
    1570             :         }
    1571           0 :         else if (attrNameSpaceID != kNameSpaceID_None || attr != nsGkAtoms::parent) {
    1572             :             // It's a simple RDF test
    1573           0 :             nsCOMPtr<nsIRDFResource> property;
    1574           0 :             rv = nsXULContentUtils::GetResource(attrNameSpaceID, attr, getter_AddRefs(property));
    1575           0 :             if (NS_FAILED(rv))
    1576           0 :                 return rv;
    1577             : 
    1578             :             // XXXwaterson this is so manky
    1579           0 :             nsCOMPtr<nsIRDFNode> target;
    1580           0 :             if (value.FindChar(':') != -1) { // XXXwaterson WRONG WRONG WRONG!
    1581           0 :                 nsCOMPtr<nsIRDFResource> resource;
    1582           0 :                 rv = gRDFService->GetUnicodeResource(value, getter_AddRefs(resource));
    1583           0 :                 if (NS_FAILED(rv))
    1584           0 :                     return rv;
    1585             : 
    1586           0 :                 target = do_QueryInterface(resource);
    1587             :             }
    1588             :             else {
    1589           0 :               nsAutoString parseType;
    1590           0 :               aQueryElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parsetype, parseType);
    1591           0 :               rv = ParseLiteral(parseType, value, getter_AddRefs(target));
    1592           0 :               if (NS_FAILED(rv))
    1593           0 :                   return rv;
    1594             :             }
    1595             : 
    1596           0 :             testnode = new nsRDFPropertyTestNode(prevnode, this,
    1597           0 :                                                  aQuery->mMemberVariable, property, target);
    1598           0 :             rv = mAllTests.Add(testnode);
    1599           0 :             if (NS_FAILED(rv)) {
    1600           0 :                 delete testnode;
    1601           0 :                 return rv;
    1602             :             }
    1603             : 
    1604           0 :             rv = mRDFTests.Add(testnode);
    1605           0 :             if (NS_FAILED(rv))
    1606           0 :                 return rv;
    1607             :         }
    1608             : 
    1609           0 :         if (testnode) {
    1610           0 :             if (prevnode) {
    1611           0 :                 rv = prevnode->AddChild(testnode);
    1612           0 :                 if (NS_FAILED(rv))
    1613           0 :                     return rv;
    1614             :             }
    1615             :             else {
    1616           0 :                 aQuery->SetRoot(testnode);
    1617             :             }
    1618             : 
    1619           0 :             prevnode = testnode;
    1620             :         }
    1621             :     }
    1622             : 
    1623           0 :     *aLastNode = prevnode;
    1624             : 
    1625           0 :     return NS_OK;
    1626             : }
    1627             : 
    1628             : RDFBindingSet*
    1629           0 : nsXULTemplateQueryProcessorRDF::GetBindingsForRule(nsIDOMNode* aRuleNode)
    1630             : {
    1631           0 :     return mRuleToBindingsMap.GetWeak(aRuleNode);
    1632             : }
    1633             : 
    1634             : void
    1635           0 : nsXULTemplateQueryProcessorRDF::AddBindingDependency(nsXULTemplateResultRDF* aResult,
    1636             :                                                      nsIRDFResource* aResource)
    1637             : {
    1638             :     ResultArray* arr;
    1639           0 :     if (!mBindingDependencies.Get(aResource, &arr)) {
    1640           0 :         arr = new ResultArray();
    1641             : 
    1642           0 :         mBindingDependencies.Put(aResource, arr);
    1643             :     }
    1644             : 
    1645           0 :     int32_t index = arr->IndexOf(aResult);
    1646           0 :     if (index == -1)
    1647           0 :         arr->AppendElement(aResult);
    1648           0 : }
    1649             : 
    1650             : void
    1651           0 : nsXULTemplateQueryProcessorRDF::RemoveBindingDependency(nsXULTemplateResultRDF* aResult,
    1652             :                                                         nsIRDFResource* aResource)
    1653             : {
    1654             :     ResultArray* arr;
    1655           0 :     if (mBindingDependencies.Get(aResource, &arr)) {
    1656           0 :         int32_t index = arr->IndexOf(aResult);
    1657           0 :         if (index >= 0)
    1658           0 :             arr->RemoveElementAt(index);
    1659             :     }
    1660           0 : }
    1661             : 
    1662             : 
    1663             : nsresult
    1664           0 : nsXULTemplateQueryProcessorRDF::AddMemoryElements(const Instantiation& aInst,
    1665             :                                                   nsXULTemplateResultRDF* aResult)
    1666             : {
    1667             :     // Add the result to a table indexed by supporting MemoryElement
    1668           0 :     MemoryElementSet::ConstIterator last = aInst.mSupport.Last();
    1669           0 :     for (MemoryElementSet::ConstIterator element = aInst.mSupport.First();
    1670             :                                          element != last; ++element) {
    1671             : 
    1672           0 :         PLHashNumber hash = (element.operator->())->Hash();
    1673             : 
    1674             :         nsCOMArray<nsXULTemplateResultRDF>* arr;
    1675           0 :         if (!mMemoryElementToResultMap.Get(hash, &arr)) {
    1676           0 :             arr = new nsCOMArray<nsXULTemplateResultRDF>();
    1677           0 :             mMemoryElementToResultMap.Put(hash, arr);
    1678             :         }
    1679             : 
    1680             :         // results may be added more than once so they will all get deleted properly
    1681           0 :         arr->AppendObject(aResult);
    1682             :     }
    1683             : 
    1684           0 :     return NS_OK;
    1685             : }
    1686             : 
    1687             : nsresult
    1688           0 : nsXULTemplateQueryProcessorRDF::RemoveMemoryElements(const Instantiation& aInst,
    1689             :                                                      nsXULTemplateResultRDF* aResult)
    1690             : {
    1691             :     // Remove the results mapped by the supporting MemoryElement
    1692           0 :     MemoryElementSet::ConstIterator last = aInst.mSupport.Last();
    1693           0 :     for (MemoryElementSet::ConstIterator element = aInst.mSupport.First();
    1694             :                                          element != last; ++element) {
    1695             : 
    1696           0 :         PLHashNumber hash = (element.operator->())->Hash();
    1697             : 
    1698             :         nsCOMArray<nsXULTemplateResultRDF>* arr;
    1699           0 :         if (mMemoryElementToResultMap.Get(hash, &arr)) {
    1700           0 :             int32_t index = arr->IndexOf(aResult);
    1701           0 :             if (index >= 0)
    1702           0 :                 arr->RemoveObjectAt(index);
    1703             : 
    1704           0 :             uint32_t length = arr->Count();
    1705           0 :             if (! length)
    1706           0 :                 mMemoryElementToResultMap.Remove(hash);
    1707             :         }
    1708             :     }
    1709             : 
    1710           0 :     return NS_OK;
    1711             : }
    1712             : 
    1713             : void
    1714           0 : nsXULTemplateQueryProcessorRDF::RetractElement(const MemoryElement& aMemoryElement)
    1715             : {
    1716           0 :     if (! mBuilder)
    1717           0 :         return;
    1718             : 
    1719             :     // when an assertion is removed, look through the memory elements and
    1720             :     // find results that are associated with them. Those results will need
    1721             :     // to be removed because they no longer match.
    1722           0 :     PLHashNumber hash = aMemoryElement.Hash();
    1723             : 
    1724             :     nsCOMArray<nsXULTemplateResultRDF>* arr;
    1725           0 :     if (mMemoryElementToResultMap.Get(hash, &arr)) {
    1726           0 :         uint32_t length = arr->Count();
    1727             : 
    1728           0 :         for (int32_t r = length - 1; r >= 0; r--) {
    1729           0 :             nsXULTemplateResultRDF* result = (*arr)[r];
    1730           0 :             if (result) {
    1731             :                 // because the memory elements are hashed by an integer,
    1732             :                 // sometimes two different memory elements will have the same
    1733             :                 // hash code. In this case we check the result to make sure
    1734             :                 // and only remove those that refer to that memory element.
    1735           0 :                 if (result->HasMemoryElement(aMemoryElement)) {
    1736           0 :                     nsITemplateRDFQuery* query = result->Query();
    1737           0 :                     if (query) {
    1738           0 :                         nsCOMPtr<nsIDOMNode> querynode;
    1739           0 :                         query->GetQueryNode(getter_AddRefs(querynode));
    1740             : 
    1741           0 :                         mBuilder->RemoveResult(result);
    1742             :                     }
    1743             : 
    1744             :                     // a call to RemoveMemoryElements may have removed it
    1745           0 :                     if (!mMemoryElementToResultMap.Get(hash, nullptr))
    1746           0 :                         return;
    1747             : 
    1748             :                     // the array should have been reduced by one, but check
    1749             :                     // just to make sure
    1750           0 :                     uint32_t newlength = arr->Count();
    1751           0 :                     if (r > (int32_t)newlength)
    1752           0 :                         r = newlength;
    1753             :                 }
    1754             :             }
    1755             :         }
    1756             : 
    1757             :         // if there are no items left, remove the memory element from the hashtable
    1758           0 :         if (!arr->Count())
    1759           0 :             mMemoryElementToResultMap.Remove(hash);
    1760             :     }
    1761             : }
    1762             : 
    1763             : int32_t
    1764           0 : nsXULTemplateQueryProcessorRDF::GetContainerIndexOf(nsIXULTemplateResult* aResult)
    1765             : {
    1766             :     // get the reference variable and look up the container in the result
    1767           0 :     nsCOMPtr<nsISupports> ref;
    1768           0 :     nsresult rv = aResult->GetBindingObjectFor(mRefVariable,
    1769           0 :                                                getter_AddRefs(ref));
    1770           0 :     if (NS_FAILED(rv) || !mDB)
    1771           0 :         return -1;
    1772             : 
    1773           0 :     nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
    1774           0 :     if (container) {
    1775             :         // if the container is an RDF Seq, return the index of the result
    1776             :         // in the container.
    1777           0 :         bool isSequence = false;
    1778           0 :         gRDFContainerUtils->IsSeq(mDB, container, &isSequence);
    1779           0 :         if (isSequence) {
    1780           0 :             nsCOMPtr<nsIRDFResource> resource;
    1781           0 :             aResult->GetResource(getter_AddRefs(resource));
    1782           0 :             if (resource) {
    1783             :                 int32_t index;
    1784           0 :                 gRDFContainerUtils->IndexOf(mDB, container, resource, &index);
    1785           0 :                 return index;
    1786             :             }
    1787             :         }
    1788             :     }
    1789             : 
    1790             :     // if the container isn't a Seq, or the result isn't in the container,
    1791             :     // return -1 indicating no index.
    1792           0 :     return -1;
    1793             : }
    1794             : 
    1795             : nsresult
    1796           0 : nsXULTemplateQueryProcessorRDF::GetSortValue(nsIXULTemplateResult* aResult,
    1797             :                                              nsIRDFResource* aPredicate,
    1798             :                                              nsIRDFResource* aSortPredicate,
    1799             :                                              nsISupports** aResultNode)
    1800             : {
    1801           0 :     nsCOMPtr<nsIRDFResource> source;
    1802           0 :     nsresult rv = aResult->GetResource(getter_AddRefs(source));
    1803           0 :     if (NS_FAILED(rv))
    1804           0 :         return rv;
    1805             : 
    1806           0 :     nsCOMPtr<nsIRDFNode> value;
    1807           0 :     if (source && mDB) {
    1808             :         // first check predicate?sort=true so that datasources may use a
    1809             :         // custom value for sorting
    1810           0 :         rv = mDB->GetTarget(source, aSortPredicate, true,
    1811           0 :                             getter_AddRefs(value));
    1812           0 :         if (NS_FAILED(rv))
    1813           0 :             return rv;
    1814             : 
    1815           0 :         if (!value) {
    1816           0 :             rv = mDB->GetTarget(source, aPredicate, true,
    1817           0 :                                 getter_AddRefs(value));
    1818           0 :             if (NS_FAILED(rv))
    1819           0 :                 return rv;
    1820             :         }
    1821             :     }
    1822             : 
    1823           0 :     *aResultNode = value;
    1824           0 :     NS_IF_ADDREF(*aResultNode);
    1825           0 :     return NS_OK;
    1826             : }

Generated by: LCOV version 1.13