/[suikacvs]/markup/html/whatpm/Whatpm/HTMLTable.pm
Suika

Contents of /markup/html/whatpm/Whatpm/HTMLTable.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Sat Aug 4 13:23:36 2007 UTC (17 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.5: +4 -6 lines
++ whatpm/Whatpm/ChangeLog	4 Aug 2007 13:23:30 -0000
2007-08-04  Wakaba  <wakaba@suika.fam.cx>

	* ContentChecker.pm: HTML |time| element is implemented.

	* HTMLTable.pm: Comments are updated as HTML5 is revised.

1 wakaba 1.1 package Whatpm::HTMLTable;
2     use strict;
3    
4     ## An implementation of "Forming a table" algorithm in HTML5
5     sub form_table ($$$) {
6     my (undef, $table_el, $onerror) = @_;
7 wakaba 1.2 $onerror ||= sub { };
8 wakaba 1.1
9     ## Step 1
10     my $x_max = 0;
11    
12     ## Step 2
13     my $y_max = 0;
14     my $y_max_node;
15    
16     ## Step 3
17     my $table = {
18     #caption
19     column => [],
20     column_group => [],
21 wakaba 1.2 # no |row| since HTML5 algorithm doesn't associate rows with <tr>s
22 wakaba 1.1 row_group => [],
23     cell => [],
24     };
25    
26     my @has_anchored_cell;
27     my @column_generated_by;
28     my $check_empty_column = sub {
29     for (1..$x_max) {
30     unless ($has_anchored_cell[$_]) {
31     if ($table->{column}->[$_]) {
32     $onerror->(type => 'column with no anchored cell',
33     node => $table->{column}->[$_]->{element});
34     } else {
35 wakaba 1.4 $onerror->(type => 'colspan creates column with no anchored cell',
36 wakaba 1.1 node => $column_generated_by[$_]);
37     }
38     }
39     }
40     }; # $check_empty_column
41    
42     ## Step 4
43     ## "If the table element has no table children, then return the table (which will be empty), and abort these steps."
44     ## ISSUE: What is "table children"?
45     my @table_child = @{$table_el->child_nodes};
46     return unless @table_child; # don't call $check_empty_column
47    
48     ## Step 5, 6, 8
49     my $current_element;
50     my $current_ln;
51     NEXT_CHILD: {
52     $current_element = shift @table_child;
53     if (defined $current_element) {
54     redo NEXT_CHILD unless $current_element->node_type == 1;
55     my $nsuri = $current_element->namespace_uri;
56     redo NEXT_CHILD unless defined $nsuri and
57     $nsuri eq q<http://www.w3.org/1999/xhtml>;
58     $current_ln = $current_element->manakai_local_name;
59    
60     if ($current_ln eq 'caption' and not defined $table->{caption}) {
61     ## Step 7
62     $table->{caption} = {element => $current_element};
63     redo NEXT_CHILD; # Step 8
64     }
65    
66     redo NEXT_CHILD unless {
67     #caption => 1, ## Step 6
68     colgroup => 1,
69     thead => 1,
70     tbody => 1,
71     tfoot => 1,
72     tr => 1,
73     }->{$current_ln};
74     } else {
75     ## End of subsection
76     $check_empty_column->();
77     ## Step 5 2nd paragraph
78     return $table;
79     }
80     } # NEXT_CHILD
81    
82     ## Step 9
83 wakaba 1.6 while ($current_ln eq 'colgroup') { # Step 9, Step 9.4
84     ## Step 9.1: column groups
85 wakaba 1.1 my @col = grep {
86     $_->node_type == 1 and
87     defined $_->namespace_uri and
88     $_->namespace_uri eq q<http://www.w3.org/1999/xhtml> and
89     $_->manakai_local_name eq 'col'
90     } @{$current_element->child_nodes};
91     if (@col) {
92     ## Step 1
93     my $x_start = $x_max + 1;
94    
95     ## Step 2, 6
96     while (@col) {
97     my $current_column = shift @col;
98    
99     ## Step 3: columns
100     my $span = 1;
101     my $col_span = $current_column->get_attribute_ns (undef, 'span');
102     ## Parse non-negative integer
103     if (defined $col_span and $col_span =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
104     $span = $1 || 1;
105     }
106     ## ISSUE: If span=0, what is /span/ value?
107    
108     ## Step 4, 5
109     $table->{column}->[++$x_max] = {element => $current_column} for 1..$span;
110     }
111    
112     ## Step 7
113     my $cg = {element => $current_element,
114     x => $x_start, y => 1,
115 wakaba 1.2 width => $x_max - $x_start - 1}; ## ISSUE: Spec incorrect
116     $cg->{width} = $x_max - $x_start + 1;
117 wakaba 1.1 $table->{column_group}->[$_] = $cg for $x_start .. $x_max;
118     } else { # no <col> children
119     ## Step 1
120     my $span = 1;
121     my $col_span = $current_element->get_attribute_ns (undef, 'span');
122     ## Parse non-negative integer
123     if (defined $col_span and $col_span =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
124     $span = $1 || 1;
125     }
126     ## ISSUE: If span=0, what is /span/ value?
127    
128     ## Step 2
129     $x_max += $span;
130    
131     ## Step 3
132     my $cg = {element => $current_element,
133     x => $x_max - $span + 1, y => 1,
134     width => $span};
135     $table->{column_group}->[$_] = $cg for (($x_max - $span + 1) .. $x_max);
136     }
137    
138 wakaba 1.6 ## Step 9.2, 9.3
139 wakaba 1.1 NEXT_CHILD: {
140     $current_element = shift @table_child;
141     if (defined $current_element) {
142     redo NEXT_CHILD unless $current_element->node_type == 1;
143     my $nsuri = $current_element->namespace_uri;
144     redo NEXT_CHILD unless defined $nsuri and
145     $nsuri eq q<http://www.w3.org/1999/xhtml>;
146     $current_ln = $current_element->manakai_local_name;
147    
148     redo NEXT_CHILD unless {
149     colgroup => 1,
150     thead => 1,
151     tbody => 1,
152     tfoot => 1,
153     tr => 1,
154     }->{$current_ln};
155     } else {
156     ## End of subsection
157     $check_empty_column->();
158     ## Step 5 of overall steps 2nd paragraph
159     return $table;
160     }
161     } # NEXT_CHILD
162     }
163    
164     ## Step 10
165     my $y_current = 0;
166    
167     ## Step 11
168     my @downward_growing_cells;
169    
170     my $growing_downward_growing_cells = sub {
171     ## Step 1
172     return unless @downward_growing_cells;
173    
174     ## Step 2
175     if ($y_max < $y_current) {
176     $y_max++;
177     undef $y_max_node;
178     }
179    
180     ## Step 3
181     for (@downward_growing_cells) {
182     for my $x ($_->[1] .. ($_->[1] + $_->[2] - 1)) {
183     $table->{cell}->[$x]->[$y_current] = [$_->[0]];
184     $_->[0]->{height}++;
185     }
186     }
187     }; # $growing_downward_growing_cells
188    
189     my $process_row = sub {
190     ## Step 1
191     $y_current++;
192    
193     ## Step 2
194     $growing_downward_growing_cells->();
195    
196     ## Step 3
197     my $x_current = 1;
198    
199     ## Step 4
200     my $tr = shift;
201     my @tdth = grep {
202     $_->node_type == 1 and
203     defined $_->namespace_uri and
204     $_->namespace_uri eq q<http://www.w3.org/1999/xhtml> and
205     {td => 1, th => 1}->{$_->manakai_local_name}
206     } @{$tr->child_nodes};
207     #return unless @tdth; # redundant with |while| below
208    
209     ## Step 5, 16, 17, 18
210     ## ISSUE: Step 18 says "step 5 (cells)" while "cells" is step 6.
211     while (@tdth) {
212     my $current_cell = shift @tdth;
213    
214     ## Step 6: cells
215     $x_current++
216     while ($x_current <= $x_max and
217     $table->{cell}->[$x_current]->[$y_current]);
218    
219     ## Step 7
220     if ($x_current > $x_max) {
221     $x_max++;
222     }
223    
224     ## Step 8
225     ## ISSUE: How to parse |colspan| is not explicitly specified
226     ## (while |span| was).
227 wakaba 1.3 ## <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2006-November/007981.html>
228 wakaba 1.1 my $colspan = 1;
229     my $attr_value = $current_cell->get_attribute_ns (undef, 'colspan');
230     if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
231     $colspan = $1 || 1;
232     }
233    
234     ## Step 9
235     my $rowspan = 1;
236     ## ISSUE: How to parse
237 wakaba 1.3 ## <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2006-November/007981.html>
238 wakaba 1.1 my $attr_value = $current_cell->get_attribute_ns (undef, 'rowspan');
239     if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
240     $rowspan = $1;
241     }
242    
243     ## Step 10
244     my $cell_grows_downward;
245     if ($rowspan == 0) {
246     $cell_grows_downward = 1;
247     $rowspan = 1;
248     }
249    
250     ## Step 11
251     if ($x_max < $x_current + $colspan - 1) {
252     @column_generated_by[$_] = $current_cell
253     for $x_max + 1 .. $x_current + $colspan - 1;
254     $x_max = $x_current + $colspan - 1;
255     }
256    
257     ## Step 12
258     if ($y_max < $y_current + $rowspan - 1) {
259     $y_max = $y_current + $rowspan - 1;
260     $y_max_node = $current_cell;
261     }
262    
263     ## Step 13
264     my $cell = {
265 wakaba 1.2 is_header => ($current_cell->manakai_local_name eq 'th'),
266 wakaba 1.1 element => $current_cell,
267     x => $x_current, y => $y_current,
268     width => $colspan, height => $rowspan,
269     };
270     $has_anchored_cell[$x_current] = 1;
271     for my $x ($x_current .. ($x_current + $colspan - 1)) {
272     for my $y ($y_current .. ($y_current + $rowspan - 1)) {
273     unless ($table->{cell}->[$x]->[$y]) {
274     $table->{cell}->[$x]->[$y] = [$cell];
275     } else {
276     $onerror->(type => "cell overlapping:$x:$y", node => $current_cell);
277     push @{$table->{cell}->[$x]->[$y]}, $cell;
278     }
279     }
280     }
281    
282     ## Step 14
283     if ($cell_grows_downward) {
284     push @downward_growing_cells, [$cell, $x_current, $colspan];
285     }
286    
287     ## Step 15
288     $x_current += $colspan;
289     }
290     }; # $process_row
291    
292     ## Step 12: rows
293     unshift @table_child, $current_element;
294     ROWS: {
295     NEXT_CHILD: {
296     $current_element = shift @table_child;
297     if (defined $current_element) {
298     redo NEXT_CHILD unless $current_element->node_type == 1;
299     my $nsuri = $current_element->namespace_uri;
300     redo NEXT_CHILD unless defined $nsuri and
301     $nsuri eq q<http://www.w3.org/1999/xhtml>;
302     $current_ln = $current_element->manakai_local_name;
303    
304     redo NEXT_CHILD unless {
305     thead => 1,
306     tbody => 1,
307     tfoot => 1,
308     tr => 1,
309     }->{$current_ln};
310     } else {
311     ## Step 10 2nd sentense
312     if ($y_current != $y_max) {
313 wakaba 1.5 $onerror->(type => 'no cell in last row', node => $table_el);
314 wakaba 1.1 }
315     ## End of subsection
316     $check_empty_column->();
317     ## Step 5 2nd paragraph
318     return $table;
319     }
320     } # NEXT_CHILD
321    
322     ## Step 13
323     if ($current_ln eq 'tr') {
324     $process_row->($current_element);
325     redo ROWS;
326     }
327    
328     ## Step 14
329     ## Ending a row group
330     ## Step 1
331     if ($y_current < $y_max) {
332     $onerror->(type => 'rowspan expands table', node => $y_max_node);
333     }
334     ## Step 2
335     while ($y_current < $y_max) {
336     ## Step 1
337     $y_current++;
338     $growing_downward_growing_cells->();
339     }
340     ## Step 3
341     @downward_growing_cells = ();
342    
343     ## Step 15
344     my $y_start = $y_max + 1;
345    
346     ## Step 16
347     for (grep {
348     $_->node_type == 1 and
349     defined $_->namespace_uri and
350     $_->namespace_uri eq q<http://www.w3.org/1999/xhtml> and
351     $_->manakai_local_name eq 'tr'
352     } @{$current_element->child_nodes}) {
353     $process_row->($_);
354     }
355    
356     ## Step 17
357     if ($y_max >= $y_start) {
358     my $rg = {element => $current_element,
359     x => 1, y => $y_start,
360     height => $y_max - $y_start + 1};
361     $table->{row_group}->[$_] = $rg for $y_start .. $y_max;
362     }
363    
364     ## Step 18
365     ## Ending a row group
366     ## Step 1
367     if ($y_current < $y_max) {
368     $onerror->(type => 'rowspan expands table', node => $y_max_node);
369     }
370     ## Step 2
371     while ($y_current < $y_max) {
372     ## Step 1
373     $y_current++;
374     $growing_downward_growing_cells->();
375     }
376     ## Step 3
377     @downward_growing_cells = ();
378    
379     ## Step 19
380     redo ROWS; # Step 12
381     } # ROWS
382     } # form_table
383    
384     ## TODO: Implement scope="" algorithm
385    
386     1;
387 wakaba 1.6 ## $Date: 2007/07/01 04:46:48 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24