1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* utilities for regression tests based on frame tree comparison */
39 :
40 : #include "nsIFrameUtil.h"
41 : #include "nsFrame.h"
42 : #include "nsString.h"
43 : #include "nsRect.h"
44 : #include <stdlib.h>
45 : #include "plstr.h"
46 :
47 :
48 : #ifdef NS_DEBUG
49 : class nsFrameUtil : public nsIFrameUtil {
50 : public:
51 : nsFrameUtil();
52 : virtual ~nsFrameUtil();
53 :
54 : NS_DECL_ISUPPORTS
55 :
56 : NS_IMETHOD CompareRegressionData(FILE* aFile1, FILE* aFile2,PRInt32 aRegressionOutput=0);
57 : NS_IMETHOD DumpRegressionData(FILE* aInputFile, FILE* aOutputFile);
58 :
59 : struct Node;
60 : struct Tag;
61 :
62 : struct NodeList {
63 : NodeList();
64 : ~NodeList();
65 :
66 : static void Destroy(NodeList* aLists);
67 :
68 : NodeList* next; // for lists of lists
69 : Node* node;
70 : char* name;
71 : };
72 :
73 : struct Node {
74 : Node();
75 : ~Node();
76 :
77 : static void Destroy(Node* aNode);
78 :
79 : static Node* Read(FILE* aFile, Tag* aTag);
80 :
81 : static Node* ReadTree(FILE* aFile);
82 :
83 : Node* next;
84 : char* type;
85 : PRUint32 state;
86 : nsRect bbox;
87 : nsCString styleData;
88 : NodeList* lists;
89 : };
90 :
91 : struct Tag {
92 : Tag();
93 : ~Tag();
94 :
95 : static Tag* Parse(FILE* aFile);
96 :
97 : void AddAttr(char* aAttr, char* aValue);
98 :
99 : const char* GetAttr(const char* aAttr);
100 :
101 : void ReadAttrs(FILE* aFile);
102 :
103 : void ToString(nsString& aResult);
104 :
105 : enum Type {
106 : open,
107 : close,
108 : openClose
109 : };
110 :
111 : char* name;
112 : Type type;
113 : char** attributes;
114 : PRInt32 num;
115 : PRInt32 size;
116 : char** values;
117 : };
118 :
119 : static char* Copy(const char* aString);
120 :
121 : static void DumpNode(Node* aNode, FILE* aOutputFile, PRInt32 aIndent);
122 : static void DumpTree(Node* aNode, FILE* aOutputFile, PRInt32 aIndent);
123 : static bool CompareTrees(Node* aNode1, Node* aNode2);
124 : };
125 :
126 : char*
127 0 : nsFrameUtil::Copy(const char* aString)
128 : {
129 0 : if (aString) {
130 0 : int l = ::strlen(aString);
131 0 : char* c = new char[l+1];
132 0 : if (!c)
133 0 : return nsnull;
134 0 : memcpy(c, aString, l+1);
135 0 : return c;
136 : }
137 0 : return nsnull;
138 : }
139 :
140 : //----------------------------------------------------------------------
141 :
142 0 : nsFrameUtil::NodeList::NodeList()
143 0 : : next(nsnull), node(nsnull), name(nsnull)
144 : {
145 0 : }
146 :
147 0 : nsFrameUtil::NodeList::~NodeList()
148 : {
149 0 : if (nsnull != name) {
150 0 : delete name;
151 : }
152 0 : if (nsnull != node) {
153 0 : Node::Destroy(node);
154 : }
155 0 : }
156 :
157 : void
158 0 : nsFrameUtil::NodeList::Destroy(NodeList* aLists)
159 : {
160 0 : while (nsnull != aLists) {
161 0 : NodeList* next = aLists->next;
162 0 : delete aLists;
163 0 : aLists = next;
164 : }
165 0 : }
166 :
167 : //----------------------------------------------------------------------
168 :
169 0 : nsFrameUtil::Node::Node()
170 0 : : next(nsnull), type(nsnull), state(0), lists(nsnull)
171 : {
172 0 : }
173 :
174 0 : nsFrameUtil::Node::~Node()
175 : {
176 0 : if (nsnull != type) {
177 0 : delete type;
178 : }
179 0 : if (nsnull != lists) {
180 0 : NodeList::Destroy(lists);
181 : }
182 0 : }
183 :
184 : void
185 0 : nsFrameUtil::Node::Destroy(Node* aList)
186 : {
187 0 : while (nsnull != aList) {
188 0 : Node* next = aList->next;
189 0 : delete aList;
190 0 : aList = next;
191 : }
192 0 : }
193 :
194 0 : static PRInt32 GetInt(nsFrameUtil::Tag* aTag, const char* aAttr)
195 : {
196 0 : const char* value = aTag->GetAttr(aAttr);
197 0 : if (nsnull != value) {
198 0 : return PRInt32( atoi(value) );
199 : }
200 0 : return 0;
201 : }
202 :
203 : nsFrameUtil::Node*
204 0 : nsFrameUtil::Node::ReadTree(FILE* aFile)
205 : {
206 0 : Tag* tag = Tag::Parse(aFile);
207 0 : if (nsnull == tag) {
208 0 : return nsnull;
209 : }
210 0 : if (PL_strcmp(tag->name, "frame") != 0) {
211 0 : delete tag;
212 0 : return nsnull;
213 : }
214 0 : Node* result = Read(aFile, tag);
215 0 : fclose(aFile);
216 0 : return result;
217 : }
218 :
219 : nsFrameUtil::Node*
220 0 : nsFrameUtil::Node::Read(FILE* aFile, Tag* tag)
221 : {
222 0 : Node* node = new Node;
223 0 : node->type = Copy(tag->GetAttr("type"));
224 0 : if (!node->type) {
225 : /* crash() */
226 : }
227 0 : node->state = GetInt(tag, "state");
228 0 : delete tag;
229 :
230 0 : for (;;) {
231 0 : tag = Tag::Parse(aFile);
232 0 : if (nsnull == tag) break;
233 0 : if (PL_strcmp(tag->name, "frame") == 0) {
234 0 : delete tag;
235 0 : break;
236 : }
237 0 : if (PL_strcmp(tag->name, "bbox") == 0) {
238 0 : nscoord x = nscoord( GetInt(tag, "x") );
239 0 : nscoord y = nscoord( GetInt(tag, "y") );
240 0 : nscoord w = nscoord( GetInt(tag, "w") );
241 0 : nscoord h = nscoord( GetInt(tag, "h") );
242 0 : node->bbox.SetRect(x, y, w, h);
243 : }
244 0 : else if (PL_strcmp(tag->name, "child-list") == 0) {
245 0 : NodeList* list = new NodeList();
246 0 : list->name = Copy(tag->GetAttr("name"));
247 0 : if (!list->name) {
248 : /* crash() */
249 : }
250 0 : list->next = node->lists;
251 0 : node->lists = list;
252 0 : delete tag;
253 :
254 0 : Node** tailp = &list->node;
255 0 : for (;;) {
256 0 : tag = Tag::Parse(aFile);
257 0 : if (nsnull == tag) {
258 0 : break;
259 : }
260 0 : if (PL_strcmp(tag->name, "child-list") == 0) {
261 0 : break;
262 : }
263 0 : if (PL_strcmp(tag->name, "frame") != 0) {
264 0 : break;
265 : }
266 0 : Node* child = Node::Read(aFile, tag);
267 0 : if (nsnull == child) {
268 0 : break;
269 : }
270 0 : *tailp = child;
271 0 : tailp = &child->next;
272 : }
273 : }
274 0 : else if((PL_strcmp(tag->name, "font") == 0) ||
275 0 : (PL_strcmp(tag->name, "color") == 0) ||
276 0 : (PL_strcmp(tag->name, "spacing") == 0) ||
277 0 : (PL_strcmp(tag->name, "list") == 0) ||
278 0 : (PL_strcmp(tag->name, "position") == 0) ||
279 0 : (PL_strcmp(tag->name, "text") == 0) ||
280 0 : (PL_strcmp(tag->name, "display") == 0) ||
281 0 : (PL_strcmp(tag->name, "table") == 0) ||
282 0 : (PL_strcmp(tag->name, "content") == 0) ||
283 0 : (PL_strcmp(tag->name, "UI") == 0) ||
284 0 : (PL_strcmp(tag->name, "print") == 0)) {
285 0 : const char* attr = tag->GetAttr("data");
286 0 : node->styleData.Append('|');
287 0 : node->styleData.Append(attr ? attr : "null attr");
288 : }
289 :
290 0 : delete tag;
291 : }
292 0 : return node;
293 : }
294 :
295 : //----------------------------------------------------------------------
296 :
297 0 : nsFrameUtil::Tag::Tag()
298 : : name(nsnull), type(open), attributes(nsnull), num(0), size(0),
299 0 : values(nsnull)
300 : {
301 0 : }
302 :
303 0 : nsFrameUtil::Tag::~Tag()
304 : {
305 0 : PRInt32 i, n = num;
306 0 : if (0 != n) {
307 0 : for (i = 0; i < n; i++) {
308 0 : delete attributes[i];
309 0 : delete values[i];
310 : }
311 0 : delete attributes;
312 0 : delete values;
313 : }
314 0 : }
315 :
316 : void
317 0 : nsFrameUtil::Tag::AddAttr(char* aAttr, char* aValue)
318 : {
319 0 : if (num == size) {
320 0 : PRInt32 newSize = size * 2 + 4;
321 0 : char** a = new char*[newSize];
322 0 : char** v = new char*[newSize];
323 0 : if (0 != num) {
324 0 : memcpy(a, attributes, num * sizeof(char*));
325 0 : memcpy(v, values, num * sizeof(char*));
326 0 : delete attributes;
327 0 : delete values;
328 : }
329 0 : attributes = a;
330 0 : values = v;
331 0 : size = newSize;
332 : }
333 0 : attributes[num] = aAttr;
334 0 : values[num] = aValue;
335 0 : num = num + 1;
336 0 : }
337 :
338 : const char*
339 0 : nsFrameUtil::Tag::GetAttr(const char* aAttr)
340 : {
341 0 : PRInt32 i, n = num;
342 0 : for (i = 0; i < n; i++) {
343 0 : if (PL_strcmp(attributes[i], aAttr) == 0) {
344 0 : return values[i];
345 : }
346 : }
347 0 : return nsnull;
348 : }
349 :
350 0 : static inline int IsWhiteSpace(int c) {
351 0 : return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
352 : }
353 :
354 0 : static bool EatWS(FILE* aFile)
355 : {
356 0 : for (;;) {
357 0 : int c = getc(aFile);
358 0 : if (c < 0) {
359 0 : return false;
360 : }
361 0 : if (!IsWhiteSpace(c)) {
362 0 : ungetc(c, aFile);
363 : break;
364 : }
365 : }
366 0 : return true;
367 : }
368 :
369 0 : static bool Expect(FILE* aFile, char aChar)
370 : {
371 0 : int c = getc(aFile);
372 0 : if (c < 0) return false;
373 0 : if (c != aChar) {
374 0 : ungetc(c, aFile);
375 0 : return false;
376 : }
377 0 : return true;
378 : }
379 :
380 0 : static char* ReadIdent(FILE* aFile)
381 : {
382 : char id[1000];
383 0 : char* ip = id;
384 0 : char* end = ip + sizeof(id) - 1;
385 0 : while (ip < end) {
386 0 : int c = fgetc(aFile);
387 0 : if (c < 0) return nsnull;
388 0 : if ((c == '=') || (c == '>') || (c == '/') || IsWhiteSpace(c)) {
389 0 : ungetc(c, aFile);
390 0 : break;
391 : }
392 0 : *ip++ = char(c);
393 : }
394 0 : *ip = '\0';
395 0 : return nsFrameUtil::Copy(id);
396 : /* may return a null pointer */
397 : }
398 :
399 0 : static char* ReadString(FILE* aFile)
400 : {
401 0 : if (!Expect(aFile, '\"')) {
402 0 : return nsnull;
403 : }
404 : char id[1000];
405 0 : char* ip = id;
406 0 : char* end = ip + sizeof(id) - 1;
407 0 : while (ip < end) {
408 0 : int c = fgetc(aFile);
409 0 : if (c < 0) return nsnull;
410 0 : if (c == '\"') {
411 0 : break;
412 : }
413 0 : *ip++ = char(c);
414 : }
415 0 : *ip = '\0';
416 0 : return nsFrameUtil::Copy(id);
417 : /* may return a null pointer */
418 : }
419 :
420 : void
421 0 : nsFrameUtil::Tag::ReadAttrs(FILE* aFile)
422 : {
423 0 : for (;;) {
424 0 : if (!EatWS(aFile)) {
425 0 : break;
426 : }
427 0 : int c = getc(aFile);
428 0 : if (c < 0) break;
429 0 : if (c == '/') {
430 0 : if (!EatWS(aFile)) {
431 0 : return;
432 : }
433 0 : if (Expect(aFile, '>')) {
434 0 : type = openClose;
435 0 : break;
436 : }
437 : }
438 0 : else if (c == '>') {
439 0 : break;
440 : }
441 0 : ungetc(c, aFile);
442 0 : char* attr = ReadIdent(aFile);
443 0 : if ((nsnull == attr) || !EatWS(aFile)) {
444 0 : break;
445 : }
446 0 : char* value = nsnull;
447 0 : if (Expect(aFile, '=')) {
448 0 : value = ReadString(aFile);
449 0 : if (nsnull == value) {
450 0 : delete [] attr;
451 0 : break;
452 : }
453 : }
454 0 : AddAttr(attr, value);
455 : }
456 : }
457 :
458 : nsFrameUtil::Tag*
459 0 : nsFrameUtil::Tag::Parse(FILE* aFile)
460 : {
461 0 : if (!EatWS(aFile)) {
462 0 : return nsnull;
463 : }
464 0 : if (Expect(aFile, '<')) {
465 0 : Tag* tag = new Tag;
466 0 : if (Expect(aFile, '/')) {
467 0 : tag->type = close;
468 : }
469 : else {
470 0 : tag->type = open;
471 : }
472 0 : tag->name = ReadIdent(aFile);
473 0 : tag->ReadAttrs(aFile);
474 0 : return tag;
475 : }
476 0 : return nsnull;
477 : }
478 :
479 : void
480 0 : nsFrameUtil::Tag::ToString(nsString& aResult)
481 : {
482 0 : aResult.Truncate();
483 0 : aResult.Append(PRUnichar('<'));
484 0 : if (type == close) {
485 0 : aResult.Append(PRUnichar('/'));
486 : }
487 0 : aResult.AppendASCII(name);
488 0 : if (0 != num) {
489 0 : PRInt32 i, n = num;
490 0 : for (i = 0; i < n; i++) {
491 0 : aResult.Append(PRUnichar(' '));
492 0 : aResult.AppendASCII(attributes[i]);
493 0 : if (values[i]) {
494 0 : aResult.AppendLiteral("=\"");
495 0 : aResult.AppendASCII(values[i]);
496 0 : aResult.Append(PRUnichar('\"'));
497 : }
498 : }
499 : }
500 0 : if (type == openClose) {
501 0 : aResult.Append(PRUnichar('/'));
502 : }
503 0 : aResult.Append(PRUnichar('>'));
504 0 : }
505 :
506 : //----------------------------------------------------------------------
507 :
508 : nsresult
509 0 : NS_NewFrameUtil(nsIFrameUtil** aResult)
510 : {
511 0 : NS_PRECONDITION(nsnull != aResult, "null pointer");
512 0 : if (nsnull == aResult) {
513 0 : return NS_ERROR_NULL_POINTER;
514 : }
515 :
516 0 : nsFrameUtil* it = new nsFrameUtil();
517 :
518 0 : NS_ADDREF(*aResult = it);
519 0 : return NS_OK;
520 : }
521 :
522 0 : nsFrameUtil::nsFrameUtil()
523 : {
524 0 : }
525 :
526 0 : nsFrameUtil::~nsFrameUtil()
527 : {
528 0 : }
529 :
530 0 : NS_IMPL_ISUPPORTS1(nsFrameUtil, nsIFrameUtil)
531 :
532 : void
533 0 : nsFrameUtil::DumpNode(Node* aNode, FILE* aOutputFile, PRInt32 aIndent)
534 : {
535 0 : nsFrame::IndentBy(aOutputFile, aIndent);
536 : fprintf(aOutputFile, "%s 0x%x %d,%d,%d,%d, %s\n", aNode->type, aNode->state,
537 : aNode->bbox.x, aNode->bbox.y,
538 : aNode->bbox.width, aNode->bbox.height,
539 0 : aNode->styleData.get());
540 0 : }
541 :
542 : void
543 0 : nsFrameUtil::DumpTree(Node* aNode, FILE* aOutputFile, PRInt32 aIndent)
544 : {
545 0 : while (nsnull != aNode) {
546 0 : DumpNode(aNode, aOutputFile, aIndent);
547 0 : nsFrameUtil::NodeList* lists = aNode->lists;
548 0 : if (nsnull != lists) {
549 0 : while (nsnull != lists) {
550 0 : nsFrame::IndentBy(aOutputFile, aIndent);
551 : fprintf(aOutputFile, " list: %s\n",
552 0 : lists->name ? lists->name : "primary");
553 0 : DumpTree(lists->node, aOutputFile, aIndent + 1);
554 0 : lists = lists->next;
555 : }
556 : }
557 0 : aNode = aNode->next;
558 : }
559 0 : }
560 :
561 : bool
562 0 : nsFrameUtil::CompareTrees(Node* tree1, Node* tree2)
563 : {
564 0 : bool result = true;
565 0 : for (;; tree1 = tree1->next, tree2 = tree2->next) {
566 : // Make sure both nodes are non-null, or at least agree with each other
567 0 : if (nsnull == tree1) {
568 0 : if (nsnull == tree2) {
569 : break;
570 : }
571 0 : printf("first tree prematurely ends\n");
572 0 : return false;
573 : }
574 0 : else if (nsnull == tree2) {
575 0 : printf("second tree prematurely ends\n");
576 0 : return false;
577 : }
578 :
579 : // Check the attributes that we care about
580 0 : if (0 != PL_strcmp(tree1->type, tree2->type)) {
581 0 : printf("frame type mismatch: %s vs. %s\n", tree1->type, tree2->type);
582 0 : printf("Node 1:\n");
583 0 : DumpNode(tree1, stdout, 1);
584 0 : printf("Node 2:\n");
585 0 : DumpNode(tree2, stdout, 1);
586 0 : return false;
587 : }
588 :
589 : // Ignore the XUL scrollbar frames
590 : static const char kScrollbarFrame[] = "ScrollbarFrame";
591 0 : if (0 == PL_strncmp(tree1->type, kScrollbarFrame, sizeof(kScrollbarFrame) - 1))
592 0 : continue;
593 :
594 0 : if (tree1->state != tree2->state) {
595 : printf("frame state mismatch: 0x%x vs. 0x%x\n",
596 0 : tree1->state, tree2->state);
597 0 : printf("Node 1:\n");
598 0 : DumpNode(tree1, stdout, 1);
599 0 : printf("Node 2:\n");
600 0 : DumpNode(tree2, stdout, 1);
601 0 : result = false; // we have a non-critical failure, so remember that but continue
602 : }
603 0 : if (tree1->bbox.IsEqualInterior(tree2->bbox)) {
604 : printf("frame bbox mismatch: %d,%d,%d,%d vs. %d,%d,%d,%d\n",
605 : tree1->bbox.x, tree1->bbox.y,
606 : tree1->bbox.width, tree1->bbox.height,
607 : tree2->bbox.x, tree2->bbox.y,
608 0 : tree2->bbox.width, tree2->bbox.height);
609 0 : printf("Node 1:\n");
610 0 : DumpNode(tree1, stdout, 1);
611 0 : printf("Node 2:\n");
612 0 : DumpNode(tree2, stdout, 1);
613 0 : result = false; // we have a non-critical failure, so remember that but continue
614 : }
615 0 : if (tree1->styleData != tree2->styleData) {
616 : printf("frame style data mismatch: %s vs. %s\n",
617 : tree1->styleData.get(),
618 0 : tree2->styleData.get());
619 : }
620 :
621 : // Check child lists too
622 0 : NodeList* list1 = tree1->lists;
623 0 : NodeList* list2 = tree2->lists;
624 0 : for (;;) {
625 0 : if (nsnull == list1) {
626 0 : if (nsnull != list2) {
627 0 : printf("first tree prematurely ends (no child lists)\n");
628 0 : printf("Node 1:\n");
629 0 : DumpNode(tree1, stdout, 1);
630 0 : printf("Node 2:\n");
631 0 : DumpNode(tree2, stdout, 1);
632 0 : return false;
633 : }
634 : else {
635 0 : break;
636 : }
637 : }
638 0 : if (nsnull == list2) {
639 0 : printf("second tree prematurely ends (no child lists)\n");
640 0 : printf("Node 1:\n");
641 0 : DumpNode(tree1, stdout, 1);
642 0 : printf("Node 2:\n");
643 0 : DumpNode(tree2, stdout, 1);
644 0 : return false;
645 : }
646 0 : if (0 != PL_strcmp(list1->name, list2->name)) {
647 : printf("child-list name mismatch: %s vs. %s\n",
648 : list1->name ? list1->name : "(null)",
649 0 : list2->name ? list2->name : "(null)");
650 0 : result = false; // we have a non-critical failure, so remember that but continue
651 : }
652 : else {
653 0 : bool equiv = CompareTrees(list1->node, list2->node);
654 0 : if (!equiv) {
655 0 : return equiv;
656 : }
657 : }
658 0 : list1 = list1->next;
659 0 : list2 = list2->next;
660 : }
661 : }
662 0 : return result;
663 : }
664 :
665 : NS_IMETHODIMP
666 0 : nsFrameUtil::CompareRegressionData(FILE* aFile1, FILE* aFile2,PRInt32 aRegressionOutput)
667 : {
668 0 : Node* tree1 = Node::ReadTree(aFile1);
669 0 : Node* tree2 = Node::ReadTree(aFile2);
670 :
671 0 : nsresult rv = NS_OK;
672 0 : if (!CompareTrees(tree1, tree2)) {
673 : // only output this if aRegressionOutput is 0
674 0 : if( 0 == aRegressionOutput ){
675 0 : printf("Regression data 1:\n");
676 0 : DumpTree(tree1, stdout, 0);
677 0 : printf("Regression data 2:\n");
678 0 : DumpTree(tree2, stdout, 0);
679 : }
680 0 : rv = NS_ERROR_FAILURE;
681 : }
682 :
683 0 : Node::Destroy(tree1);
684 0 : Node::Destroy(tree2);
685 :
686 0 : return rv;
687 : }
688 :
689 : NS_IMETHODIMP
690 0 : nsFrameUtil::DumpRegressionData(FILE* aInputFile, FILE* aOutputFile)
691 : {
692 0 : Node* tree1 = Node::ReadTree(aInputFile);
693 0 : if (nsnull != tree1) {
694 0 : DumpTree(tree1, aOutputFile, 0);
695 0 : Node::Destroy(tree1);
696 0 : return NS_OK;
697 : }
698 0 : return NS_ERROR_FAILURE;
699 : }
700 : #endif
|