source: sandbox/filemanager/tp/dompdf/include/frame.cls.php @ 1575

Revision 1575, 21.9 KB checked in by amuller, 15 years ago (diff)

Ticket #597 - Implentação, melhorias do modulo gerenciador de arquivos

Line 
1<?php
2/**
3 * DOMPDF - PHP5 HTML to PDF renderer
4 *
5 * File: $RCSfile: frame.cls.php,v $
6 * Created on: 2004-06-02
7 *
8 * Copyright (c) 2004 - Benj Carson <benjcarson@digitaljunkies.ca>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library in the file LICENSE.LGPL; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA
24 *
25 * Alternatively, you may distribute this software under the terms of the
26 * PHP License, version 3.0 or later.  A copy of this license should have
27 * been distributed with this file in the file LICENSE.PHP .  If this is not
28 * the case, you can obtain a copy at http://www.php.net/license/3_0.txt.
29 *
30 * The latest version of DOMPDF might be available at:
31 * http://www.digitaljunkies.ca/dompdf
32 *
33 * @link http://www.digitaljunkies.ca/dompdf
34 * @copyright 2004 Benj Carson
35 * @author Benj Carson <benjcarson@digitaljunkies.ca>
36 * @package dompdf
37 * @version 0.5.1
38 */
39
40/* $Id: frame.cls.php,v 1.11 2006/07/07 21:31:03 benjcarson Exp $ */
41
42/**
43 * The main Frame class
44 *
45 * This class represents a single HTML element.  This class stores
46 * positioning information as well as containing block location and
47 * dimensions. Style information for the element is stored in a {@link
48 * Style} object.  Tree structure is maintained via the parent & children
49 * links.
50 *
51 * @access protected
52 * @package dompdf
53 */
54class Frame {
55 
56  /**
57   * The DOMNode object this frame represents
58   *
59   * @var DOMNode
60   */
61  protected $_node;
62
63  /**
64   * Unique identifier for this frame.  Used to reference this frame
65   * via the node.
66   *
67   * @var string
68   */
69  protected $_id;
70
71  /**
72   * This frame's calculated style
73   *
74   * @var Style
75   */
76  protected $_style;
77
78  /**
79   * This frame's original style.  Needed for cases where frames are
80   * split across pages.
81   *
82   * @var Style
83   */
84  protected $_original_style;
85 
86  /**
87   * This frame's parent in the document tree.
88   *
89   * @var Frame
90   */
91  protected $_parent;
92
93  /**
94   * This frame's first child.  All children are handled as a
95   * doubly-linked list.
96   *
97   * @var Frame
98   */
99  protected $_first_child;
100
101  /**
102   * This frame's last child.
103   *
104   * @var Frame
105   */
106  protected $_last_child;
107
108  /**
109   * This frame's previous sibling in the document tree.
110   *
111   * @var Frame
112   */
113  protected $_prev_sibling;
114
115  /**
116   * This frame's next sibling in the document tree.
117   *
118   * @var Frame
119   */
120  protected $_next_sibling;
121 
122  /**
123   * This frame's containing block (used in layout): array(x, y, w, h)
124   *
125   * @var array
126   */
127  protected $_containing_block;
128
129  /**
130   * Position on the page of the top-left corner of the margin box of
131   * this frame: array(x,y)
132   *
133   * @var array
134   */
135  protected $_position;
136
137  /**
138   * This frame's decorator
139   *
140   * @var Frame_Decorator
141   */
142  protected $_decorator;
143   
144  /**
145   * Class constructor
146   *
147   * @param DOMNode $node the DOMNode this frame represents
148   */
149  function __construct(DomNode $node) {
150    $this->_node = $node;
151     
152    $this->_parent = null;
153    $this->_first_child = null;
154    $this->_last_child = null;
155    $this->_prev_sibling = $this->_next_sibling = null;
156   
157    $this->_style = null;
158    $this->_original_style = null;
159   
160    $this->_containing_block = array("x" => null,
161                                     "y" => null,
162                                     "w" => null,
163                                     "h" => null);
164    $this->_position = array("x" => null,
165                             "y" => null);
166
167    $this->_decorator = null;
168
169    $this->set_id( uniqid(rand()) );
170  }
171
172  /**
173   * "Destructor": forcibly free all references held by this frame
174   *
175   * @param bool $recursive if true, call dispose on all children
176   */
177  function dispose($recursive = false) {
178
179    if ( $recursive ) {
180      while ( $child = $this->_first_child )
181        $child->dispose(true);
182    }
183
184    // Remove this frame from the tree
185    if ( $this->_prev_sibling ) {
186      $this->_prev_sibling->_next_sibling = $this->_next_sibling;     
187    }
188
189    if ( $this->_next_sibling ) {
190      $this->_next_sibling->_prev_sibling = $this->_prev_sibling;
191    }
192
193    if ( $this->_parent && $this->_parent->_first_child === $this ) {
194      $this->_parent->_first_child = $this->_next_sibling;
195    }
196
197    if ( $this->_parent && $this->_parent->_last_child === $this ) {
198      $this->_parent->_last_child = $this->_prev_sibling;
199    }
200
201    if ( $this->_parent ) {
202      $this->_parent->get_node()->removeChild($this->_node);
203    }
204
205    $this->_style->dispose();
206    unset($this->_style);
207    $this->_original_style->dispose();
208    unset($this->_original_style);
209   
210  }
211
212  // Re-initialize the frame
213  function reset() {
214    $this->_position = array("x" => null,
215                             "y" => null);
216    $this->_containing_block = array("x" => null,
217                                     "y" => null,
218                                     "w" => null,
219                                     "h" => null);
220
221    unset($this->_style);   
222    $this->_style = clone $this->_original_style;
223   
224  }
225 
226  //........................................................................
227
228  // Accessor methods
229  function get_node() { return $this->_node; }
230  function get_id() { return $this->_id; }
231  function get_style() { return $this->_style; }
232  function get_original_style() { return $this->_original_style; }
233  function get_parent() { return $this->_parent; }
234  function get_decorator() { return $this->_decorator; }
235  function get_first_child() { return $this->_first_child; }
236  function get_last_child() { return $this->_last_child; }
237  function get_prev_sibling() { return $this->_prev_sibling; }
238  function get_next_sibling() { return $this->_next_sibling; }
239
240  function get_children() { return new FrameList($this); }
241 
242  // Layout property accessors
243  function get_containing_block($i = null) {
244    if ( isset($i) )
245      return $this->_containing_block[$i];   
246    return $this->_containing_block;
247  }
248 
249  function get_position($i = null) {
250    if ( isset($i) )
251      return $this->_position[$i];
252    return array($this->_position["x"],
253                 $this->_position["y"],
254                 "x"=>$this->_position["x"],
255                 "y"=>$this->_position["y"]);
256  }
257   
258  //........................................................................
259
260  // Return the height of the margin box of the frame, in pt.  Meaningless
261  // unless the height has been calculated properly.
262  function get_margin_height() {     
263    return $this->_style->length_in_pt(array($this->_style->height,
264                                             $this->_style->margin_top,
265                                             $this->_style->margin_bottom,
266                                             $this->_style->border_top_width,
267                                             $this->_style->border_bottom_width,
268                                             $this->_style->padding_top,
269                                             $this->_style->padding_bottom),
270                                       $this->_containing_block["w"]);
271  }
272
273  // Return the width of the margin box of the frame, in pt.  Meaningless
274  // unless the width has been calculted properly.
275  function get_margin_width() {
276    return $this->_style->length_in_pt(array($this->_style->width,
277                                     $this->_style->margin_left,
278                                     $this->_style->margin_right,
279                                     $this->_style->border_left_width,
280                                     $this->_style->border_right_width,
281                                     $this->_style->padding_left,
282                                     $this->_style->padding_right),
283                               $this->_containing_block["w"]);
284  }
285
286  // Return the padding box (x,y,w,h) of the frame
287  function get_padding_box() {
288    $x = $this->_position["x"] +
289      $this->_style->length_in_pt(array($this->_style->margin_left,
290                                $this->_style->border_left_width),
291                          $this->_containing_block["w"]);
292    $y = $this->_position["y"] +
293      $this->_style->length_in_pt(array($this->_style->margin_top,
294                                $this->_style->border_top_width),
295                          $this->_containing_block["w"]);
296   
297    $w = $this->_style->length_in_pt(array($this->_style->padding_left,
298                                   $this->_style->width,
299                                   $this->_style->padding_right),
300                             $this->_containing_block["w"]);
301
302    $h = $this->_style->length_in_pt(array($this->_style->padding_top,
303                                   $this->_style->height,
304                                   $this->_style->padding_bottom),
305                             $this->_containing_block["w"]);
306
307    return array(0 => $x, "x" => $x,
308                 1 => $y, "y" => $y,
309                 2 => $w, "w" => $w,
310                 3 => $h, "h" => $h);
311  }
312
313  // Return the border box of the frame
314  function get_border_box() {
315    $x = $this->_position["x"] +
316      $this->_style->length_in_pt($this->_style->margin_left,
317                          $this->_containing_block["w"]);
318    $y = $this->_position["y"] +
319      $this->_style->length_in_pt($this->_style->margin_top,
320                          $this->_containing_block["w"]);
321
322    $w = $this->_style->length_in_pt(array($this->_style->border_left_width,
323                                   $this->_style->padding_left,
324                                   $this->_style->width,
325                                   $this->_style->padding_right,
326                                   $this->_style->border_right_width),
327                             $this->_containing_block["w"]);
328
329    $h = $this->_style->length_in_pt(array($this->_style->border_top_width,
330                                   $this->_style->padding_top,
331                                   $this->_style->height,
332                                   $this->_style->padding_bottom,
333                                   $this->_style->border_bottom_width),
334                             $this->_containing_block["w"]);
335
336    return array(0 => $x, "x" => $x,
337                 1 => $y, "y" => $y,
338                 2 => $w, "w" => $w,
339                 3 => $h, "h" => $h);
340   
341  }
342 
343  //........................................................................
344
345  // Set methods
346  function set_id($id) {
347    $this->_id = $id;
348
349    // We can only set attributes of DOMElement objects (nodeType == 1).
350    // Since these are the only objects that we can assign CSS rules to,
351    // this shortcoming is okay.
352    if ( $this->_node->nodeType == 1)
353      $this->_node->setAttribute("frame_id", $id);
354  }
355
356  function set_style(Style $style) {
357    if ( is_null($this->_style) )
358      $this->_original_style = clone $style;
359   
360    $this->_style = $style;
361  }
362 
363  function set_decorator(Frame_Decorator $decorator) {
364    $this->_decorator = $decorator;
365  }
366 
367  function set_containing_block($x = null, $y = null, $w = null, $h = null) {
368    if ( is_array($x) )
369      extract($x);
370   
371    if (is_numeric($x)) {
372      $this->_containing_block[0] = $x;
373      $this->_containing_block["x"] = $x;
374    }
375   
376    if (is_numeric($y)) {
377      $this->_containing_block[1] = $y;
378      $this->_containing_block["y"] = $y;
379    }
380   
381    if (is_numeric($w)) {
382      $this->_containing_block[2] = $w;
383      $this->_containing_block["w"] = $w;
384    }
385   
386    if (is_numeric($h)) {
387      $this->_containing_block[3] = $h;
388      $this->_containing_block["h"] = $h;
389    }
390   
391  }
392
393  function set_position($x = null, $y = null) {
394    if ( is_array($x) )
395      extract($x);
396   
397    if ( is_numeric($x) ) {
398      $this->_position[0] = $x;
399      $this->_position["x"] = $x;
400    }
401
402    if ( is_numeric($y) ) {
403      $this->_position[1] = $y;
404      $this->_position["y"] = $y;
405    }
406  }
407
408  //........................................................................
409
410  function prepend_child(Frame $child, $update_node = true) {
411
412    if ( $update_node )
413      $this->_node->insertBefore($child->_node, $this->_first_child ? $this->_first_child->_node : null);
414
415    // Remove the child from its parent
416    if ( $child->_parent )
417      $child->_parent->remove_child($child, false);
418   
419    $child->_parent = $this;
420    $child->_prev_sibling = null;
421   
422    // Handle the first child
423    if ( !$this->_first_child ) {
424      $this->_first_child = $child;
425      $this->_last_child = $child;
426      $child->_next_sibling = null;
427     
428    } else {
429
430      $this->_first_child->_prev_sibling = $child;
431      $child->_next_sibling = $this->_first_child;     
432      $this->_first_child = $child;
433     
434    }
435  }
436 
437  function append_child(Frame $child, $update_node = true) {
438
439    if ( $update_node )
440      $this->_node->appendChild($child->_node);
441
442    // Remove the child from its parent
443    if ( $child->_parent )
444      $child->_parent->remove_child($child, false);
445
446    $child->_parent = $this;
447    $child->_next_sibling = null;
448   
449    // Handle the first child
450    if ( !$this->_last_child ) {
451      $this->_first_child = $child;
452      $this->_last_child = $child;
453      $child->_prev_sibling = null;
454     
455    } else {
456
457      $this->_last_child->_next_sibling = $child;
458      $child->_prev_sibling = $this->_last_child;
459      $this->_last_child = $child;
460
461    }
462  } 
463
464  // Inserts a new child immediately before the specified frame
465  function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) {
466
467    if ( $ref === $this->_first_child ) {
468      $this->prepend_child($new_child, $update_node);
469      return;
470    }
471
472    if ( is_null($ref) ) {
473      $this->append_child($new_child, $update_node);
474      return;
475    }
476   
477    if ( $ref->_parent !== $this )
478      throw new DOMPDF_Exception("Reference child is not a child of this node.");
479
480    // Update the node   
481    if ( $update_node )
482      $this->_node->insertBefore($new_child->_node, $ref->_node);
483
484    // Remove the child from its parent
485    if ( $new_child->_parent )
486      $new_child->_parent->remove_child($new_child, false);
487   
488    $new_child->_parent = $this;
489    $new_child->_next_sibling = $ref;
490    $new_child->_prev_sibling = $ref->_prev_sibling;
491
492    if ( $ref->_prev_sibling )
493      $ref->_prev_sibling->_next_sibling = $new_child;
494   
495    $ref->_prev_sibling = $new_child;
496  }
497 
498  // Inserts a new child immediately after the specified frame
499  function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) {   
500
501    if ( $ref === $this->_last_child ) {
502      $this->append_child($new_child, $update_node);
503      return;
504    }
505
506    if ( is_null($ref) ) {
507      $this->prepend_child($new_child, $update_node);
508      return;
509    }
510   
511    if ( $ref->_parent !== $this )
512      throw new DOMPDF_Exception("Reference child is not a child of this node.");
513
514    // Update the node
515    if ( $update_node ) {
516      if ( $ref->_next_sibling ) {
517        $next_node = $ref->_next_sibling->_node;
518        $this->_node->insertBefore($new_child->_node, $next_node);
519      } else {
520        $new_child->_node = $this->_node->appendChild($new_child);
521      }
522    }
523   
524    // Remove the child from its parent
525    if ( $new_child->_parent)
526      $new_child->_parent->remove_child($new_child, false);
527   
528    $new_child->_parent = $this;
529    $new_child->_prev_sibling = $ref;
530    $new_child->_next_sibling = $ref->_next_sibling;
531
532    if ( $ref->_next_sibling )
533      $ref->_next_sibling->_prev_sibling = $new_child;
534
535    $ref->_next_sibling = $new_child;
536  }
537
538
539  function remove_child(Frame $child, $update_node = true) {
540
541    if ( $child->_parent !== $this )
542      throw new DOMPDF_Exception("Child not found in this frame");
543
544    if ( $update_node )
545      $this->_node->removeChild($child->_node);
546   
547    if ( $child === $this->_first_child )
548      $this->_first_child = $child->_next_sibling;
549
550    if ( $child === $this->_last_child )
551      $this->_last_child = $child->_prev_sibling;
552
553    if ( $child->_prev_sibling )
554      $child->_prev_sibling->_next_sibling = $child->_next_sibling;
555
556    if ( $child->_next_sibling )
557      $child->_next_sibling->_prev_sibling = $child->_prev_sibling;   
558
559    $child->_next_sibling = null;
560    $child->_prev_sibling = null;
561    $child->_parent = null;
562    return $child;
563       
564  }
565
566  //........................................................................
567
568  // Debugging function:
569  function __toString() {
570
571    // Skip empty text frames
572    if ( $this->_node->nodeName == "#text" &&
573         preg_replace("/\s/", "", $this->_node->data) === "" )
574      return "";
575   
576   
577    $str = "<b>" . $this->_node->nodeName . ":</b><br/>";
578    $str .= (string)$this->_node . "<br/>";
579    $str .= "Id: " .$this->get_id() . "<br/>";
580    $str .= "Class: " .get_class($this) . "<br/>";
581   
582    if ( $this->_node->nodeName == "#text" ) {
583      $tmp = htmlspecialchars($this->_node->nodeValue);
584      $str .= "<pre>'" .  mb_substr($tmp,0,70) .
585        (mb_strlen($tmp) > 70 ? "..." : "") . "'</pre>";
586    }
587    if ( $this->_parent )
588      $str .= "\nParent:" . $this->_parent->_node->nodeName .
589        " (" . (string)$this->_parent->_node . ") " .
590        "<br/>";
591
592    if ( $this->_prev_sibling )
593      $str .= "Prev: " . $this->_prev_sibling->_node->nodeName .
594        " (" . (string)$this->_prev_sibling->_node . ") " .
595        "<br/>";
596
597    if ( $this->_next_sibling )
598      $str .= "Next: " . $this->_next_sibling->_node->nodeName .
599        " (" . (string)$this->_next_sibling->_node . ") " .
600        "<br/>";
601
602    $d = $this->get_decorator();
603    while ($d && $d != $d->get_decorator()) {
604      $str .= "Decorator: " . get_class($d) . "<br/>";
605      $d = $d->get_decorator();
606    }
607
608    $str .= "Position: " . pre_r($this->_position, true);
609    $str .= "\nContaining block: " . pre_r($this->_containing_block, true);
610    $str .= "\nMargin width: " . pre_r($this->get_margin_width(), true);
611    $str .= "\nMargin height: " . pre_r($this->get_margin_height(), true);
612   
613    $str .= "\nStyle: <pre>". $this->_style->__toString() . "</pre>";
614
615    if ( $this->_decorator instanceof Block_Frame_Decorator ) {
616      $str .= "Lines:<pre>";
617      foreach ($this->_decorator->get_lines() as $line) {
618        foreach ($line["frames"] as $frame) {
619          if ($frame instanceof Text_Frame_Decorator) {
620            $str .= "\ntext: ";         
621            $str .= htmlspecialchars($frame->get_text());
622          } else {
623            $str .= "\nBlock: " . $frame->get_node()->nodeName . " (" . (string)$frame->get_node() . ")";
624          }
625        }
626       
627        $str .=
628          //"\ncount => " . $line["count"] . "\n".
629          "\ny => " . $line["y"] . "\n" .
630          "w => " . $line["w"] . "\n" .
631          "h => " . $line["h"] . "\n";
632      }
633      $str .= "</pre>";
634    }
635    $str .= "\n";
636    if ( php_sapi_name() == "cli" )
637      $str = strip_tags(str_replace(array("<br/>","<b>","</b>"),
638                                    array("\n","",""),
639                                    $str));
640   
641    return $str;
642  }
643       
644}
645
646//------------------------------------------------------------------------
647
648/**
649 * Linked-list IteratorAggregate
650 *
651 * @access private
652 * @package dompdf
653 */
654class FrameList implements IteratorAggregate {
655  protected $_frame;
656
657  function __construct($frame) { $this->_frame = $frame; }
658  function getIterator() { return new FrameListIterator($this->_frame); }
659}
660 
661/**
662 * Linked-list Iterator
663 *
664 * Returns children in order and allows for list to change during iteration,
665 * provided the changes occur to or after the current element
666 *
667 * @access private
668 * @package dompdf
669 */
670class FrameListIterator implements Iterator {
671
672  protected $_parent;
673  protected $_cur;
674  protected $_num;
675
676  function __construct(Frame $frame) {
677    $this->_parent = $frame;
678    $this->_cur = $frame->get_first_child();
679    $this->_num = 0;
680  }
681
682  function rewind() {
683    $this->_cur = $this->_parent->get_first_child();
684    $this->_num = 0;
685  }
686
687  function valid() {
688    return isset($this->_cur);// && ($this->_cur->get_prev_sibling() === $this->_prev);
689  }
690  function key() { return $this->_num; }
691  function current() { return $this->_cur; }
692
693  function next() {
694
695    $ret = $this->_cur;
696    if ( !$ret )
697      return null;
698   
699    $this->_cur = $this->_cur->get_next_sibling();
700    $this->_num++;
701    return $ret;
702  }
703}
704
705//------------------------------------------------------------------------
706
707/**
708 * Pre-order IteratorAggregate
709 *
710 * @access private
711 * @package dompdf
712 */
713class FrameTreeList implements IteratorAggregate {
714
715  protected $_root;
716  function __construct(Frame $root) { $this->_root = $root; }
717  function getIterator() { return new FrameTreeIterator($this->_root); }
718
719}
720
721/**
722 * Pre-order Iterator
723 *
724 * Returns frames in preorder traversal order (parent then children)
725 *
726 * @access private
727 * @package dompdf
728 */
729class FrameTreeIterator implements Iterator {
730
731  protected $_root;
732  protected $_stack = array();
733  protected $_num;
734 
735  function __construct(Frame $root) {
736    $this->_stack[] = $this->_root = $root;
737    $this->_num = 0;
738  }
739
740  function rewind() {
741    $this->_stack = array($this->_root);
742    $this->_num = 0;
743  }
744   
745  function valid() { return count($this->_stack) > 0; }
746  function key() { return $this->_num; }
747  function current() { return end($this->_stack); }
748
749  function next() {
750    $b = end($this->_stack);
751   
752    // Pop last element
753    unset($this->_stack[ key($this->_stack) ]);
754    $this->_num++;
755   
756    // Push all children onto the stack in reverse order
757    if ( $c = $b->get_last_child() ) {
758      $this->_stack[] = $c;
759      while ( $c = $c->get_prev_sibling() )
760        $this->_stack[] = $c;
761    }
762    return $b;
763  }
764}
765
766?>
Note: See TracBrowser for help on using the repository browser.