KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > w3c > tidy > PPrint


1 /*
2  * @(#)PPrint.java 1.11 2000/08/16
3  *
4  */

5
6 package org.w3c.tidy;
7
8 /**
9  *
10  * Pretty print parse tree
11  *
12  * (c) 1998-2000 (W3C) MIT, INRIA, Keio University
13  * See Tidy.java for the copyright notice.
14  * Derived from <a HREF="http://www.w3.org/People/Raggett/tidy">
15  * HTML Tidy Release 4 Aug 2000</a>
16  *
17  * @author Dave Raggett <dsr@w3.org>
18  * @author Andy Quick <ac.quick@sympatico.ca> (translation to Java)
19  * @version 1.0, 1999/05/22
20  * @version 1.0.1, 1999/05/29
21  * @version 1.1, 1999/06/18 Java Bean
22  * @version 1.2, 1999/07/10 Tidy Release 7 Jul 1999
23  * @version 1.3, 1999/07/30 Tidy Release 26 Jul 1999
24  * @version 1.4, 1999/09/04 DOM support
25  * @version 1.5, 1999/10/23 Tidy Release 27 Sep 1999
26  * @version 1.6, 1999/11/01 Tidy Release 22 Oct 1999
27  * @version 1.7, 1999/12/06 Tidy Release 30 Nov 1999
28  * @version 1.8, 2000/01/22 Tidy Release 13 Jan 2000
29  * @version 1.9, 2000/06/03 Tidy Release 30 Apr 2000
30  * @version 1.10, 2000/07/22 Tidy Release 8 Jul 2000
31  * @version 1.11, 2000/08/16 Tidy Release 4 Aug 2000
32  */

33
34 /*
35   Block-level and unknown elements are printed on
36   new lines and their contents indented 2 spaces
37
38   Inline elements are printed inline.
39
40   Inline content is wrapped on spaces (except in
41   attribute values or preformatted text, after
42   start tags and before end tags
43 */

44
45 import java.io.FileOutputStream JavaDoc;
46 import java.io.File JavaDoc;
47
48 import java.io.IOException JavaDoc;
49 import java.io.FileNotFoundException JavaDoc;
50
51 public class PPrint {
52
53     /* page transition effects */
54
55     public static final short EFFECT_BLEND = -1;
56     public static final short EFFECT_BOX_IN = 0;
57     public static final short EFFECT_BOX_OUT = 1;
58     public static final short EFFECT_CIRCLE_IN = 2;
59     public static final short EFFECT_CIRCLE_OUT = 3;
60     public static final short EFFECT_WIPE_UP = 4;
61     public static final short EFFECT_WIPE_DOWN = 5;
62     public static final short EFFECT_WIPE_RIGHT = 6;
63     public static final short EFFECT_WIPE_LEFT = 7;
64     public static final short EFFECT_VERT_BLINDS = 8;
65     public static final short EFFECT_HORZ_BLINDS = 9;
66     public static final short EFFECT_CHK_ACROSS = 10;
67     public static final short EFFECT_CHK_DOWN = 11;
68     public static final short EFFECT_RND_DISSOLVE = 12;
69     public static final short EFFECT_SPLIT_VIRT_IN = 13;
70     public static final short EFFECT_SPLIT_VIRT_OUT = 14;
71     public static final short EFFECT_SPLIT_HORZ_IN = 15;
72     public static final short EFFECT_SPLIT_HORZ_OUT = 16;
73     public static final short EFFECT_STRIPS_LEFT_DOWN = 17;
74     public static final short EFFECT_STRIPS_LEFT_UP = 18;
75     public static final short EFFECT_STRIPS_RIGHT_DOWN = 19;
76     public static final short EFFECT_STRIPS_RIGHT_UP = 20;
77     public static final short EFFECT_RND_BARS_HORZ = 21;
78     public static final short EFFECT_RND_BARS_VERT = 22;
79     public static final short EFFECT_RANDOM = 23;
80
81     private static final short NORMAL = 0;
82     private static final short PREFORMATTED = 1;
83     private static final short COMMENT = 2;
84     private static final short ATTRIBVALUE = 4;
85     private static final short NOWRAP = 8;
86     private static final short CDATA = 16;
87
88     private int[] linebuf = null;
89     private int lbufsize = 0;
90     private int linelen = 0;
91     private int wraphere = 0;
92     private boolean inAttVal = false;
93     private boolean InString = false;
94
95     private int slide = 0;
96     private int count = 0;
97     private Node slidecontent = null;
98
99     private Configuration configuration;
100
101     public PPrint(Configuration configuration)
102     {
103         this.configuration = configuration;
104     }
105
106     /*
107       1010 A
108       1011 B
109       1100 C
110       1101 D
111       1110 E
112       1111 F
113     */

114
115     /* return one less that the number of bytes used by UTF-8 char */
116     /* str points to 1st byte, *ch initialized to 1st byte */
117     public static int getUTF8(byte[] str, int start, MutableInteger ch)
118     {
119         int c, n, i, bytes;
120
121         c = ((int)str[start]) & 0xFF; // Convert to unsigned.
122

123         if ((c & 0xE0) == 0xC0) /* 110X XXXX two bytes */
124         {
125             n = c & 31;
126             bytes = 2;
127         }
128         else if ((c & 0xF0) == 0xE0) /* 1110 XXXX three bytes */
129         {
130             n = c & 15;
131             bytes = 3;
132         }
133         else if ((c & 0xF8) == 0xF0) /* 1111 0XXX four bytes */
134         {
135             n = c & 7;
136             bytes = 4;
137         }
138         else if ((c & 0xFC) == 0xF8) /* 1111 10XX five bytes */
139         {
140             n = c & 3;
141             bytes = 5;
142         }
143         else if ((c & 0xFE) == 0xFC) /* 1111 110X six bytes */
144
145         {
146             n = c & 1;
147             bytes = 6;
148         }
149         else /* 0XXX XXXX one byte */
150         {
151             ch.value = c;
152             return 0;
153         }
154
155         /* successor bytes should have the form 10XX XXXX */
156         for (i = 1; i < bytes; ++i)
157         {
158             c = ((int)str[start + i]) & 0xFF; // Convert to unsigned.
159
n = (n << 6) | (c & 0x3F);
160         }
161
162         ch.value = n;
163         return bytes - 1;
164     }
165
166     /* store char c as UTF-8 encoded byte stream */
167     public static int putUTF8(byte[] buf, int start, int c)
168     {
169         if (c < 128)
170             buf[start++] = (byte)c;
171         else if (c <= 0x7FF)
172         {
173             buf[start++] = (byte)(0xC0 | (c >> 6));
174             buf[start++] = (byte)(0x80 | (c & 0x3F));
175         }
176         else if (c <= 0xFFFF)
177         {
178             buf[start++] = (byte)(0xE0 | (c >> 12));
179             buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F));
180             buf[start++] = (byte)(0x80 | (c & 0x3F));
181         }
182         else if (c <= 0x1FFFFF)
183         {
184             buf[start++] = (byte)(0xF0 | (c >> 18));
185             buf[start++] = (byte)(0x80 | ((c >> 12) & 0x3F));
186             buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F));
187             buf[start++] = (byte)(0x80 | (c & 0x3F));
188         }
189         else
190         {
191             buf[start++] = (byte)(0xF8 | (c >> 24));
192             buf[start++] = (byte)(0x80 | ((c >> 18) & 0x3F));
193             buf[start++] = (byte)(0x80 | ((c >> 12) & 0x3F));
194             buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F));
195             buf[start++] = (byte)(0x80 | (c & 0x3F));
196         }
197
198         return start;
199     }
200
201     private void addC(int c, int index)
202     {
203         if (index + 1 >= lbufsize)
204         {
205             while (index + 1 >= lbufsize)
206             {
207                 if (lbufsize == 0)
208                     lbufsize = 256;
209                 else
210                     lbufsize = lbufsize * 2;
211             }
212
213            int[] temp = new int[ lbufsize ];
214            if (linebuf != null)
215                System.arraycopy(linebuf, 0, temp, 0, index);
216            linebuf = temp;
217         }
218
219         linebuf[index] = c;
220     }
221
222     private void wrapLine(Out fout, int indent)
223     {
224         int i, p, q;
225
226         if (wraphere == 0)
227             return;
228
229         for (i = 0; i < indent; ++i)
230             fout.outc((int)' ');
231
232         for (i = 0; i < wraphere; ++i)
233             fout.outc(linebuf[i]);
234
235         if (InString)
236         {
237             fout.outc((int)' ');
238             fout.outc((int)'\\');
239         }
240
241         fout.newline();
242
243         if (linelen > wraphere)
244         {
245             p = 0;
246
247             if (linebuf[wraphere] == ' ')
248                 ++wraphere;
249
250             q = wraphere;
251             addC('\0', linelen);
252
253             while (true)
254             {
255                 linebuf[p] = linebuf[q];
256                 if (linebuf[q] == 0) break;
257                 p++;
258                 q++;
259             }
260             linelen -= wraphere;
261         }
262         else
263             linelen = 0;
264
265         wraphere = 0;
266     }
267
268     private void wrapAttrVal(Out fout, int indent, boolean inString)
269     {
270         int i, p, q;
271
272         for (i = 0; i < indent; ++i)
273             fout.outc((int)' ');
274
275         for (i = 0; i < wraphere; ++i)
276             fout.outc(linebuf[i]);
277
278         fout.outc((int)' ');
279
280         if (inString)
281             fout.outc((int)'\\');
282
283         fout.newline();
284
285         if (linelen > wraphere)
286         {
287             p = 0;
288
289             if (linebuf[wraphere] == ' ')
290                 ++wraphere;
291
292             q = wraphere;
293             addC('\0', linelen);
294
295             while (true)
296             {
297                 linebuf[p] = linebuf[q];
298                 if (linebuf[q] == 0) break;
299                 p++;
300                 q++;
301             }
302             linelen -= wraphere;
303         }
304         else
305             linelen = 0;
306
307         wraphere = 0;
308     }
309
310     public void flushLine(Out fout, int indent)
311     {
312         int i;
313
314         if (linelen > 0)
315         {
316             if (indent + linelen >= this.configuration.wraplen)
317                 wrapLine(fout, indent);
318
319             if (!inAttVal || this.configuration.IndentAttributes)
320             {
321                 for (i = 0; i < indent; ++i)
322                     fout.outc((int)' ');
323             }
324
325             for (i = 0; i < linelen; ++i)
326                 fout.outc(linebuf[i]);
327         }
328
329         fout.newline();
330         linelen = 0;
331         wraphere = 0;
332         inAttVal = false;
333     }
334
335     public void condFlushLine(Out fout, int indent)
336     {
337         int i;
338
339         if (linelen > 0)
340         {
341             if (indent + linelen >= this.configuration.wraplen)
342                 wrapLine(fout, indent);
343
344             if (!inAttVal || this.configuration.IndentAttributes)
345             {
346                 for (i = 0; i < indent; ++i)
347                     fout.outc((int)' ');
348             }
349
350             for (i = 0; i < linelen; ++i)
351                 fout.outc(linebuf[i]);
352
353             fout.newline();
354             linelen = 0;
355             wraphere = 0;
356             inAttVal = false;
357         }
358     }
359
360     private void printChar(int c, short mode)
361     {
362         String JavaDoc entity;
363
364         if (c == ' ' && !((mode & (PREFORMATTED | COMMENT | ATTRIBVALUE)) != 0))
365         {
366             /* coerce a space character to a non-breaking space */
367             if ((mode & NOWRAP) != 0)
368             {
369                 /* by default XML doesn't define &nbsp; */
370                 if (this.configuration.NumEntities || this.configuration.XmlTags)
371                 {
372                     addC('&', linelen++);
373                     addC('#', linelen++);
374                     addC('1', linelen++);
375                     addC('6', linelen++);
376                     addC('0', linelen++);
377                     addC(';', linelen++);
378                 }
379                 else /* otherwise use named entity */
380                 {
381                     addC('&', linelen++);
382                     addC('n', linelen++);
383                     addC('b', linelen++);
384                     addC('s', linelen++);
385                     addC('p', linelen++);
386                     addC(';', linelen++);
387                 }
388                 return;
389             }
390             else
391                 wraphere = linelen;
392         }
393
394         /* comment characters are passed raw */
395         if ((mode & COMMENT) != 0)
396         {
397             addC(c, linelen++);
398             return;
399         }
400
401         /* except in CDATA map < to &lt; etc. */
402         if (! ((mode & CDATA) != 0) )
403         {
404             if (c == '<')
405             {
406                 addC('&', linelen++);
407                 addC('l', linelen++);
408                 addC('t', linelen++);
409                 addC(';', linelen++);
410                 return;
411             }
412             
413             if (c == '>')
414             {
415                 addC('&', linelen++);
416                 addC('g', linelen++);
417                 addC('t', linelen++);
418                 addC(';', linelen++);
419                 return;
420             }
421
422             /*
423               naked '&' chars can be left alone or
424               quoted as &amp; The latter is required
425               for XML where naked '&' are illegal.
426             */

427             if (c == '&' && this.configuration.QuoteAmpersand)
428             {
429                 addC('&', linelen++);
430                 addC('a', linelen++);
431                 addC('m', linelen++);
432                 addC('p', linelen++);
433                 addC(';', linelen++);
434                 return;
435             }
436
437             if (c == '"' && this.configuration.QuoteMarks)
438             {
439                 addC('&', linelen++);
440                 addC('q', linelen++);
441                 addC('u', linelen++);
442                 addC('o', linelen++);
443                 addC('t', linelen++);
444                 addC(';', linelen++);
445                 return;
446             }
447
448             if (c == '\'' && this.configuration.QuoteMarks)
449             {
450                 addC('&', linelen++);
451                 addC('#', linelen++);
452                 addC('3', linelen++);
453                 addC('9', linelen++);
454                 addC(';', linelen++);
455                 return;
456             }
457
458             if (c == 160 && this.configuration.CharEncoding != Configuration.RAW)
459             {
460                 if (this.configuration.QuoteNbsp)
461                 {
462                     addC('&', linelen++);
463
464                     if (this.configuration.NumEntities)
465                     {
466                         addC('#', linelen++);
467                         addC('1', linelen++);
468                         addC('6', linelen++);
469                         addC('0', linelen++);
470                     }
471                     else
472                     {
473                         addC('n', linelen++);
474                         addC('b', linelen++);
475                         addC('s', linelen++);
476                         addC('p', linelen++);
477                     }
478
479                     addC(';', linelen++);
480                 }
481                 else
482                     addC(c, linelen++);
483
484                 return;
485             }
486         }
487
488         /* otherwise ISO 2022 characters are passed raw */
489         if (this.configuration.CharEncoding == Configuration.ISO2022 ||
490             this.configuration.CharEncoding == Configuration.RAW)
491         {
492             addC(c, linelen++);
493             return;
494         }
495
496         /* if preformatted text, map &nbsp; to space */
497         if (c == 160 && ((mode & PREFORMATTED) != 0))
498         {
499             addC(' ', linelen++);
500             return;
501         }
502
503         /*
504          Filters from Word and PowerPoint often use smart
505          quotes resulting in character codes between 128
506          and 159. Unfortunately, the corresponding HTML 4.0
507          entities for these are not widely supported. The
508          following converts dashes and quotation marks to
509          the nearest ASCII equivalent. My thanks to
510          Andrzej Novosiolov for his help with this code.
511         */

512
513         if (this.configuration.MakeClean)
514         {
515             if (c >= 0x2013 && c <= 0x201E)
516             {
517                 switch (c) {
518                 case 0x2013:
519                 case 0x2014:
520                   c = '-';
521                   break;
522                 case 0x2018:
523                 case 0x2019:
524                 case 0x201A:
525                   c = '\'';
526                   break;
527                 case 0x201C:
528                 case 0x201D:
529                 case 0x201E:
530                   c = '"';
531                   break;
532                 }
533             }
534         }
535
536         /* don't map latin-1 chars to entities */
537         if (this.configuration.CharEncoding == Configuration.LATIN1)
538         {
539             if (c > 255) /* multi byte chars */
540             {
541                 if (!this.configuration.NumEntities)
542                 {
543                     entity = EntityTable.getDefaultEntityTable().entityName((short)c);
544                     if (entity != null)
545                         entity = "&" + entity + ";";
546                     else
547                         entity = "&#" + c + ";";
548                 }
549                 else
550                     entity = "&#" + c + ";";
551
552                 for (int i = 0; i < entity.length(); i++)
553                     addC((int)entity.charAt(i), linelen++);
554
555                 return;
556             }
557
558             if (c > 126 && c < 160)
559             {
560                 entity = "&#" + c + ";";
561
562                 for (int i = 0; i < entity.length(); i++)
563                     addC((int)entity.charAt(i), linelen++);
564
565                 return;
566             }
567
568             addC(c, linelen++);
569             return;
570         }
571
572         /* don't map utf8 chars to entities */
573         if (this.configuration.CharEncoding == Configuration.UTF8)
574         {
575             addC(c, linelen++);
576             return;
577         }
578
579         /* use numeric entities only for XML */
580         if (this.configuration.XmlTags)
581         {
582             /* if ASCII use numeric entities for chars > 127 */
583             if (c > 127 && this.configuration.CharEncoding == Configuration.ASCII)
584             {
585                 entity = "&#" + c + ";";
586
587                 for (int i = 0; i < entity.length(); i++)
588                     addC((int)entity.charAt(i), linelen++);
589
590                 return;
591             }
592
593             /* otherwise output char raw */
594             addC(c, linelen++);
595             return;
596         }
597
598         /* default treatment for ASCII */
599         if (c > 126 || (c < ' ' && c != '\t'))
600         {
601             if (!this.configuration.NumEntities)
602             {
603                 entity = EntityTable.getDefaultEntityTable().entityName((short)c);
604                 if (entity != null)
605                     entity = "&" + entity + ";";
606                 else
607                     entity = "&#" + c + ";";
608             }
609             else
610                 entity = "&#" + c + ";";
611
612             for (int i = 0; i < entity.length(); i++)
613                 addC((int)entity.charAt(i), linelen++);
614
615             return;
616         }
617
618         addC(c, linelen++);
619     }
620
621     /*
622       The line buffer is uint not char so we can
623       hold Unicode values unencoded. The translation
624       to UTF-8 is deferred to the outc routine called
625       to flush the line buffer.
626     */

627     private void printText(Out fout, short mode, int indent,
628                            byte[] textarray, int start, int end)
629     {
630         int i, c;
631         MutableInteger ci = new MutableInteger();
632
633         for (i = start; i < end; ++i)
634         {
635             if (indent + linelen >= this.configuration.wraplen)
636                 wrapLine(fout, indent);
637
638             c = ((int)textarray[i]) & 0xFF; // Convert to unsigned.
639

640             /* look for UTF-8 multibyte character */
641             if (c > 0x7F)
642             {
643                  i += getUTF8(textarray, i, ci);
644                  c = ci.value;
645             }
646
647             if (c == '\n')
648             {
649                 flushLine(fout, indent);
650                 continue;
651             }
652
653             printChar(c, mode);
654         }
655     }
656
657     private void printString(Out fout, int indent, String JavaDoc str)
658     {
659         for (int i = 0; i < str.length(); i++ )
660             addC((int)str.charAt(i), linelen++);
661     }
662
663     private void printAttrValue(Out fout, int indent, String JavaDoc value, int delim, boolean wrappable)
664     {
665         int c;
666         MutableInteger ci = new MutableInteger();
667         boolean wasinstring = false;
668         byte[] valueChars = null;
669         int i;
670         short mode = (wrappable ? (short)(NORMAL | ATTRIBVALUE) :
671                                   (short)(PREFORMATTED | ATTRIBVALUE));
672
673         if (value != null)
674         {
675             valueChars = Lexer.getBytes(value);
676         }
677
678         /* look for ASP, Tango or PHP instructions for computed attribute value */
679         if (valueChars != null && valueChars.length >= 5 && valueChars[0] == '<')
680         {
681             if (valueChars[1] == '%' || valueChars[1] == '@'||
682                 (new String JavaDoc(valueChars, 0, 5)).equals("<?php"))
683                 mode |= CDATA;
684         }
685
686         if (delim == 0)
687             delim = '"';
688
689         addC('=', linelen++);
690
691         /* don't wrap after "=" for xml documents */
692         if (!this.configuration.XmlOut) {
693
694             if (indent + linelen < this.configuration.wraplen)
695                 wraphere = linelen;
696
697             if (indent + linelen >= this.configuration.wraplen)
698                 wrapLine(fout, indent);
699
700             if (indent + linelen < this.configuration.wraplen)
701                 wraphere = linelen;
702             else
703                 condFlushLine(fout, indent);
704         }
705
706         addC(delim, linelen++);
707
708         if (value != null)
709         {
710             InString = false;
711
712             i = 0;
713             while (i < valueChars.length)
714             {
715                 c = ((int)valueChars[i]) & 0xFF; // Convert to unsigned.
716

717                 if (wrappable && c == ' ' && indent + linelen < this.configuration.wraplen)
718                 {
719                     wraphere = linelen;
720                     wasinstring = InString;
721                 }
722
723                 if (wrappable && wraphere > 0 && indent + linelen >= this.configuration.wraplen)
724                     wrapAttrVal(fout, indent, wasinstring);
725
726                 if (c == delim)
727                 {
728                     String JavaDoc entity;
729
730                     entity = (c == '"' ? "&quot;" : "&#39;");
731
732                     for (int j = 0; j < entity.length(); j++ )
733                         addC(entity.charAt(j), linelen++);
734
735                     ++i;
736                     continue;
737                 }
738                 else if (c == '"')
739                 {
740                     if (this.configuration.QuoteMarks)
741                     {
742                         addC('&', linelen++);
743                         addC('q', linelen++);
744                         addC('u', linelen++);
745                         addC('o', linelen++);
746                         addC('t', linelen++);
747                         addC(';', linelen++);
748                     }
749                     else
750                         addC('"', linelen++);
751
752                     if (delim == '\'')
753                         InString = !InString;
754
755                     ++i;
756                     continue;
757                 }
758                 else if (c == '\'')
759                 {
760                     if (this.configuration.QuoteMarks)
761                     {
762                         addC('&', linelen++);
763                         addC('#', linelen++);
764                         addC('3', linelen++);
765                         addC('9', linelen++);
766                         addC(';', linelen++);
767                     }
768                     else
769                         addC('\'', linelen++);
770
771                     if (delim == '"')
772                         InString = !InString;
773
774                     ++i;
775                     continue;
776                 }
777
778                 /* look for UTF-8 multibyte character */
779                 if (c > 0x7F)
780                 {
781                      i += getUTF8(valueChars, i, ci);
782                      c = ci.value;
783                 }
784
785                 ++i;
786
787                 if (c == '\n')
788                 {
789                     flushLine(fout, indent);
790                     continue;
791                 }
792
793                 printChar(c, mode);
794             }
795         }
796
797         InString = false;
798         addC(delim, linelen++);
799     }
800
801     private void printAttribute(Out fout, int indent, Node node, AttVal attr)
802     {
803         String JavaDoc name;
804         boolean wrappable = false;
805
806         if (this.configuration.IndentAttributes)
807         {
808             flushLine(fout, indent);
809             indent += this.configuration.spaces;
810         }
811
812         name = attr.attribute;
813
814         if (indent + linelen >= this.configuration.wraplen)
815             wrapLine(fout, indent);
816
817         if (!this.configuration.XmlTags && !this.configuration.XmlOut && attr.dict != null)
818         {
819             if (AttributeTable.getDefaultAttributeTable().isScript(name))
820                 wrappable = this.configuration.WrapScriptlets;
821             else if (!attr.dict.nowrap && this.configuration.WrapAttVals)
822                 wrappable = true;
823         }
824
825         if (indent + linelen < this.configuration.wraplen)
826         {
827             wraphere = linelen;
828             addC(' ', linelen++);
829         }
830         else
831         {
832             condFlushLine(fout, indent);
833             addC(' ', linelen++);
834         }
835
836         for (int i = 0; i < name.length(); i++ )
837             addC((int)Lexer.foldCase(name.charAt(i),
838                                      this.configuration.UpperCaseAttrs,
839                                      this.configuration.XmlTags),
840                  linelen++);
841
842         if (indent + linelen >= this.configuration.wraplen)
843             wrapLine(fout, indent);
844  
845         if (attr.value == null)
846         {
847             if (this.configuration.XmlTags || this.configuration.XmlOut)
848                 printAttrValue(fout, indent, attr.attribute, attr.delim, true);
849             else if (!attr.isBoolAttribute() && !Node.isNewNode(node))
850                 printAttrValue(fout, indent, "", attr.delim, true);
851             else if (indent + linelen < this.configuration.wraplen)
852                 wraphere = linelen;
853
854         }
855         else
856             printAttrValue(fout, indent, attr.value, attr.delim, wrappable);
857     }
858
859     private void printAttrs(Out fout, int indent,
860                             Node node, AttVal attr)
861     {
862         if (attr != null)
863         {
864             if (attr.next != null)
865                 printAttrs(fout, indent, node, attr.next);
866
867             if (attr.attribute != null)
868                 printAttribute(fout, indent, node, attr);
869             else if (attr.asp != null)
870             {
871                 addC(' ', linelen++);
872                 printAsp(fout, indent, attr.asp);
873             }
874             else if (attr.php != null)
875             {
876                 addC(' ', linelen++);
877                 printPhp(fout, indent, attr.php);
878             }
879         }
880
881         /* add xml:space attribute to pre and other elements */
882         if (configuration.XmlOut &&
883                 configuration.XmlSpace &&
884                 ParserImpl.XMLPreserveWhiteSpace(node, configuration.tt) &&
885                 node.getAttrByName("xml:space") == null)
886             printString(fout, indent, " xml:space=\"preserve\"");
887     }
888
889     /*
890      Line can be wrapped immediately after inline start tag provided
891      if follows a text node ending in a space, or it parent is an
892      inline element that that rule applies to. This behaviour was
893      reverse engineered from Netscape 3.0
894     */

895     private static boolean afterSpace(Node node)
896     {
897         Node prev;
898         int c;
899
900         if (node == null || node.tag == null || !((node.tag.model & Dict.CM_INLINE) != 0))
901             return true;
902
903         prev = node.prev;
904
905         if (prev != null)
906         {
907             if (prev.type == Node.TextNode && prev.end > prev.start)
908             {
909                 c = ((int)prev.textarray[prev.end - 1]) & 0xFF; // Convert to unsigned.
910

911                 if (c == 160 || c == ' ' || c == '\n')
912                     return true;
913             }
914
915             return false;
916         }
917
918         return afterSpace(node.parent);
919     }
920
921     private void printTag(Lexer lexer, Out fout, short mode, int indent, Node node)
922     {
923         char c;
924         String JavaDoc p;
925         TagTable tt = this.configuration.tt;
926
927         addC('<', linelen++);
928
929         if (node.type == Node.EndTag)
930             addC('/', linelen++);
931
932         p = node.element;
933         for (int i = 0; i < p.length(); i++ )
934             addC((int)Lexer.foldCase(p.charAt(i),
935                                      this.configuration.UpperCaseTags,
936                                      this.configuration.XmlTags),
937                  linelen++);
938
939         printAttrs(fout, indent, node, node.attributes);
940
941         if ((this.configuration.XmlOut || lexer != null && lexer.isvoyager) &&
942                 (node.type == Node.StartEndTag || (node.tag.model & Dict.CM_EMPTY) != 0))
943         {
944             addC(' ', linelen++); /* compatibility hack */
945             addC('/', linelen++);
946         }
947
948         addC('>', linelen++);;
949
950         if (node.type != Node.StartEndTag && !((mode & PREFORMATTED) != 0))
951         {
952             if (indent + linelen >= this.configuration.wraplen)
953                 wrapLine(fout, indent);
954
955             if (indent + linelen < this.configuration.wraplen)
956             {
957                 /*
958                  wrap after start tag if is <br/> or if it's not
959                  inline or it is an empty tag followed by </a>
960                 */

961                 if (afterSpace(node))
962                 {
963                     if (!((mode & NOWRAP) != 0) &&
964                         (!((node.tag.model & Dict.CM_INLINE) != 0) ||
965                           (node.tag == tt.tagBr) ||
966                           (((node.tag.model & Dict.CM_EMPTY) != 0) &&
967                           node.next == null &&
968                           node.parent.tag == tt.tagA)))
969                     {
970                         wraphere = linelen;
971                     }
972                 }
973             }
974             else
975                 condFlushLine(fout, indent);
976         }
977     }
978
979     private void printEndTag(Out fout, short mode, int indent, Node node)
980     {
981         char c;
982         String JavaDoc p;
983
984        /*
985          Netscape ignores SGML standard by not ignoring a
986          line break before </A> or </U> etc. To avoid rendering
987          this as an underlined space, I disable line wrapping
988          before inline end tags by the #if 0 ... #endif
989        */

990 if (false) {
991         if (indent + linelen < this.configuration.wraplen && !((mode & NOWRAP) != 0))
992             wraphere = linelen;
993 }
994
995         addC('<', linelen++);
996         addC('/', linelen++);
997
998         p = node.element;
999         for (int i = 0; i < p.length(); i++ )
1000            addC((int)Lexer.foldCase(p.charAt(i),
1001                                     this.configuration.UpperCaseTags,
1002                                     this.configuration.XmlTags),
1003                 linelen++);
1004
1005        addC('>', linelen++);
1006    }
1007
1008    private void printComment(Out fout, int indent, Node node)
1009    {
1010        if (indent + linelen < this.configuration.wraplen)
1011            wraphere = linelen;
1012
1013        addC('<', linelen++);
1014        addC('!', linelen++);
1015        addC('-', linelen++);
1016        addC('-', linelen++);
1017if (false) {
1018        if (linelen < this.configuration.wraplen)
1019            wraphere = linelen;
1020}
1021        printText(fout, COMMENT, indent,
1022                        node.textarray, node.start, node.end);
1023if (false) {
1024        if (indent + linelen < this.configuration.wraplen)
1025            wraphere = linelen;
1026}
1027        // See Lexer.java: AQ 8Jul2000
1028
addC('-', linelen++);
1029        addC('-', linelen++);
1030        addC('>', linelen++);
1031
1032        if (node.linebreak)
1033            flushLine(fout, indent);
1034    }
1035
1036    private void printDocType(Out fout, int indent, Node node)
1037    {
1038        boolean q = this.configuration.QuoteMarks;
1039
1040        this.configuration.QuoteMarks = false;
1041
1042        if (indent + linelen < this.configuration.wraplen)
1043            wraphere = linelen;
1044
1045        condFlushLine(fout, indent);
1046
1047        addC('<', linelen++);
1048        addC('!', linelen++);
1049        addC('D', linelen++);
1050        addC('O', linelen++);
1051        addC('C', linelen++);
1052        addC('T', linelen++);
1053        addC('Y', linelen++);
1054        addC('P', linelen++);
1055        addC('E', linelen++);
1056        addC(' ', linelen++);
1057
1058        if (indent + linelen < this.configuration.wraplen)
1059            wraphere = linelen;
1060
1061        printText(fout, (short)0, indent,
1062                        node.textarray, node.start, node.end);
1063
1064        if (linelen < this.configuration.wraplen)
1065            wraphere = linelen;
1066
1067        addC('>', linelen++);
1068        this.configuration.QuoteMarks = q;
1069        condFlushLine(fout, indent);
1070    }
1071
1072    private void printPI(Out fout, int indent, Node node)
1073    {
1074        if (indent + linelen < this.configuration.wraplen)
1075            wraphere = linelen;
1076
1077        addC('<', linelen++);
1078        addC('?', linelen++);
1079
1080        /* set CDATA to pass < and > unescaped */
1081        printText(fout, CDATA, indent,
1082                    node.textarray, node.start, node.end);
1083
1084        if (node.textarray[node.end - 1] != (byte)'?')
1085            addC('?', linelen++);
1086
1087        addC('>', linelen++);
1088        condFlushLine(fout, indent);
1089    }
1090
1091    /* note ASP and JSTE share <% ... %> syntax */
1092    private void printAsp(Out fout, int indent, Node node)
1093    {
1094        int savewraplen = this.configuration.wraplen;
1095
1096        /* disable wrapping if so requested */
1097
1098        if (!this.configuration.WrapAsp || !this.configuration.WrapJste)
1099            this.configuration.wraplen = 0xFFFFFF; /* a very large number */
1100if (false) { //#if 0
1101
if (indent + linelen < this.configuration.wraplen)
1102            wraphere = linelen;
1103} //#endif
1104

1105        addC('<', linelen++);
1106        addC('%', linelen++);
1107
1108        printText(fout, (this.configuration.WrapAsp ? CDATA : COMMENT), indent,
1109                    node.textarray, node.start, node.end);
1110
1111        addC('%', linelen++);
1112        addC('>', linelen++);
1113        /* condFlushLine(fout, indent); */
1114        this.configuration.wraplen = savewraplen;
1115    }
1116
1117    /* JSTE also supports <# ... #> syntax */
1118    private void printJste(Out fout, int indent, Node node)
1119    {
1120        int savewraplen = this.configuration.wraplen;
1121
1122        /* disable wrapping if so requested */
1123
1124        if (!this.configuration.WrapJste)
1125            this.configuration.wraplen = 0xFFFFFF; /* a very large number */
1126
1127        addC('<', linelen++);
1128        addC('#', linelen++);
1129
1130        printText(fout, (this.configuration.WrapJste ? CDATA : COMMENT), indent,
1131                    node.textarray, node.start, node.end);
1132
1133        addC('#', linelen++);
1134        addC('>', linelen++);
1135        /* condFlushLine(fout, indent); */
1136        this.configuration.wraplen = savewraplen;
1137    }
1138
1139    /* PHP is based on XML processing instructions */
1140    private void printPhp(Out fout, int indent, Node node)
1141    {
1142        int savewraplen = this.configuration.wraplen;
1143
1144        /* disable wrapping if so requested */
1145
1146        if (!this.configuration.WrapPhp)
1147            this.configuration.wraplen = 0xFFFFFF; /* a very large number */
1148
1149if (false) { //#if 0
1150
if (indent + linelen < this.configuration.wraplen)
1151            wraphere = linelen;
1152} //#endif
1153
addC('<', linelen++);
1154        addC('?', linelen++);
1155
1156        printText(fout, (this.configuration.WrapPhp ? CDATA : COMMENT), indent,
1157                        node.textarray, node.start, node.end);
1158
1159        addC('?', linelen++);
1160        addC('>', linelen++);
1161        /* PCondFlushLine(fout, indent); */
1162        this.configuration.wraplen = savewraplen;
1163    }
1164
1165    private void printCDATA(Out fout, int indent, Node node)
1166    {
1167        int savewraplen = this.configuration.wraplen;
1168
1169        condFlushLine(fout, indent);
1170
1171        /* disable wrapping */
1172
1173        this.configuration.wraplen = 0xFFFFFF; /* a very large number */
1174
1175        addC('<', linelen++);
1176        addC('!', linelen++);
1177        addC('[', linelen++);
1178        addC('C', linelen++);
1179        addC('D', linelen++);
1180        addC('A', linelen++);
1181        addC('T', linelen++);
1182        addC('A', linelen++);
1183        addC('[', linelen++);
1184
1185        printText(fout, COMMENT, indent,
1186                        node.textarray, node.start, node.end);
1187
1188        addC(']', linelen++);
1189        addC(']', linelen++);
1190        addC('>', linelen++);
1191        condFlushLine(fout, indent);
1192        this.configuration.wraplen = savewraplen;
1193    }
1194
1195    private void printSection(Out fout, int indent, Node node)
1196    {
1197        int savewraplen = this.configuration.wraplen;
1198
1199        /* disable wrapping if so requested */
1200
1201        if (!this.configuration.WrapSection)
1202            this.configuration.wraplen = 0xFFFFFF; /* a very large number */
1203
1204if (false) { //#if 0
1205
if (indent + linelen < this.configuration.wraplen)
1206            wraphere = linelen;
1207} //#endif
1208
addC('<', linelen++);
1209        addC('!', linelen++);
1210        addC('[', linelen++);
1211
1212        printText(fout, (this.configuration.WrapSection ? CDATA : COMMENT), indent,
1213                        node.textarray, node.start, node.end);
1214
1215        addC(']', linelen++);
1216        addC('>', linelen++);
1217        /* PCondFlushLine(fout, indent); */
1218        this.configuration.wraplen = savewraplen;
1219    }
1220
1221    private boolean shouldIndent(Node node)
1222    {
1223        TagTable tt = this.configuration.tt;
1224
1225        if (!this.configuration.IndentContent)
1226            return false;
1227
1228        if (this.configuration.SmartIndent)
1229        {
1230            if (node.content != null && ((node.tag.model & Dict.CM_NO_INDENT) != 0))
1231            {
1232                for (node = node.content; node != null; node = node.next)
1233                    if (node.tag != null && (node.tag.model & Dict.CM_BLOCK) != 0)
1234                        return true;
1235
1236                return false;
1237            }
1238
1239            if ((node.tag.model & Dict.CM_HEADING) != 0)
1240                return false;
1241
1242            if (node.tag == tt.tagP)
1243                return false;
1244
1245            if (node.tag == tt.tagTitle)
1246                return false;
1247        }
1248
1249        if ((node.tag.model & (Dict.CM_FIELD | Dict.CM_OBJECT)) != 0)
1250            return true;
1251
1252        if (node.tag == tt.tagMap)
1253            return true;
1254
1255        return !((node.tag.model & Dict.CM_INLINE) != 0);
1256    }
1257
1258    public void printTree(Out fout, short mode, int indent,
1259                          Lexer lexer, Node node)
1260    {
1261        Node content, last;
1262        TagTable tt = this.configuration.tt;
1263
1264        if (node == null)
1265            return;
1266
1267        if (node.type == Node.TextNode)
1268            printText(fout, mode, indent,
1269                        node.textarray, node.start, node.end);
1270        else if (node.type == Node.CommentTag)
1271        {
1272            printComment(fout, indent, node);
1273        }
1274        else if (node.type == Node.RootNode)
1275        {
1276            for (content = node.content;
1277                    content != null;
1278                    content = content.next)
1279               printTree(fout, mode, indent, lexer, content);
1280        }
1281        else if (node.type == Node.DocTypeTag)
1282            printDocType(fout, indent, node);
1283        else if (node.type == Node.ProcInsTag)
1284            printPI(fout, indent, node);
1285        else if (node.type == Node.CDATATag)
1286            printCDATA(fout, indent, node);
1287        else if (node.type == Node.SectionTag)
1288            printSection(fout, indent, node);
1289        else if (node.type == Node.AspTag)
1290            printAsp(fout, indent, node);
1291        else if (node.type == Node.JsteTag)
1292            printJste(fout, indent, node);
1293        else if (node.type == Node.PhpTag)
1294            printPhp(fout, indent, node);
1295        else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag)
1296        {
1297            if (!((node.tag.model & Dict.CM_INLINE) != 0))
1298                condFlushLine(fout, indent);
1299
1300            if (node.tag == tt.tagBr && node.prev != null &&
1301                node.prev.tag != tt.tagBr && this.configuration.BreakBeforeBR)
1302                flushLine(fout, indent);
1303
1304            if (this.configuration.MakeClean && node.tag == tt.tagWbr)
1305                printString(fout, indent, " ");
1306            else
1307                printTag(lexer, fout, mode, indent, node);
1308
1309            if (node.tag == tt.tagParam || node.tag == tt.tagArea)
1310                condFlushLine(fout, indent);
1311            else if (node.tag == tt.tagBr || node.tag == tt.tagHr)
1312                flushLine(fout, indent);
1313        }
1314        else /* some kind of container element */
1315        {
1316            if (node.tag != null && node.tag.parser == ParserImpl.getParsePre())
1317            {
1318                condFlushLine(fout, indent);
1319
1320                indent = 0;
1321                condFlushLine(fout, indent);
1322                printTag(lexer, fout, mode, indent, node);
1323                flushLine(fout, indent);
1324
1325                for (content = node.content;
1326                        content != null;
1327                        content = content.next)
1328                    printTree(fout, (short)(mode | PREFORMATTED | NOWRAP), indent, lexer, content);
1329
1330                condFlushLine(fout, indent);
1331                printEndTag(fout, mode, indent, node);
1332                flushLine(fout, indent);
1333
1334                if (this.configuration.IndentContent == false && node.next != null)
1335                    flushLine(fout, indent);
1336            }
1337            else if (node.tag == tt.tagStyle || node.tag == tt.tagScript)
1338            {
1339                condFlushLine(fout, indent);
1340
1341                indent = 0;
1342                condFlushLine(fout, indent);
1343                printTag(lexer, fout, mode, indent, node);
1344                flushLine(fout, indent);
1345
1346                for (content = node.content;
1347                        content != null;
1348                        content = content.next)
1349                    printTree(fout, (short)(mode | PREFORMATTED | NOWRAP |CDATA), indent, lexer, content);
1350
1351                condFlushLine(fout, indent);
1352                printEndTag(fout, mode, indent, node);
1353                flushLine(fout, indent);
1354
1355                if (this.configuration.IndentContent == false && node.next != null)
1356                    flushLine(fout, indent);
1357            }
1358            else if ((node.tag.model & Dict.CM_INLINE) != 0)
1359            {
1360                if (this.configuration.MakeClean)
1361                {
1362                    /* discards <font> and </font> tags */
1363                    if (node.tag == tt.tagFont)
1364                    {
1365                        for (content = node.content;
1366                                content != null;
1367                                content = content.next)
1368                            printTree(fout, mode, indent, lexer, content);
1369                        return;
1370                    }
1371
1372                    /* replace <nobr>...</nobr> by &nbsp; or &#160; etc. */
1373                    if (node.tag == tt.tagNobr)
1374                    {
1375                        for (content = node.content;
1376                                content != null;
1377                                content = content.next)
1378                            printTree(fout, (short)(mode|NOWRAP), indent, lexer, content);
1379                        return;
1380                    }
1381                }
1382
1383                /* otherwise a normal inline element */
1384
1385                printTag(lexer, fout, mode, indent, node);
1386
1387                /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */
1388
1389                if (shouldIndent(node))
1390                {
1391                    condFlushLine(fout, indent);
1392                    indent += this.configuration.spaces;
1393
1394                    for (content = node.content;
1395                            content != null;
1396                            content = content.next)
1397                        printTree(fout, mode, indent, lexer, content);
1398
1399                    condFlushLine(fout, indent);
1400                    indent -= this.configuration.spaces;
1401                    condFlushLine(fout, indent);
1402                }
1403                else
1404                {
1405
1406                    for (content = node.content;
1407                            content != null;
1408                            content = content.next)
1409                        printTree(fout, mode, indent, lexer, content);
1410                }
1411
1412                printEndTag(fout, mode, indent, node);
1413            }
1414            else /* other tags */
1415            {
1416                condFlushLine(fout, indent);
1417
1418                if (this.configuration.SmartIndent && node.prev != null)
1419                    flushLine(fout, indent);
1420
1421                if (this.configuration.HideEndTags == false ||
1422                    !(node.tag != null && ((node.tag.model & Dict.CM_OMITST) != 0)))
1423                {
1424                    printTag(lexer, fout, mode, indent, node);
1425
1426                    if (shouldIndent(node))
1427                        condFlushLine(fout, indent);
1428                    else if ((node.tag.model & Dict.CM_HTML) != 0 ||
1429                             node.tag == tt.tagNoframes ||
1430                                ((node.tag.model & Dict.CM_HEAD) != 0 &&
1431                                !(node.tag == tt.tagTitle)))
1432                        flushLine(fout, indent);
1433                }
1434
1435                if (node.tag == tt.tagBody && this.configuration.BurstSlides)
1436                    printSlide(fout, mode, (this.configuration.IndentContent ? indent+this.configuration.spaces : indent), lexer);
1437                else
1438                {
1439                    last = null;
1440
1441                    for (content = node.content;
1442                            content != null; content = content.next)
1443                    {
1444                        /* kludge for naked text before block level tag */
1445                        if (last != null && !this.configuration.IndentContent && last.type == Node.TextNode &&
1446                            content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0)
1447                        {
1448                            flushLine(fout, indent);
1449                            flushLine(fout, indent);
1450                        }
1451
1452                        printTree(fout, mode,
1453                            (shouldIndent(node) ? indent+this.configuration.spaces : indent), lexer, content);
1454
1455                        last = content;
1456                    }
1457                }
1458
1459                /* don't flush line for td and th */
1460                if (shouldIndent(node) ||
1461                    (((node.tag.model & Dict.CM_HTML) != 0 || node.tag == tt.tagNoframes ||
1462                        ((node.tag.model & Dict.CM_HEAD) != 0 && !(node.tag == tt.tagTitle)))
1463                        && this.configuration.HideEndTags == false))
1464                {
1465                    condFlushLine(fout, (this.configuration.IndentContent ? indent+this.configuration.spaces : indent));
1466
1467                    if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0))
1468                    {
1469                        printEndTag(fout, mode, indent, node);
1470                        flushLine(fout, indent);
1471                    }
1472                }
1473                else
1474                {
1475                    if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0))
1476                        printEndTag(fout, mode, indent, node);
1477
1478                    flushLine(fout, indent);
1479                }
1480
1481                if (this.configuration.IndentContent == false &&
1482                    node.next != null &&
1483                    this.configuration.HideEndTags == false &&
1484                    (node.tag.model & (Dict.CM_BLOCK|Dict.CM_LIST|Dict.CM_DEFLIST|Dict.CM_TABLE)) != 0)
1485                {
1486                    flushLine(fout, indent);
1487                }
1488            }
1489        }
1490    }
1491
1492    public void printXMLTree(Out fout, short mode, int indent,
1493                             Lexer lexer, Node node)
1494    {
1495        TagTable tt = this.configuration.tt;
1496
1497        if (node == null)
1498            return;
1499
1500        if (node.type == Node.TextNode)
1501        {
1502            printText(fout, mode, indent,
1503                        node.textarray, node.start, node.end);
1504        }
1505        else if (node.type == Node.CommentTag)
1506        {
1507            condFlushLine(fout, indent);
1508            printComment(fout, 0, node);
1509            condFlushLine(fout, 0);
1510        }
1511        else if (node.type == Node.RootNode)
1512        {
1513            Node content;
1514
1515            for (content = node.content;
1516                    content != null;
1517                    content = content.next)
1518               printXMLTree(fout, mode, indent, lexer, content);
1519        }
1520        else if (node.type == Node.DocTypeTag)
1521            printDocType(fout, indent, node);
1522        else if (node.type == Node.ProcInsTag)
1523            printPI(fout, indent, node);
1524        else if (node.type == Node.SectionTag)
1525            printSection(fout, indent, node);
1526        else if (node.type == Node.AspTag)
1527            printAsp(fout, indent, node);
1528        else if (node.type == Node.JsteTag)
1529            printJste(fout, indent, node);
1530        else if (node.type == Node.PhpTag)
1531            printPhp(fout, indent, node);
1532        else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag)
1533        {
1534            condFlushLine(fout, indent);
1535            printTag(lexer, fout, mode, indent, node);
1536            flushLine(fout, indent);
1537
1538            if (node.next != null)
1539                flushLine(fout, indent);
1540        }
1541        else /* some kind of container element */
1542        {
1543            Node content;
1544            boolean mixed = false;
1545            int cindent;
1546
1547            for (content = node.content; content != null; content = content.next)
1548            {
1549                if (content.type == Node.TextNode)
1550                {
1551                    mixed = true;
1552                    break;
1553                }
1554            }
1555
1556            condFlushLine(fout, indent);
1557
1558            if (ParserImpl.XMLPreserveWhiteSpace(node, tt))
1559            {
1560                indent = 0;
1561                cindent = 0;
1562                mixed = false;
1563            }
1564            else if (mixed)
1565                cindent = indent;
1566            else
1567                cindent = indent + this.configuration.spaces;
1568
1569            printTag(lexer, fout, mode, indent, node);
1570
1571            if (!mixed)
1572                flushLine(fout, indent);
1573 
1574            for (content = node.content;
1575                    content != null;
1576                    content = content.next)
1577                printXMLTree(fout, mode, cindent, lexer, content);
1578
1579            if (!mixed)
1580                condFlushLine(fout, cindent);
1581            printEndTag(fout, mode, indent, node);
1582            condFlushLine(fout, indent);
1583
1584            if (node.next != null)
1585                flushLine(fout, indent);
1586        }
1587    }
1588
1589
1590    /* split parse tree by h2 elements and output to separate files */
1591
1592    /* counts number of h2 children belonging to node */
1593    public int countSlides(Node node)
1594    {
1595        int n = 1;
1596        TagTable tt = this.configuration.tt;
1597
1598        for (node = node.content; node != null; node = node.next)
1599            if (node.tag == tt.tagH2)
1600                ++n;
1601
1602        return n;
1603    }
1604
1605    /*
1606       inserts a space gif called "dot.gif" to ensure
1607       that the slide is at least n pixels high
1608     */

1609    private void printVertSpacer(Out fout, int indent)
1610    {
1611        condFlushLine(fout, indent);
1612        printString(fout, indent ,
1613        "<img width=\"0\" height=\"0\" hspace=\"1\" SRC=\"dot.gif\" vspace=\"%d\" align=\"left\">");
1614        condFlushLine(fout, indent);
1615    }
1616
1617    private void printNavBar(Out fout, int indent)
1618    {
1619        String JavaDoc buf;
1620
1621        condFlushLine(fout, indent);
1622        printString(fout, indent , "<center><small>");
1623
1624        if (slide > 1)
1625        {
1626            buf = "<a HREF=\"slide" +
1627                  (new Integer JavaDoc(slide - 1)).toString() +
1628                  ".html\">previous</a> | ";
1629            printString(fout, indent , buf);
1630            condFlushLine(fout, indent);
1631
1632            if (slide < count)
1633                printString(fout, indent , "<a HREF=\"slide1.html\">start</a> | ");
1634            else
1635                printString(fout, indent , "<a HREF=\"slide1.html\">start</a>");
1636
1637            condFlushLine(fout, indent);
1638        }
1639
1640        if (slide < count)
1641        {
1642            buf = "<a HREF=\"slide" +
1643                  (new Integer JavaDoc(slide + 1)).toString() +
1644                  ".html\">next</a>";
1645            printString(fout, indent , buf);
1646        }
1647
1648        printString(fout, indent , "</small></center>");
1649        condFlushLine(fout, indent);
1650    }
1651
1652    /*
1653      Called from printTree to print the content of a slide from
1654      the node slidecontent. On return slidecontent points to the
1655      node starting the next slide or null. The variables slide
1656      and count are used to customise the navigation bar.
1657    */

1658    public void printSlide(Out fout, short mode, int indent, Lexer lexer)
1659    {
1660        Node content, last;
1661        TagTable tt = this.configuration.tt;
1662
1663        /* insert div for onclick handler */
1664        String JavaDoc s;
1665        s = "<div onclick=\"document.location='slide" +
1666            (new Integer JavaDoc(slide < count ? slide + 1 : 1)).toString() +
1667            ".html'\">";
1668        printString(fout, indent, s);
1669        condFlushLine(fout, indent);
1670
1671        /* first print the h2 element and navbar */
1672        if (slidecontent.tag == tt.tagH2)
1673        {
1674            printNavBar(fout, indent);
1675
1676            /* now print an hr after h2 */
1677
1678            addC('<', linelen++);
1679
1680
1681            addC((int)Lexer.foldCase('h',
1682                                     this.configuration.UpperCaseTags,
1683                                     this.configuration.XmlTags),
1684                 linelen++);
1685            addC((int)Lexer.foldCase('r',
1686                                     this.configuration.UpperCaseTags,
1687                                     this.configuration.XmlTags),
1688                 linelen++);
1689
1690            if (this.configuration.XmlOut == true)
1691                printString(fout, indent , " />");
1692            else
1693                addC('>', linelen++);
1694
1695
1696            if (this.configuration.IndentContent == true)
1697                condFlushLine(fout, indent);
1698
1699            /* PrintVertSpacer(fout, indent); */
1700
1701            /*condFlushLine(fout, indent); */
1702
1703            /* print the h2 element */
1704            printTree(fout, mode,
1705                (this.configuration.IndentContent ? indent+this.configuration.spaces : indent), lexer, slidecontent);
1706
1707            slidecontent = slidecontent.next;
1708        }
1709    
1710        /* now continue until we reach the next h2 */
1711
1712        last = null;
1713        content = slidecontent;
1714
1715        for (; content != null; content = content.next)
1716        {
1717            if (content.tag == tt.tagH2)
1718                break;
1719
1720            /* kludge for naked text before block level tag */
1721            if (last != null && !this.configuration.IndentContent && last.type == Node.TextNode &&
1722                content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0)
1723            {
1724                flushLine(fout, indent);
1725                flushLine(fout, indent);
1726            }
1727
1728            printTree(fout, mode,
1729                (this.configuration.IndentContent ? indent+this.configuration.spaces : indent), lexer, content);
1730
1731            last = content;
1732        }
1733
1734        slidecontent = content;
1735
1736        /* now print epilog */
1737
1738        condFlushLine(fout, indent);
1739
1740        printString(fout, indent , "<br clear=\"all\">");
1741        condFlushLine(fout, indent);
1742
1743        addC('<', linelen++);
1744
1745
1746        addC((int)Lexer.foldCase('h',
1747                                 this.configuration.UpperCaseTags,
1748                                 this.configuration.XmlTags),
1749             linelen++);
1750        addC((int)Lexer.foldCase('r',
1751                                 this.configuration.UpperCaseTags,
1752                                 this.configuration.XmlTags),
1753             linelen++);
1754
1755        if (this.configuration.XmlOut == true)
1756            printString(fout, indent , " />");
1757        else
1758            addC('>', linelen++);
1759
1760
1761        if (this.configuration.IndentContent == true)
1762            condFlushLine(fout, indent);
1763
1764        printNavBar(fout, indent);
1765
1766        /* end tag for div */
1767        printString(fout, indent, "</div>");
1768        condFlushLine(fout, indent);
1769    }
1770
1771
1772    /*
1773    Add meta element for page transition effect, this works on IE but not NS
1774    */

1775
1776    public void addTransitionEffect(Lexer lexer, Node root, short effect, double duration)
1777    {
1778        Node head = root.findHEAD(lexer.configuration.tt);
1779        String JavaDoc transition;
1780
1781        if (0 <= effect && effect <= 23)
1782            transition = "revealTrans(Duration=" +
1783                         (new Double JavaDoc(duration)).toString() +
1784                         ",Transition=" + effect + ")";
1785        else
1786            transition = "blendTrans(Duration=" +
1787                         (new Double JavaDoc(duration)).toString() + ")";
1788
1789        if (head != null)
1790        {
1791            Node meta = lexer.inferredTag("meta");
1792            meta.addAttribute("http-equiv", "Page-Enter");
1793            meta.addAttribute("content", transition);
1794            Node.insertNodeAtStart(head, meta);
1795        }
1796    }
1797
1798    public void createSlides(Lexer lexer, Node root)
1799    {
1800        Node body;
1801        String JavaDoc buf;
1802        Out out = new OutImpl();
1803
1804        body = root.findBody(lexer.configuration.tt);
1805        count = countSlides(body);
1806        slidecontent = body.content;
1807        addTransitionEffect(lexer, root, EFFECT_BLEND, 3.0);
1808
1809        for (slide = 1; slide <= count; ++slide)
1810        {
1811            buf = "slide" + slide + ".html";
1812            out.state = StreamIn.FSM_ASCII;
1813            out.encoding = this.configuration.CharEncoding;
1814
1815            try
1816            {
1817                out.out = new FileOutputStream JavaDoc(buf);
1818                printTree(out, (short)0, 0, lexer, root);
1819                flushLine(out, 0);
1820                out.out.close();
1821            }
1822            catch (IOException JavaDoc e)
1823            {
1824                System.err.println(buf + e.toString() );
1825            }
1826        }
1827
1828        /*
1829         delete superfluous slides by deleting slideN.html
1830         for N = count+1, count+2, etc. until no such file
1831         is found.
1832        */

1833
1834        for (;;)
1835        {
1836            buf = "slide" + slide + "html";
1837
1838            if (!(new File JavaDoc(buf)).delete())
1839                break;
1840
1841            ++slide;
1842        }
1843    }
1844
1845}
1846
Popular Tags