4 # A sub-class container of the `Formatter' class to produce HTML.
6 # Copyright 2002, 2003, 2005-2008, 2013, 2014 by
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.
15 # The parent class is contained in file `formatter.py'.
20 from formatter
import *
25 # The following strings define the HTML header used by all generated pages.
27 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
28 "http://www.w3.org/TR/html4/loose.dtd">
31 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
37 <style type="text/css">
38 a:link { color: #0000EF; }
39 a:visited { color: #51188E; }
40 a:hover { color: #FF0000; }
42 body { font-family: Verdana, Geneva, Arial, Helvetica, serif;
48 div.section { width: 75%;
50 div.section hr { margin: 4ex 0 1ex 0; }
51 div.section h4 { background-color: #EEEEFF;
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;
67 margin: 1.5ex 0 1.5ex 0; }
69 h1 { text-align: center; }
70 h3 { font-size: medium;
71 margin: 4ex 0 1.5ex 0; }
73 p { text-align: justify; }
75 pre.colored { color: blue; }
77 span.keyword { font-family: monospace;
82 table.fields td.val { font-weight: bold;
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;
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%;
100 margin: 1ex 0 1ex 0; }
101 table.index-toc-link td.left { padding: 0 0.5em 0 0.5em;
104 table.index-toc-link td.middle { padding: 0 0.5em 0 0.5em;
106 text-align: center; }
107 table.index-toc-link td.right { padding: 0 0.5em 0 0.5em;
110 table.synopsis { margin: 6ex auto 6ex auto;
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%;
118 vertical-align: baseline;
119 padding: 1ex 1em 1ex 0; }
120 table.toc td.desc { vertical-align: baseline;
121 padding: 1ex 0 1ex 1em;
123 table.toc td.desc p:first-child { margin: 0;
125 table.toc td.desc p { margin: 1.5ex 0 0 0;
134 <table class="index-toc-link"><tr><td class="left">[<a href="\
138 <table class="index-toc-link"><tr><td class="right">[<a href="\
142 ">Index</a>]</td><td class="right">[<a href="\
145 html_header_5t
= """\
146 ">TOC</a>]</td></tr></table>
150 html_header_5i
= """\
151 ">Index</a>]</td></tr></table>
160 # The HTML footer used by all generated pages.
166 # The header and footer used for each section.
167 section_title_header
= "<h1>"
168 section_title_footer
= "</h1>"
170 # The header and footer used for code segments.
171 code_header
= '<pre class="colored">'
172 code_footer
= '</pre>'
174 # Paragraph header and footer.
178 # Block header and footer.
179 block_header
= '<div class="section">'
180 block_footer_start
= """\
182 <table class="index-toc-link"><tr><td class="left">[<a href="\
184 block_footer_middle
= """\
186 <td class="middle">[<a href="#">Top</a>]</td>\
187 <td class="right">[<a href="\
189 block_footer_end
= """\
190 ">TOC</a>]</td></tr></table></div>
193 # Description header/footer.
194 description_header
= ""
195 description_footer
= ""
197 # Marker header/inter/footer combination.
198 marker_header
= "<h4>"
199 marker_inter
= "</h4>"
202 # Header location header/footer.
203 header_location_header
= "<p>"
204 header_location_footer
= "</p>"
206 # Source code extracts header/footer.
207 source_header
= "<pre>"
208 source_footer
= "</pre>"
210 # Chapter header/inter/footer.
211 chapter_header
= """\
212 <div class="section">
215 chapter_inter
= '</h2>'
216 chapter_footer
= '</div>'
219 index_footer_start
= """\
221 <table class="index-toc-link"><tr><td class="right">[<a href="\
223 index_footer_end
= """\
224 ">TOC</a>]</td></tr></table>
228 toc_footer_start
= """\
230 <table class="index-toc-link"><tr><td class="left">[<a href="\
232 toc_footer_end
= """\
233 ">Index</a>]</td></tr></table>
237 # Source language keyword coloration and styling.
238 keyword_prefix
= '<span class="keyword">'
239 keyword_suffix
= '</span>'
241 section_synopsis_header
= '<h2>Synopsis</h2>'
242 section_synopsis_footer
= ''
245 # Translate a single line of source to HTML. This converts `<', `>', and
246 # `&' into `<',`>', and `&'.
248 def html_quote( line
):
249 result
= string
.replace( line
, "&", "&" )
250 result
= string
.replace( result
, "<", "<" )
251 result
= string
.replace( result
, ">", ">" )
255 ################################################################
257 ## HTML FORMATTER CLASS
259 class HtmlFormatter( Formatter
):
261 def __init__( self
, processor
, project_title
, file_prefix
):
262 Formatter
.__init
__( self
, processor
)
266 global html_header_3l
, html_header_3r
268 global html_header_5t
, html_header_5i
273 file_prefix
= file_prefix
+ "-"
277 self
.headers
= processor
.headers
278 self
.project_title
= project_title
279 self
.file_prefix
= file_prefix
281 html_header_1
+ project_title
283 + html_header_3l
+ file_prefix
+ "index.html"
284 + html_header_4
+ file_prefix
+ "toc.html"
285 + html_header_5t
+ project_title
287 self
.html_index_header
= (
288 html_header_1
+ project_title
290 + html_header_3r
+ file_prefix
+ "toc.html"
291 + html_header_5t
+ project_title
293 self
.html_toc_header
= (
294 html_header_1
+ project_title
296 + html_header_3l
+ file_prefix
+ "index.html"
297 + html_header_5i
+ project_title
300 '<div class="timestamp">generated on '
301 + time
.asctime( time
.localtime( time
.time() ) )
302 + "</div>" + html_footer
)
306 def make_section_url( self
, section
):
307 return self
.file_prefix
+ section
.name
+ ".html"
309 def make_block_url( self
, block
, name
= None ):
312 return self
.make_section_url( block
.section
) + "#" + name
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
)
322 block
= self
.identifiers
[name
]
323 url
= self
.make_block_url( block
)
324 return '<a href="' + url
+ '">' + name
+ '</a>' + rest
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
331 # handle markup for italic and bold
332 m
= re_italic
.match( word
)
336 return '<i>' + name
+ '</i>' + rest
338 m
= re_bold
.match( word
)
342 return '<b>' + name
+ '</b>' + rest
344 return html_quote( word
)
346 def make_html_para( self
, words
):
347 """Convert words of a paragraph into tagged HTML text. Also handle
351 line
= self
.make_html_word( words
[0] )
352 for word
in words
[1:]:
353 line
= line
+ " " + self
.make_html_word( word
)
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‘\2’\3',
360 # convert tilde into non-breakable space
361 line
= string
.replace( line
, "~", " " )
363 return para_header
+ line
+ para_footer
365 def make_html_code( self
, lines
):
366 """Convert a code sequence to HTML."""
367 line
= code_header
+ '\n'
369 line
= line
+ html_quote( l
) + '\n'
371 return line
+ code_footer
373 def make_html_items( self
, items
):
374 """Convert a field's content into HTML."""
378 lines
.append( self
.make_html_code( item
.lines
) )
380 lines
.append( self
.make_html_para( item
.words
) )
382 return string
.join( lines
, '\n' )
384 def print_html_items( self
, items
):
385 print self
.make_html_items( items
)
387 def print_html_field( self
, field
):
389 print( '<table><tr valign="top"><td><b>'
393 print self
.make_html_items( field
.items
)
396 print "</td></tr></table>"
398 def html_source_quote( self
, line
, block_name
= None ):
401 m
= re_source_crossref
.match( line
)
404 prefix
= html_quote( m
.group( 1 ) )
405 length
= len( m
.group( 0 ) )
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
]
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
:
426 result
= ( result
+ prefix
428 + self
.make_block_url( block
, id )
429 + '">' + name
+ '</a>' )
431 result
= result
+ html_quote( line
[:length
] )
435 result
= result
+ html_quote( line
)
440 def print_html_field_list( self
, fields
):
441 print '<table class="fields">'
443 print ( '<tr><td class="val" id="' + field
.name
+ '">'
445 + '</td><td class="desc">' )
446 self
.print_html_items( field
.items
)
450 def print_html_markup( self
, markup
):
452 for field
in markup
.fields
:
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
)
460 self
.print_html_field_list( table_fields
)
463 self
.print_html_items( field
.items
)
466 self
.print_html_field_list( table_fields
)
469 # formatting the index
471 def index_enter( self
):
472 print self
.html_index_header
473 self
.index_items
= {}
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
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
485 print '<table class="index">'
486 for r
in range( rows
):
488 for c
in range( self
.columns
):
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>' )
496 line
= line
+ '<td></td>'
497 line
= line
+ "</tr>"
502 print( index_footer_start
503 + self
.file_prefix
+ "toc.html"
506 print self
.html_footer
508 self
.index_items
= {}
510 def index_dump( self
, index_filename
= None ):
511 if index_filename
== None:
512 index_filename
= self
.file_prefix
+ "index.html"
514 Formatter
.index_dump( self
, index_filename
)
517 # formatting the table of contents
519 def toc_enter( self
):
520 print self
.html_toc_header
521 print "<h1>Table of Contents</h1>"
523 def toc_chapter_enter( self
, chapter
):
524 print chapter_header
+ string
.join( chapter
.title
) + chapter_inter
525 print '<table class="toc">'
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
)
533 def toc_section_exit( self
, section
):
536 def toc_chapter_exit( self
, chapter
):
540 def toc_index( self
, index_filename
):
541 print( chapter_header
542 + '<a href="' + index_filename
+ '">Global Index</a>'
543 + chapter_inter
+ chapter_footer
)
545 def toc_exit( self
):
546 print( toc_footer_start
547 + self
.file_prefix
+ "index.html"
550 print self
.html_footer
552 def toc_dump( self
, toc_filename
= None, index_filename
= None ):
553 if toc_filename
== None:
554 toc_filename
= self
.file_prefix
+ "toc.html"
556 if index_filename
== None:
557 index_filename
= self
.file_prefix
+ "index.html"
559 Formatter
.toc_dump( self
, toc_filename
, index_filename
)
562 # formatting sections
564 def section_enter( self
, section
):
565 print self
.html_header
567 print section_title_header
+ section
.title
+ section_title_footer
570 for b
in section
.blocks
.values():
571 if len( b
.name
) > maxwidth
:
572 maxwidth
= len( b
.name
)
574 width
= 70 # XXX magic number
576 # print section synopsis
577 print section_synopsis_header
578 print '<table class="synopsis">'
580 columns
= width
// maxwidth
584 count
= len( section
.block_names
)
585 # don't handle last entry if it is empty
586 if section
.block_names
[-1] == "/empty/":
588 rows
= ( count
+ columns
- 1 ) // columns
590 for r
in range( rows
):
592 for c
in range( columns
):
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
+ " "
604 line
= ( line
+ '<a href="#' + name
+ '">'
607 line
= line
+ '</td>'
608 line
= line
+ "</tr>"
612 print section_synopsis_footer
614 print description_header
615 print self
.make_html_items( section
.description
)
616 print description_footer
618 def block_enter( self
, block
):
621 # place html anchor if needed
623 print( '<h3 id="' + block
.name
+ '">' + block
.name
+ '</h3>' )
625 # dump the block C source lines now
628 for f
in self
.headers
.keys():
629 if block
.source
.filename
.find( f
) >= 0:
630 header
= self
.headers
[f
] + ' (' + f
+ ')'
635 # "WARNING: No header macro for"
636 # + " '" + block.source.filename + "'.\n" )
639 print ( header_location_header
640 + 'Defined in ' + header
+ '.'
641 + header_location_footer
)
645 print self
.html_source_quote( l
, block
.name
)
648 def markup_enter( self
, markup
, block
):
649 if markup
.tag
== "description":
650 print description_header
652 print marker_header
+ markup
.tag
+ marker_inter
654 self
.print_html_markup( markup
)
656 def markup_exit( self
, markup
, block
):
657 if markup
.tag
== "description":
658 print description_footer
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"
667 def section_exit( self
, section
):
670 def section_dump_all( self
):
671 for section
in self
.sections
:
672 self
.section_dump( section
,
673 self
.file_prefix
+ section
.name
+ '.html' )