source: sandbox/filemanager/tp/dompdf/include/cellmap.cls.php @ 1575

Revision 1575, 18.9 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implentação, melhorias do modulo gerenciador de arquivos

Line 
1<?php
2/**
3 * DOMPDF - PHP5 HTML to PDF renderer
4 *
5 * File: $RCSfile: cellmap.cls.php,v $
6 * Created on: 2004-07-28
7 *
8 * Copyright (c) 2004 - Benj Carson <benjcarson@digitaljunkies.ca>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library in the file LICENSE.LGPL; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA
24 *
25 * Alternatively, you may distribute this software under the terms of the
26 * PHP License, version 3.0 or later.  A copy of this license should have
27 * been distributed with this file in the file LICENSE.PHP .  If this is not
28 * the case, you can obtain a copy at http://www.php.net/license/3_0.txt.
29 *
30 * The latest version of DOMPDF might be available at:
31 * http://www.digitaljunkies.ca/dompdf
32 *
33 * @link http://www.digitaljunkies.ca/dompdf
34 * @copyright 2004 Benj Carson
35 * @author Benj Carson <benjcarson@digitaljunkies.ca>
36 * @package dompdf
37 * @version 0.5.1
38 */
39
40/* $Id: cellmap.cls.php,v 1.12 2006/07/07 21:31:03 benjcarson Exp $ */
41
42/**
43 * Maps table cells to the table grid.
44 *
45 * This class resolves borders in tables with collapsed borders and helps
46 * place row & column spanned table cells.
47 *
48 * @access private
49 * @package dompdf
50 */
51class Cellmap {
52
53  /**
54   * Border style weight lookup for collapsed border resolution.
55   *
56   * @var array
57   */
58  static protected $_BORDER_STYLE_SCORE = array("inset"  => 1,
59                                                "groove" => 2,
60                                                "outset" => 3,
61                                                "ridge"  => 4,
62                                                "dotted" => 5,
63                                                "dashed" => 6,
64                                                "solid"  => 7,
65                                                "double" => 8,
66                                                "none"   => 0);
67
68  /**
69   * The table object this cellmap is attached to.
70   *
71   * @var Table_Frame_Decorator
72   */
73  protected $_table;
74 
75  /**
76   * The total number of rows in the table
77   *
78   * @var int
79   */
80  protected $_num_rows;
81
82  /**
83   * The total number of columns in the table
84   *
85   * @var int
86   */
87  protected $_num_cols;
88
89  /**
90   * 2D array mapping <row,column> to frames
91   *
92   * @var array
93   */
94  protected $_cells;
95
96  /**
97   * 1D array of column dimensions
98   *
99   * @var array
100   */
101  protected $_columns;
102
103  /**
104   * 1D array of row dimensions
105   *
106   * @var array
107   */
108  protected $_rows;
109
110  /**
111   * 2D array of border specs
112   *
113   * @var array
114   */
115  protected $_borders;
116
117  /**
118   * 1D Array mapping frames to (multiple) <row, col> pairs, keyed on
119   * frame_id.
120   *
121   * @var array
122   */
123  protected $_frames;
124
125  /**
126   * Current column when adding cells, 0-based
127   *
128   * @var int
129   */
130  private $__col;
131
132  /**
133   * Current row when adding cells, 0-based
134   *
135   * @var int
136   */
137  private $__row;
138 
139  //........................................................................
140
141  function __construct(Table_Frame_Decorator $table) {
142    $this->_table = $table;
143    $this->reset();
144  }
145
146  //........................................................................
147
148  function reset() {   
149    $this->_num_rows = 0;
150    $this->_num_cols = 0;
151
152    $this->_cells  = array();
153    $this->_frames = array();
154
155    $this->_columns = array();
156    $this->_rows = array();   
157
158    $this->_borders = array();
159   
160    $this->__col = $this->__row = 0;
161  }
162 
163  //........................................................................
164
165  function get_num_rows() { return $this->_num_rows; }
166  function get_num_cols() { return $this->_num_cols; }
167
168  function &get_columns() {
169    return $this->_columns;
170  }
171 
172  function &get_column($i) {
173    if ( !isset($this->_columns[$i]) )
174      $this->_columns[$i] = array("x" => 0,
175                                  "min-width" => 0,
176                                  "max-width" => 0,
177                                  "used-width" => null,
178                                  "absolute" => 0,
179                                  "percent" => 0,
180                                  "auto" => true);
181
182    return $this->_columns[$i];
183  }
184
185  function &get_rows() {
186    return $this->_rows;
187  }
188 
189  function &get_row($j) {
190    if ( !isset($this->_rows[$j]) )
191      $this->_rows[$j] = array("y" => 0,
192                               "first-column" => 0,
193                               "height" => null);
194    return $this->_rows[$j];
195  }
196
197  function get_border($i, $j, $h_v, $prop = null) {
198    if ( !isset($this->_borders[$i][$j][$h_v]) )
199      $this->_borders[$i][$j][$h_v] = array("width" => 0,
200                                           "style" => "solid",
201                                           "color" => "black");
202    if ( isset($prop) )
203      return $this->_borders[$i][$j][$h_v][$prop];
204   
205    return $this->_borders[$i][$j][$h_v];
206  }
207 
208  function get_border_properties($i, $j) {
209   
210    $left = $this->get_border($i, $j, "vertical");
211    $right = $this->get_border($i, $j+1, "vertical");
212    $top = $this->get_border($i, $j, "horizontal");
213    $bottom = $this->get_border($i+1, $j, "horizontal");
214   
215    return compact("top", "bottom", "left", "right");
216  }
217 
218  //........................................................................
219
220  function get_spanned_cells($frame) {
221    $key = $frame->get_id();
222
223    if ( !isset($this->_frames[$key]) ) {
224      throw new DOMPDF_Internal_Exception("Frame not found in cellmap");
225    }
226     
227    return $this->_frames[$key];
228   
229  }
230
231  function get_frame_position($frame) {
232    global $_dompdf_warnings;
233   
234    $key = $frame->get_id();
235
236    if ( !isset($this->_frames[$key]) ) {
237      throw new DOMPDF_Internal_Exception("Frame not found in cellmap");
238    }
239
240    $col = $this->_frames[$key]["columns"][0];
241    $row = $this->_frames[$key]["rows"][0];
242
243    if ( !isset($this->_columns[$col])) {
244      $_dompdf_warnings[] = "Frame not found in columns array.  Check your table layout for missing or extra TDs.";
245      $x = 0;
246    } else
247      $x = $this->_columns[$col]["x"];
248   
249    if ( !isset($this->_rows[$row])) {
250      $_dompdf_warnings[] = "Frame not found in row array.  Check your table layout for missing or extra TDs.";
251      $y = 0;
252    } else
253      $y = $this->_rows[$row]["y"];
254
255    return array($x, $y, "x" => $x, "y" => $y);
256  }
257 
258  function get_frame_width($frame) {
259    $key = $frame->get_id();
260
261    if ( !isset($this->_frames[$key]) ) {
262      throw new DOMPDF_Internal_Exception("Frame not found in cellmap");
263    }
264
265    $cols = $this->_frames[$key]["columns"];
266    $w = 0;
267    foreach ($cols as $i)
268      $w += $this->_columns[$i]["used-width"];
269
270    return $w;
271   
272  }
273 
274  function get_frame_height($frame) {
275    $key = $frame->get_id();
276
277    if ( !isset($this->_frames[$key]) )
278      throw new DOMPDF_Internal_Exception("Frame not found in cellmap");
279
280    $rows = $this->_frames[$key]["rows"];
281    $h = 0;
282    foreach ($rows as $i) {
283      if ( !isset($this->_rows[$i]) )  {
284        throw new Exception("foo");
285      }
286      $h += $this->_rows[$i]["height"];
287    }
288    return $h;
289   
290  }
291
292 
293  //........................................................................
294
295  function set_column_width($j, $width) {
296    $col =& $this->get_column($j);
297    $col["used-width"] = $width;
298    $next_col =& $this->get_column($j+1);
299    $next_col["x"] = $next_col["x"] + $width;   
300  }
301 
302  function set_row_height($i, $height) {
303    $row =& $this->get_row($i);   
304    if ( $height <= $row["height"] )
305      return;
306   
307    $row["height"] = $height;
308    $next_row =& $this->get_row($i+1);
309    $next_row["y"] = $row["y"] + $height;
310
311  }
312
313  //........................................................................
314
315
316  protected function _resolve_border($i, $j, $h_v, $border_spec) {
317    $n_width = $border_spec["width"];
318    $n_style = $border_spec["style"];
319    $n_color = $border_spec["color"];
320   
321    if ( !isset($this->_borders[$i][$j][$h_v]) ) {
322      $this->_borders[$i][$j][$h_v] = $border_spec;
323      return $this->_borders[$i][$j][$h_v]["width"];
324    }
325   
326    $o_width = $this->_borders[$i][$j][$h_v]["width"];
327    $o_style = $this->_borders[$i][$j][$h_v]["style"];
328    $o_color = $this->_borders[$i][$j][$h_v]["color"];
329
330    if ( ($n_style === "hidden" ||
331          $n_width  >  $o_width ||
332          $o_style === "none")
333
334         or
335
336         ($o_width == $n_width &&
337          in_array($n_style, self::$_BORDER_STYLE_SCORE) &&
338          self::$_BORDER_STYLE_SCORE[ $n_style ] > self::$_BORDER_STYLE_SCORE[ $o_style ]) )
339      $this->_borders[$i][$j][$h_v] = $border_spec;
340
341    return $this->_borders[$i][$j][$h_v]["width"];
342  }
343 
344  //........................................................................
345
346  function add_frame(Frame $frame) {
347    $style = $frame->get_style();   
348    $display = $style->display;
349   
350    $collapse = $this->_table->get_style()->border_collapse == "collapse";
351   
352    // Recursively add the frames within tables, table-row-groups and table-rows
353    if ( $display == "table-row" ||
354         $display == "table" ||
355         in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {
356
357      $start_row = $this->__row;
358      foreach ( $frame->get_children() as $child )
359        $this->add_frame( $child );
360
361      if ( $display == "table-row" )
362        $this->add_row();
363
364      $num_rows = $this->__row - $start_row - 1;
365      $key = $frame->get_id();
366
367      // Row groups always span across the entire table
368      $this->_frames[ $key ]["columns"] = range(0,max(0,$this->_num_cols-1));
369      $this->_frames[ $key ]["rows"] = range($start_row, max(0, $this->__row - 1));
370      $this->_frames[ $key ]["frame"] = $frame;
371
372      if ( $display != "table-row" && $collapse ) {
373
374        $bp = $style->get_border_properties();
375       
376        // Resolve the borders
377        for ( $i = 0; $i < $num_rows+1; $i++) {
378          $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
379          $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
380        }
381
382        for ( $j = 0; $j < $this->_num_cols; $j++) {
383          $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
384          $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
385        }
386      }
387     
388     
389      return;
390    }
391     
392    // Determine where this cell is going
393    $colspan = $frame->get_node()->getAttribute("colspan");
394    $rowspan = $frame->get_node()->getAttribute("rowspan");
395   
396    if ( !$colspan ) {
397      $colspan = 1;
398      $frame->get_node()->setAttribute("colspan",1);
399    }
400
401    if ( !$rowspan ) {
402      $rowspan = 1;
403      $frame->get_node()->setAttribute("rowspan",1);
404    }
405    $key = $frame->get_id();
406
407    $bp = $style->get_border_properties();
408   
409   
410    // Add the frame to the cellmap
411    $max_left = $max_right = 0;
412   
413    // Rows:
414    for ( $i = 0; $i < $rowspan; $i++ ) {
415      $row = $this->__row + $i;
416
417      $this->_frames[ $key ]["rows"][] = $row;
418
419      for ( $j = 0; $j < $colspan; $j++)
420        $this->_cells[$row][$this->__col + $j] = $frame;
421
422      if ( $collapse ) {
423        // Resolve vertical borders
424        $max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
425        $max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
426      }
427    }
428
429    $max_top = $max_bottom = 0;
430   
431    // Columns:
432    for ( $j = 0; $j < $colspan; $j++ ) {
433      $col = $this->__col + $j;       
434      $this->_frames[ $key ]["columns"][] = $col;
435
436      if ( $collapse ) {
437        // Resolve horizontal borders
438        $max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
439        $max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
440      }
441    }
442   
443    $this->_frames[ $key ]["frame"] = $frame;
444   
445    // Handle seperated border model
446    if ( !$collapse ) {
447      list($h, $v) = $this->_table->get_style()->border_spacing;
448
449      // Border spacing is effectively a margin between cells
450      $v = $style->length_in_pt($v) / 2;
451      $h = $style->length_in_pt($h) / 2;
452      $style->margin = "$v $h";
453
454      // The additional 1/2 width gets added to the table proper
455     
456    } else {
457
458      // Drop the frame's actual border
459      $style->border_left_width = $max_left / 2;
460      $style->border_right_width = $max_right / 2;
461      $style->border_top_width = $max_top / 2;
462      $style->border_bottom_width = $max_bottom / 2;
463      $style->margin = "none";
464    }
465
466    // Resolve the frame's width
467    list($frame_min, $frame_max) = $frame->get_min_max_width();   
468    $width = $style->width;
469   
470    if ( is_percent($width) ) {
471      $var = "percent";
472      $val = (float)rtrim($width, "% ") / $colspan;
473       
474    } else if ( $width !== "auto" ) {
475      $var = "absolute";
476      $val = $style->length_in_pt($frame_min) / $colspan;
477    }
478
479    $min = 0;
480    $max = 0;
481    for ( $cs = 0; $cs < $colspan; $cs++ ) {
482
483      // Resolve the frame's width(s) with other cells
484      $col =& $this->get_column( $this->__col + $cs );
485
486      // Note: $var is either 'percent' or 'absolute'.  We compare the
487      // requested percentage or absolute values with the existing widths
488      // and adjust accordingly.
489      if ( isset($var) && $val > $col[$var] ) {
490        $col[$var] = $val;
491        $col["auto"] = false;
492      }
493
494      $min += $col["min-width"];
495      $max += $col["max-width"];
496    }
497   
498   
499    if ( $frame_min > $min ) {
500      // The frame needs more space.  Expand each sub-column
501      $inc = ($frame_min - $min) / $colspan;
502      for ($c = 0; $c < $colspan; $c++) {
503        $col =& $this->get_column($this->__col + $c);
504        $col["min-width"] += $inc;
505      }       
506    }
507
508    if ( $frame_max > $max ) {
509      $inc = ($frame_max - $max) / $colspan;
510      for ($c = 0; $c < $colspan; $c++) {
511        $col =& $this->get_column($this->__col + $c);
512        $col["max-width"] += $inc;
513      }
514    }
515   
516    $this->__col += $colspan;
517    if ( $this->__col > $this->_num_cols )
518      $this->_num_cols = $this->__col;
519   
520  }
521
522  //........................................................................
523 
524  function add_row() {
525
526    $this->__row++;
527    $this->_num_rows++;
528   
529    // Find the next available column
530    $i = 0;
531    while ( isset($this->_cells[$this->__row][$i]) )
532      $i++;
533   
534    $this->__col = $i;
535   
536  }
537
538  //........................................................................
539
540  /**
541   * Remove a row from the cellmap.
542   *
543   * @param Frame
544   */
545  function remove_row(Frame $row) {
546
547    $key = $row->get_id();
548    if ( !isset($this->_frames[$key]) )
549      return;  // Presumably this row has alredy been removed
550   
551    $this->_row = $this->_num_rows--;
552
553    $rows = $this->_frames[$key]["rows"];
554    $columns = $this->_frames[$key]["columns"];
555
556    // Remove all frames from this row
557    foreach ( $rows as $r ) {
558      foreach ( $columns as $c ) {
559        $frame = $this->_cells[$r][$c];
560        unset($this->_frames[ $frame->get_id() ]);
561        unset($this->_cells[$r][$c]);
562      }
563    }
564
565    unset($this->_frames[$key]);
566
567  }
568
569  /**
570   * Remove a row group from the cellmap.
571   *
572   * @param Frame $group  The group to remove
573   */
574  function remove_row_group(Frame $group) {
575    $key = $group->get_id();
576    if ( !isset($this->_frames[$key]) )
577      return;  // Presumably this row has alredy been removed
578
579    $iter = $group->get_first_child();
580    while ($iter) {
581      $this->remove_row($iter);
582      $iter = $iter->get_next_sibling();
583    }
584     
585    unset($this->_frames[$key]);
586  }
587 
588  /**
589   * Update a row group after rows have been removed
590   *
591   * @param Frame $group    The group to update
592   * @param Frame $last_row The last row in the row group
593   */
594  function update_row_group(Frame $group, Frame $last_row) {
595
596    $g_key = $group->get_id();
597    $r_key = $last_row->get_id();
598
599    $r_rows = $this->_frames[$r_key]["rows"];
600    $this->_frames[$g_key]["rows"] = range( $this->_frames[$g_key]["rows"][0], end($r_rows) );
601   
602  }
603 
604  //........................................................................
605 
606  function assign_x_positions() {
607    // Pre-condition: widths must be resolved and assigned to columns and
608    // column[0]["x"] must be set.
609   
610    $x = $this->_columns[0]["x"];
611    foreach ( array_keys($this->_columns) as $j ) {
612      $this->_columns[$j]["x"] = $x;
613      $x += $this->_columns[$j]["used-width"];
614
615    }
616
617  }
618
619  function assign_frame_heights() {
620    // Pre-condition: widths and heights of each column & row must be
621    // calcluated
622   
623    foreach ( $this->_frames as $arr ) {
624      $frame = $arr["frame"];
625     
626      $h = 0;
627      foreach( $arr["rows"] as $row ) {
628        if ( !isset($this->_rows[$row]) )
629          // The row has been removed because of a page split, so skip it.
630          continue;
631        $h += $this->_rows[$row]["height"];
632      }
633     
634      if ( $frame instanceof Table_Cell_Frame_Decorator )
635        $frame->set_cell_height($h);
636      else
637        $frame->get_style()->height = $h;
638    }
639
640  }
641
642  //........................................................................
643
644  /**
645   * Re-adjust frame height if the table height is larger than its content
646   */
647  function set_frame_heights($table_height, $content_height) {
648
649   
650    // Distribute the increased height proportionally amongst each row
651    foreach ( $this->_frames as $arr ) {
652      $frame = $arr["frame"];
653
654      $h = 0;
655      foreach ($arr["rows"] as $row ) {
656        if ( !isset($this->_rows[$row]) )
657          continue;
658
659        $h += $this->_rows[$row]["height"];
660      }
661     
662      $new_height = ($h / $content_height) * $table_height;
663     
664      if ( $frame instanceof Table_Cell_Frame_Decorator )
665        $frame->set_cell_height($new_height);
666      else
667        $frame->get_style()->height = $new_height;
668    }
669   
670  }
671 
672  //........................................................................
673
674  // Used for debugging:
675  function __toString() {
676    $str = "";
677    $str .= "Columns:<br/>";
678    $str .= pre_r($this->_columns, true);
679    $str .=  "Rows:<br/>";
680    $str .= pre_r($this->_rows, true);
681   
682    $str .=  "Frames:<br/>";
683    $arr = array();
684    foreach ( $this->_frames as $key => $val )
685      $arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]);
686                         
687    $str .= pre_r($arr, true);
688
689    if ( php_sapi_name() == "cli" )
690      $str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
691                                    array("\n",chr(27)."[01;33m", chr(27)."[0m"),
692                                    $str));
693    return $str;
694  }
695}
696?>
Note: See TracBrowser for help on using the repository browser.