tizen 2.3.1 release
[framework/graphics/freetype.git] / src / tools / docmaker / tohtml.py
1 #
2 #  tohtml.py
3 #
4 #    A sub-class container of the `Formatter' class to produce HTML.
5 #
6 #  Copyright 2002, 2003, 2005-2008, 2013, 2014 by
7 #  David Turner.
8 #
9 #  This file is part of the FreeType project, and may only be used,
10 #  modified, and distributed under the terms of the FreeType project
11 #  license, LICENSE.TXT.  By continuing to use, modify, or distribute
12 #  this file you indicate that you have read the license and
13 #  understand and accept it fully.
14
15 # The parent class is contained in file `formatter.py'.
16
17
18 from sources import *
19 from content import *
20 from formatter import *
21
22 import time
23
24
25 # The following strings define the HTML header used by all generated pages.
26 html_header_1 = """\
27 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
28 "http://www.w3.org/TR/html4/loose.dtd">
29 <html>
30 <head>
31 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
32 <title>\
33 """
34
35 html_header_2 = """\
36  API Reference</title>
37 <style type="text/css">
38   a:link { color: #0000EF; }
39   a:visited { color: #51188E; }
40   a:hover { color: #FF0000; }
41
42   body { font-family: Verdana, Geneva, Arial, Helvetica, serif;
43          color: #000000;
44          background: #FFFFFF;
45          width: 87%;
46          margin: auto; }
47
48   div.section { width: 75%;
49                 margin: auto; }
50   div.section hr { margin: 4ex 0 1ex 0; }
51   div.section h4 { background-color: #EEEEFF;
52                    font-size: medium;
53                    font-style: oblique;
54                    font-weight: bold;
55                    margin: 3ex 0 1.5ex 9%;
56                    padding: 0.3ex 0 0.3ex 1%; }
57   div.section p { margin: 1.5ex 0 1.5ex 10%; }
58   div.section pre { margin: 3ex 0 3ex 9%;
59                     background-color: #D6E8FF;
60                     padding: 2ex 0 2ex 1%; }
61   div.section table.fields { width: 90%;
62                              margin: 1.5ex 0 1.5ex 10%; }
63   div.section table.toc { width: 95%;
64                           margin: 1.5ex 0 1.5ex 5%; }
65   div.timestamp { text-align: center;
66                   font-size: 69%;
67                   margin: 1.5ex 0 1.5ex 0; }
68
69   h1 { text-align: center; }
70   h3 { font-size: medium;
71        margin: 4ex 0 1.5ex 0; }
72
73   p { text-align: justify; }
74
75   pre.colored { color: blue; }
76
77   span.keyword { font-family: monospace;
78                  text-align: left;
79                  white-space: pre;
80                  color: darkblue; }
81
82   table.fields td.val { font-weight: bold;
83                         text-align: right;
84                         width: 30%;
85                         vertical-align: baseline;
86                         padding: 1ex 1em 1ex 0; }
87   table.fields td.desc { vertical-align: baseline;
88                          padding: 1ex 0 1ex 1em; }
89   table.fields td.desc p:first-child { margin: 0; }
90   table.fields td.desc p { margin: 1.5ex 0 0 0; }
91   table.index { margin: 6ex auto 6ex auto;
92                 border: 0;
93                 border-collapse: separate;
94                 border-spacing: 1em 0.3ex; }
95   table.index tr { padding: 0; }
96   table.index td { padding: 0; }
97   table.index-toc-link { width: 100%;
98                          border: 0;
99                          border-spacing: 0;
100                          margin: 1ex 0 1ex 0; }
101   table.index-toc-link td.left { padding: 0 0.5em 0 0.5em;
102                                  font-size: 83%;
103                                  text-align: left; }
104   table.index-toc-link td.middle { padding: 0 0.5em 0 0.5em;
105                                    font-size: 83%;
106                                    text-align: center; }
107   table.index-toc-link td.right { padding: 0 0.5em 0 0.5em;
108                                   font-size: 83%;
109                                   text-align: right; }
110   table.synopsis { margin: 6ex auto 6ex auto;
111                    border: 0;
112                    border-collapse: separate;
113                    border-spacing: 2em 0.6ex; }
114   table.synopsis tr { padding: 0; }
115   table.synopsis td { padding: 0; }
116   table.toc td.link { width: 30%;
117                       text-align: right;
118                       vertical-align: baseline;
119                       padding: 1ex 1em 1ex 0; }
120   table.toc td.desc { vertical-align: baseline;
121                       padding: 1ex 0 1ex 1em;
122                       text-align: left; }
123   table.toc td.desc p:first-child { margin: 0;
124                                     text-align: left; }
125   table.toc td.desc p { margin: 1.5ex 0 0 0;
126                         text-align: left; }
127
128 </style>
129 </head>
130 <body>
131 """
132
133 html_header_3l = """
134 <table class="index-toc-link"><tr><td class="left">[<a href="\
135 """
136
137 html_header_3r = """
138 <table class="index-toc-link"><tr><td class="right">[<a href="\
139 """
140
141 html_header_4 = """\
142 ">Index</a>]</td><td class="right">[<a href="\
143 """
144
145 html_header_5t = """\
146 ">TOC</a>]</td></tr></table>
147 <h1>\
148 """
149
150 html_header_5i = """\
151 ">Index</a>]</td></tr></table>
152 <h1>\
153 """
154
155 html_header_6 = """\
156  API Reference</h1>
157 """
158
159
160 # The HTML footer used by all generated pages.
161 html_footer = """\
162 </body>
163 </html>\
164 """
165
166 # The header and footer used for each section.
167 section_title_header = "<h1>"
168 section_title_footer = "</h1>"
169
170 # The header and footer used for code segments.
171 code_header = '<pre class="colored">'
172 code_footer = '</pre>'
173
174 # Paragraph header and footer.
175 para_header = "<p>"
176 para_footer = "</p>"
177
178 # Block header and footer.
179 block_header        = '<div class="section">'
180 block_footer_start  = """\
181 <hr>
182 <table class="index-toc-link"><tr><td class="left">[<a href="\
183 """
184 block_footer_middle = """\
185 ">Index</a>]</td>\
186 <td class="middle">[<a href="#">Top</a>]</td>\
187 <td class="right">[<a href="\
188 """
189 block_footer_end    = """\
190 ">TOC</a>]</td></tr></table></div>
191 """
192
193 # Description header/footer.
194 description_header = ""
195 description_footer = ""
196
197 # Marker header/inter/footer combination.
198 marker_header = "<h4>"
199 marker_inter  = "</h4>"
200 marker_footer = ""
201
202 # Header location header/footer.
203 header_location_header = "<p>"
204 header_location_footer = "</p>"
205
206 # Source code extracts header/footer.
207 source_header = "<pre>"
208 source_footer = "</pre>"
209
210 # Chapter header/inter/footer.
211 chapter_header = """\
212 <div class="section">
213 <h2>\
214 """
215 chapter_inter  = '</h2>'
216 chapter_footer = '</div>'
217
218 # Index footer.
219 index_footer_start = """\
220 <hr>
221 <table class="index-toc-link"><tr><td class="right">[<a href="\
222 """
223 index_footer_end = """\
224 ">TOC</a>]</td></tr></table>
225 """
226
227 # TOC footer.
228 toc_footer_start = """\
229 <hr>
230 <table class="index-toc-link"><tr><td class="left">[<a href="\
231 """
232 toc_footer_end = """\
233 ">Index</a>]</td></tr></table>
234 """
235
236
237 # Source language keyword coloration and styling.
238 keyword_prefix = '<span class="keyword">'
239 keyword_suffix = '</span>'
240
241 section_synopsis_header = '<h2>Synopsis</h2>'
242 section_synopsis_footer = ''
243
244
245 # Translate a single line of source to HTML.  This converts `<', `>', and
246 # `&' into `&lt;',`&gt;', and `&amp;'.
247 #
248 def  html_quote( line ):
249     result = string.replace( line,   "&", "&amp;" )
250     result = string.replace( result, "<", "&lt;"  )
251     result = string.replace( result, ">", "&gt;"  )
252     return result
253
254
255 ################################################################
256 ##
257 ##  HTML FORMATTER CLASS
258 ##
259 class  HtmlFormatter( Formatter ):
260
261     def  __init__( self, processor, project_title, file_prefix ):
262         Formatter.__init__( self, processor )
263
264         global html_header_1
265         global html_header_2
266         global html_header_3l, html_header_3r
267         global html_header_4
268         global html_header_5t, html_header_5i
269         global html_header_6
270         global html_footer
271
272         if file_prefix:
273             file_prefix = file_prefix + "-"
274         else:
275             file_prefix = ""
276
277         self.headers       = processor.headers
278         self.project_title = project_title
279         self.file_prefix   = file_prefix
280         self.html_header   = (
281           html_header_1 + project_title
282           + html_header_2
283           + html_header_3l + file_prefix + "index.html"
284           + html_header_4 + file_prefix + "toc.html"
285           + html_header_5t + project_title
286           + html_header_6 )
287         self.html_index_header = (
288           html_header_1 + project_title
289           + html_header_2
290           + html_header_3r + file_prefix + "toc.html"
291           + html_header_5t + project_title
292           + html_header_6 )
293         self.html_toc_header = (
294           html_header_1 + project_title
295           + html_header_2
296           + html_header_3l + file_prefix + "index.html"
297           + html_header_5i + project_title
298           + html_header_6 )
299         self.html_footer = (
300           '<div class="timestamp">generated on '
301           + time.asctime( time.localtime( time.time() ) )
302           + "</div>" + html_footer )
303
304         self.columns = 3
305
306     def  make_section_url( self, section ):
307         return self.file_prefix + section.name + ".html"
308
309     def  make_block_url( self, block, name = None ):
310         if name == None:
311             name = block.name
312         return self.make_section_url( block.section ) + "#" + name
313
314     def  make_html_word( self, word ):
315         """Analyze a simple word to detect cross-references and markup."""
316         # handle cross-references
317         m = re_crossref.match( word )
318         if m:
319             try:
320                 name = m.group( 1 )
321                 rest = m.group( 2 )
322                 block = self.identifiers[name]
323                 url   = self.make_block_url( block )
324                 return '<a href="' + url + '">' + name + '</a>' + rest
325             except:
326                 # we detected a cross-reference to an unknown item
327                 sys.stderr.write( "WARNING: undefined cross reference"
328                                   + " '" + name + "'.\n" )
329                 return '?' + name + '?' + rest
330
331         # handle markup for italic and bold
332         m = re_italic.match( word )
333         if m:
334             name = m.group( 1 )
335             rest = m.group( 2 )
336             return '<i>' + name + '</i>' + rest
337
338         m = re_bold.match( word )
339         if m:
340             name = m.group( 1 )
341             rest = m.group( 2 )
342             return '<b>' + name + '</b>' + rest
343
344         return html_quote( word )
345
346     def  make_html_para( self, words ):
347         """Convert words of a paragraph into tagged HTML text.  Also handle
348            cross references."""
349         line = ""
350         if words:
351             line = self.make_html_word( words[0] )
352             for word in words[1:]:
353                 line = line + " " + self.make_html_word( word )
354             # handle hyperlinks
355             line = re_url.sub( r'<a href="\1">\1</a>', line )
356             # convert `...' quotations into real left and right single quotes
357             line = re.sub( r"(^|\W)`(.*?)'(\W|$)",
358                            r'\1&lsquo;\2&rsquo;\3',
359                            line )
360             # convert tilde into non-breakable space
361             line = string.replace( line, "~", "&nbsp;" )
362
363         return para_header + line + para_footer
364
365     def  make_html_code( self, lines ):
366         """Convert a code sequence to HTML."""
367         line = code_header + '\n'
368         for l in lines:
369             line = line + html_quote( l ) + '\n'
370
371         return line + code_footer
372
373     def  make_html_items( self, items ):
374         """Convert a field's content into HTML."""
375         lines = []
376         for item in items:
377             if item.lines:
378                 lines.append( self.make_html_code( item.lines ) )
379             else:
380                 lines.append( self.make_html_para( item.words ) )
381
382         return string.join( lines, '\n' )
383
384     def  print_html_items( self, items ):
385         print self.make_html_items( items )
386
387     def  print_html_field( self, field ):
388         if field.name:
389             print( '<table><tr valign="top"><td><b>'
390                    + field.name
391                    + "</b></td><td>" )
392
393         print self.make_html_items( field.items )
394
395         if field.name:
396             print "</td></tr></table>"
397
398     def  html_source_quote( self, line, block_name = None ):
399         result = ""
400         while line:
401             m = re_source_crossref.match( line )
402             if m:
403                 name   = m.group( 2 )
404                 prefix = html_quote( m.group( 1 ) )
405                 length = len( m.group( 0 ) )
406
407                 if name == block_name:
408                     # this is the current block name, if any
409                     result = result + prefix + '<b>' + name + '</b>'
410                 elif re_source_keywords.match( name ):
411                     # this is a C keyword
412                     result = ( result + prefix
413                                + keyword_prefix + name + keyword_suffix )
414                 elif name in self.identifiers:
415                     # this is a known identifier
416                     block = self.identifiers[name]
417                     id = block.name
418
419                     # link to a field ID if possible
420                     for markup in block.markups:
421                         if markup.tag == 'values':
422                             for field in markup.fields:
423                                 if field.name:
424                                     id = name
425
426                     result = ( result + prefix
427                                + '<a href="'
428                                + self.make_block_url( block, id )
429                                + '">' + name + '</a>' )
430                 else:
431                     result = result + html_quote( line[:length] )
432
433                 line = line[length:]
434             else:
435                 result = result + html_quote( line )
436                 line   = []
437
438         return result
439
440     def  print_html_field_list( self, fields ):
441         print '<table class="fields">'
442         for field in fields:
443             print ( '<tr><td class="val" id="' + field.name + '">'
444                     + field.name
445                     + '</td><td class="desc">' )
446             self.print_html_items( field.items )
447             print "</td></tr>"
448         print "</table>"
449
450     def  print_html_markup( self, markup ):
451         table_fields = []
452         for field in markup.fields:
453             if field.name:
454                 # We begin a new series of field or value definitions.  We
455                 # record them in the `table_fields' list before outputting
456                 # all of them as a single table.
457                 table_fields.append( field )
458             else:
459                 if table_fields:
460                     self.print_html_field_list( table_fields )
461                     table_fields = []
462
463                 self.print_html_items( field.items )
464
465         if table_fields:
466             self.print_html_field_list( table_fields )
467
468     #
469     # formatting the index
470     #
471     def  index_enter( self ):
472         print self.html_index_header
473         self.index_items = {}
474
475     def  index_name_enter( self, name ):
476         block = self.identifiers[name]
477         url   = self.make_block_url( block )
478         self.index_items[name] = url
479
480     def  index_exit( self ):
481         # `block_index' already contains the sorted list of index names
482         count = len( self.block_index )
483         rows  = ( count + self.columns - 1 ) // self.columns
484
485         print '<table class="index">'
486         for r in range( rows ):
487             line = "<tr>"
488             for c in range( self.columns ):
489                 i = r + c * rows
490                 if i < count:
491                     bname = self.block_index[r + c * rows]
492                     url   = self.index_items[bname]
493                     line  = ( line + '<td><a href="' + url + '">'
494                               + bname + '</a></td>' )
495                 else:
496                     line = line + '<td></td>'
497             line = line + "</tr>"
498             print line
499
500         print "</table>"
501
502         print( index_footer_start
503                + self.file_prefix + "toc.html"
504                + index_footer_end )
505
506         print self.html_footer
507
508         self.index_items = {}
509
510     def  index_dump( self, index_filename = None ):
511         if index_filename == None:
512             index_filename = self.file_prefix + "index.html"
513
514         Formatter.index_dump( self, index_filename )
515
516     #
517     # formatting the table of contents
518     #
519     def  toc_enter( self ):
520         print self.html_toc_header
521         print "<h1>Table of Contents</h1>"
522
523     def  toc_chapter_enter( self, chapter ):
524         print chapter_header + string.join( chapter.title ) + chapter_inter
525         print '<table class="toc">'
526
527     def  toc_section_enter( self, section ):
528         print ( '<tr><td class="link">'
529                 + '<a href="' + self.make_section_url( section ) + '">'
530                 + section.title + '</a></td><td class="desc">' )
531         print self.make_html_para( section.abstract )
532
533     def  toc_section_exit( self, section ):
534         print "</td></tr>"
535
536     def  toc_chapter_exit( self, chapter ):
537         print "</table>"
538         print chapter_footer
539
540     def  toc_index( self, index_filename ):
541         print( chapter_header
542                + '<a href="' + index_filename + '">Global Index</a>'
543                + chapter_inter + chapter_footer )
544
545     def  toc_exit( self ):
546         print( toc_footer_start
547                + self.file_prefix + "index.html"
548                + toc_footer_end )
549
550         print self.html_footer
551
552     def  toc_dump( self, toc_filename = None, index_filename = None ):
553         if toc_filename == None:
554             toc_filename = self.file_prefix + "toc.html"
555
556         if index_filename == None:
557             index_filename = self.file_prefix + "index.html"
558
559         Formatter.toc_dump( self, toc_filename, index_filename )
560
561     #
562     # formatting sections
563     #
564     def  section_enter( self, section ):
565         print self.html_header
566
567         print section_title_header + section.title + section_title_footer
568
569         maxwidth = 0
570         for b in section.blocks.values():
571             if len( b.name ) > maxwidth:
572                 maxwidth = len( b.name )
573
574         width = 70  # XXX magic number
575         if maxwidth > 0:
576             # print section synopsis
577             print section_synopsis_header
578             print '<table class="synopsis">'
579
580             columns = width // maxwidth
581             if columns < 1:
582                 columns = 1
583
584             count = len( section.block_names )
585             # don't handle last entry if it is empty
586             if section.block_names[-1] == "/empty/":
587                 count -= 1
588             rows  = ( count + columns - 1 ) // columns
589
590             for r in range( rows ):
591                 line = "<tr>"
592                 for c in range( columns ):
593                     i = r + c * rows
594                     line = line + '<td>'
595                     if i < count:
596                         name = section.block_names[i]
597                         if name == "/empty/":
598                             # it can happen that a complete row is empty, and
599                             # without a proper `filler' the browser might
600                             # collapse the row to a much smaller height (or
601                             # even omit it completely)
602                             line = line + "&nbsp;"
603                         else:
604                             line = ( line + '<a href="#' + name + '">'
605                                      + name + '</a>' )
606
607                     line = line + '</td>'
608                 line = line + "</tr>"
609                 print line
610
611             print "</table>"
612             print section_synopsis_footer
613
614         print description_header
615         print self.make_html_items( section.description )
616         print description_footer
617
618     def  block_enter( self, block ):
619         print block_header
620
621         # place html anchor if needed
622         if block.name:
623             print( '<h3 id="' + block.name + '">' + block.name + '</h3>' )
624
625         # dump the block C source lines now
626         if block.code:
627             header = ''
628             for f in self.headers.keys():
629                 if block.source.filename.find( f ) >= 0:
630                     header = self.headers[f] + ' (' + f + ')'
631                     break
632
633 #           if not header:
634 #               sys.stderr.write(
635 #                 "WARNING: No header macro for"
636 #                 + " '" + block.source.filename + "'.\n" )
637
638             if header:
639                 print ( header_location_header
640                         + 'Defined in ' + header + '.'
641                         + header_location_footer )
642
643             print source_header
644             for l in block.code:
645                 print self.html_source_quote( l, block.name )
646             print source_footer
647
648     def  markup_enter( self, markup, block ):
649         if markup.tag == "description":
650             print description_header
651         else:
652             print marker_header + markup.tag + marker_inter
653
654         self.print_html_markup( markup )
655
656     def  markup_exit( self, markup, block ):
657         if markup.tag == "description":
658             print description_footer
659         else:
660             print marker_footer
661
662     def  block_exit( self, block ):
663         print( block_footer_start + self.file_prefix + "index.html"
664                + block_footer_middle + self.file_prefix + "toc.html"
665                + block_footer_end )
666
667     def  section_exit( self, section ):
668         print html_footer
669
670     def  section_dump_all( self ):
671         for section in self.sections:
672             self.section_dump( section,
673                                self.file_prefix + section.name + '.html' )
674
675 # eof