blob: bc6bcf051102476543c1d047c981b0524b07f359 [file] [log] [blame]
#
# tohtml.py
#
# A sub-class container of the `Formatter' class to produce HTML.
#
# Copyright 2002-2015 by
# David Turner.
#
# This file is part of the FreeType project, and may only be used,
# modified, and distributed under the terms of the FreeType project
# license, LICENSE.TXT. By continuing to use, modify, or distribute
# this file you indicate that you have read the license and
# understand and accept it fully.
# The parent class is contained in file `formatter.py'.
from sources import *
from content import *
from formatter import *
import time
# The following strings define the HTML header used by all generated pages.
html_header_1 = """\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>\
"""
html_header_2 = """\
API Reference</title>
<style type="text/css">
a:link { color: #0000EF; }
a:visited { color: #51188E; }
a:hover { color: #FF0000; }
body { font-family: Verdana, Geneva, Arial, Helvetica, serif;
color: #000000;
background: #FFFFFF;
width: 87%;
margin: auto; }
div.section { width: 75%;
margin: auto; }
div.section hr { margin: 4ex 0 1ex 0; }
div.section h4 { background-color: #EEEEFF;
font-size: medium;
font-style: oblique;
font-weight: bold;
margin: 3ex 0 1.5ex 9%;
padding: 0.3ex 0 0.3ex 1%; }
div.section p { margin: 1.5ex 0 1.5ex 10%; }
div.section pre { margin: 3ex 0 3ex 9%;
background-color: #D6E8FF;
padding: 2ex 0 2ex 1%; }
div.section table.fields { width: 90%;
margin: 1.5ex 0 1.5ex 10%; }
div.section table.toc { width: 95%;
margin: 1.5ex 0 1.5ex 5%; }
div.timestamp { text-align: center;
font-size: 69%;
margin: 1.5ex 0 1.5ex 0; }
h1 { text-align: center; }
h3 { font-size: medium;
margin: 4ex 0 1.5ex 0; }
p { text-align: justify; }
pre.colored { color: blue; }
span.keyword { font-family: monospace;
text-align: left;
white-space: pre;
color: darkblue; }
table.fields td.val { font-weight: bold;
text-align: right;
width: 30%;
vertical-align: baseline;
padding: 1ex 1em 1ex 0; }
table.fields td.desc { vertical-align: baseline;
padding: 1ex 0 1ex 1em; }
table.fields td.desc p:first-child { margin: 0; }
table.fields td.desc p { margin: 1.5ex 0 0 0; }
table.index { margin: 6ex auto 6ex auto;
border: 0;
border-collapse: separate;
border-spacing: 1em 0.3ex; }
table.index tr { padding: 0; }
table.index td { padding: 0; }
table.index-toc-link { width: 100%;
border: 0;
border-spacing: 0;
margin: 1ex 0 1ex 0; }
table.index-toc-link td.left { padding: 0 0.5em 0 0.5em;
font-size: 83%;
text-align: left; }
table.index-toc-link td.middle { padding: 0 0.5em 0 0.5em;
font-size: 83%;
text-align: center; }
table.index-toc-link td.right { padding: 0 0.5em 0 0.5em;
font-size: 83%;
text-align: right; }
table.synopsis { margin: 6ex auto 6ex auto;
border: 0;
border-collapse: separate;
border-spacing: 2em 0.6ex; }
table.synopsis tr { padding: 0; }
table.synopsis td { padding: 0; }
table.toc td.link { width: 30%;
text-align: right;
vertical-align: baseline;
padding: 1ex 1em 1ex 0; }
table.toc td.desc { vertical-align: baseline;
padding: 1ex 0 1ex 1em;
text-align: left; }
table.toc td.desc p:first-child { margin: 0;
text-align: left; }
table.toc td.desc p { margin: 1.5ex 0 0 0;
text-align: left; }
</style>
</head>
<body>
"""
html_header_3l = """
<table class="index-toc-link"><tr><td class="left">[<a href="\
"""
html_header_3r = """
<table class="index-toc-link"><tr><td class="right">[<a href="\
"""
html_header_4 = """\
">Index</a>]</td><td class="right">[<a href="\
"""
html_header_5t = """\
">TOC</a>]</td></tr></table>
<h1>\
"""
html_header_5i = """\
">Index</a>]</td></tr></table>
<h1>\
"""
html_header_6 = """\
API Reference</h1>
"""
# The HTML footer used by all generated pages.
html_footer = """\
</body>
</html>\
"""
# The header and footer used for each section.
section_title_header = "<h1>"
section_title_footer = "</h1>"
# The header and footer used for code segments.
code_header = '<pre class="colored">'
code_footer = '</pre>'
# Paragraph header and footer.
para_header = "<p>"
para_footer = "</p>"
# Block header and footer.
block_header = '<div class="section">'
block_footer_start = """\
<hr>
<table class="index-toc-link"><tr><td class="left">[<a href="\
"""
block_footer_middle = """\
">Index</a>]</td>\
<td class="middle">[<a href="#">Top</a>]</td>\
<td class="right">[<a href="\
"""
block_footer_end = """\
">TOC</a>]</td></tr></table></div>
"""
# Description header/footer.
description_header = ""
description_footer = ""
# Marker header/inter/footer combination.
marker_header = "<h4>"
marker_inter = "</h4>"
marker_footer = ""
# Header location header/footer.
header_location_header = "<p>"
header_location_footer = "</p>"
# Source code extracts header/footer.
source_header = "<pre>"
source_footer = "</pre>"
# Chapter header/inter/footer.
chapter_header = """\
<div class="section">
<h2>\
"""
chapter_inter = '</h2>'
chapter_footer = '</div>'
# Index footer.
index_footer_start = """\
<hr>
<table class="index-toc-link"><tr><td class="right">[<a href="\
"""
index_footer_end = """\
">TOC</a>]</td></tr></table>
"""
# TOC footer.
toc_footer_start = """\
<hr>
<table class="index-toc-link"><tr><td class="left">[<a href="\
"""
toc_footer_end = """\
">Index</a>]</td></tr></table>
"""
# Source language keyword coloration and styling.
keyword_prefix = '<span class="keyword">'
keyword_suffix = '</span>'
section_synopsis_header = '<h2>Synopsis</h2>'
section_synopsis_footer = ''
# Translate a single line of source to HTML. This converts `<', `>', and
# `&' into `&lt;',`&gt;', and `&amp;'.
#
def html_quote( line ):
result = string.replace( line, "&", "&amp;" )
result = string.replace( result, "<", "&lt;" )
result = string.replace( result, ">", "&gt;" )
return result
################################################################
##
## HTML FORMATTER CLASS
##
class HtmlFormatter( Formatter ):
def __init__( self, processor, project_title, file_prefix ):
Formatter.__init__( self, processor )
global html_header_1
global html_header_2
global html_header_3l, html_header_3r
global html_header_4
global html_header_5t, html_header_5i
global html_header_6
global html_footer
if file_prefix:
file_prefix = file_prefix + "-"
else:
file_prefix = ""
self.headers = processor.headers
self.project_title = project_title
self.file_prefix = file_prefix
self.html_header = (
html_header_1 + project_title
+ html_header_2
+ html_header_3l + file_prefix + "index.html"
+ html_header_4 + file_prefix + "toc.html"
+ html_header_5t + project_title
+ html_header_6 )
self.html_index_header = (
html_header_1 + project_title
+ html_header_2
+ html_header_3r + file_prefix + "toc.html"
+ html_header_5t + project_title
+ html_header_6 )
self.html_toc_header = (
html_header_1 + project_title
+ html_header_2
+ html_header_3l + file_prefix + "index.html"
+ html_header_5i + project_title
+ html_header_6 )
self.html_footer = (
'<div class="timestamp">generated on '
+ time.asctime( time.localtime( time.time() ) )
+ "</div>" + html_footer )
self.columns = 3
def make_section_url( self, section ):
return self.file_prefix + section.name + ".html"
def make_block_url( self, block, name = None ):
if name == None:
name = block.name
return self.make_section_url( block.section ) + "#" + name
def make_html_word( self, word ):
"""Analyze a simple word to detect cross-references and markup."""
# handle cross-references
m = re_crossref.match( word )
if m:
try:
name = m.group( 1 )
rest = m.group( 2 )
block = self.identifiers[name]
url = self.make_block_url( block )
return '<a href="' + url + '">' + name + '</a>' + rest
except:
# we detected a cross-reference to an unknown item
sys.stderr.write( "WARNING: undefined cross reference"
+ " '" + name + "'.\n" )
return '?' + name + '?' + rest
# handle markup for italic and bold
m = re_italic.match( word )
if m:
name = m.group( 1 )
rest = m.group( 2 )
return '<i>' + name + '</i>' + rest
m = re_bold.match( word )
if m:
name = m.group( 1 )
rest = m.group( 2 )
return '<b>' + name + '</b>' + rest
return html_quote( word )
def make_html_para( self, words ):
"""Convert words of a paragraph into tagged HTML text. Also handle
cross references."""
line = ""
if words:
line = self.make_html_word( words[0] )
for word in words[1:]:
line = line + " " + self.make_html_word( word )
# handle hyperlinks
line = re_url.sub( r'<a href="\1">\1</a>', line )
# convert `...' quotations into real left and right single quotes
line = re.sub( r"(^|\W)`(.*?)'(\W|$)",
r'\1&lsquo;\2&rsquo;\3',
line )
# convert tilde into non-breakable space
line = string.replace( line, "~", "&nbsp;" )
return para_header + line + para_footer
def make_html_code( self, lines ):
"""Convert a code sequence to HTML."""
line = code_header + '\n'
for l in lines:
line = line + html_quote( l ) + '\n'
return line + code_footer
def make_html_items( self, items ):
"""Convert a field's content into HTML."""
lines = []
for item in items:
if item.lines:
lines.append( self.make_html_code( item.lines ) )
else:
lines.append( self.make_html_para( item.words ) )
return string.join( lines, '\n' )
def print_html_items( self, items ):
print self.make_html_items( items )
def print_html_field( self, field ):
if field.name:
print( '<table><tr valign="top"><td><b>'
+ field.name
+ "</b></td><td>" )
print self.make_html_items( field.items )
if field.name:
print "</td></tr></table>"
def html_source_quote( self, line, block_name = None ):
result = ""
while line:
m = re_source_crossref.match( line )
if m:
name = m.group( 2 )
prefix = html_quote( m.group( 1 ) )
length = len( m.group( 0 ) )
if name == block_name:
# this is the current block name, if any
result = result + prefix + '<b>' + name + '</b>'
elif re_source_keywords.match( name ):
# this is a C keyword
result = ( result + prefix
+ keyword_prefix + name + keyword_suffix )
elif name in self.identifiers:
# this is a known identifier
block = self.identifiers[name]
id = block.name
# link to a field ID if possible
for markup in block.markups:
if markup.tag == 'values':
for field in markup.fields:
if field.name:
id = name
result = ( result + prefix
+ '<a href="'
+ self.make_block_url( block, id )
+ '">' + name + '</a>' )
else:
result = result + html_quote( line[:length] )
line = line[length:]
else:
result = result + html_quote( line )
line = []
return result
def print_html_field_list( self, fields ):
print '<table class="fields">'
for field in fields:
print ( '<tr><td class="val" id="' + field.name + '">'
+ field.name
+ '</td><td class="desc">' )
self.print_html_items( field.items )
print "</td></tr>"
print "</table>"
def print_html_markup( self, markup ):
table_fields = []
for field in markup.fields:
if field.name:
# We begin a new series of field or value definitions. We
# record them in the `table_fields' list before outputting
# all of them as a single table.
table_fields.append( field )
else:
if table_fields:
self.print_html_field_list( table_fields )
table_fields = []
self.print_html_items( field.items )
if table_fields:
self.print_html_field_list( table_fields )
#
# formatting the index
#
def index_enter( self ):
print self.html_index_header
self.index_items = {}
def index_name_enter( self, name ):
block = self.identifiers[name]
url = self.make_block_url( block )
self.index_items[name] = url
def index_exit( self ):
# `block_index' already contains the sorted list of index names
count = len( self.block_index )
rows = ( count + self.columns - 1 ) // self.columns
print '<table class="index">'
for r in range( rows ):
line = "<tr>"
for c in range( self.columns ):
i = r + c * rows
if i < count:
bname = self.block_index[r + c * rows]
url = self.index_items[bname]
line = ( line + '<td><a href="' + url + '">'
+ bname + '</a></td>' )
else:
line = line + '<td></td>'
line = line + "</tr>"
print line
print "</table>"
print( index_footer_start
+ self.file_prefix + "toc.html"
+ index_footer_end )
print self.html_footer
self.index_items = {}
def index_dump( self, index_filename = None ):
if index_filename == None:
index_filename = self.file_prefix + "index.html"
Formatter.index_dump( self, index_filename )
#
# formatting the table of contents
#
def toc_enter( self ):
print self.html_toc_header
print "<h1>Table of Contents</h1>"
def toc_chapter_enter( self, chapter ):
print chapter_header + string.join( chapter.title ) + chapter_inter
print '<table class="toc">'
def toc_section_enter( self, section ):
print ( '<tr><td class="link">'
+ '<a href="' + self.make_section_url( section ) + '">'
+ section.title + '</a></td><td class="desc">' )
print self.make_html_para( section.abstract )
def toc_section_exit( self, section ):
print "</td></tr>"
def toc_chapter_exit( self, chapter ):
print "</table>"
print chapter_footer
def toc_index( self, index_filename ):
print( chapter_header
+ '<a href="' + index_filename + '">Global Index</a>'
+ chapter_inter + chapter_footer )
def toc_exit( self ):
print( toc_footer_start
+ self.file_prefix + "index.html"
+ toc_footer_end )
print self.html_footer
def toc_dump( self, toc_filename = None, index_filename = None ):
if toc_filename == None:
toc_filename = self.file_prefix + "toc.html"
if index_filename == None:
index_filename = self.file_prefix + "index.html"
Formatter.toc_dump( self, toc_filename, index_filename )
#
# formatting sections
#
def section_enter( self, section ):
print self.html_header
print section_title_header + section.title + section_title_footer
maxwidth = 0
for b in section.blocks.values():
if len( b.name ) > maxwidth:
maxwidth = len( b.name )
width = 70 # XXX magic number
if maxwidth > 0:
# print section synopsis
print section_synopsis_header
print '<table class="synopsis">'
columns = width // maxwidth
if columns < 1:
columns = 1
count = len( section.block_names )
# don't handle last entry if it is empty
if section.block_names[-1] == "/empty/":
count -= 1
rows = ( count + columns - 1 ) // columns
for r in range( rows ):
line = "<tr>"
for c in range( columns ):
i = r + c * rows
line = line + '<td>'
if i < count:
name = section.block_names[i]
if name == "/empty/":
# it can happen that a complete row is empty, and
# without a proper `filler' the browser might
# collapse the row to a much smaller height (or
# even omit it completely)
line = line + "&nbsp;"
else:
line = ( line + '<a href="#' + name + '">'
+ name + '</a>' )
line = line + '</td>'
line = line + "</tr>"
print line
print "</table>"
print section_synopsis_footer
print description_header
print self.make_html_items( section.description )
print description_footer
def block_enter( self, block ):
print block_header
# place html anchor if needed
if block.name:
print( '<h3 id="' + block.name + '">' + block.name + '</h3>' )
# dump the block C source lines now
if block.code:
header = ''
for f in self.headers.keys():
if block.source.filename.find( f ) >= 0:
header = self.headers[f] + ' (' + f + ')'
break
# if not header:
# sys.stderr.write(
# "WARNING: No header macro for"
# + " '" + block.source.filename + "'.\n" )
if header:
print ( header_location_header
+ 'Defined in ' + header + '.'
+ header_location_footer )
print source_header
for l in block.code:
print self.html_source_quote( l, block.name )
print source_footer
def markup_enter( self, markup, block ):
if markup.tag == "description":
print description_header
else:
print marker_header + markup.tag + marker_inter
self.print_html_markup( markup )
def markup_exit( self, markup, block ):
if markup.tag == "description":
print description_footer
else:
print marker_footer
def block_exit( self, block ):
print( block_footer_start + self.file_prefix + "index.html"
+ block_footer_middle + self.file_prefix + "toc.html"
+ block_footer_end )
def section_exit( self, section ):
print html_footer
def section_dump_all( self ):
for section in self.sections:
self.section_dump( section,
self.file_prefix + section.name + '.html' )
# eof