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 "mozilla/FloatingPoint.h"
7 : #include "mozilla/Move.h"
8 :
9 : #include "txStylesheet.h"
10 : #include "txExpr.h"
11 : #include "txXSLTPatterns.h"
12 : #include "txToplevelItems.h"
13 : #include "txInstructions.h"
14 : #include "txXSLTFunctions.h"
15 : #include "txLog.h"
16 : #include "txKey.h"
17 : #include "txXPathTreeWalker.h"
18 :
19 : using mozilla::LogLevel;
20 : using mozilla::Move;
21 :
22 0 : txStylesheet::txStylesheet()
23 0 : : mRootFrame(nullptr)
24 : {
25 0 : }
26 :
27 : nsresult
28 0 : txStylesheet::init()
29 : {
30 0 : mRootFrame = new ImportFrame;
31 :
32 : // Create default templates
33 : // element/root template
34 0 : mContainerTemplate = new txPushParams;
35 :
36 0 : nsAutoPtr<txNodeTest> nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
37 0 : nsAutoPtr<Expr> nodeExpr(new LocationStep(nt, LocationStep::CHILD_AXIS));
38 0 : nt.forget();
39 :
40 0 : txPushNewContext* pushContext = new txPushNewContext(Move(nodeExpr));
41 0 : mContainerTemplate->mNext = pushContext;
42 :
43 : txApplyDefaultElementTemplate* applyTemplates =
44 0 : new txApplyDefaultElementTemplate;
45 0 : pushContext->mNext = applyTemplates;
46 :
47 0 : txLoopNodeSet* loopNodeSet = new txLoopNodeSet(applyTemplates);
48 0 : applyTemplates->mNext = loopNodeSet;
49 :
50 0 : txPopParams* popParams = new txPopParams;
51 0 : pushContext->mBailTarget = loopNodeSet->mNext = popParams;
52 :
53 0 : popParams->mNext = new txReturn();
54 :
55 : // attribute/textnode template
56 0 : nt = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
57 0 : nodeExpr = new LocationStep(nt, LocationStep::SELF_AXIS);
58 0 : nt.forget();
59 :
60 0 : mCharactersTemplate = new txValueOf(Move(nodeExpr), false);
61 0 : mCharactersTemplate->mNext = new txReturn();
62 :
63 : // pi/comment/namespace template
64 0 : mEmptyTemplate = new txReturn();
65 :
66 0 : return NS_OK;
67 : }
68 :
69 0 : txStylesheet::~txStylesheet()
70 : {
71 : // Delete all ImportFrames
72 0 : delete mRootFrame;
73 0 : txListIterator frameIter(&mImportFrames);
74 0 : while (frameIter.hasNext()) {
75 0 : delete static_cast<ImportFrame*>(frameIter.next());
76 : }
77 :
78 0 : txListIterator instrIter(&mTemplateInstructions);
79 0 : while (instrIter.hasNext()) {
80 0 : delete static_cast<txInstruction*>(instrIter.next());
81 : }
82 :
83 : // We can't make the map own its values because then we wouldn't be able
84 : // to merge attributesets of the same name
85 0 : txExpandedNameMap<txInstruction>::iterator attrSetIter(mAttributeSets);
86 0 : while (attrSetIter.next()) {
87 0 : delete attrSetIter.value();
88 : }
89 0 : }
90 :
91 : nsresult
92 0 : txStylesheet::findTemplate(const txXPathNode& aNode,
93 : const txExpandedName& aMode,
94 : txIMatchContext* aContext,
95 : ImportFrame* aImportedBy,
96 : txInstruction** aTemplate,
97 : ImportFrame** aImportFrame)
98 : {
99 0 : NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
100 :
101 0 : *aTemplate = nullptr;
102 0 : *aImportFrame = nullptr;
103 0 : ImportFrame* endFrame = nullptr;
104 0 : txListIterator frameIter(&mImportFrames);
105 :
106 0 : if (aImportedBy) {
107 0 : ImportFrame* curr = static_cast<ImportFrame*>(frameIter.next());
108 0 : while (curr != aImportedBy) {
109 0 : curr = static_cast<ImportFrame*>(frameIter.next());
110 : }
111 0 : endFrame = aImportedBy->mFirstNotImported;
112 : }
113 :
114 : #if defined(TX_TO_STRING)
115 0 : txPattern* match = 0;
116 : #endif
117 :
118 : ImportFrame* frame;
119 0 : while (!*aTemplate &&
120 0 : (frame = static_cast<ImportFrame*>(frameIter.next())) &&
121 : frame != endFrame) {
122 :
123 : // get templatelist for this mode
124 : nsTArray<MatchableTemplate>* templates =
125 0 : frame->mMatchableTemplates.get(aMode);
126 :
127 0 : if (templates) {
128 : // Find template with highest priority
129 0 : uint32_t i, len = templates->Length();
130 0 : for (i = 0; i < len && !*aTemplate; ++i) {
131 0 : MatchableTemplate& templ = (*templates)[i];
132 : bool matched;
133 0 : nsresult rv = templ.mMatch->matches(aNode, aContext, matched);
134 0 : NS_ENSURE_SUCCESS(rv, rv);
135 :
136 0 : if (matched) {
137 0 : *aTemplate = templ.mFirstInstruction;
138 0 : *aImportFrame = frame;
139 : #if defined(TX_TO_STRING)
140 0 : match = templ.mMatch;
141 : #endif
142 : }
143 : }
144 : }
145 : }
146 :
147 0 : if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Debug)) {
148 0 : nsAutoString mode, nodeName;
149 0 : if (aMode.mLocalName) {
150 0 : aMode.mLocalName->ToString(mode);
151 : }
152 0 : txXPathNodeUtils::getNodeName(aNode, nodeName);
153 0 : if (*aTemplate) {
154 0 : nsAutoString matchAttr;
155 : #ifdef TX_TO_STRING
156 0 : match->toString(matchAttr);
157 : #endif
158 0 : MOZ_LOG(txLog::xslt, LogLevel::Debug,
159 : ("MatchTemplate, Pattern %s, Mode %s, Node %s\n",
160 : NS_LossyConvertUTF16toASCII(matchAttr).get(),
161 : NS_LossyConvertUTF16toASCII(mode).get(),
162 : NS_LossyConvertUTF16toASCII(nodeName).get()));
163 : }
164 : else {
165 0 : MOZ_LOG(txLog::xslt, LogLevel::Debug,
166 : ("No match, Node %s, Mode %s\n",
167 : NS_LossyConvertUTF16toASCII(nodeName).get(),
168 : NS_LossyConvertUTF16toASCII(mode).get()));
169 : }
170 : }
171 :
172 0 : if (!*aTemplate) {
173 : // Test for these first since a node can be both a text node
174 : // and a root (if it is orphaned)
175 0 : if (txXPathNodeUtils::isAttribute(aNode) ||
176 0 : txXPathNodeUtils::isText(aNode)) {
177 0 : *aTemplate = mCharactersTemplate;
178 : }
179 0 : else if (txXPathNodeUtils::isElement(aNode) ||
180 0 : txXPathNodeUtils::isRoot(aNode)) {
181 0 : *aTemplate = mContainerTemplate;
182 : }
183 : else {
184 0 : *aTemplate = mEmptyTemplate;
185 : }
186 : }
187 :
188 0 : return NS_OK;
189 : }
190 :
191 : txDecimalFormat*
192 0 : txStylesheet::getDecimalFormat(const txExpandedName& aName)
193 : {
194 0 : return mDecimalFormats.get(aName);
195 : }
196 :
197 : txInstruction*
198 0 : txStylesheet::getAttributeSet(const txExpandedName& aName)
199 : {
200 0 : return mAttributeSets.get(aName);
201 : }
202 :
203 : txInstruction*
204 0 : txStylesheet::getNamedTemplate(const txExpandedName& aName)
205 : {
206 0 : return mNamedTemplates.get(aName);
207 : }
208 :
209 : txOutputFormat*
210 0 : txStylesheet::getOutputFormat()
211 : {
212 0 : return &mOutputFormat;
213 : }
214 :
215 : txStylesheet::GlobalVariable*
216 0 : txStylesheet::getGlobalVariable(const txExpandedName& aName)
217 : {
218 0 : return mGlobalVariables.get(aName);
219 : }
220 :
221 : const txOwningExpandedNameMap<txXSLKey>&
222 0 : txStylesheet::getKeyMap()
223 : {
224 0 : return mKeys;
225 : }
226 :
227 : nsresult
228 0 : txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode,
229 : txIMatchContext* aContext, bool& aAllowed)
230 : {
231 0 : int32_t frameCount = mStripSpaceTests.Length();
232 0 : if (frameCount == 0) {
233 0 : aAllowed = false;
234 :
235 0 : return NS_OK;
236 : }
237 :
238 0 : txXPathTreeWalker walker(aNode);
239 :
240 0 : if (txXPathNodeUtils::isText(walker.getCurrentPosition()) &&
241 0 : (!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent())) {
242 0 : aAllowed = false;
243 :
244 0 : return NS_OK;
245 : }
246 :
247 0 : const txXPathNode& node = walker.getCurrentPosition();
248 :
249 0 : if (!txXPathNodeUtils::isElement(node)) {
250 0 : aAllowed = false;
251 :
252 0 : return NS_OK;
253 : }
254 :
255 : // check Whitespace stipping handling list against given Node
256 : int32_t i;
257 0 : for (i = 0; i < frameCount; ++i) {
258 0 : txStripSpaceTest* sst = mStripSpaceTests[i];
259 : bool matched;
260 0 : nsresult rv = sst->matches(node, aContext, matched);
261 0 : NS_ENSURE_SUCCESS(rv, rv);
262 :
263 0 : if (matched) {
264 0 : aAllowed = sst->stripsSpace() &&
265 0 : !XMLUtils::getXMLSpacePreserve(node);
266 :
267 0 : return NS_OK;
268 : }
269 : }
270 :
271 0 : aAllowed = false;
272 :
273 0 : return NS_OK;
274 : }
275 :
276 : nsresult
277 0 : txStylesheet::doneCompiling()
278 : {
279 0 : nsresult rv = NS_OK;
280 : // Collect all importframes into a single ordered list
281 0 : txListIterator frameIter(&mImportFrames);
282 0 : rv = frameIter.addAfter(mRootFrame);
283 0 : NS_ENSURE_SUCCESS(rv, rv);
284 :
285 0 : mRootFrame = nullptr;
286 0 : frameIter.next();
287 0 : rv = addFrames(frameIter);
288 0 : NS_ENSURE_SUCCESS(rv, rv);
289 :
290 : // Loop through importframes in decreasing-precedence-order and process
291 : // all items
292 0 : frameIter.reset();
293 : ImportFrame* frame;
294 0 : while ((frame = static_cast<ImportFrame*>(frameIter.next()))) {
295 0 : nsTArray<txStripSpaceTest*> frameStripSpaceTests;
296 :
297 0 : txListIterator itemIter(&frame->mToplevelItems);
298 0 : itemIter.resetToEnd();
299 : txToplevelItem* item;
300 0 : while ((item = static_cast<txToplevelItem*>(itemIter.previous()))) {
301 0 : switch (item->getType()) {
302 : case txToplevelItem::attributeSet:
303 : {
304 : rv = addAttributeSet(static_cast<txAttributeSetItem*>
305 0 : (item));
306 0 : NS_ENSURE_SUCCESS(rv, rv);
307 0 : break;
308 : }
309 : case txToplevelItem::dummy:
310 : case txToplevelItem::import:
311 : {
312 0 : break;
313 : }
314 : case txToplevelItem::output:
315 : {
316 0 : mOutputFormat.merge(static_cast<txOutputItem*>(item)->mFormat);
317 0 : break;
318 : }
319 : case txToplevelItem::stripSpace:
320 : {
321 : rv = addStripSpace(static_cast<txStripSpaceItem*>(item),
322 0 : frameStripSpaceTests);
323 0 : NS_ENSURE_SUCCESS(rv, rv);
324 0 : break;
325 : }
326 : case txToplevelItem::templ:
327 : {
328 : rv = addTemplate(static_cast<txTemplateItem*>(item),
329 0 : frame);
330 0 : NS_ENSURE_SUCCESS(rv, rv);
331 :
332 0 : break;
333 : }
334 : case txToplevelItem::variable:
335 : {
336 : rv = addGlobalVariable(static_cast<txVariableItem*>
337 0 : (item));
338 0 : NS_ENSURE_SUCCESS(rv, rv);
339 :
340 0 : break;
341 : }
342 : }
343 0 : delete item;
344 0 : itemIter.remove(); //remove() moves to the previous
345 0 : itemIter.next();
346 : }
347 0 : if (!mStripSpaceTests.AppendElements(frameStripSpaceTests)) {
348 0 : return NS_ERROR_OUT_OF_MEMORY;
349 : }
350 :
351 0 : frameStripSpaceTests.Clear();
352 : }
353 :
354 0 : if (!mDecimalFormats.get(txExpandedName())) {
355 0 : nsAutoPtr<txDecimalFormat> format(new txDecimalFormat);
356 0 : rv = mDecimalFormats.add(txExpandedName(), format);
357 0 : NS_ENSURE_SUCCESS(rv, rv);
358 :
359 0 : format.forget();
360 : }
361 :
362 0 : return NS_OK;
363 : }
364 :
365 : nsresult
366 0 : txStylesheet::addTemplate(txTemplateItem* aTemplate,
367 : ImportFrame* aImportFrame)
368 : {
369 0 : NS_ASSERTION(aTemplate, "missing template");
370 :
371 0 : txInstruction* instr = aTemplate->mFirstInstruction;
372 0 : nsresult rv = mTemplateInstructions.add(instr);
373 0 : NS_ENSURE_SUCCESS(rv, rv);
374 :
375 : // mTemplateInstructions now owns the instructions
376 0 : aTemplate->mFirstInstruction.forget();
377 :
378 0 : if (!aTemplate->mName.isNull()) {
379 0 : rv = mNamedTemplates.add(aTemplate->mName, instr);
380 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv) || rv == NS_ERROR_XSLT_ALREADY_SET,
381 : rv);
382 : }
383 :
384 0 : if (!aTemplate->mMatch) {
385 : // This is no error, see section 6 Named Templates
386 :
387 0 : return NS_OK;
388 : }
389 :
390 : // get the txList for the right mode
391 : nsTArray<MatchableTemplate>* templates =
392 0 : aImportFrame->mMatchableTemplates.get(aTemplate->mMode);
393 :
394 0 : if (!templates) {
395 : nsAutoPtr< nsTArray<MatchableTemplate> > newList(
396 0 : new nsTArray<MatchableTemplate>);
397 0 : rv = aImportFrame->mMatchableTemplates.set(aTemplate->mMode, newList);
398 0 : NS_ENSURE_SUCCESS(rv, rv);
399 :
400 0 : templates = newList.forget();
401 : }
402 :
403 : // Add the simple patterns to the list of matchable templates, according
404 : // to default priority
405 0 : nsAutoPtr<txPattern> simple = Move(aTemplate->mMatch);
406 0 : nsAutoPtr<txPattern> unionPattern;
407 0 : if (simple->getType() == txPattern::UNION_PATTERN) {
408 0 : unionPattern = Move(simple);
409 0 : simple = unionPattern->getSubPatternAt(0);
410 0 : unionPattern->setSubPatternAt(0, nullptr);
411 : }
412 :
413 0 : uint32_t unionPos = 1; // only used when unionPattern is set
414 0 : while (simple) {
415 0 : double priority = aTemplate->mPrio;
416 0 : if (mozilla::IsNaN(priority)) {
417 0 : priority = simple->getDefaultPriority();
418 0 : NS_ASSERTION(!mozilla::IsNaN(priority),
419 : "simple pattern without default priority");
420 : }
421 :
422 0 : uint32_t i, len = templates->Length();
423 0 : for (i = 0; i < len; ++i) {
424 0 : if (priority > (*templates)[i].mPriority) {
425 0 : break;
426 : }
427 : }
428 :
429 0 : MatchableTemplate* nt = templates->InsertElementAt(i);
430 0 : NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
431 :
432 0 : nt->mFirstInstruction = instr;
433 0 : nt->mMatch = Move(simple);
434 0 : nt->mPriority = priority;
435 :
436 0 : if (unionPattern) {
437 0 : simple = unionPattern->getSubPatternAt(unionPos);
438 0 : if (simple) {
439 0 : unionPattern->setSubPatternAt(unionPos, nullptr);
440 : }
441 0 : ++unionPos;
442 : }
443 : }
444 :
445 0 : return NS_OK;
446 : }
447 :
448 : nsresult
449 0 : txStylesheet::addFrames(txListIterator& aInsertIter)
450 : {
451 0 : ImportFrame* frame = static_cast<ImportFrame*>(aInsertIter.current());
452 0 : nsresult rv = NS_OK;
453 0 : txListIterator iter(&frame->mToplevelItems);
454 : txToplevelItem* item;
455 0 : while ((item = static_cast<txToplevelItem*>(iter.next()))) {
456 0 : if (item->getType() == txToplevelItem::import) {
457 0 : txImportItem* import = static_cast<txImportItem*>(item);
458 0 : import->mFrame->mFirstNotImported =
459 0 : static_cast<ImportFrame*>(aInsertIter.next());
460 0 : rv = aInsertIter.addBefore(import->mFrame);
461 0 : NS_ENSURE_SUCCESS(rv, rv);
462 :
463 0 : import->mFrame.forget();
464 0 : aInsertIter.previous();
465 0 : rv = addFrames(aInsertIter);
466 0 : NS_ENSURE_SUCCESS(rv, rv);
467 0 : aInsertIter.previous();
468 : }
469 : }
470 :
471 0 : return NS_OK;
472 : }
473 :
474 : nsresult
475 0 : txStylesheet::addStripSpace(txStripSpaceItem* aStripSpaceItem,
476 : nsTArray<txStripSpaceTest*>& aFrameStripSpaceTests)
477 : {
478 0 : int32_t testCount = aStripSpaceItem->mStripSpaceTests.Length();
479 0 : for (; testCount > 0; --testCount) {
480 0 : txStripSpaceTest* sst = aStripSpaceItem->mStripSpaceTests[testCount-1];
481 0 : double priority = sst->getDefaultPriority();
482 0 : int32_t i, frameCount = aFrameStripSpaceTests.Length();
483 0 : for (i = 0; i < frameCount; ++i) {
484 0 : if (aFrameStripSpaceTests[i]->getDefaultPriority() < priority) {
485 0 : break;
486 : }
487 : }
488 0 : if (!aFrameStripSpaceTests.InsertElementAt(i, sst)) {
489 0 : return NS_ERROR_OUT_OF_MEMORY;
490 : }
491 :
492 0 : aStripSpaceItem->mStripSpaceTests.RemoveElementAt(testCount-1);
493 : }
494 :
495 0 : return NS_OK;
496 : }
497 :
498 : nsresult
499 0 : txStylesheet::addAttributeSet(txAttributeSetItem* aAttributeSetItem)
500 : {
501 0 : nsresult rv = NS_OK;
502 0 : txInstruction* oldInstr = mAttributeSets.get(aAttributeSetItem->mName);
503 0 : if (!oldInstr) {
504 0 : rv = mAttributeSets.add(aAttributeSetItem->mName,
505 0 : aAttributeSetItem->mFirstInstruction);
506 0 : NS_ENSURE_SUCCESS(rv, rv);
507 :
508 0 : aAttributeSetItem->mFirstInstruction.forget();
509 :
510 0 : return NS_OK;
511 : }
512 :
513 : // We need to prepend the new instructions before the existing ones.
514 0 : txInstruction* instr = aAttributeSetItem->mFirstInstruction;
515 0 : txInstruction* lastNonReturn = nullptr;
516 0 : while (instr->mNext) {
517 0 : lastNonReturn = instr;
518 0 : instr = instr->mNext;
519 : }
520 :
521 0 : if (!lastNonReturn) {
522 : // The new attributeset is empty, so lets just ignore it.
523 0 : return NS_OK;
524 : }
525 :
526 0 : rv = mAttributeSets.set(aAttributeSetItem->mName,
527 0 : aAttributeSetItem->mFirstInstruction);
528 0 : NS_ENSURE_SUCCESS(rv, rv);
529 :
530 0 : aAttributeSetItem->mFirstInstruction.forget();
531 :
532 0 : lastNonReturn->mNext = oldInstr; // ...and link up the old instructions.
533 :
534 0 : return NS_OK;
535 : }
536 :
537 : nsresult
538 0 : txStylesheet::addGlobalVariable(txVariableItem* aVariable)
539 : {
540 0 : if (mGlobalVariables.get(aVariable->mName)) {
541 0 : return NS_OK;
542 : }
543 : nsAutoPtr<GlobalVariable> var(
544 0 : new GlobalVariable(Move(aVariable->mValue),
545 0 : Move(aVariable->mFirstInstruction),
546 0 : aVariable->mIsParam));
547 0 : nsresult rv = mGlobalVariables.add(aVariable->mName, var);
548 0 : NS_ENSURE_SUCCESS(rv, rv);
549 :
550 0 : var.forget();
551 :
552 0 : return NS_OK;
553 :
554 : }
555 :
556 : nsresult
557 0 : txStylesheet::addKey(const txExpandedName& aName,
558 : nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
559 : {
560 0 : nsresult rv = NS_OK;
561 :
562 0 : txXSLKey* xslKey = mKeys.get(aName);
563 0 : if (!xslKey) {
564 0 : xslKey = new txXSLKey(aName);
565 0 : rv = mKeys.add(aName, xslKey);
566 0 : if (NS_FAILED(rv)) {
567 0 : delete xslKey;
568 0 : return rv;
569 : }
570 : }
571 0 : if (!xslKey->addKey(Move(aMatch), Move(aUse))) {
572 0 : return NS_ERROR_OUT_OF_MEMORY;
573 : }
574 0 : return NS_OK;
575 : }
576 :
577 : nsresult
578 0 : txStylesheet::addDecimalFormat(const txExpandedName& aName,
579 : nsAutoPtr<txDecimalFormat>&& aFormat)
580 : {
581 0 : txDecimalFormat* existing = mDecimalFormats.get(aName);
582 0 : if (existing) {
583 0 : NS_ENSURE_TRUE(existing->isEqual(aFormat),
584 : NS_ERROR_XSLT_PARSE_FAILURE);
585 :
586 0 : return NS_OK;
587 : }
588 :
589 0 : nsresult rv = mDecimalFormats.add(aName, aFormat);
590 0 : NS_ENSURE_SUCCESS(rv, rv);
591 :
592 0 : aFormat.forget();
593 :
594 0 : return NS_OK;
595 : }
596 :
597 0 : txStylesheet::ImportFrame::~ImportFrame()
598 : {
599 0 : txListIterator tlIter(&mToplevelItems);
600 0 : while (tlIter.hasNext()) {
601 0 : delete static_cast<txToplevelItem*>(tlIter.next());
602 : }
603 0 : }
604 :
605 0 : txStylesheet::GlobalVariable::GlobalVariable(nsAutoPtr<Expr>&& aExpr,
606 : nsAutoPtr<txInstruction>&& aInstr,
607 0 : bool aIsParam)
608 0 : : mExpr(Move(aExpr)),
609 0 : mFirstInstruction(Move(aInstr)),
610 0 : mIsParam(aIsParam)
611 : {
612 0 : }
|