nsXULTemplateQueryProcessorRDF.cpp 59 KB

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