| 1 |
<?php |
| 2 |
/** |
| 3 |
* @package dompdf |
| 4 |
* @link https://github.com/dompdf/dompdf |
| 5 |
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License |
| 6 |
*/ |
| 7 |
namespace Dompdf\FrameReflower; |
| 8 |
|
| 9 |
use Dompdf\FrameDecorator\Block as BlockFrameDecorator; |
| 10 |
use Dompdf\FrameDecorator\Table as TableFrameDecorator; |
| 11 |
use Dompdf\Helpers; |
| 12 |
|
| 13 |
/** |
| 14 |
* Reflows table cells |
| 15 |
* |
| 16 |
* @package dompdf |
| 17 |
*/ |
| 18 |
class TableCell extends Block |
| 19 |
{ |
| 20 |
/** |
| 21 |
* TableCell constructor. |
| 22 |
* @param BlockFrameDecorator $frame |
| 23 |
*/ |
| 24 |
function __construct(BlockFrameDecorator $frame) |
| 25 |
{ |
| 26 |
parent::__construct($frame); |
| 27 |
} |
| 28 |
|
| 29 |
/** |
| 30 |
* @param BlockFrameDecorator|null $block |
| 31 |
*/ |
| 32 |
function reflow(BlockFrameDecorator $block = null) |
| 33 |
{ |
| 34 |
// Counters and generated content |
| 35 |
$this->_set_content(); |
| 36 |
|
| 37 |
$style = $this->_frame->get_style(); |
| 38 |
|
| 39 |
$table = TableFrameDecorator::find_parent_table($this->_frame); |
| 40 |
$cellmap = $table->get_cellmap(); |
| 41 |
|
| 42 |
list($x, $y) = $cellmap->get_frame_position($this->_frame); |
| 43 |
$this->_frame->set_position($x, $y); |
| 44 |
|
| 45 |
$cells = $cellmap->get_spanned_cells($this->_frame); |
| 46 |
|
| 47 |
$w = 0; |
| 48 |
foreach ($cells["columns"] as $i) { |
| 49 |
$col = $cellmap->get_column($i); |
| 50 |
$w += $col["used-width"]; |
| 51 |
} |
| 52 |
|
| 53 |
//FIXME? |
| 54 |
$h = $this->_frame->get_containing_block("h"); |
| 55 |
|
| 56 |
$left_space = (float)$style->length_in_pt([$style->margin_left, |
| 57 |
$style->padding_left, |
| 58 |
$style->border_left_width], |
| 59 |
$w); |
| 60 |
|
| 61 |
$right_space = (float)$style->length_in_pt([$style->padding_right, |
| 62 |
$style->margin_right, |
| 63 |
$style->border_right_width], |
| 64 |
$w); |
| 65 |
|
| 66 |
$top_space = (float)$style->length_in_pt([$style->margin_top, |
| 67 |
$style->padding_top, |
| 68 |
$style->border_top_width], |
| 69 |
$h); |
| 70 |
$bottom_space = (float)$style->length_in_pt([$style->margin_bottom, |
| 71 |
$style->padding_bottom, |
| 72 |
$style->border_bottom_width], |
| 73 |
$h); |
| 74 |
|
| 75 |
$cb_w = $w - $left_space - $right_space; |
| 76 |
$style->set_used("width", $cb_w); |
| 77 |
|
| 78 |
$content_x = $x + $left_space; |
| 79 |
$content_y = $line_y = $y + $top_space; |
| 80 |
|
| 81 |
// Adjust the first line based on the text-indent property |
| 82 |
$indent = (float)$style->length_in_pt($style->text_indent, $w); |
| 83 |
$this->_frame->increase_line_width($indent); |
| 84 |
|
| 85 |
$page = $this->_frame->get_root(); |
| 86 |
|
| 87 |
// Set the y position of the first line in the cell |
| 88 |
$line_box = $this->_frame->get_current_line_box(); |
| 89 |
$line_box->y = $line_y; |
| 90 |
|
| 91 |
// Set the containing blocks and reflow each child |
| 92 |
foreach ($this->_frame->get_children() as $child) { |
| 93 |
$child->set_containing_block($content_x, $content_y, $cb_w, $h); |
| 94 |
$this->process_clear($child); |
| 95 |
$child->reflow($this->_frame); |
| 96 |
$this->process_float($child, $content_x, $cb_w); |
| 97 |
|
| 98 |
if ($page->is_full()) { |
| 99 |
break; |
| 100 |
} |
| 101 |
} |
| 102 |
|
| 103 |
// Determine our height |
| 104 |
$style_height = (float)$style->length_in_pt($style->height, $h); |
| 105 |
|
| 106 |
/** @var FrameDecorator\TableCell */ |
| 107 |
$frame = $this->_frame; |
| 108 |
|
| 109 |
$frame->set_content_height($this->_calculate_content_height()); |
| 110 |
|
| 111 |
$height = max($style_height, (float)$frame->get_content_height()); |
| 112 |
|
| 113 |
// Let the cellmap know our height |
| 114 |
$cell_height = $height / count($cells["rows"]); |
| 115 |
|
| 116 |
if ($style_height <= $height) { |
| 117 |
$cell_height += $top_space + $bottom_space; |
| 118 |
} |
| 119 |
|
| 120 |
foreach ($cells["rows"] as $i) { |
| 121 |
$cellmap->set_row_height($i, $cell_height); |
| 122 |
} |
| 123 |
|
| 124 |
$style->set_used("height", $height); |
| 125 |
|
| 126 |
$this->_text_align(); |
| 127 |
$this->vertical_align(); |
| 128 |
|
| 129 |
// Handle relative positioning |
| 130 |
foreach ($this->_frame->get_children() as $child) { |
| 131 |
$this->position_relative($child); |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
public function get_min_max_content_width(): array |
| 136 |
{ |
| 137 |
// Ignore percentage values for a specified width here, as they are |
| 138 |
// relative to the table width, which is not determined yet |
| 139 |
$style = $this->_frame->get_style(); |
| 140 |
$width = $style->width; |
| 141 |
$fixed_width = $width !== "auto" && !Helpers::is_percent($width); |
| 142 |
|
| 143 |
[$min, $max] = $this->get_min_max_child_width(); |
| 144 |
|
| 145 |
// For table cells: Use specified width if it is greater than the |
| 146 |
// minimum defined by the content |
| 147 |
if ($fixed_width) { |
| 148 |
$width = (float) $style->length_in_pt($width, 0); |
| 149 |
$min = max($width, $min); |
| 150 |
$max = $min; |
| 151 |
} |
| 152 |
|
| 153 |
// Handle min/max width style properties |
| 154 |
$min_width = $this->resolve_min_width(null); |
| 155 |
$max_width = $this->resolve_max_width(null); |
| 156 |
$min = Helpers::clamp($min, $min_width, $max_width); |
| 157 |
$max = Helpers::clamp($max, $min_width, $max_width); |
| 158 |
|
| 159 |
return [$min, $max]; |
| 160 |
} |
| 161 |
} |
| 162 |
|