[ PHPXref.com ] [ Generated: Sun Jul 20 17:19:34 2008 ] [ dompdf 0.5 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/include/ -> block_frame_reflower.cls.php (source)

   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.3
  38   */
  39  
  40  /* $Id: block_frame_reflower.cls.php,v 1.13 2006/04/06 19:30:46 benjcarson Exp $ */
  41  
  42  /**
  43   * Reflows block frames
  44   *
  45   * @access private
  46   * @package dompdf
  47   */
  48  class 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      $cb = $this->_frame->get_containing_block();
  62      
  63      $r = $style->length_in_pt($style->margin_right, $cb["w"]);
  64      $l = $style->length_in_pt($style->margin_left, $cb["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                    $l !== "auto" ? $l : 0,
  73                    $r !== "auto" ? $r : 0);
  74      
  75      $sum = $style->length_in_pt($dims, $cb["w"]);
  76  
  77      // Compare to the containing block
  78      $diff = $cb["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      $width = $style->length_in_pt($style->width, $cb["w"]);
 114  
 115      extract($this->_calculate_width($width));
 116  
 117      // Handle min/max width
 118      $min_width = $style->length_in_pt($style->min_width, $cb["w"]);
 119      $max_width = $style->length_in_pt($style->max_width, $cb["w"]);
 120  
 121      if ( $max_width !== "none" && $min_width > $max_width)
 122        // Swap 'em
 123        list($max_width, $min_width) = array($min_width, $max_width);
 124      
 125      if ( $max_width !== "none" && $width > $max_width )
 126        extract($this->_calculate_width($max_width));
 127      
 128      if ( $width < $min_width )
 129        extract($this->_calculate_width($min_width));    
 130        
 131      return array($width, $margin_left, $margin_right);
 132  
 133    }
 134  
 135    //........................................................................
 136  
 137    // Determine the unrestricted height of content within the block
 138    protected function _calculate_content_height() {
 139      $style = $this->_frame->get_style();
 140      $cb = $this->_frame->get_containing_block();
 141  
 142      $height = $style->height;
 143  
 144      // Handle percentage heights
 145      if ( isset($cb["h"]) ) 
 146        $height = $style->length_in_pt($height, $cb["h"]);
 147        
 148      else if ( mb_strpos($height, "%") !== false )
 149        $height = "auto";
 150  
 151      else
 152        $height = $style->length_in_pt($height, $cb["w"]);
 153  
 154      // FIXME: not sure about this...  What if height is specified precisely,
 155      // but overflow is visible?
 156      if ( $style->overflow === "visible" ||
 157           ($style->overflow === "hidden" && $height === "auto") ) {
 158  
 159        // Calculate the actual height
 160        $height = 0;
 161  
 162        // Add the height of all lines
 163        foreach ($this->_frame->get_lines() as $line)
 164          $height += $line["h"];
 165  
 166      }
 167  
 168      return $height;
 169    }
 170    
 171    // Determine the frame's restricted height
 172    protected function _calculate_restricted_height() {
 173      $style = $this->_frame->get_style();
 174      $height = $this->_calculate_content_height();
 175      
 176      $cb = $this->_frame->get_containing_block();
 177  
 178      if ( !($style->overflow === "visible" ||
 179             ($style->overflow === "hidden" && $height === "auto")) ) {
 180  
 181        // Only handle min/max height if the height is independent of the frame's content
 182      
 183        $min_height = $style->min_height;
 184        $max_height = $style->max_height;
 185  
 186        if ( isset($cb["h"]) ) {
 187          $min_height = $style->length_in_pt($min_height, $cb["h"]);
 188          $max_height = $style->length_in_pt($max_height, $cb["h"]);
 189  
 190        } else if ( isset($cb["w"]) ) {
 191  
 192          if ( mb_strpos($min_height, "%") !== false )
 193            $min_height = 0;
 194          else
 195            $min_height = $style->length_in_pt($min_height, $cb["w"]);
 196        
 197          if ( mb_strpos($max_height, "%") !== false )
 198            $max_height = "none";
 199          else
 200            $max_height = $style->length_in_pt($max_height, $cb["w"]);
 201        }
 202  
 203        if ( $max_height !== "none" && $min_height > $max_height )
 204          // Swap 'em
 205          list($max_height, $min_height) = array($min_height, $max_height);
 206        
 207        if ( $max_height !== "none" && $height > $max_height )
 208          $height = $max_height;
 209  
 210        if ( $height < $min_height )
 211          $height = $min_height;
 212      }
 213  
 214      return $height;
 215      
 216    }
 217  
 218    //........................................................................
 219  
 220    protected function _text_align() {
 221      $style = $this->_frame->get_style();
 222      
 223      // Adjust the justification of each of our lines.
 224      // http://www.w3.org/TR/CSS21/text.html#propdef-text-align
 225      switch ($style->text_align) {
 226  
 227      default:
 228      case "left":
 229        return;
 230  
 231      case "right":
 232        foreach ($this->_frame->get_lines() as $line) {
 233  
 234          // Move each child over by $dx
 235          $dx = $style->width - $line["w"];        
 236          foreach($line["frames"] as $frame) 
 237            $frame->set_position( $frame->get_position("x") + $dx );
 238  
 239        }
 240        break;
 241  
 242        
 243      case "justify":
 244        foreach ($this->_frame->get_lines() as $i => $line) {
 245          
 246          // Only set the spacing if the line is long enough.  This is really
 247          // just an aesthetic choice ;)
 248          if ( $line["w"] > self::MIN_JUSTIFY_WIDTH * $style->width ) {
 249            // Set the spacing for each child
 250            if ( $line["wc"] > 1 )
 251              $spacing = ($style->width - $line["w"]) / ($line["wc"] - 1);
 252            else
 253              $spacing = 0;
 254            
 255            $dx = 0;
 256            foreach($line["frames"] as $frame) {
 257              if ( !$frame instanceof Text_Frame_Decorator )
 258                continue;
 259              
 260              $frame->set_position( $frame->get_position("x") + $dx );
 261              $frame->set_text_spacing($spacing);
 262              $dx += mb_substr_count($frame->get_text(), " ") * $spacing;
 263            }
 264  
 265            // The line (should) now occupy the entire width
 266            $this->_frame->set_line($i, null, $style->width);
 267  
 268          }
 269        }
 270        break;
 271  
 272      case "center":
 273      case "centre":
 274        foreach ($this->_frame->get_lines() as $i => $line) {
 275          // Centre each line by moving each frame in the line by:
 276          $dx = ($style->width - $line["w"]) / 2;
 277          foreach ($line["frames"] as $frame) 
 278            $frame->set_position( $frame->get_position("x") + $dx );
 279        }
 280        break;
 281      }
 282  
 283    }
 284    /**
 285     * Align inline children vertically
 286     */
 287    function vertical_align() {
 288      // Align each child vertically after each line is reflowed
 289      foreach ( $this->_frame->get_lines() as $i => $line ) {
 290                   
 291        foreach ( $line["frames"] as $frame ) {
 292          $style = $frame->get_style();
 293  
 294          if ( $style->display != "inline" && $style->display != "text" )
 295            continue;
 296  
 297          $align = $style->vertical_align;
 298  
 299          $frame_h = $style->length_in_pt($style->height);
 300          
 301          switch ($align) {
 302  
 303          case "baseline":
 304            $y = $line["y"] + $line["h"] - $frame_h;
 305            break;
 306            
 307          case "middle":
 308            $y = $line["y"] + ($line["h"] + $frame_h) / 2;
 309            break;
 310            
 311          case "sub":
 312            $y = $line["y"] + 0.9 * $line["h"];
 313            break;
 314            
 315          case "super":
 316            $y = $line["y"] + 0.1 * $line["h"];
 317            break;
 318            
 319          case  "text-top":
 320          case "top": // Not strictly accurate, but good enough for now
 321            $y = $line["y"];
 322            break;
 323            
 324          case "text-bottom":
 325          case "bottom":
 326            $y = $line["y"] + $line["h"] - $frame_h;
 327            break;
 328          }
 329  
 330          $x = $frame->get_position("x");
 331          $frame->set_position($x, $y);
 332          
 333        }
 334      }
 335    }
 336    
 337    //........................................................................
 338  
 339    function reflow() {
 340  
 341      // Check if a page break is forced
 342      $page = $this->_frame->get_root();
 343      $page->check_forced_page_break($this->_frame);
 344  
 345      // Bail if the page is full
 346      if ( $page->is_full() )
 347        return;    
 348      
 349      // Collapse margins if required
 350      $this->_collapse_margins();
 351      
 352      $this->_frame->position();
 353  
 354      $style = $this->_frame->get_style();    
 355      $cb = $this->_frame->get_containing_block();
 356      list($x, $y) = $this->_frame->get_position();
 357          
 358      // Determine the constraints imposed by this frame: calculate the width
 359      // of the content area:
 360      list($w, $left, $right) = $this->_calculate_restricted_width();
 361  
 362      // Store the calculated properties
 363      $style->width = $w;
 364      $style->margin_left = $left."pt";
 365      $style->margin_right = $right."pt";
 366  
 367  
 368      // Adjust the first line based on the text-indent property
 369      $indent = $style->length_in_pt($style->text_indent, $cb["w"]);
 370      $this->_frame->increase_line_width($indent);
 371      
 372      // Determine the content edge
 373      $top = $style->length_in_pt(array($style->margin_top,
 374                                        $style->padding_top,
 375                                        $style->border_top_width), $cb["h"]);
 376  
 377      $bottom = $style->length_in_pt(array($style->border_bottom_width,
 378                                           $style->margin_bottom,
 379                                           $style->padding_bottom), $cb["h"]);
 380  
 381      $cb_x = $x + $left +
 382        $style->length_in_pt($style->border_left_width, $cb["w"]) +
 383        $style->length_in_pt($style->padding_left, $cb["w"]);
 384  
 385      $cb_y = $line_y = $y + $top;
 386  
 387      $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y;
 388      
 389      // Set the y position of the first line in this block
 390      $this->_frame->set_current_line($line_y);
 391      
 392      // Set the containing blocks and reflow each child
 393      foreach ( $this->_frame->get_children() as $child ) {
 394  
 395        // Bail out if the page is full
 396        if ( $page->is_full() )
 397          break;
 398        
 399        $child->set_containing_block($cb_x, $cb_y, $w, $cb_h);
 400        $child->reflow();
 401        
 402        // Don't add the child to the line if a page break has occurred
 403        if ( $page->check_page_break($child) )
 404          break;      
 405              
 406        // It's okay to add the frame to the line
 407        $this->_frame->add_frame_to_line( $child );
 408      }
 409  
 410      // Determine our height
 411      $style->height = $this->_calculate_restricted_height();
 412      
 413      $this->_text_align();
 414  
 415      $this->vertical_align();
 416    }
 417  
 418    //........................................................................
 419  
 420  }
 421  ?>


[ Powered by PHPXref - Served by Debian GNU/Linux ]