nsXULTemplateBuilder.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. #ifndef nsXULTemplateBuilder_h__
  6. #define nsXULTemplateBuilder_h__
  7. #include "nsStubDocumentObserver.h"
  8. #include "nsIScriptSecurityManager.h"
  9. #include "nsIObserver.h"
  10. #include "nsIRDFCompositeDataSource.h"
  11. #include "nsIRDFContainer.h"
  12. #include "nsIRDFContainerUtils.h"
  13. #include "nsIRDFDataSource.h"
  14. #include "nsIRDFObserver.h"
  15. #include "nsIRDFService.h"
  16. #include "nsIXULTemplateBuilder.h"
  17. #include "nsCOMArray.h"
  18. #include "nsTArray.h"
  19. #include "nsDataHashtable.h"
  20. #include "nsTemplateRule.h"
  21. #include "nsTemplateMatch.h"
  22. #include "nsIXULTemplateQueryProcessor.h"
  23. #include "nsCycleCollectionParticipant.h"
  24. #include "mozilla/Logging.h"
  25. extern mozilla::LazyLogModule gXULTemplateLog;
  26. class nsIContent;
  27. class nsIObserverService;
  28. class nsIRDFCompositeDataSource;
  29. /**
  30. * An object that translates an RDF graph into a presentation using a
  31. * set of rules.
  32. */
  33. class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
  34. public nsIObserver,
  35. public nsStubDocumentObserver
  36. {
  37. void CleanUp(bool aIsFinal);
  38. void DestroyMatchMap();
  39. public:
  40. nsXULTemplateBuilder();
  41. nsresult InitGlobals();
  42. /**
  43. * Clear the template builder structures. The aIsFinal flag is set to true
  44. * when the template is going away.
  45. */
  46. virtual void Uninit(bool aIsFinal);
  47. // nsISupports interface
  48. NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  49. NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateBuilder,
  50. nsIXULTemplateBuilder)
  51. // nsIXULTemplateBuilder interface
  52. NS_DECL_NSIXULTEMPLATEBUILDER
  53. // nsIObserver Interface
  54. NS_DECL_NSIOBSERVER
  55. // nsIMutationObserver
  56. NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
  57. NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
  58. NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
  59. /**
  60. * Remove an old result and/or add a new result. This method will retrieve
  61. * the set of containers where the result could be inserted and either add
  62. * the new result to those containers, or remove the result from those
  63. * containers. UpdateResultInContainer is called for each container.
  64. *
  65. * @param aOldResult result to remove
  66. * @param aNewResult result to add
  67. * @param aQueryNode query node for new result
  68. */
  69. nsresult
  70. UpdateResult(nsIXULTemplateResult* aOldResult,
  71. nsIXULTemplateResult* aNewResult,
  72. nsIDOMNode* aQueryNode);
  73. /**
  74. * Remove an old result and/or add a new result from a specific container.
  75. *
  76. * @param aOldResult result to remove
  77. * @param aNewResult result to add
  78. * @param aQueryNode queryset for the new result
  79. * @param aOldId id of old result
  80. * @param aNewId id of new result
  81. * @param aInsertionPoint container to remove or add result inside
  82. */
  83. nsresult
  84. UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
  85. nsIXULTemplateResult* aNewResult,
  86. nsTemplateQuerySet* aQuerySet,
  87. nsIRDFResource* aOldId,
  88. nsIRDFResource* aNewId,
  89. nsIContent* aInsertionPoint);
  90. nsresult
  91. ComputeContainmentProperties();
  92. static bool
  93. IsTemplateElement(nsIContent* aContent);
  94. virtual nsresult
  95. RebuildAll() = 0; // must be implemented by subclasses
  96. void RunnableRebuild() { Rebuild(); }
  97. void RunnableLoadAndRebuild() {
  98. Uninit(false); // Reset results
  99. nsCOMPtr<nsIDocument> doc = mRoot ? mRoot->GetComposedDoc() : nullptr;
  100. if (doc) {
  101. bool shouldDelay;
  102. LoadDataSources(doc, &shouldDelay);
  103. if (!shouldDelay) {
  104. Rebuild();
  105. }
  106. }
  107. }
  108. // mRoot should not be cleared until after Uninit is finished so that
  109. // generated content can be removed during uninitialization.
  110. void UninitFalse() { Uninit(false); mRoot = nullptr; }
  111. void UninitTrue() { Uninit(true); mRoot = nullptr; }
  112. /**
  113. * Find the <template> tag that applies for this builder
  114. */
  115. nsresult
  116. GetTemplateRoot(nsIContent** aResult);
  117. /**
  118. * Compile the template's queries
  119. */
  120. nsresult
  121. CompileQueries();
  122. /**
  123. * Compile the template given a <template> in aTemplate. This function
  124. * is called recursively to handle queries inside a queryset. For the
  125. * outer pass, aIsQuerySet will be false, while the inner pass this will
  126. * be true.
  127. *
  128. * aCanUseTemplate will be set to true if the template's queries could be
  129. * compiled, and false otherwise. If false, the entire template is
  130. * invalid.
  131. *
  132. * @param aTemplate <template> to compile
  133. * @param aQuerySet first queryset
  134. * @param aIsQuerySet true if
  135. * @param aPriority the queryset index, incremented when a new one is added
  136. * @param aCanUseTemplate true if template is valid
  137. */
  138. nsresult
  139. CompileTemplate(nsIContent* aTemplate,
  140. nsTemplateQuerySet* aQuerySet,
  141. bool aIsQuerySet,
  142. int32_t* aPriority,
  143. bool* aCanUseTemplate);
  144. /**
  145. * Compile a query using the extended syntax. For backwards compatible RDF
  146. * syntax where there is no <query>, the <conditions> becomes the query.
  147. *
  148. * @param aRuleElement <rule> element
  149. * @param aActionElement <action> element
  150. * @param aMemberVariable member variable for the query
  151. * @param aQuerySet the queryset
  152. */
  153. nsresult
  154. CompileExtendedQuery(nsIContent* aRuleElement,
  155. nsIContent* aActionElement,
  156. nsIAtom* aMemberVariable,
  157. nsTemplateQuerySet* aQuerySet);
  158. /**
  159. * Determine the ref variable and tag from inside a RDF query.
  160. */
  161. void DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** tag);
  162. /**
  163. * Determine the member variable from inside an action body. It will be
  164. * the value of the uri attribute on a node.
  165. */
  166. already_AddRefed<nsIAtom> DetermineMemberVariable(nsIContent* aElement);
  167. /**
  168. * Compile a simple query. A simple query is one that doesn't have a
  169. * <query> and should use a default query which would normally just return
  170. * a list of children of the reference point.
  171. *
  172. * @param aRuleElement the <rule>
  173. * @param aQuerySet the query set
  174. * @param aCanUseTemplate true if the query is valid
  175. */
  176. nsresult
  177. CompileSimpleQuery(nsIContent* aRuleElement,
  178. nsTemplateQuerySet* aQuerySet,
  179. bool* aCanUseTemplate);
  180. /**
  181. * Compile the <conditions> tag in a rule
  182. *
  183. * @param aRule template rule
  184. * @param aConditions <conditions> element
  185. */
  186. nsresult
  187. CompileConditions(nsTemplateRule* aRule, nsIContent* aConditions);
  188. /**
  189. * Compile a <where> tag in a condition. The caller should set
  190. * *aCurrentCondition to null for the first condition. This value will be
  191. * updated to point to the new condition before returning. The conditions
  192. * will be added to the rule aRule by this method.
  193. *
  194. * @param aRule template rule
  195. * @param aCondition <where> element
  196. * @param aCurrentCondition compiled condition
  197. */
  198. nsresult
  199. CompileWhereCondition(nsTemplateRule* aRule,
  200. nsIContent* aCondition,
  201. nsTemplateCondition** aCurrentCondition);
  202. /**
  203. * Compile the <bindings> for an extended template syntax rule.
  204. */
  205. nsresult
  206. CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings);
  207. /**
  208. * Compile a single binding for an extended template syntax rule.
  209. */
  210. nsresult
  211. CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
  212. /**
  213. * Add automatic bindings for simple rules
  214. */
  215. nsresult
  216. AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement);
  217. static void
  218. AddBindingsFor(nsXULTemplateBuilder* aSelf,
  219. const nsAString& aVariable,
  220. void* aClosure);
  221. /**
  222. * Load the datasources for the template. shouldDelayBuilding is an out
  223. * parameter which will be set to true to indicate that content building
  224. * should not be performed yet as the datasource has not yet loaded. If
  225. * false, the datasource has already loaded so building can proceed
  226. * immediately. In the former case, the datasource or query processor
  227. * should either rebuild the template or update results when the
  228. * datasource is loaded as needed.
  229. */
  230. nsresult
  231. LoadDataSources(nsIDocument* aDoc, bool* shouldDelayBuilding);
  232. /**
  233. * Called by LoadDataSources to load a datasource given a uri list
  234. * in aDataSource. The list is a set of uris separated by spaces.
  235. * If aIsRDFQuery is true, then this is for an RDF datasource which
  236. * causes the method to check for additional flags specific to the
  237. * RDF processor.
  238. */
  239. nsresult
  240. LoadDataSourceUrls(nsIDocument* aDocument,
  241. const nsAString& aDataSources,
  242. bool aIsRDFQuery,
  243. bool* aShouldDelayBuilding);
  244. nsresult
  245. InitHTMLTemplateRoot();
  246. /**
  247. * Determine which rule matches a given result. aContainer is used for
  248. * tag matching and is optional for non-content generating builders.
  249. * The returned matched rule is always one of the rules owned by the
  250. * query set aQuerySet.
  251. *
  252. * @param aContainer parent where generated content will be inserted
  253. * @param aResult result to match
  254. * @param aQuerySet query set to examine the rules of
  255. * @param aMatchedRule [out] rule that has matched, or null if any.
  256. * @param aRuleIndex [out] index of the rule
  257. */
  258. nsresult
  259. DetermineMatchedRule(nsIContent* aContainer,
  260. nsIXULTemplateResult* aResult,
  261. nsTemplateQuerySet* aQuerySet,
  262. nsTemplateRule** aMatchedRule,
  263. int16_t *aRuleIndex);
  264. // XXX sigh, the string template foo doesn't mix with
  265. // operator->*() on egcs-1.1.2, so we'll need to explicitly pass
  266. // "this" and use good ol' fashioned static callbacks.
  267. void
  268. ParseAttribute(const nsAString& aAttributeValue,
  269. void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
  270. void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
  271. void* aClosure);
  272. nsresult
  273. SubstituteText(nsIXULTemplateResult* aMatch,
  274. const nsAString& aAttributeValue,
  275. nsAString& aResult);
  276. static void
  277. SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAString& aText, void* aClosure);
  278. static void
  279. SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);
  280. nsresult
  281. IsSystemPrincipal(nsIPrincipal *principal, bool *result);
  282. /**
  283. * Convenience method which gets a resource for a result. If a result
  284. * doesn't have a resource set, it will create one from the result's id.
  285. */
  286. nsresult GetResultResource(nsIXULTemplateResult* aResult,
  287. nsIRDFResource** aResource);
  288. protected:
  289. virtual ~nsXULTemplateBuilder();
  290. nsCOMPtr<nsISupports> mDataSource;
  291. nsCOMPtr<nsIRDFDataSource> mDB;
  292. nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;
  293. /**
  294. * Circular reference, broken when the document is destroyed.
  295. */
  296. nsCOMPtr<nsIContent> mRoot;
  297. /**
  298. * The root result, translated from the root element's ref
  299. */
  300. nsCOMPtr<nsIXULTemplateResult> mRootResult;
  301. nsCOMArray<nsIXULBuilderListener> mListeners;
  302. /**
  303. * The query processor which generates results
  304. */
  305. nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor;
  306. /**
  307. * The list of querysets
  308. */
  309. nsTArray<nsTemplateQuerySet *> mQuerySets;
  310. /**
  311. * Set to true if the rules have already been compiled
  312. */
  313. bool mQueriesCompiled;
  314. /**
  315. * The default reference and member variables.
  316. */
  317. nsCOMPtr<nsIAtom> mRefVariable;
  318. nsCOMPtr<nsIAtom> mMemberVariable;
  319. /**
  320. * The match map contains nsTemplateMatch objects, one for each unique
  321. * match found, keyed by the resource for that match. A particular match
  322. * will contain a linked list of all of the matches for that unique result
  323. * id. Only one is active at a time. When a match is retracted, look in
  324. * the match map, remove it, and apply the next valid match in sequence to
  325. * make active.
  326. */
  327. nsDataHashtable<nsISupportsHashKey, nsTemplateMatch*> mMatchMap;
  328. // pseudo-constants
  329. static nsrefcnt gRefCnt;
  330. static nsIRDFService* gRDFService;
  331. static nsIRDFContainerUtils* gRDFContainerUtils;
  332. static nsIScriptSecurityManager* gScriptSecurityManager;
  333. static nsIPrincipal* gSystemPrincipal;
  334. static nsIObserverService* gObserverService;
  335. enum {
  336. eDontTestEmpty = (1 << 0),
  337. eDontRecurse = (1 << 1),
  338. eLoggingEnabled = (1 << 2)
  339. };
  340. int32_t mFlags;
  341. /**
  342. * Stack-based helper class to maintain a list of ``activated''
  343. * resources; i.e., resources for which we are currently building
  344. * content.
  345. */
  346. class ActivationEntry {
  347. public:
  348. nsIRDFResource *mResource;
  349. ActivationEntry *mPrevious;
  350. ActivationEntry **mLink;
  351. ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink)
  352. : mResource(aResource),
  353. mPrevious(*aLink),
  354. mLink(aLink) { *mLink = this; }
  355. ~ActivationEntry() { *mLink = mPrevious; }
  356. };
  357. /**
  358. * The top of the stack of resources that we're currently building
  359. * content for.
  360. */
  361. ActivationEntry *mTop;
  362. /**
  363. * Determine if a resource is currently on the activation stack.
  364. */
  365. bool
  366. IsActivated(nsIRDFResource *aResource);
  367. /**
  368. * Returns true if content may be generated for a result, or false if it
  369. * cannot, for example, if it would be created inside a closed container.
  370. * Those results will be generated when the container is opened.
  371. * If false is returned, no content should be generated. Possible
  372. * insertion locations may optionally be set for new content, depending on
  373. * the builder being used. Note that *aLocations or some items within
  374. * aLocations may be null.
  375. */
  376. virtual bool
  377. GetInsertionLocations(nsIXULTemplateResult* aResult,
  378. nsCOMArray<nsIContent>** aLocations) = 0;
  379. /**
  380. * Must be implemented by subclasses. Handle removing the generated
  381. * output for aOldMatch and adding new output for aNewMatch. Either
  382. * aOldMatch or aNewMatch may be null. aContext is the location returned
  383. * from the call to MayGenerateResult.
  384. */
  385. virtual nsresult
  386. ReplaceMatch(nsIXULTemplateResult* aOldResult,
  387. nsTemplateMatch* aNewMatch,
  388. nsTemplateRule* aNewMatchRule,
  389. void *aContext) = 0;
  390. /**
  391. * Must be implemented by subclasses. Handle change in bound
  392. * variable values for aResult. aModifiedVars contains the set
  393. * of variables that have changed.
  394. * @param aResult the ersult for which variable bindings has changed.
  395. * @param aModifiedVars the set of variables for which the bindings
  396. * have changed.
  397. */
  398. virtual nsresult
  399. SynchronizeResult(nsIXULTemplateResult* aResult) = 0;
  400. /**
  401. * Output a new match or removed match to the console.
  402. *
  403. * @param aId id of the result
  404. * @param aMatch new or removed match
  405. * @param aIsNew true for new matched, false for removed matches
  406. */
  407. void
  408. OutputMatchToLog(nsIRDFResource* aId,
  409. nsTemplateMatch* aMatch,
  410. bool aIsNew);
  411. virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const
  412. {
  413. }
  414. /**
  415. * Start observing events from the observer service and the given
  416. * document.
  417. *
  418. * @param aDocument the document to observe
  419. */
  420. void StartObserving(nsIDocument* aDocument);
  421. /**
  422. * Stop observing events from the observer service and any associated
  423. * document.
  424. */
  425. void StopObserving();
  426. /**
  427. * Document that we're observing. Weak ref!
  428. */
  429. nsIDocument* mObservedDocument;
  430. };
  431. #endif // nsXULTemplateBuilder_h__