Commit | Line | Data |
---|---|---|
7f254ad8 AE |
1 | <?php |
2 | /** | |
3 | * @package dompdf | |
4 | * @link http://dompdf.github.com/ | |
5 | * @author Benj Carson <benjcarson@digitaljunkies.ca> | |
6 | * @author Fabien Ménager <fabien.menager@gmail.com> | |
7 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License | |
8 | */ | |
9 | namespace Dompdf\FrameReflower; | |
10 | ||
11 | use Dompdf\Frame; | |
12 | use Dompdf\FrameDecorator\Block as BlockFrameDecorator; | |
13 | use Dompdf\FrameDecorator\Page as PageFrameDecorator; | |
14 | ||
15 | /** | |
16 | * Reflows pages | |
17 | * | |
18 | * @package dompdf | |
19 | */ | |
20 | class Page extends AbstractFrameReflower | |
21 | { | |
22 | ||
23 | /** | |
24 | * Cache of the callbacks array | |
25 | * | |
26 | * @var array | |
27 | */ | |
28 | private $_callbacks; | |
29 | ||
30 | /** | |
31 | * Cache of the canvas | |
32 | * | |
33 | * @var \Dompdf\Canvas | |
34 | */ | |
35 | private $_canvas; | |
36 | ||
37 | function __construct(PageFrameDecorator $frame) | |
38 | { | |
39 | parent::__construct($frame); | |
40 | } | |
41 | ||
42 | function apply_page_style(Frame $frame, $page_number) | |
43 | { | |
44 | $style = $frame->get_style(); | |
45 | $page_styles = $style->get_stylesheet()->get_page_styles(); | |
46 | ||
47 | // http://www.w3.org/TR/CSS21/page.html#page-selectors | |
48 | if (count($page_styles) > 1) { | |
49 | $odd = $page_number % 2 == 1; | |
50 | $first = $page_number == 1; | |
51 | ||
52 | $style = clone $page_styles["base"]; | |
53 | ||
54 | // FIXME RTL | |
55 | if ($odd && isset($page_styles[":right"])) { | |
56 | $style->merge($page_styles[":right"]); | |
57 | } | |
58 | ||
59 | if ($odd && isset($page_styles[":odd"])) { | |
60 | $style->merge($page_styles[":odd"]); | |
61 | } | |
62 | ||
63 | // FIXME RTL | |
64 | if (!$odd && isset($page_styles[":left"])) { | |
65 | $style->merge($page_styles[":left"]); | |
66 | } | |
67 | ||
68 | if (!$odd && isset($page_styles[":even"])) { | |
69 | $style->merge($page_styles[":even"]); | |
70 | } | |
71 | ||
72 | if ($first && isset($page_styles[":first"])) { | |
73 | $style->merge($page_styles[":first"]); | |
74 | } | |
75 | ||
76 | $frame->set_style($style); | |
77 | } | |
78 | } | |
79 | ||
80 | //........................................................................ | |
81 | ||
82 | /** | |
83 | * Paged layout: | |
84 | * http://www.w3.org/TR/CSS21/page.html | |
85 | */ | |
86 | function reflow(BlockFrameDecorator $block = null) | |
87 | { | |
88 | $fixed_children = array(); | |
89 | $prev_child = null; | |
90 | $child = $this->_frame->get_first_child(); | |
91 | $current_page = 0; | |
92 | ||
93 | while ($child) { | |
94 | $this->apply_page_style($this->_frame, $current_page + 1); | |
95 | ||
96 | $style = $this->_frame->get_style(); | |
97 | ||
98 | // Pages are only concerned with margins | |
99 | $cb = $this->_frame->get_containing_block(); | |
100 | $left = $style->length_in_pt($style->margin_left, $cb["w"]); | |
101 | $right = $style->length_in_pt($style->margin_right, $cb["w"]); | |
102 | $top = $style->length_in_pt($style->margin_top, $cb["h"]); | |
103 | $bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); | |
104 | ||
105 | $content_x = $cb["x"] + $left; | |
106 | $content_y = $cb["y"] + $top; | |
107 | $content_width = $cb["w"] - $left - $right; | |
108 | $content_height = $cb["h"] - $top - $bottom; | |
109 | ||
110 | // Only if it's the first page, we save the nodes with a fixed position | |
111 | if ($current_page == 0) { | |
112 | $children = $child->get_children(); | |
113 | foreach ($children as $onechild) { | |
114 | if ($onechild->get_style()->position === "fixed") { | |
115 | $fixed_children[] = $onechild->deep_copy(); | |
116 | } | |
117 | } | |
118 | $fixed_children = array_reverse($fixed_children); | |
119 | } | |
120 | ||
121 | $child->set_containing_block($content_x, $content_y, $content_width, $content_height); | |
122 | ||
123 | // Check for begin reflow callback | |
124 | $this->_check_callbacks("begin_page_reflow", $child); | |
125 | ||
126 | //Insert a copy of each node which have a fixed position | |
127 | if ($current_page >= 1) { | |
128 | foreach ($fixed_children as $fixed_child) { | |
129 | $child->insert_child_before($fixed_child->deep_copy(), $child->get_first_child()); | |
130 | } | |
131 | } | |
132 | ||
133 | $child->reflow(); | |
134 | $next_child = $child->get_next_sibling(); | |
135 | ||
136 | // Check for begin render callback | |
137 | $this->_check_callbacks("begin_page_render", $child); | |
138 | ||
139 | // Render the page | |
140 | $this->_frame->get_renderer()->render($child); | |
141 | ||
142 | // Check for end render callback | |
143 | $this->_check_callbacks("end_page_render", $child); | |
144 | ||
145 | if ($next_child) { | |
146 | $this->_frame->next_page(); | |
147 | } | |
148 | ||
149 | // Wait to dispose of all frames on the previous page | |
150 | // so callback will have access to them | |
151 | if ($prev_child) { | |
152 | $prev_child->dispose(true); | |
153 | } | |
154 | $prev_child = $child; | |
155 | $child = $next_child; | |
156 | $current_page++; | |
157 | } | |
158 | ||
159 | // Dispose of previous page if it still exists | |
160 | if ($prev_child) { | |
161 | $prev_child->dispose(true); | |
162 | } | |
163 | } | |
164 | ||
165 | //........................................................................ | |
166 | ||
167 | /** | |
168 | * Check for callbacks that need to be performed when a given event | |
169 | * gets triggered on a page | |
170 | * | |
171 | * @param string $event the type of event | |
172 | * @param Frame $frame the frame that event is triggered on | |
173 | */ | |
174 | protected function _check_callbacks($event, $frame) | |
175 | { | |
176 | if (!isset($this->_callbacks)) { | |
177 | $dompdf = $this->_frame->get_dompdf(); | |
178 | $this->_callbacks = $dompdf->get_callbacks(); | |
179 | $this->_canvas = $dompdf->get_canvas(); | |
180 | } | |
181 | ||
182 | if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) { | |
183 | $info = array( | |
184 | 0 => $this->_canvas, "canvas" => $this->_canvas, | |
185 | 1 => $frame, "frame" => $frame, | |
186 | ); | |
187 | $fs = $this->_callbacks[$event]; | |
188 | foreach ($fs as $f) { | |
189 | if (is_callable($f)) { | |
190 | if (is_array($f)) { | |
191 | $f[0]->{$f[1]}($info); | |
192 | } else { | |
193 | $f($info); | |
194 | } | |
195 | } | |
196 | } | |
197 | } | |
198 | } | |
199 | } |