function get_min_max_width() { if (!is_null($this->_min_max_cache)) { return $this->_min_max_cache; } $style = $this->_frame->get_style(); $this->_frame->normalise(); // Add the cells to the cellmap (this will calcluate column widths as // frames are added) $this->_frame->get_cellmap()->add_frame($this->_frame); // Find the min/max width of the table and sort the columns into // absolute/percent/auto arrays $this->_state = array(); $this->_state["min_width"] = 0; $this->_state["max_width"] = 0; $this->_state["percent_used"] = 0; $this->_state["absolute_used"] = 0; $this->_state["auto_min"] = 0; $this->_state["absolute"] = array(); $this->_state["percent"] = array(); $this->_state["auto"] = array(); $columns =& $this->_frame->get_cellmap()->get_columns(); foreach (array_keys($columns) as $i) { $this->_state["min_width"] += $columns[$i]["min-width"]; $this->_state["max_width"] += $columns[$i]["max-width"]; if ($columns[$i]["absolute"] > 0) { $this->_state["absolute"][] = $i; $this->_state["absolute_used"] += $columns[$i]["absolute"]; } else { if ($columns[$i]["percent"] > 0) { $this->_state["percent"][] = $i; $this->_state["percent_used"] += $columns[$i]["percent"]; } else { $this->_state["auto"][] = $i; $this->_state["auto_min"] += $columns[$i]["min-width"]; } } } // Account for margins & padding $dims = array($style->border_left_width, $style->border_right_width, $style->padding_left, $style->padding_right, $style->margin_left, $style->margin_right); if ($style->border_collapse !== "collapse") { list($dims[]) = $style->border_spacing; } $delta = $style->length_in_pt($dims, $this->_frame->get_containing_block("w")); $this->_state["min_width"] += $delta; $this->_state["max_width"] += $delta; return $this->_min_max_cache = array($this->_state["min_width"], $this->_state["max_width"], "min" => $this->_state["min_width"], "max" => $this->_state["max_width"]); }
/** * @param Frame $frame */ public 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, TableFrameDecorator::$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; } $node = $frame->get_node(); // Determine where this cell is going $colspan = $node->getAttribute("colspan"); $rowspan = $node->getAttribute("rowspan"); if (!$colspan) { $colspan = 1; $node->setAttribute("colspan", 1); } if (!$rowspan) { $rowspan = 1; $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"; } if (!$this->_columns_locked) { // Resolve the frame's width if ($this->_fixed_layout) { list($frame_min, $frame_max) = array(0, 1.0E-9); } else { list($frame_min, $frame_max) = $frame->get_min_max_width(); } $width = $style->width; $val = null; if (Helpers::is_percent($width)) { $var = "percent"; $val = (double) 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 // FIXME try to avoid putting this dummy value when table-layout:fixed $inc = $this->is_layout_fixed() ? 1.0E-9 : ($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) { // FIXME try to avoid putting this dummy value when table-layout:fixed $inc = $this->is_layout_fixed() ? 1.0E-9 : ($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; } }