t2h.pm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. # makeinfo HTML output init file
  2. #
  3. # Copyright (c) 2011, 2012 Free Software Foundation, Inc.
  4. # Copyright (c) 2014 Andreas Cadhalpun
  5. # Copyright (c) 2014 Tiancheng "Timothy" Gu
  6. #
  7. # This file is part of FFmpeg.
  8. #
  9. # FFmpeg is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 3 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # FFmpeg is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. # General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public
  20. # License along with FFmpeg; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. # Texinfo 7.0 changed the syntax of various functions.
  23. # Provide a shim for older versions.
  24. sub ff_set_from_init_file($$) {
  25. my $key = shift;
  26. my $value = shift;
  27. if (exists &{'texinfo_set_from_init_file'}) {
  28. texinfo_set_from_init_file($key, $value);
  29. } else {
  30. set_from_init_file($key, $value);
  31. }
  32. }
  33. sub ff_get_conf($) {
  34. my $key = shift;
  35. if (exists &{'texinfo_get_conf'}) {
  36. texinfo_get_conf($key);
  37. } else {
  38. get_conf($key);
  39. }
  40. }
  41. sub get_formatting_function($$) {
  42. my $obj = shift;
  43. my $func = shift;
  44. my $sub = $obj->can('formatting_function');
  45. if ($sub) {
  46. return $obj->formatting_function($func);
  47. } else {
  48. return $obj->{$func};
  49. }
  50. }
  51. # determine texinfo version
  52. my $package_version = ff_get_conf('PACKAGE_VERSION');
  53. $package_version =~ s/\+dev$//;
  54. my $program_version_num = version->declare($package_version)->numify;
  55. my $program_version_6_8 = $program_version_num >= 6.008000;
  56. # no navigation elements
  57. ff_set_from_init_file('HEADERS', 0);
  58. my %sectioning_commands = %Texinfo::Common::sectioning_commands;
  59. if (scalar(keys(%sectioning_commands)) == 0) {
  60. %sectioning_commands = %Texinfo::Commands::sectioning_heading_commands;
  61. }
  62. my %root_commands = %Texinfo::Common::root_commands;
  63. if (scalar(keys(%root_commands)) == 0) {
  64. %root_commands = %Texinfo::Commands::root_commands;
  65. }
  66. sub ffmpeg_heading_command($$$$$)
  67. {
  68. my $self = shift;
  69. my $cmdname = shift;
  70. my $command = shift;
  71. my $args = shift;
  72. my $content = shift;
  73. my $result = '';
  74. # not clear that it may really happen
  75. if ($self->in_string) {
  76. $result .= $self->command_string($command) ."\n" if ($cmdname ne 'node');
  77. $result .= $content if (defined($content));
  78. return $result;
  79. }
  80. # no need to set it as the $element_id is output unconditionally
  81. my $heading_id;
  82. my $element_id = $self->command_id($command);
  83. $result .= "<a name=\"$element_id\"></a>\n"
  84. if (defined($element_id) and $element_id ne '');
  85. print STDERR "Process $command "
  86. .Texinfo::Structuring::_print_root_command_texi($command)."\n"
  87. if ($self->get_conf('DEBUG'));
  88. my $output_unit;
  89. if ($root_commands{$command->{'cmdname'}}) {
  90. if ($command->{'associated_unit'}) {
  91. $output_unit = $command->{'associated_unit'};
  92. } elsif ($command->{'structure'}
  93. and $command->{'structure'}->{'associated_unit'}) {
  94. $output_unit = $command->{'structure'}->{'associated_unit'};
  95. } elsif ($command->{'parent'}
  96. and $command->{'parent'}->{'type'}
  97. and $command->{'parent'}->{'type'} eq 'element') {
  98. $output_unit = $command->{'parent'};
  99. }
  100. }
  101. if ($output_unit) {
  102. $result .= &{get_formatting_function($self, 'format_element_header')}($self, $cmdname,
  103. $command, $output_unit);
  104. }
  105. my $heading_level;
  106. # node is used as heading if there is nothing else.
  107. if ($cmdname eq 'node') {
  108. if (!$output_unit or
  109. (((!$output_unit->{'extra'}->{'section'}
  110. and $output_unit->{'extra'}->{'node'}
  111. and $output_unit->{'extra'}->{'node'} eq $command)
  112. or
  113. ((($output_unit->{'extra'}->{'unit_command'}
  114. and $output_unit->{'extra'}->{'unit_command'} eq $command)
  115. or
  116. ($output_unit->{'unit_command'}
  117. and $output_unit->{'unit_command'} eq $command))
  118. and $command->{'extra'}
  119. and not $command->{'extra'}->{'associated_section'}))
  120. # bogus node may not have been normalized
  121. and defined($command->{'extra'}->{'normalized'}))) {
  122. if ($command->{'extra'}->{'normalized'} eq 'Top') {
  123. $heading_level = 0;
  124. } else {
  125. $heading_level = 3;
  126. }
  127. }
  128. } else {
  129. if (defined($command->{'extra'})
  130. and defined($command->{'extra'}->{'section_level'})) {
  131. $heading_level = $command->{'extra'}->{'section_level'};
  132. } elsif ($command->{'structure'}
  133. and defined($command->{'structure'}->{'section_level'})) {
  134. $heading_level = $command->{'structure'}->{'section_level'};
  135. } else {
  136. $heading_level = $command->{'level'};
  137. }
  138. }
  139. my $heading = $self->command_text($command);
  140. # $heading not defined may happen if the command is a @node, for example
  141. # if there is an error in the node.
  142. if (defined($heading) and $heading ne '' and defined($heading_level)) {
  143. if ($root_commands{$cmdname}
  144. and $sectioning_commands{$cmdname}) {
  145. my $content_href = $self->command_contents_href($command, 'contents',
  146. $self->{'current_filename'});
  147. if ($content_href) {
  148. my $this_href = $content_href =~ s/^\#toc-/\#/r;
  149. $heading .= '<span class="pull-right">'.
  150. '<a class="anchor hidden-xs" '.
  151. "href=\"$this_href\" aria-hidden=\"true\">".
  152. ($ENV{"FA_ICONS"} ? '<i class="fa fa-link"></i>'
  153. : '#').
  154. '</a> '.
  155. '<a class="anchor hidden-xs"'.
  156. "href=\"$content_href\" aria-hidden=\"true\">".
  157. ($ENV{"FA_ICONS"} ? '<i class="fa fa-navicon"></i>'
  158. : 'TOC').
  159. '</a>'.
  160. '</span>';
  161. }
  162. }
  163. my $in_preformatted;
  164. if ($program_version_num >= 7.001090) {
  165. $in_preformatted = $self->in_preformatted_context();
  166. } else {
  167. $in_preformatted = $self->in_preformatted();
  168. }
  169. if ($in_preformatted) {
  170. $result .= $heading."\n";
  171. } else {
  172. # if the level was changed, set the command name right
  173. if ($cmdname ne 'node'
  174. and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
  175. $cmdname
  176. = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
  177. }
  178. if ($program_version_num >= 7.000000) {
  179. $result .= &{get_formatting_function($self,'format_heading_text')}($self,
  180. $cmdname, [$cmdname], $heading,
  181. $heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1,
  182. $heading_id, $command);
  183. } else {
  184. $result .= &{get_formatting_function($self,'format_heading_text')}(
  185. $self, $cmdname, $heading,
  186. $heading_level +
  187. $self->get_conf('CHAPTER_HEADER_LEVEL') - 1, $command);
  188. }
  189. }
  190. }
  191. $result .= $content if (defined($content));
  192. return $result;
  193. }
  194. foreach my $command (keys(%sectioning_commands), 'node') {
  195. texinfo_register_command_formatting($command, \&ffmpeg_heading_command);
  196. }
  197. # print the TOC where @contents is used
  198. if ($program_version_6_8) {
  199. ff_set_from_init_file('CONTENTS_OUTPUT_LOCATION', 'inline');
  200. } else {
  201. ff_set_from_init_file('INLINE_CONTENTS', 1);
  202. }
  203. # make chapters <h2>
  204. ff_set_from_init_file('CHAPTER_HEADER_LEVEL', 2);
  205. # Do not add <hr>
  206. ff_set_from_init_file('DEFAULT_RULE', '');
  207. ff_set_from_init_file('BIG_RULE', '');
  208. # Customized file beginning
  209. sub ffmpeg_begin_file($$$)
  210. {
  211. my $self = shift;
  212. my $filename = shift;
  213. my $element = shift;
  214. my ($element_command, $node_command, $command_for_title);
  215. if ($element) {
  216. if ($element->{'unit_command'}) {
  217. $element_command = $element->{'unit_command'};
  218. } elsif ($self->can('tree_unit_element_command')) {
  219. $element_command = $self->tree_unit_element_command($element);
  220. } elsif ($self->can('tree_unit_element_command')) {
  221. $element_command = $self->element_command($element);
  222. }
  223. $node_command = $element_command;
  224. if ($element_command and $element_command->{'cmdname'}
  225. and $element_command->{'cmdname'} ne 'node'
  226. and $element_command->{'extra'}
  227. and $element_command->{'extra'}->{'associated_node'}) {
  228. $node_command = $element_command->{'extra'}->{'associated_node'};
  229. }
  230. $command_for_title = $element_command if ($self->get_conf('SPLIT'));
  231. }
  232. my ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype,
  233. $root_html_element_attributes, $body_attributes, $copying_comment,
  234. $after_body_open, $extra_head, $program_and_version, $program_homepage,
  235. $program, $generator);
  236. if ($program_version_num >= 7.001090) {
  237. ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype,
  238. $root_html_element_attributes, $body_attributes, $copying_comment,
  239. $after_body_open, $extra_head, $program_and_version, $program_homepage,
  240. $program, $generator) = $self->_file_header_information($command_for_title,
  241. $filename);
  242. } elsif ($program_version_num >= 7.000000) {
  243. ($title, $description, $encoding, $date, $css_lines, $doctype,
  244. $root_html_element_attributes, $copying_comment, $after_body_open,
  245. $extra_head, $program_and_version, $program_homepage,
  246. $program, $generator) = $self->_file_header_information($command_for_title,
  247. $filename);
  248. } else {
  249. ($title, $description, $encoding, $date, $css_lines,
  250. $doctype, $root_html_element_attributes, $copying_comment,
  251. $after_body_open, $extra_head, $program_and_version, $program_homepage,
  252. $program, $generator) = $self->_file_header_informations($command_for_title);
  253. }
  254. my $links;
  255. if ($program_version_num >= 7.000000) {
  256. $links = $self->_get_links($filename, $element, $node_command);
  257. } else {
  258. $links = $self->_get_links ($filename, $element);
  259. }
  260. my $head1 = $ENV{"FFMPEG_HEADER1"} || <<EOT;
  261. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  262. <html>
  263. <!-- Created by $program_and_version, $program_homepage -->
  264. <head>
  265. <meta charset="utf-8">
  266. <title>
  267. EOT
  268. my $head_title = <<EOT;
  269. $title
  270. EOT
  271. my $head2 = $ENV{"FFMPEG_HEADER2"} || <<EOT;
  272. </title>
  273. <meta name="viewport" content="width=device-width,initial-scale=1.0">
  274. <link rel="stylesheet" type="text/css" href="bootstrap.min.css">
  275. <link rel="stylesheet" type="text/css" href="style.min.css">
  276. </head>
  277. <body>
  278. <div class="container">
  279. <h1>
  280. EOT
  281. my $head3 = $ENV{"FFMPEG_HEADER3"} || <<EOT;
  282. </h1>
  283. EOT
  284. return $head1 . $head_title . $head2 . $head_title . $head3;
  285. }
  286. if ($program_version_6_8) {
  287. texinfo_register_formatting_function('format_begin_file', \&ffmpeg_begin_file);
  288. } else {
  289. texinfo_register_formatting_function('begin_file', \&ffmpeg_begin_file);
  290. }
  291. sub ffmpeg_program_string($)
  292. {
  293. my $self = shift;
  294. if (defined($self->get_conf('PROGRAM'))
  295. and $self->get_conf('PROGRAM') ne ''
  296. and defined($self->get_conf('PACKAGE_URL'))) {
  297. if ($program_version_num >= 7.001090) {
  298. return $self->convert_tree(
  299. $self->cdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.',
  300. { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')},
  301. 'program' => {'text' => $self->get_conf('PROGRAM') }}));
  302. } else {
  303. return $self->convert_tree(
  304. $self->gdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.',
  305. { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')},
  306. 'program' => {'text' => $self->get_conf('PROGRAM') }}));
  307. }
  308. } else {
  309. if ($program_version_num >= 7.001090) {
  310. return $self->convert_tree(
  311. $self->cdt('This document was generated automatically.'));
  312. } else {
  313. return $self->convert_tree(
  314. $self->gdt('This document was generated automatically.'));
  315. }
  316. }
  317. }
  318. if ($program_version_6_8) {
  319. texinfo_register_formatting_function('format_program_string', \&ffmpeg_program_string);
  320. } else {
  321. texinfo_register_formatting_function('program_string', \&ffmpeg_program_string);
  322. }
  323. # Customized file ending
  324. sub ffmpeg_end_file($)
  325. {
  326. my $self = shift;
  327. my $program_string = &{get_formatting_function($self,'format_program_string')}($self);
  328. my $program_text = <<EOT;
  329. <p style="font-size: small;">
  330. $program_string
  331. </p>
  332. EOT
  333. my $footer = $ENV{FFMPEG_FOOTER} || <<EOT;
  334. </div>
  335. </body>
  336. </html>
  337. EOT
  338. return $program_text . $footer;
  339. }
  340. if ($program_version_6_8) {
  341. texinfo_register_formatting_function('format_end_file', \&ffmpeg_end_file);
  342. } else {
  343. texinfo_register_formatting_function('end_file', \&ffmpeg_end_file);
  344. }
  345. # Dummy title command
  346. # Ignore title. Title is handled through ffmpeg_begin_file().
  347. ff_set_from_init_file('USE_TITLEPAGE_FOR_TITLE', 1);
  348. sub ffmpeg_title($$$$)
  349. {
  350. return '';
  351. }
  352. texinfo_register_command_formatting('titlefont',
  353. \&ffmpeg_title);
  354. # Customized float command. Part of code borrowed from GNU Texinfo.
  355. sub ffmpeg_float($$$$$)
  356. {
  357. my $self = shift;
  358. my $cmdname = shift;
  359. my $command = shift;
  360. my $args = shift;
  361. my $content = shift;
  362. my ($caption, $prepended);
  363. if ($program_version_num >= 7.000000) {
  364. ($caption, $prepended) = Texinfo::Convert::Converter::float_name_caption($self,
  365. $command);
  366. } else {
  367. ($caption, $prepended) = Texinfo::Common::float_name_caption($self,
  368. $command);
  369. }
  370. my $caption_text = '';
  371. my $prepended_text;
  372. my $prepended_save = '';
  373. if ($self->in_string()) {
  374. if ($prepended) {
  375. $prepended_text = $self->convert_tree_new_formatting_context(
  376. $prepended, 'float prepended');
  377. } else {
  378. $prepended_text = '';
  379. }
  380. if ($caption) {
  381. $caption_text = $self->convert_tree_new_formatting_context(
  382. {'contents' => $caption->{'args'}->[0]->{'contents'}},
  383. 'float caption');
  384. }
  385. return $prepended.$content.$caption_text;
  386. }
  387. my $id = $self->command_id($command);
  388. my $label;
  389. if (defined($id) and $id ne '') {
  390. $label = "<a name=\"$id\"></a>";
  391. } else {
  392. $label = '';
  393. }
  394. if ($prepended) {
  395. if ($caption) {
  396. # prepend the prepended tree to the first paragraph
  397. my @caption_original_contents = @{$caption->{'args'}->[0]->{'contents'}};
  398. my @caption_contents;
  399. my $new_paragraph;
  400. while (@caption_original_contents) {
  401. my $content = shift @caption_original_contents;
  402. if ($content->{'type'} and $content->{'type'} eq 'paragraph') {
  403. %{$new_paragraph} = %{$content};
  404. $new_paragraph->{'contents'} = [@{$content->{'contents'}}];
  405. unshift (@{$new_paragraph->{'contents'}}, {'cmdname' => 'strong',
  406. 'args' => [{'type' => 'brace_command_arg',
  407. 'contents' => [$prepended]}]});
  408. push @caption_contents, $new_paragraph;
  409. last;
  410. } else {
  411. push @caption_contents, $content;
  412. }
  413. }
  414. push @caption_contents, @caption_original_contents;
  415. if ($new_paragraph) {
  416. $caption_text = $self->convert_tree_new_formatting_context(
  417. {'contents' => \@caption_contents}, 'float caption');
  418. $prepended_text = '';
  419. }
  420. }
  421. if ($caption_text eq '') {
  422. $prepended_text = $self->convert_tree_new_formatting_context(
  423. $prepended, 'float prepended');
  424. if ($prepended_text ne '') {
  425. $prepended_save = $prepended_text;
  426. $prepended_text = '<p><strong>'.$prepended_text.'</strong></p>';
  427. }
  428. }
  429. } else {
  430. $prepended_text = '';
  431. }
  432. if ($caption and $caption_text eq '') {
  433. $caption_text = $self->convert_tree_new_formatting_context(
  434. $caption->{'args'}->[0], 'float caption');
  435. }
  436. if ($prepended_text.$caption_text ne '') {
  437. if ($program_version_num >= 7.000000) {
  438. $prepended_text = $self->html_attribute_class('div',['float-caption']). '>'
  439. . $prepended_text;
  440. } else {
  441. $prepended_text = $self->_attribute_class('div','float-caption'). '>'
  442. . $prepended_text;
  443. }
  444. $caption_text .= '</div>';
  445. }
  446. my $html_class = '';
  447. if ($prepended_save =~ /NOTE/) {
  448. $html_class = 'info';
  449. $prepended_text = '';
  450. $caption_text = '';
  451. } elsif ($prepended_save =~ /IMPORTANT/) {
  452. $html_class = 'warning';
  453. $prepended_text = '';
  454. $caption_text = '';
  455. }
  456. if ($program_version_num >= 7.000000) {
  457. return $self->html_attribute_class('div', [$html_class]). '>' . "\n" .
  458. $prepended_text . $caption_text . $content . '</div>';
  459. } else {
  460. return $self->_attribute_class('div', $html_class). '>' . "\n" .
  461. $prepended_text . $caption_text . $content . '</div>';
  462. }
  463. }
  464. texinfo_register_command_formatting('float',
  465. \&ffmpeg_float);
  466. 1;