1<?php
2// $Header: /cvsroot/html2ps/output._generic.class.php,v 1.17 2007/05/17 13:55:13 Konstantin Exp $
3
4class OutputDriverGeneric extends OutputDriver {
5  var $media;
6  var $bottom;
7  var $left;
8  var $width;
9  var $height;
10
11  var $_watermark;
12
13  // Offset (in device points) of the current page from the first page.
14  // Can be treated as coordinate of the bottom page edge (as first page
15  // will have zero Y value at its bottom).
16  // Note that ir is PAGE edge coordinate, NOT PRINTABLE AREA! If you want to get
17  // the position of the lowest pixel on the page which won't be cut-off, use
18  // $offset+$bottom expression, as $bottom contains bottom white margin size
19  var $offset;
20
21  var $expected_pages;
22  var $current_page;
23
24  var $filename;
25
26  // Properties
27
28  var $debug_boxes;
29  var $show_page_border;
30
31  var $error_message;
32
33  var $_footnote_area_height;
34  var $_footnote_count;
35
36  var $_page_height;
37
38  var $_postponed;
39
40  var $anchors;
41
42  function OutputDriverGeneric() {
43    // Properties setup
44    $this->set_debug_boxes(false);
45    $this->set_filename($this->mk_filename());
46    $this->set_show_page_border(false);
47
48    $this->setFootnoteAreaHeight(0);
49    $this->setFootnoteCount(0);
50
51    $this->_postponed = array();
52
53    $this->anchors = array();
54  }
55
56  function postpone(&$box) {
57    $this->_postponed[] =& $box;
58  }
59
60  function show_postponed() {
61    $size = count($this->_postponed);
62    for ($i=0; $i<$size; $i++) {
63      $box =& $this->_postponed[$i];
64
65      $this->save();
66      $box->_setupClip($this);
67      $box->show_postponed($this, true);
68      $this->restore();
69    };
70  }
71
72  function show_postponed_in_absolute() {
73    $size = count($this->_postponed);
74    for ($i=0; $i<$size; $i++) {
75      $box =& $this->_postponed[$i];
76
77      if ($box->hasAbsolutePositionedParent()) {
78
79        $this->save();
80        $box->_setupClip($this);
81        $box->show_postponed($this, true);
82        $this->restore();
83      };
84    };
85  }
86
87  function show_postponed_in_fixed() {
88    $size = count($this->_postponed);
89    for ($i=0; $i<$size; $i++) {
90      $box =& $this->_postponed[$i];
91
92      if ($box->hasFixedPositionedParent()) {
93        $this->save();
94        $box->_setupClip($this);
95        $box->show_postponed($this, true);
96        $this->restore();
97      };
98    };
99  }
100
101  function next_page($old_page_height) {
102    $this->setFootnoteAreaHeight(0);
103    $this->setFootnoteCount(0);
104    $this->setPageHeight(mm2pt($this->media->real_height()));
105
106    $this->_postponed = array();
107    $this->current_page ++;
108  }
109
110  function setPageHeight($value) {
111    $this->_page_height = $value;
112  }
113
114  function getPageHeight() {
115    return $this->_page_height;
116  }
117
118  function getPageMaxHeight() {
119    return round(mm2pt($this->media->real_height()),2);
120  }
121
122  function getPageWidth() {
123    return round(mm2pt($this->media->real_width()),2);
124  }
125
126  function getPageLeft() {
127    return round(mm2pt($this->media->margins['left']),2);
128  }
129
130  function getPageTop() {
131    return round($this->offset + mm2pt($this->media->height() - $this->media->margins['top']),2);
132  }
133
134  function getPageBottom() {
135    return $this->getPageTop() - $this->getPageHeight();
136  }
137
138  function getFootnoteTop() {
139    return round($this->offset +
140                 mm2pt($this->media->margins['bottom']) +
141                 $this->getFootnoteAreaHeight(),
142                 2);
143  }
144
145  function getFootnoteAreaHeight() {
146    return $this->_footnote_area_height;
147  }
148
149  function setFootnoteAreaHeight($value) {
150    $this->_footnote_area_height = $value;
151  }
152
153  function setFootnoteCount($value) {
154    $this->_footnote_count = $value;
155  }
156
157  function getFootnoteCount() {
158    return $this->_footnote_count;
159  }
160
161  function error_message() {
162    return $this->error_message;
163  }
164
165  /**
166   * Checks if a given box should be drawn on the current page.
167   * Basically, box should be drawn if its top or bottom edge is "inside" the page "viewport"
168   *
169   * @param GenericBox $box Box we're using for check
170   * @return boolean flag indicating of any part of this box should be placed on the current page
171   */
172  function contains(&$box) {
173    return $this->willContain($box, 0);
174  }
175
176  function willContain(&$box, $footnote_height) {
177    /**
178     * These two types of boxes are not visual and
179     * may have incorrect position
180     */
181    if (is_a($box, 'TableSectionBox')) { return true; };
182    if (is_a($box, 'TableRowBox')) { return true; };
183
184    $top    = round($box->get_top(),2);
185    $bottom = round($box->get_bottom(),2);
186
187    $vp_top    = $this->getPageTop();
188    $vp_bottom = max($this->getFootnoteTop() + $footnote_height,
189                     $this->getPageTop() - $this->getPageHeight());
190
191    return ($top > $vp_bottom &&
192            $bottom <= $vp_top);
193  }
194
195  function draw_page_border() {
196    $this->setlinewidth(1);
197    $this->setrgbcolor(0,0,0);
198
199    $this->moveto($this->left, $this->bottom + $this->offset);
200    $this->lineto($this->left, $this->bottom + $this->height + $this->offset);
201    $this->lineto($this->left + $this->width, $this->bottom + $this->height + $this->offset);
202    $this->lineto($this->left + $this->width, $this->bottom + $this->offset);
203    $this->closepath();
204    $this->stroke();
205  }
206
207  function get_expected_pages() {
208    return $this->expected_pages;
209  }
210
211  function mk_filename() {
212    // Check if we can use tempnam to create files (so, we have PHP version
213    // with fixed bug it this function behaviour and open_basedir/environment
214    // variables are not maliciously set to move temporary files out of open_basedir
215    // In general, we'll try to create these files in ./temp subdir of current
216    // directory, but it can be overridden by environment vars both on Windows and
217    // Linux
218    $filename = tempnam(WRITER_TEMPDIR,WRITER_FILE_PREFIX);
219    $filehandle = @fopen($filename, "wb");
220
221    // Now, if we have had any troubles, $filehandle will be
222    if ($filehandle === false) {
223      // Note: that we definitely need to unlink($filename); - tempnam just created it for us!
224      // but we can't ;) because of open_basedir (or whatelse prevents us from opening it)
225
226      // Fallback to some stupid algorithm of filename generation
227      $tries = 0;
228      do {
229        $filename = WRITER_TEMPDIR.DIRECTORY_SEPARATOR.WRITER_FILE_PREFIX.md5(uniqid(rand(), true));
230        // Note: "x"-mode prevents us from re-using existing files
231        // But it require PHP 4.3.2 or later
232        $filehandle = @fopen($filename, "xb");
233        $tries++;
234      } while (!$filehandle && $tries < WRITER_RETRIES);
235    };
236
237    if (!$filehandle) {
238      die(WRITER_CANNOT_CREATE_FILE);
239    };
240
241    // Release this filehandle - we'll reopen it using some gzip wrappers
242    // (if they are available)
243    fclose($filehandle);
244
245    // Remove temporary file we've just created during testing
246    unlink($filename);
247
248    return $filename;
249  }
250
251  function get_filename() {
252    return $this->filename;
253  }
254
255  function &get_font_resolver() {
256    global $g_font_resolver_pdf;
257    return $g_font_resolver_pdf;
258  }
259
260  function is_debug_boxes() {
261    return $this->debug_boxes;
262  }
263
264  function is_show_page_border() {
265    return $this->show_page_border;
266  }
267
268  function rect($x, $y, $w, $h) {
269    $this->moveto($x, $y);
270    $this->lineto($x + $w, $y);
271    $this->lineto($x + $w, $y + $h);
272    $this->lineto($x, $y + $h);
273    $this->closepath();
274  }
275
276  function set_debug_boxes($debug) {
277    $this->debug_boxes = $debug;
278  }
279
280  function set_expected_pages($num) {
281    $this->expected_pages = $num;
282  }
283
284  function set_filename($filename) {
285    $this->filename = $filename;
286  }
287
288  function set_show_page_border($show) {
289    $this->show_page_border = $show;
290  }
291
292  function setup_clip() {
293    if (!$GLOBALS['g_config']['debugnoclip']) {
294      $this->moveto($this->left, $this->bottom + $this->height + $this->offset);
295      $this->lineto($this->left + $this->width, $this->bottom + $this->height + $this->offset);
296      $this->lineto($this->left + $this->width, $this->bottom + $this->height + $this->offset - $this->getPageHeight());
297      $this->lineto($this->left, $this->bottom + $this->height + $this->offset - $this->getPageHeight());
298      $this->clip();
299    };
300  }
301
302  function prepare() {
303  }
304
305  function reset(&$media) {
306    $this->update_media($media);
307    $this->_postponed = array();
308
309    $this->offset =  0;
310    $this->offset_delta = 0;
311    $this->expected_pages = 0;
312    $this->current_page = 0;
313  }
314
315  function &get_media() {
316    return $this->media;
317  }
318
319  function update_media(&$media) {
320    $this->media  =& $media;
321    $this->width  =  mm2pt($media->width() - $media->margins['left'] - $media->margins['right']);
322    $this->height =  mm2pt($media->height() - $media->margins['top'] - $media->margins['bottom']);
323    $this->left   =  mm2pt($media->margins['left']);
324    $this->bottom =  mm2pt($media->margins['bottom']);
325
326    $this->setPageHeight(mm2pt($media->real_height()));
327  }
328}
329?>