source: branches/2.2/filemanager/tp/dompdf/include/frame.cls.php @ 3019

Revision 3019, 22.8 KB checked in by amuller, 14 years ago (diff)

Ticket #1135 - Corrigindo CSS e adicionando filemanager

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