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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.14 by wakaba, Sat May 10 12:13:43 2008 UTC revision 1.17 by wakaba, Sat Aug 30 15:14:32 2008 UTC
# Line 3  use strict; Line 3  use strict;
3    
4  ## An implementation of "Forming a table" algorithm in HTML5  ## An implementation of "Forming a table" algorithm in HTML5
5  sub form_table ($$$;$) {  sub form_table ($$$;$) {
6    my (undef, $table_el, $onerror, $must_level) = @_;    my (undef, $table_el, $onerror, $levels) = @_;
7    $onerror ||= sub { };    $onerror ||= sub { };
8    $must_level ||= 'm';    $levels ||= {must => 'm'};
9        
10    ## Step 1    ## Step 1
11    my $x_width = 0;    my $x_width = 0;
# Line 65  sub form_table ($$$;$) { Line 65  sub form_table ($$$;$) {
65          if ($table->{column}->[$_]) {          if ($table->{column}->[$_]) {
66            $onerror->(type => 'column with no anchored cell',            $onerror->(type => 'column with no anchored cell',
67                       node => $table->{column}->[$_]->{element},                       node => $table->{column}->[$_]->{element},
68                       level => $must_level);                       level => $levels->{must});
69          } else {          } else {
70            $onerror->(type => 'colspan creates column with no anchored cell',            $onerror->(type => 'colspan creates column with no anchored cell',
71                       node => $column_generated_by[$_],                       node => $column_generated_by[$_],
72                      level => $must_level);                       level => $levels->{must});
73          }          }
74          last; # only one error.          last; # only one error.
75        }        }
# Line 79  sub form_table ($$$;$) { Line 79  sub form_table ($$$;$) {
79          if ($table->{row}->[$_]) {          if ($table->{row}->[$_]) {
80            $onerror->(type => 'row with no anchored cell',            $onerror->(type => 'row with no anchored cell',
81                       node => $table->{row}->[$_]->{element},                       node => $table->{row}->[$_]->{element},
82                       level => $must_level);                       level => $levels->{must});
83          } else {          } else {
84            $onerror->(type => 'rowspan creates row with no anchored cell',            $onerror->(type => 'rowspan creates row with no anchored cell',
85                       node => $row_generated_by[$_],                       node => $row_generated_by[$_],
86                       level => $must_level);                       level => $levels->{must});
87          }          }
88          last; # only one error.          last; # only one error.
89        }        }
# Line 226  sub form_table ($$$;$) { Line 226  sub form_table ($$$;$) {
226      ## Step 2      ## Step 2
227      my $x_current = 0;      my $x_current = 0;
228    
229      ## Step 3      ## Step 5
230      my $tr = shift;      my $tr = shift;
231      $table->{row}->[$y_current] = {element => $tr};      $table->{row}->[$y_current] = {element => $tr};
232      my @tdth = grep {      my @tdth = grep {
# Line 237  sub form_table ($$$;$) { Line 237  sub form_table ($$$;$) {
237      } @{$tr->child_nodes};      } @{$tr->child_nodes};
238      my $current_cell = shift @tdth;      my $current_cell = shift @tdth;
239    
240      ## Step 4      ## Step 3
241      $growing_downward_growing_cells->();      $growing_downward_growing_cells->();
242    
243  return unless $current_cell;      ## Step 4
244  ## ISSUE: Support for empty <tr></tr> (removed at revision 1376).      return unless $current_cell;
245    
246      CELL: while (1) {      CELL: while (1) {
247        ## Step 5: cells        ## Step 6: cells
248        $x_current++        $x_current++
249          while ($x_current < $x_width and          while ($x_current < $x_width and
250                 $table->{cell}->[$x_current]->[$y_current]);                 $table->{cell}->[$x_current]->[$y_current]);
251    
252        ## Step 6        ## Step 7
253        $x_width++ if $x_current == $x_width;        $x_width++ if $x_current == $x_width;
254    
255        ## Step 7        ## Step 8
256        my $colspan = 1;        my $colspan = 1;
257        my $attr_value = $current_cell->get_attribute_ns (undef, 'colspan');        my $attr_value = $current_cell->get_attribute_ns (undef, 'colspan');
258        if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {        if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
259          $colspan = $1 || 1;          $colspan = $1 || 1;
260        }        }
261                
262        ## Step 8        ## Step 9
263        my $rowspan = 1;        my $rowspan = 1;
264        my $attr_value = $current_cell->get_attribute_ns (undef, 'rowspan');        my $attr_value = $current_cell->get_attribute_ns (undef, 'rowspan');
265        if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {        if (defined $attr_value and $attr_value =~ /^[\x09-\x0D\x20]*([0-9]+)/) {
266          $rowspan = $1;          $rowspan = $1;
267        }        }
268                
269        ## Step 9        ## Step 10
270        my $cell_grows_downward;        my $cell_grows_downward;
271        if ($rowspan == 0) {        if ($rowspan == 0) {
272          $cell_grows_downward = 1;          $cell_grows_downward = 1;
273          $rowspan = 1;          $rowspan = 1;
274        }        }
275                
276        ## Step 10        ## Step 11
277        if ($x_width < $x_current + $colspan) {        if ($x_width < $x_current + $colspan) {
278          @column_generated_by[$_] = $current_cell          @column_generated_by[$_] = $current_cell
279            for $x_width .. $x_current + $colspan - 1;            for $x_width .. $x_current + $colspan - 1;
280          $x_width = $x_current + $colspan;          $x_width = $x_current + $colspan;
281        }        }
282                
283        ## Step 11        ## Step 12
284        if ($y_height < $y_current + $rowspan) {        if ($y_height < $y_current + $rowspan) {
285          @row_generated_by[$_] = $current_cell          @row_generated_by[$_] = $current_cell
286              for $y_height .. $y_current + $rowspan - 1;              for $y_height .. $y_current + $rowspan - 1;
# Line 288  return unless $current_cell; Line 288  return unless $current_cell;
288          $y_max_node = $current_cell;          $y_max_node = $current_cell;
289        }        }
290                
291        ## Step 12        ## Step 13
292        my $cell = {        my $cell = {
293                    is_header => ($current_cell->manakai_local_name eq 'th'),                    is_header => ($current_cell->manakai_local_name eq 'th'),
294                    element => $current_cell,                    element => $current_cell,
# Line 302  return unless $current_cell; Line 302  return unless $current_cell;
302            unless ($table->{cell}->[$x]->[$y]) {            unless ($table->{cell}->[$x]->[$y]) {
303              $table->{cell}->[$x]->[$y] = [$cell];              $table->{cell}->[$x]->[$y] = [$cell];
304            } else {            } else {
305              $onerror->(type => "cell overlapping:$x:$y", node => $current_cell,              $onerror->(type => 'cell overlapping',
306                         level => $must_level);                         text => "$x,$y",
307                           node => $current_cell,
308                           level => $levels->{must});
309              push @{$table->{cell}->[$x]->[$y]}, $cell;              push @{$table->{cell}->[$x]->[$y]}, $cell;
310            }            }
311          }          }
# Line 315  return unless $current_cell; Line 317  return unless $current_cell;
317          for my $node (@{$current_cell->child_nodes}) {          for my $node (@{$current_cell->child_nodes}) {
318            my $nt = $node->node_type;            my $nt = $node->node_type;
319            if ($nt == 3 or $nt == 4) { # TEXT_NODE / CDATA_SECTION_NODE            if ($nt == 3 or $nt == 4) { # TEXT_NODE / CDATA_SECTION_NODE
320              if ($node->data =~ /\P{Zs}/) { ## TOOD: non-Zs class              if ($node->data =~ /\P{WhiteSpace}/) {
321                delete $cell->{is_empty};                delete $cell->{is_empty};
322                last;                last;
323              }              }
# Line 327  return unless $current_cell; Line 329  return unless $current_cell;
329          ## NOTE: Entity references are not supported          ## NOTE: Entity references are not supported
330        }        }
331                
332        ## Step 13        ## Step 14
333        if ($cell_grows_downward) {        if ($cell_grows_downward) {
334          push @downward_growing_cells, [$cell, $x_current, $colspan];          push @downward_growing_cells, [$cell, $x_current, $colspan];
335        }        }
336                
337        ## Step 14        ## Step 15
338        $x_current += $colspan;        $x_current += $colspan;
339    
340        ## Step 15-17        ## Step 16-18
341        $current_cell = shift @tdth;        $current_cell = shift @tdth;
342        if (defined $current_cell) {        if (defined $current_cell) {
343          ## Step 16-17          ## Step 17-18
344          #          #
345        } else {        } else {
346          ## Step 15          ## Step 16
347          $y_current++;          $y_current++;
348          last CELL;          last CELL;
349        }        }
# Line 456  return unless $current_cell; Line 458  return unless $current_cell;
458  } # form_table  } # form_table
459    
460  sub assign_header ($$;$$) {  sub assign_header ($$;$$) {
461    my (undef, $table, $onerror, $must_level) = @_;    my (undef, $table, $onerror, $levels) = @_;
462    $onerror ||= sub { };    $onerror ||= sub { };
463    $must_level ||= 'm';    $levels ||= {must => 'm'};
464    
465    my $assign_header = sub ($$$) {    my $assign_header = sub ($$$) {
466      my $_cell = shift;      my $_cell = shift;
# Line 547  sub assign_header ($$;$$) { Line 549  sub assign_header ($$;$$) {
549              my $_x = $x + $header_width;              my $_x = $x + $header_width;
550    
551              ## 3.              ## 3.
552                my $_y = $y + $cell->{height}; # $cell->{height} == header_{height}
553    
554                ## 4.
555              HORIZONTAL: {              HORIZONTAL: {
556                last HORIZONTAL if $_x == $table->{width}; # goto Vertical                last HORIZONTAL if $_x == $table->{width}; # goto Vertical
557    
558                ## 4. # goto Vertical                ## 5. # goto Vertical
559                last HORIZONTAL                last HORIZONTAL
560                    if $table->{cell}->[$_x]->[$y] and                    if $table->{cell}->[$_x]->[$y] and
561                        $table->{cell}->[$_x]->[$y]->[0] and # anchored                        $table->{cell}->[$_x]->[$y]->[0] and # anchored
562                        $table->{cell}->[$_x]->[$y]->[0]->{is_header};                        $table->{cell}->[$_x]->[$y]->[0]->{is_header};
563    
564                ## 5.                ## 6.
565                for my $_y ($y .. $y + $cell->{height} - 1) {                for my $_y ($y .. $y + $cell->{height} - 1) {
566                  $assign_header->($table->{cell}->[$_x]->[$_y] => $x, $y);                  $assign_header->($table->{cell}->[$_x]->[$_y] => $x, $y);
567                }                }
568    
569                ## 6.                ## 7.
570                $_x++;                $_x++;
571    
572                ## 7.                ## 8.
573                redo HORIZONTAL;                redo HORIZONTAL;
574              } # HORIZONTAL              } # HORIZONTAL
575    
576              ## 8. Vertical              ## 9. Vertical
             my $_y = $y + $cell->{height};  
   
577              VERTICAL: {              VERTICAL: {
578                ## 9. # goto END                last VERTICAL if $_y == $table->{height}; # goto END
               last VERTICAL if $_y == $table->{height};  
579    
580                ## 10.                ## 10.
581                if ($table->{cell}->[$x]->[$_y]) {                if ($table->{cell}->[$x]->[$_y]) {
# Line 631  sub assign_header ($$;$$) { Line 633  sub assign_header ($$;$$) {
633          $onerror->(type => 'duplicate token', value => $header_id,          $onerror->(type => 'duplicate token', value => $header_id,
634                     node => $headers_cell->{element}->get_attribute_node_ns                     node => $headers_cell->{element}->get_attribute_node_ns
635                         (undef, 'headers'),                         (undef, 'headers'),
636                     level => $must_level);                     level => $levels->{must});
637          next;          next;
638        }        }
639        $headers{$header_id} = 1;        $headers{$header_id} = 1;
# Line 640  sub assign_header ($$;$$) { Line 642  sub assign_header ($$;$$) {
642          my $header_cell = $id_to_cell->{$header_id};          my $header_cell = $id_to_cell->{$header_id};
643          $headers_cell->{header}->{$header_cell->{x}}->{$header_cell->{y}} = 1;          $headers_cell->{header}->{$header_cell->{x}}->{$header_cell->{y}} = 1;
644        } else {        } else {
645          $onerror->(type => 'no header cell', value => $header_id,          $onerror->(type => 'no referenced header cell', value => $header_id,
646                     node => $headers_cell->{element}->get_attribute_node_ns                     node => $headers_cell->{element}->get_attribute_node_ns
647                         (undef, 'headers'),                         (undef, 'headers'),
648                     level => $must_level);                     level => $levels->{must});
649        }        }
650      }      }
651    }    }

Legend:
Removed from v.1.14  
changed lines
  Added in v.1.17

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24