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

Revision 1575, 12.8 KB checked in by amuller, 14 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: block_frame_reflower.cls.php,v $
6 * Created on: 2004-06-17
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: block_frame_reflower.cls.php,v 1.16 2006/07/07 21:31:02 benjcarson Exp $ */
41
42/**
43 * Reflows block frames
44 *
45 * @access private
46 * @package dompdf
47 */
48class Block_Frame_Reflower extends Frame_Reflower {
49  const MIN_JUSTIFY_WIDTH = 0.80;  // (Minimum line width to justify, as
50                                   // fraction of available width)
51
52  function __construct(Block_Frame_Decorator $frame) { parent::__construct($frame); }
53
54  //........................................................................
55
56  // Calculate the ideal used value for the width property as per:
57  // http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins
58
59  protected function _calculate_width($width) {
60    $style = $this->_frame->get_style();
61    $w = $this->_frame->get_containing_block("w");
62
63    $r = $style->length_in_pt($style->margin_right, $w);
64    $l = $style->length_in_pt($style->margin_left, $w);
65
66    // Handle 'auto' values
67    $dims = array($style->border_left_width,
68                  $style->border_right_width,
69                  $style->padding_left,
70                  $style->padding_right,
71                  $width !== "auto" ? $width : 0,
72                  $r !== "auto" ? $r : 0,
73                  $l !== "auto" ? $l : 0);
74
75    $sum = $style->length_in_pt($dims, $w);
76
77    // Compare to the containing block
78    $diff = $w - $sum;
79
80    if ( $diff > 0 ) {
81
82      // Find auto properties and get them to take up the slack
83      if ( $width === "auto" )
84        $width = $diff;
85
86      else if ( $l === "auto" && $r === "auto" )
87        $l = $r = round($diff / 2);
88
89      else if ( $l === "auto" )
90        $l = $diff;
91
92      else if ( $r === "auto" )
93        $r = $diff;
94
95    } else if ($diff < 0) {
96
97      // We are over constrained--set margin-right to the difference
98      $r = $diff;
99
100    }
101
102    return array("width"=> $width, "margin_left" => $l, "margin_right" => $r);
103  }
104
105  // Call the above function, but resolve max/min widths
106  protected function _calculate_restricted_width() {
107    $style = $this->_frame->get_style();
108    $cb = $this->_frame->get_containing_block();
109
110    if ( !isset($cb["w"]) )
111      throw new DOMPDF_Exception("Box property calculation requires containing block width");
112
113    // Treat width 100% as auto
114    if ( $style->width === "100%" )
115      $width = "auto";
116    else
117      $width = $style->length_in_pt($style->width, $cb["w"]);
118
119    extract($this->_calculate_width($width));
120
121    // Handle min/max width
122    $min_width = $style->length_in_pt($style->min_width, $cb["w"]);
123    $max_width = $style->length_in_pt($style->max_width, $cb["w"]);
124
125    if ( $max_width !== "none" && $min_width > $max_width)
126      // Swap 'em
127      list($max_width, $min_width) = array($min_width, $max_width);
128
129    if ( $max_width !== "none" && $width > $max_width )
130      extract($this->_calculate_width($max_width));
131
132    if ( $width < $min_width )
133      extract($this->_calculate_width($min_width));
134
135    return array($width, $margin_left, $margin_right);
136
137  }
138
139  //........................................................................
140
141  // Determine the unrestricted height of content within the block
142  protected function _calculate_content_height() {
143
144    // Calculate the actual height
145    $height = 0;
146   
147    // Add the height of all lines
148    foreach ($this->_frame->get_lines() as $line)
149      $height += $line["h"];
150
151    return $height;
152  }
153
154  // Determine the frame's restricted height
155  protected function _calculate_restricted_height() {
156    $style = $this->_frame->get_style();
157    $content_height = $this->_calculate_content_height();
158    $cb = $this->_frame->get_containing_block();
159
160    $height = $style->height;
161
162    // Handle percentage heights
163    if ( isset($cb["h"]) ) {
164      $height = $style->length_in_pt($height, $cb["h"]);
165
166    } else if ( mb_strpos($height, "%") !== false )
167      $height = "auto";
168
169    else
170      $height = $style->length_in_pt($height, $cb["w"]);
171
172    // Remove margin, padding & borders
173    $height -= $style->length_in_pt( array($style->margin_top,
174                                           $style->padding_top,
175                                           $style->border_top_width,
176                                           $style->border_bottom_width,
177                                           $style->padding_bottom,
178                                           $style->margin_bottom),
179                                     $cb["h"]);
180
181    // Expand the height if overflow is visible
182    if ( $content_height > $height && $style->overflow === "visible" )
183      $height = $content_height;
184
185    // Only handle min/max height if the height is independent of the frame's content
186    if ( !($style->overflow === "visible" ||
187           ($style->overflow === "hidden" && $height === "auto")) ) {
188
189      $min_height = $style->min_height;
190      $max_height = $style->max_height;
191
192      if ( isset($cb["h"]) ) {
193        $min_height = $style->length_in_pt($min_height, $cb["h"]);
194        $max_height = $style->length_in_pt($max_height, $cb["h"]);
195
196      } else if ( isset($cb["w"]) ) {
197
198        if ( mb_strpos($min_height, "%") !== false )
199          $min_height = 0;
200        else
201          $min_height = $style->length_in_pt($min_height, $cb["w"]);
202
203        if ( mb_strpos($max_height, "%") !== false )
204          $max_height = "none";
205        else
206          $max_height = $style->length_in_pt($max_height, $cb["w"]);
207      }
208
209      if ( $max_height !== "none" && $min_height > $max_height )
210        // Swap 'em
211        list($max_height, $min_height) = array($min_height, $max_height);
212
213      if ( $max_height !== "none" && $height > $max_height )
214        $height = $max_height;
215
216      if ( $height < $min_height )
217        $height = $min_height;
218    }
219
220    return $height;
221
222  }
223
224  //........................................................................
225
226  protected function _text_align() {
227    $style = $this->_frame->get_style();
228    $w = $this->_frame->get_containing_block("w");
229    $width = $style->length_in_pt($style->width, $w);
230
231    // Adjust the justification of each of our lines.
232    // http://www.w3.org/TR/CSS21/text.html#propdef-text-align
233    switch ($style->text_align) {
234
235    default:
236    case "left":
237      return;
238
239    case "right":
240      foreach ($this->_frame->get_lines() as $line) {
241
242        // Move each child over by $dx
243        $dx = $width - $line["w"];
244        foreach($line["frames"] as $frame)
245          $frame->set_position( $frame->get_position("x") + $dx );
246
247      }
248      break;
249
250
251    case "justify":
252      foreach ($this->_frame->get_lines() as $i => $line) {
253
254        // Only set the spacing if the line is long enough.  This is really
255        // just an aesthetic choice ;)
256        if ( $line["w"] > self::MIN_JUSTIFY_WIDTH * $width ) {
257          // Set the spacing for each child
258          if ( $line["wc"] > 1 )
259            $spacing = ($width - $line["w"]) / ($line["wc"] - 1);
260          else
261            $spacing = 0;
262
263          $dx = 0;
264          foreach($line["frames"] as $frame) {
265            if ( !$frame instanceof Text_Frame_Decorator )
266              continue;
267
268            $frame->set_position( $frame->get_position("x") + $dx );
269            $frame->set_text_spacing($spacing);
270            $dx += mb_substr_count($frame->get_text(), " ") * $spacing;
271          }
272
273          // The line (should) now occupy the entire width
274          $this->_frame->set_line($i, null, $width);
275
276        }
277      }
278      break;
279
280    case "center":
281    case "centre":
282      foreach ($this->_frame->get_lines() as $i => $line) {
283        // Centre each line by moving each frame in the line by:
284        $dx = ($width - $line["w"]) / 2;
285        foreach ($line["frames"] as $frame)
286          $frame->set_position( $frame->get_position("x") + $dx );
287      }
288      break;
289    }
290
291  }
292  /**
293   * Align inline children vertically
294   */
295  function vertical_align() {
296    // Align each child vertically after each line is reflowed
297    foreach ( $this->_frame->get_lines() as $i => $line ) {
298
299      foreach ( $line["frames"] as $frame ) {
300        $style = $frame->get_style();
301
302        if ( $style->display != "inline" && $style->display != "text" )
303          continue;
304
305        $align = $style->vertical_align;
306
307        $frame_h = $frame->get_margin_height();
308
309        switch ($align) {
310
311        case "baseline":
312          $y = $line["y"] + $line["h"] - $frame_h;
313          break;
314
315        case "middle":
316          $y = $line["y"] + ($line["h"] + $frame_h) / 2;
317          break;
318
319        case "sub":
320          $y = $line["y"] + 0.9 * $line["h"];
321          break;
322
323        case "super":
324          $y = $line["y"] + 0.1 * $line["h"];
325          break;
326
327        case  "text-top":
328        case "top": // Not strictly accurate, but good enough for now
329          $y = $line["y"];
330          break;
331
332        case "text-bottom":
333        case "bottom":
334          $y = $line["y"] + $line["h"] - $frame_h;
335          break;
336        }
337
338        $x = $frame->get_position("x");
339        $frame->set_position($x, $y);
340
341      }
342    }
343  }
344
345  //........................................................................
346
347  function reflow() {
348
349    // Check if a page break is forced
350    $page = $this->_frame->get_root();
351    $page->check_forced_page_break($this->_frame);
352
353    // Bail if the page is full
354    if ( $page->is_full() )
355      return;
356
357    // Collapse margins if required
358    $this->_collapse_margins();
359
360    $this->_frame->position();
361
362    $style = $this->_frame->get_style();
363    $cb = $this->_frame->get_containing_block();
364    list($x, $y) = $this->_frame->get_position();
365
366    // Determine the constraints imposed by this frame: calculate the width
367    // of the content area:
368    list($w, $left, $right) = $this->_calculate_restricted_width();
369
370    // Store the calculated properties
371    $style->width = $w;
372    $style->margin_left = $left."pt";
373    $style->margin_right = $right."pt";
374
375
376    // Adjust the first line based on the text-indent property
377    $indent = $style->length_in_pt($style->text_indent, $cb["w"]);
378    $this->_frame->increase_line_width($indent);
379
380    // Determine the content edge
381    $top = $style->length_in_pt(array($style->margin_top,
382                                      $style->padding_top,
383                                      $style->border_top_width), $cb["h"]);
384
385    $bottom = $style->length_in_pt(array($style->border_bottom_width,
386                                         $style->margin_bottom,
387                                         $style->padding_bottom), $cb["h"]);
388
389    $cb_x = $x + $left +
390      $style->length_in_pt($style->border_left_width, $cb["w"]) +
391      $style->length_in_pt($style->padding_left, $cb["w"]);
392
393    $cb_y = $line_y = $y + $top;
394
395    $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y;
396
397    // Set the y position of the first line in this block
398    $this->_frame->set_current_line($line_y);
399
400    // Set the containing blocks and reflow each child
401    foreach ( $this->_frame->get_children() as $child ) {
402
403      // Bail out if the page is full
404      if ( $page->is_full() )
405        break;
406
407      $child->set_containing_block($cb_x, $cb_y, $w, $cb_h);
408      $child->reflow();
409
410      // Don't add the child to the line if a page break has occurred
411      if ( $page->check_page_break($child) )
412        break;
413
414      // It's okay to add the frame to the line
415      $this->_frame->add_frame_to_line( $child );
416    }
417
418    // Determine our height
419    $style->height = $this->_calculate_restricted_height();
420
421    $this->_text_align();
422
423    $this->vertical_align();
424  }
425
426  //........................................................................
427
428}
429?>
Note: See TracBrowser for help on using the repository browser.