Вход Регистрация
Файл: billing/_rootinc/dompdf/include/cellmap.cls.php
Строк: 437
<?php
/**
 * DOMPDF - PHP5 HTML to PDF renderer
 *
 * File: $RCSfile: cellmap.cls.php,v $
 * Created on: 2004-07-28
 *
 * Copyright (c) 2004 - Benj Carson <benjcarson@digitaljunkies.ca>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library in the file LICENSE.LGPL; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *
 * Alternatively, you may distribute this software under the terms of the
 * PHP License, version 3.0 or later.  A copy of this license should have
 * been distributed with this file in the file LICENSE.PHP .  If this is not
 * the case, you can obtain a copy at http://www.php.net/license/3_0.txt.
 *
 * The latest version of DOMPDF might be available at:
 * http://www.digitaljunkies.ca/dompdf
 *
 * @link http://www.digitaljunkies.ca/dompdf
 * @copyright 2004 Benj Carson
 * @author Benj Carson <benjcarson@digitaljunkies.ca>
 * @package dompdf
 * @version 0.5.1
 */

/* $Id: cellmap.cls.php 185 2009-10-19 22:40:21Z eclecticgeek@gmail.com $ */

/**
 * Maps table cells to the table grid.
 *
 * This class resolves borders in tables with collapsed borders and helps
 * place row & column spanned table cells.
 *
 * @access private
 * @package dompdf
 */
class Cellmap {

  
/**
   * Border style weight lookup for collapsed border resolution.
   *
   * @var array
   */
  
static protected $_BORDER_STYLE_SCORE = array("inset"  => 1,
                                                
"groove" => 2,
                                                
"outset" => 3,
                                                
"ridge"  => 4,
                                                
"dotted" => 5,
                                                
"dashed" => 6,
                                                
"solid"  => 7,
                                                
"double" => 8,
                                                
"none"   => 0);

  
/**
   * The table object this cellmap is attached to.
   *
   * @var Table_Frame_Decorator
   */
  
protected $_table;

  
/**
   * The total number of rows in the table
   *
   * @var int
   */
  
protected $_num_rows;

  
/**
   * The total number of columns in the table
   *
   * @var int
   */
  
protected $_num_cols;

  
/**
   * 2D array mapping <row,column> to frames
   *
   * @var array
   */
  
protected $_cells;

  
/**
   * 1D array of column dimensions
   *
   * @var array
   */
  
protected $_columns;

  
/**
   * 1D array of row dimensions
   *
   * @var array
   */
  
protected $_rows;

  
/**
   * 2D array of border specs
   *
   * @var array
   */
  
protected $_borders;

  
/**
   * 1D Array mapping frames to (multiple) <row, col> pairs, keyed on
   * frame_id.
   *
   * @var array
   */
  
protected $_frames;

  
/**
   * Current column when adding cells, 0-based
   *
   * @var int
   */
  
private $__col;

  
/**
   * Current row when adding cells, 0-based
   *
   * @var int
   */
  
private $__row;

  
//........................................................................

  
function __construct(Table_Frame_Decorator $table) {
    
$this->_table = $table;
    
$this->reset();
  }

  
//........................................................................

  
function reset() {
    
$this->_num_rows = 0;
    
$this->_num_cols = 0;

    
$this->_cells  = array();
    
$this->_frames = array();

    
$this->_columns = array();
    
$this->_rows = array();

    
$this->_borders = array();

    
$this->__col = $this->__row = 0;
  }

  
//........................................................................

  
function get_num_rows() { return $this->_num_rows; }
  function 
get_num_cols() { return $this->_num_cols; }

  function &
get_columns() {
    return 
$this->_columns;
  }

  function &
get_column($i) {
    if ( !isset(
$this->_columns[$i]) )
      
$this->_columns[$i] = array("x" => 0,
                                  
"min-width" => 0,
                                  
"max-width" => 0,
                                  
"used-width" => null,
                                  
"absolute" => 0,
                                  
"percent" => 0,
                                  
"auto" => true);

    return 
$this->_columns[$i];
  }

  function &
get_rows() {
    return 
$this->_rows;
  }

  function &
get_row($j) {
    if ( !isset(
$this->_rows[$j]) )
      
$this->_rows[$j] = array("y" => 0,
                               
"first-column" => 0,
                               
"height" => null);
    return 
$this->_rows[$j];
  }

  function 
get_border($i, $j, $h_v, $prop = null) {
    if ( !isset(
$this->_borders[$i][$j][$h_v]) )
      
$this->_borders[$i][$j][$h_v] = array("width" => 0,
                                           
"style" => "solid",
                                           
"color" => "black");
    if ( isset(
$prop) )
      return 
$this->_borders[$i][$j][$h_v][$prop];

    return 
$this->_borders[$i][$j][$h_v];
  }

  function 
get_border_properties($i, $j) {

    
$left = $this->get_border($i, $j, "vertical");
    
$right = $this->get_border($i, $j+1, "vertical");
    
$top = $this->get_border($i, $j, "horizontal");
    
$bottom = $this->get_border($i+1, $j, "horizontal");

    return 
compact("top", "bottom", "left", "right");
  }

  
//........................................................................

  
function get_spanned_cells($frame) {
    
$key = $frame->get_id();

    if ( !isset(
$this->_frames[$key]) ) {
      throw new 
DOMPDF_Internal_Exception("Frame not found in cellmap");
    }

    return 
$this->_frames[$key];

  }

  function 
frame_exists_in_cellmap($frame) {
    
$key = $frame->get_id();
    return isset(
$this->_frames[$key]);
  }
  
  function 
get_frame_position($frame) {
    global 
$_dompdf_warnings;

    
$key = $frame->get_id();

    if ( !isset(
$this->_frames[$key]) ) {
      throw new 
DOMPDF_Internal_Exception("Frame not found in cellmap");
    }

    
$col = $this->_frames[$key]["columns"][0];
    
$row = $this->_frames[$key]["rows"][0];

    if ( !isset(
$this->_columns[$col])) {
      
$_dompdf_warnings[] = "Frame not found in columns array.  Check your table layout for missing or extra TDs.";
      
$x = 0;
    } else
      
$x = $this->_columns[$col]["x"];

    if ( !isset(
$this->_rows[$row])) {
      
$_dompdf_warnings[] = "Frame not found in row array.  Check your table layout for missing or extra TDs.";
      
$y = 0;
    } else
      
$y = $this->_rows[$row]["y"];

    return array(
$x, $y, "x" => $x, "y" => $y);
  }

  function 
get_frame_width($frame) {
    
$key = $frame->get_id();

    if ( !isset(
$this->_frames[$key]) ) {
      throw new 
DOMPDF_Internal_Exception("Frame not found in cellmap");
    }

    
$cols = $this->_frames[$key]["columns"];
    
$w = 0;
    foreach (
$cols as $i)
      
$w += $this->_columns[$i]["used-width"];

    return 
$w;

  }

  function 
get_frame_height($frame) {
    
$key = $frame->get_id();

    if ( !isset(
$this->_frames[$key]) )
      throw new 
DOMPDF_Internal_Exception("Frame not found in cellmap");

    
$rows = $this->_frames[$key]["rows"];
    
$h = 0;
    foreach (
$rows as $i) {
      if ( !isset(
$this->_rows[$i]) )  {
        throw new 
Exception("foo");
      }
      
$h += $this->_rows[$i]["height"];
    }
    return 
$h;

  }


  
//........................................................................

  
function set_column_width($j, $width) {
    
$col =& $this->get_column($j);
    
$col["used-width"] = $width;
    
$next_col =& $this->get_column($j+1);
    
$next_col["x"] = $next_col["x"] + $width;
  }

  function 
set_row_height($i, $height) {
    
$row =& $this->get_row($i);
    if ( 
$height <= $row["height"] )
      return;

    
$row["height"] = $height;
    
$next_row =& $this->get_row($i+1);
    
$next_row["y"] = $row["y"] + $height;

  }

  
//........................................................................


  
protected function _resolve_border($i, $j, $h_v, $border_spec) {
    
$n_width = $border_spec["width"];
    
$n_style = $border_spec["style"];
    
$n_color = $border_spec["color"];

    if ( !isset(
$this->_borders[$i][$j][$h_v]) ) {
      
$this->_borders[$i][$j][$h_v] = $border_spec;
      return 
$this->_borders[$i][$j][$h_v]["width"];
    }

    
$o_width = $this->_borders[$i][$j][$h_v]["width"];
    
$o_style = $this->_borders[$i][$j][$h_v]["style"];
    
$o_color = $this->_borders[$i][$j][$h_v]["color"];

    if ( (
$n_style === "hidden" ||
          
$n_width  >  $o_width ||
          
$o_style === "none")

         or

         (
$o_width == $n_width &&
          
in_array($n_style, self::$_BORDER_STYLE_SCORE) &&
          
self::$_BORDER_STYLE_SCORE[ $n_style ] > self::$_BORDER_STYLE_SCORE[ $o_style ]) )
      
$this->_borders[$i][$j][$h_v] = $border_spec;

    return 
$this->_borders[$i][$j][$h_v]["width"];
  }

  
//........................................................................

  
function add_frame(Frame $frame) {
    
    
$style = $frame->get_style();
    
$display = $style->display;

    
$collapse = $this->_table->get_style()->border_collapse == "collapse";

    
// Recursively add the frames within tables, table-row-groups and table-rows
    
if ( $display == "table-row" ||
         
$display == "table" ||
         
$display == "inline-table" ||
         
in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) {

      
$start_row = $this->__row;
      foreach ( 
$frame->get_children() as $child )
        
$this->add_frame( $child );

      if ( 
$display == "table-row" )
        
$this->add_row();

      
$num_rows = $this->__row - $start_row - 1;
      
$key = $frame->get_id();

      
// Row groups always span across the entire table
      
$this->_frames[ $key ]["columns"] = range(0,max(0,$this->_num_cols-1));
      
$this->_frames[ $key ]["rows"] = range($start_row, max(0, $this->__row - 1));
      
$this->_frames[ $key ]["frame"] = $frame;

      if ( 
$display != "table-row" && $collapse ) {

        
$bp = $style->get_border_properties();

        
// Resolve the borders
        
for ( $i = 0; $i < $num_rows+1; $i++) {
          
$this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
          
$this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
        }

        for ( 
$j = 0; $j < $this->_num_cols; $j++) {
          
$this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
          
$this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
        }
      }


      return;
    }

    
// Determine where this cell is going
    
$colspan = $frame->get_node()->getAttribute("colspan");
    
$rowspan = $frame->get_node()->getAttribute("rowspan");

    if ( !
$colspan ) {
      
$colspan = 1;
      
$frame->get_node()->setAttribute("colspan",1);
    }

    if ( !
$rowspan ) {
      
$rowspan = 1;
      
$frame->get_node()->setAttribute("rowspan",1);
    }
    
$key = $frame->get_id();

    
$bp = $style->get_border_properties();


    
// Add the frame to the cellmap
    
$max_left = $max_right = 0;

    
// Find the next available column (fix by Ciro Mondueri)
    
$ac = $this->__col;
    while ( isset(
$this->_cells[$this->__row][$ac]) )
       
$ac++;
    
$this->__col = $ac;

    
// Rows:
    
for ( $i = 0; $i < $rowspan; $i++ ) {
      
$row = $this->__row + $i;

      
$this->_frames[ $key ]["rows"][] = $row;

      for ( 
$j = 0; $j < $colspan; $j++)
        
$this->_cells[$row][$this->__col + $j] = $frame;

      if ( 
$collapse ) {
        
// Resolve vertical borders
        
$max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
        
$max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
      }
    }

    
$max_top = $max_bottom = 0;

    
// Columns:
    
for ( $j = 0; $j < $colspan; $j++ ) {
      
$col = $this->__col + $j;
      
$this->_frames[ $key ]["columns"][] = $col;

      if ( 
$collapse ) {
        
// Resolve horizontal borders
        
$max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
        
$max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
      }
    }

    
$this->_frames[ $key ]["frame"] = $frame;

    
// Handle seperated border model
    
if ( !$collapse ) {
      list(
$h, $v) = $this->_table->get_style()->border_spacing;

      
// Border spacing is effectively a margin between cells
      
$v = $style->length_in_pt($v) / 2;
      
$h = $style->length_in_pt($h) / 2;
      
$style->margin = "$v $h";

      
// The additional 1/2 width gets added to the table proper

    
} else {

      
// Drop the frame's actual border
      
$style->border_left_width = $max_left / 2;
      
$style->border_right_width = $max_right / 2;
      
$style->border_top_width = $max_top / 2;
      
$style->border_bottom_width = $max_bottom / 2;
      
$style->margin = "none";
    }

    
// Resolve the frame's width
    
list($frame_min, $frame_max) = $frame->get_min_max_width();

    
$width = $style->width;

    if ( 
is_percent($width) ) {
      
$var = "percent";
      
$val = (float)rtrim($width, "% ") / $colspan;

    } else if ( 
$width !== "auto" ) {
      
$var = "absolute";
      
$val = $style->length_in_pt($frame_min) / $colspan;
    }

    
$min = 0;
    
$max = 0;
    for ( 
$cs = 0; $cs < $colspan; $cs++ ) {

      
// Resolve the frame's width(s) with other cells
      
$col =& $this->get_column( $this->__col + $cs );

      
// Note: $var is either 'percent' or 'absolute'.  We compare the
      // requested percentage or absolute values with the existing widths
      // and adjust accordingly.
      
if ( isset($var) && $val > $col[$var] ) {
        
$col[$var] = $val;
        
$col["auto"] = false;
      }

      
$min += $col["min-width"];
      
$max += $col["max-width"];
    }


    if ( 
$frame_min > $min ) {
      
// The frame needs more space.  Expand each sub-column
      
$inc = ($frame_min - $min) / $colspan;
      for (
$c = 0; $c < $colspan; $c++) {
        
$col =& $this->get_column($this->__col + $c);
        
$col["min-width"] += $inc;
      }
    }

    if ( 
$frame_max > $max ) {
      
$inc = ($frame_max - $max) / $colspan;
      for (
$c = 0; $c < $colspan; $c++) {
        
$col =& $this->get_column($this->__col + $c);
        
$col["max-width"] += $inc;
      }
    }

    
$this->__col += $colspan;
    if ( 
$this->__col > $this->_num_cols )
      
$this->_num_cols = $this->__col;

  }

  
//........................................................................

  
function add_row() {

    
$this->__row++;
    
$this->_num_rows++;

    
// Find the next available column
    
$i = 0;
    while ( isset(
$this->_cells[$this->__row][$i]) )
      
$i++;

    
$this->__col = $i;

  }

  
//........................................................................

  /**
   * Remove a row from the cellmap.
   *
   * @param Frame
   */
  
function remove_row(Frame $row) {

    
$key = $row->get_id();
    if ( !isset(
$this->_frames[$key]) )
      return;  
// Presumably this row has alredy been removed

    
$this->_row = $this->_num_rows--;

    
$rows = $this->_frames[$key]["rows"];
    
$columns = $this->_frames[$key]["columns"];

    
// Remove all frames from this row
    
foreach ( $rows as $r ) {
      foreach ( 
$columns as $c ) {
        if ( isset(
$this->_cells[$r][$c]) ) {
          
$frame = $this->_cells[$r][$c];
          unset(
$this->_frames[ $frame->get_id() ]);
          unset(
$this->_cells[$r][$c]);
        }
      }
      unset(
$this->_rows[$r]);
    }

    unset(
$this->_frames[$key]);

  }

  
/**
   * Remove a row group from the cellmap.
   *
   * @param Frame $group  The group to remove
   */
  
function remove_row_group(Frame $group) {

    
$key = $group->get_id();
    if ( !isset(
$this->_frames[$key]) )
      return;  
// Presumably this row has alredy been removed

    
$iter = $group->get_first_child();
    while (
$iter) {
      
$this->remove_row($iter);
      
$iter = $iter->get_next_sibling();
    }

    unset(
$this->_frames[$key]);
  }

  
/**
   * Update a row group after rows have been removed
   *
   * @param Frame $group    The group to update
   * @param Frame $last_row The last row in the row group
   */
  
function update_row_group(Frame $group, Frame $last_row) {

    
$g_key = $group->get_id();
    
$r_key = $last_row->get_id();

    
$r_rows = $this->_frames[$r_key]["rows"];
    
$this->_frames[$g_key]["rows"] = range( $this->_frames[$g_key]["rows"][0], end($r_rows) );

  }

  
//........................................................................

  
function assign_x_positions() {
    
// Pre-condition: widths must be resolved and assigned to columns and
    // column[0]["x"] must be set.

    
$x = $this->_columns[0]["x"];
    foreach ( 
array_keys($this->_columns) as $j ) {
      
$this->_columns[$j]["x"] = $x;
      
$x += $this->_columns[$j]["used-width"];

    }

  }

  function 
assign_frame_heights() {
    
// Pre-condition: widths and heights of each column & row must be
    // calcluated

    
foreach ( $this->_frames as $arr ) {
      
$frame = $arr["frame"];

      
$h = 0;
      foreach( 
$arr["rows"] as $row ) {
        if ( !isset(
$this->_rows[$row]) )
          
// The row has been removed because of a page split, so skip it.
          
continue;
        
$h += $this->_rows[$row]["height"];
      }

      if ( 
$frame instanceof Table_Cell_Frame_Decorator )
        
$frame->set_cell_height($h);
      else
        
$frame->get_style()->height = $h;
    }

  }

  
//........................................................................

  /**
   * Re-adjust frame height if the table height is larger than its content
   */
  
function set_frame_heights($table_height, $content_height) {


    
// Distribute the increased height proportionally amongst each row
    
foreach ( $this->_frames as $arr ) {
      
$frame = $arr["frame"];

      
$h = 0;
      foreach (
$arr["rows"] as $row ) {
        if ( !isset(
$this->_rows[$row]) )
          continue;

        
$h += $this->_rows[$row]["height"];
      }

      
$new_height = ($h / $content_height) * $table_height;

      if ( 
$frame instanceof Table_Cell_Frame_Decorator )
        
$frame->set_cell_height($new_height);
      else
        
$frame->get_style()->height = $new_height;
    }

  }

  
//........................................................................

  // Used for debugging:
  
function __toString() {
    
$str = "";
    
$str .= "Columns:<br/>";
    
$str .= pre_r($this->_columns, true);
    
$str .=  "Rows:<br/>";
    
$str .= pre_r($this->_rows, true);

    
$str .=  "Frames:<br/>";
    
$arr = array();
    foreach ( 
$this->_frames as $key => $val )
      
$arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]);

    
$str .= pre_r($arr, true);

    if ( 
php_sapi_name() == "cli" )
      
$str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
                                    array(
"n",chr(27)."[01;33m", chr(27)."[0m"),
                                    
$str));
    return 
$str;
  }
}
?>
Онлайн: 3
Реклама