Block_Frame_Reflower

Reflows block frames.

Defined (1)

The class is defined in the following location(s).

/lib/dompdf/include/block_frame_reflower.cls.php  
  1. class Block_Frame_Reflower extends Frame_Reflower { 
  2. // Minimum line width to justify, as fraction of available width 
  3. const MIN_JUSTIFY_WIDTH = 0.80; 
  4.  
  5. /** 
  6. * @var Block_Frame_Decorator 
  7. */ 
  8. protected $_frame; 
  9.  
  10. function __construct(Block_Frame_Decorator $frame) { parent::__construct($frame); } 
  11.  
  12. /** 
  13. * Calculate the ideal used value for the width property as per: 
  14. * http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins 
  15. *  
  16. * @param float $width 
  17. * @return array 
  18. */ 
  19. protected function _calculate_width($width) { 
  20. $frame = $this->_frame; 
  21. $style = $frame->get_style(); 
  22. $w = $frame->get_containing_block("w"); 
  23.  
  24. if ( $style->position === "fixed" ) { 
  25. $w = $frame->get_parent()->get_containing_block("w"); 
  26.  
  27. $rm = $style->length_in_pt($style->margin_right, $w); 
  28. $lm = $style->length_in_pt($style->margin_left, $w); 
  29.  
  30. $left = $style->length_in_pt($style->left, $w); 
  31. $right = $style->length_in_pt($style->right, $w); 
  32.  
  33. // Handle 'auto' values 
  34. $dims = array($style->border_left_width,  
  35. $style->border_right_width,  
  36. $style->padding_left,  
  37. $style->padding_right,  
  38. $width !== "auto" ? $width : 0,  
  39. $rm !== "auto" ? $rm : 0,  
  40. $lm !== "auto" ? $lm : 0); 
  41.  
  42. // absolutely positioned boxes take the 'left' and 'right' properties into account 
  43. if ( $frame->is_absolute() ) { 
  44. $absolute = true; 
  45. $dims[] = $left !== "auto" ? $left : 0; 
  46. $dims[] = $right !== "auto" ? $right : 0; 
  47. else { 
  48. $absolute = false; 
  49.  
  50. $sum = $style->length_in_pt($dims, $w); 
  51.  
  52. // Compare to the containing block 
  53. $diff = $w - $sum; 
  54.  
  55. if ( $diff > 0 ) { 
  56.  
  57. if ( $absolute ) { 
  58.  
  59. // resolve auto properties: see 
  60. // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width 
  61.  
  62. if ( $width === "auto" && $left === "auto" && $right === "auto" ) { 
  63.  
  64. if ( $lm === "auto" ) $lm = 0; 
  65. if ( $rm === "auto" ) $rm = 0; 
  66.  
  67. // Technically, the width should be "shrink-to-fit" i.e. based on the 
  68. // preferred width of the content... a little too costly here as a 
  69. // special case. Just get the width to take up the slack: 
  70. $left = 0; 
  71. $right = 0; 
  72. $width = $diff; 
  73. else if ( $width === "auto" ) { 
  74.  
  75. if ( $lm === "auto" ) $lm = 0; 
  76. if ( $rm === "auto" ) $rm = 0; 
  77. if ( $left === "auto" ) $left = 0; 
  78. if ( $right === "auto" ) $right = 0; 
  79.  
  80. $width = $diff; 
  81. else if ( $left === "auto" ) { 
  82.  
  83. if ( $lm === "auto" ) $lm = 0; 
  84. if ( $rm === "auto" ) $rm = 0; 
  85. if ( $right === "auto" ) $right = 0; 
  86.  
  87. $left = $diff; 
  88. else if ( $right === "auto" ) { 
  89.  
  90. if ( $lm === "auto" ) $lm = 0; 
  91. if ( $rm === "auto" ) $rm = 0; 
  92.  
  93. $right = $diff; 
  94.  
  95. else { 
  96.  
  97. // Find auto properties and get them to take up the slack 
  98. if ( $width === "auto" ) { 
  99. $width = $diff; 
  100. else if ( $lm === "auto" && $rm === "auto" ) { 
  101. $lm = $rm = round($diff / 2); 
  102. else if ( $lm === "auto" ) { 
  103. $lm = $diff; 
  104. else if ( $rm === "auto" ) { 
  105. $rm = $diff; 
  106.  
  107. else if ($diff < 0) { 
  108.  
  109. // We are over constrained--set margin-right to the difference 
  110. $rm = $diff; 
  111.  
  112.  
  113. return array( 
  114. "width" => $width,  
  115. "margin_left" => $lm,  
  116. "margin_right" => $rm,  
  117. "left" => $left,  
  118. "right" => $right,  
  119. ); 
  120.  
  121. /** 
  122. * Call the above function, but resolve max/min widths 
  123. * @throws DOMPDF_Exception 
  124. * @return array 
  125. */ 
  126. protected function _calculate_restricted_width() { 
  127. $frame = $this->_frame; 
  128. $style = $frame->get_style(); 
  129. $cb = $frame->get_containing_block(); 
  130.  
  131. if ( $style->position === "fixed" ) { 
  132. $cb = $frame->get_root()->get_containing_block(); 
  133.  
  134. //if ( $style->position === "absolute" ) 
  135. // $cb = $frame->find_positionned_parent()->get_containing_block(); 
  136.  
  137. if ( !isset($cb["w"]) ) { 
  138. throw new DOMPDF_Exception("Box property calculation requires containing block width"); 
  139.  
  140. // Treat width 100% as auto 
  141. if ( $style->width === "100%" ) { 
  142. $width = "auto"; 
  143. else { 
  144. $width = $style->length_in_pt($style->width, $cb["w"]); 
  145.  
  146. extract($this->_calculate_width($width)); 
  147.  
  148. // Handle min/max width 
  149. $min_width = $style->length_in_pt($style->min_width, $cb["w"]); 
  150. $max_width = $style->length_in_pt($style->max_width, $cb["w"]); 
  151.  
  152. if ( $max_width !== "none" && $min_width > $max_width ) { 
  153. list($max_width, $min_width) = array($min_width, $max_width); 
  154.  
  155. if ( $max_width !== "none" && $width > $max_width ) { 
  156. extract($this->_calculate_width($max_width)); 
  157.  
  158. if ( $width < $min_width ) { 
  159. extract($this->_calculate_width($min_width)); 
  160.  
  161. return array($width, $margin_left, $margin_right, $left, $right); 
  162.  
  163. /**  
  164. * Determine the unrestricted height of content within the block 
  165. * not by adding each line's height, but by getting the last line's position.  
  166. * This because lines could have been pushed lower by a clearing element. 
  167. * @return float 
  168. */ 
  169. protected function _calculate_content_height() { 
  170. $lines = $this->_frame->get_line_boxes(); 
  171. $height = 0; 
  172.  
  173. foreach ($lines as $line) { 
  174. $height += $line->h; 
  175.  
  176. /** 
  177. $first_line = reset($lines); 
  178. $last_line = end($lines); 
  179. $height2 = $last_line->y + $last_line->h - $first_line->y; 
  180. */ 
  181.  
  182. return $height; 
  183.  
  184. /**  
  185. * Determine the frame's restricted height 
  186. * @return array 
  187. */ 
  188. protected function _calculate_restricted_height() { 
  189. $frame = $this->_frame; 
  190. $style = $frame->get_style(); 
  191. $content_height = $this->_calculate_content_height(); 
  192. $cb = $frame->get_containing_block(); 
  193.  
  194. $height = $style->length_in_pt($style->height, $cb["h"]); 
  195.  
  196. $top = $style->length_in_pt($style->top, $cb["h"]); 
  197. $bottom = $style->length_in_pt($style->bottom, $cb["h"]); 
  198.  
  199. $margin_top = $style->length_in_pt($style->margin_top, $cb["h"]); 
  200. $margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); 
  201.  
  202. if ( $frame->is_absolute() ) { 
  203.  
  204. // see http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height 
  205.  
  206. $dims = array($top !== "auto" ? $top : 0,  
  207. $style->margin_top !== "auto" ? $style->margin_top : 0,  
  208. $style->padding_top,  
  209. $style->border_top_width,  
  210. $height !== "auto" ? $height : 0,  
  211. $style->border_bottom_width,  
  212. $style->padding_bottom,  
  213. $style->margin_bottom !== "auto" ? $style->margin_bottom : 0,  
  214. $bottom !== "auto" ? $bottom : 0); 
  215.  
  216. $sum = $style->length_in_pt($dims, $cb["h"]); 
  217.  
  218. $diff = $cb["h"] - $sum;  
  219.  
  220. if ( $diff > 0 ) { 
  221.  
  222. if ( $height === "auto" && $top === "auto" && $bottom === "auto" ) { 
  223.  
  224. if ( $margin_top === "auto" ) $margin_top = 0; 
  225. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  226.  
  227. $height = $diff; 
  228. else if ( $height === "auto" && $top === "auto" ) { 
  229.  
  230. if ( $margin_top === "auto" ) $margin_top = 0; 
  231. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  232.  
  233. $height = $content_height; 
  234. $top = $diff - $content_height; 
  235. else if ( $height === "auto" && $bottom === "auto" ) { 
  236.  
  237. if ( $margin_top === "auto" ) $margin_top = 0; 
  238. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  239.  
  240. $height = $content_height; 
  241. $bottom = $diff - $content_height; 
  242. else if ( $top === "auto" && $bottom === "auto" ) { 
  243.  
  244. if ( $margin_top === "auto" ) $margin_top = 0; 
  245. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  246.  
  247. $bottom = $diff; 
  248. else if ( $top === "auto" ) { 
  249.  
  250. if ( $margin_top === "auto" ) $margin_top = 0; 
  251. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  252.  
  253. $top = $diff; 
  254. else if ( $height === "auto" ) { 
  255.  
  256. if ( $margin_top === "auto" ) $margin_top = 0; 
  257. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  258.  
  259. $height = $diff; 
  260. else if ( $bottom === "auto" ) { 
  261.  
  262. if ( $margin_top === "auto" ) $margin_top = 0; 
  263. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  264.  
  265. $bottom = $diff; 
  266. else { 
  267.  
  268. if ( $style->overflow === "visible" ) { 
  269. // set all autos to zero 
  270. if ( $margin_top === "auto" ) $margin_top = 0; 
  271. if ( $margin_bottom === "auto" ) $margin_bottom = 0; 
  272. if ( $top === "auto" ) $top = 0; 
  273. if ( $bottom === "auto" ) $bottom = 0; 
  274. if ( $height === "auto" ) $height = $content_height; 
  275.  
  276. // FIXME: overflow hidden 
  277.  
  278.  
  279. else { 
  280.  
  281. // Expand the height if overflow is visible  
  282. if ( $height === "auto" && $content_height > $height /** && $style->overflow === "visible" */) { 
  283. $height = $content_height; 
  284.  
  285. // FIXME: this should probably be moved to a seperate function as per 
  286. // _calculate_restricted_width 
  287.  
  288. // Only handle min/max height if the height is independent of the frame's content 
  289. if ( !($style->overflow === "visible" || 
  290. ($style->overflow === "hidden" && $height === "auto")) ) { 
  291.  
  292. $min_height = $style->min_height; 
  293. $max_height = $style->max_height; 
  294.  
  295. if ( isset($cb["h"]) ) { 
  296. $min_height = $style->length_in_pt($min_height, $cb["h"]); 
  297. $max_height = $style->length_in_pt($max_height, $cb["h"]); 
  298.  
  299. else if ( isset($cb["w"]) ) { 
  300.  
  301. if ( mb_strpos($min_height, "%") !== false ) { 
  302. $min_height = 0; 
  303. else { 
  304. $min_height = $style->length_in_pt($min_height, $cb["w"]); 
  305.  
  306. if ( mb_strpos($max_height, "%") !== false ) { 
  307. $max_height = "none"; 
  308. else { 
  309. $max_height = $style->length_in_pt($max_height, $cb["w"]); 
  310.  
  311. if ( $max_height !== "none" && $min_height > $max_height ) { 
  312. // Swap 'em 
  313. list($max_height, $min_height) = array($min_height, $max_height); 
  314.  
  315. if ( $max_height !== "none" && $height > $max_height ) { 
  316. $height = $max_height; 
  317.  
  318. if ( $height < $min_height ) { 
  319. $height = $min_height; 
  320.  
  321.  
  322. return array($height, $margin_top, $margin_bottom, $top, $bottom); 
  323.  
  324.  
  325. /** 
  326. * Adjust the justification of each of our lines. 
  327. * http://www.w3.org/TR/CSS21/text.html#propdef-text-align 
  328. */ 
  329. protected function _text_align() { 
  330. $style = $this->_frame->get_style(); 
  331. $w = $this->_frame->get_containing_block("w"); 
  332. $width = $style->length_in_pt($style->width, $w); 
  333.  
  334. switch ($style->text_align) { 
  335. default: 
  336. case "left": 
  337. foreach ($this->_frame->get_line_boxes() as $line) { 
  338. if ( !$line->left ) { 
  339. continue; 
  340.  
  341. foreach($line->get_frames() as $frame) { 
  342. if ( $frame instanceof Block_Frame_Decorator) { 
  343. continue; 
  344. $frame->set_position( $frame->get_position("x") + $line->left ); 
  345. return; 
  346.  
  347. case "right": 
  348. foreach ($this->_frame->get_line_boxes() as $line) { 
  349. // Move each child over by $dx 
  350. $dx = $width - $line->w - $line->right; 
  351.  
  352. foreach($line->get_frames() as $frame) { 
  353. // Block frames are not aligned by text-align 
  354. if ($frame instanceof Block_Frame_Decorator) { 
  355. continue; 
  356.  
  357. $frame->set_position( $frame->get_position("x") + $dx ); 
  358. break; 
  359.  
  360.  
  361. case "justify": 
  362. // We justify all lines except the last one 
  363. $lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards) 
  364. array_pop($lines); 
  365.  
  366. foreach($lines as $i => $line) { 
  367. if ( $line->br ) { 
  368. unset($lines[$i]); 
  369.  
  370. // One space character's width. Will be used to get a more accurate spacing 
  371. $space_width = Font_Metrics::get_text_width(" ", $style->font_family, $style->font_size); 
  372.  
  373. foreach ($lines as $line) { 
  374. if ( $line->left ) { 
  375. foreach ( $line->get_frames() as $frame ) { 
  376. if ( !$frame instanceof Text_Frame_Decorator ) { 
  377. continue; 
  378.  
  379. $frame->set_position( $frame->get_position("x") + $line->left ); 
  380.  
  381. // Only set the spacing if the line is long enough. This is really 
  382. // just an aesthetic choice ;) 
  383. //if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) { 
  384.  
  385. // Set the spacing for each child 
  386. if ( $line->wc > 1 ) { 
  387. $spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1); 
  388. else { 
  389. $spacing = 0; 
  390.  
  391. $dx = 0; 
  392. foreach($line->get_frames() as $frame) { 
  393. if ( !$frame instanceof Text_Frame_Decorator ) { 
  394. continue; 
  395.  
  396. $text = $frame->get_text(); 
  397. $spaces = mb_substr_count($text, " "); 
  398.  
  399. $char_spacing = $style->length_in_pt($style->letter_spacing); 
  400. $_spacing = $spacing + $char_spacing; 
  401.  
  402. $frame->set_position( $frame->get_position("x") + $dx ); 
  403. $frame->set_text_spacing($_spacing); 
  404.  
  405. $dx += $spaces * $_spacing; 
  406.  
  407. // The line (should) now occupy the entire width 
  408. $line->w = $width; 
  409.  
  410. //} 
  411. break; 
  412.  
  413. case "center": 
  414. case "centre": 
  415. foreach ($this->_frame->get_line_boxes() as $line) { 
  416. // Centre each line by moving each frame in the line by: 
  417. $dx = ($width + $line->left - $line->w - $line->right ) / 2; 
  418.  
  419. foreach ($line->get_frames() as $frame) { 
  420. // Block frames are not aligned by text-align 
  421. if ($frame instanceof Block_Frame_Decorator) { 
  422. continue; 
  423.  
  424. $frame->set_position( $frame->get_position("x") + $dx ); 
  425. break; 
  426.  
  427. /** 
  428. * Align inline children vertically. 
  429. * Aligns each child vertically after each line is reflowed 
  430. */ 
  431. function vertical_align() { 
  432.  
  433. $canvas = null; 
  434.  
  435. foreach ( $this->_frame->get_line_boxes() as $line ) { 
  436.  
  437. $height = $line->h; 
  438.  
  439. foreach ( $line->get_frames() as $frame ) { 
  440. $style = $frame->get_style(); 
  441.  
  442. if ( $style->display !== "inline" ) { 
  443. continue; 
  444.  
  445. $align = $frame->get_parent()->get_style()->vertical_align; 
  446.  
  447. if ( !isset($canvas) ) { 
  448. $canvas = $frame->get_root()->get_dompdf()->get_canvas(); 
  449.  
  450. $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size); 
  451. $y_offset = 0; 
  452.  
  453. switch ($align) { 
  454. case "baseline": 
  455. $y_offset = $height*0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning 
  456. break; 
  457.  
  458. case "middle": 
  459. $y_offset = ($height*0.8 - $baseline) / 2; 
  460. break; 
  461.  
  462. case "sub": 
  463. $y_offset = 0.3 * $height; 
  464. break; 
  465.  
  466. case "super": 
  467. $y_offset = -0.2 * $height; 
  468. break; 
  469.  
  470. case "text-top": 
  471. case "top": // Not strictly accurate, but good enough for now 
  472. break; 
  473.  
  474. case "text-bottom": 
  475. case "bottom": 
  476. $y_offset = $height*0.8 - $baseline; 
  477. break; 
  478.  
  479. if ( $y_offset ) { 
  480. $frame->move(0, $y_offset); 
  481.  
  482. /** 
  483. * @param Frame $child 
  484. */ 
  485. function process_clear(Frame $child) { 
  486. $enable_css_float = $this->get_dompdf()->get_option("enable_css_float"); 
  487. if ( !$enable_css_float ) { 
  488. return; 
  489.  
  490. $child_style = $child->get_style(); 
  491. $root = $this->_frame->get_root(); 
  492.  
  493. // Handle "clear" 
  494. if ( $child_style->clear !== "none" ) { 
  495. $lowest_y = $root->get_lowest_float_offset($child); 
  496.  
  497. // If a float is still applying, we handle it 
  498. if ( $lowest_y ) { 
  499. if ( $child->is_in_flow() ) { 
  500. $line_box = $this->_frame->get_current_line_box(); 
  501. $line_box->y = $lowest_y + $child->get_margin_height(); 
  502. $line_box->left = 0; 
  503. $line_box->right = 0; 
  504.  
  505. $child->move(0, $lowest_y - $child->get_position("y")); 
  506.  
  507. /** 
  508. * @param Frame $child 
  509. * @param float $cb_x 
  510. * @param float $cb_w 
  511. */ 
  512. function process_float(Frame $child, $cb_x, $cb_w) { 
  513. $enable_css_float = $this->_frame->get_dompdf()->get_option("enable_css_float"); 
  514. if ( !$enable_css_float ) { 
  515. return; 
  516.  
  517. $child_style = $child->get_style(); 
  518. $root = $this->_frame->get_root(); 
  519.  
  520. // Handle "float" 
  521. if ( $child_style->float !== "none" ) { 
  522. $root->add_floating_frame($child); 
  523.  
  524. // Remove next frame's beginning whitespace 
  525. $next = $child->get_next_sibling(); 
  526. if ( $next && $next instanceof Text_Frame_Decorator) { 
  527. $next->set_text(ltrim($next->get_text())); 
  528.  
  529. $line_box = $this->_frame->get_current_line_box(); 
  530. list($old_x, $old_y) = $child->get_position(); 
  531.  
  532. $float_x = $cb_x; 
  533. $float_y = $old_y; 
  534. $float_w = $child->get_margin_width(); 
  535.  
  536. if ( $child_style->clear === "none" ) { 
  537. switch( $child_style->float ) { 
  538. case "left":  
  539. $float_x += $line_box->left; 
  540. break; 
  541. case "right":  
  542. $float_x += ($cb_w - $line_box->right - $float_w); 
  543. break; 
  544. else { 
  545. if ( $child_style->float === "right" ) { 
  546. $float_x += ($cb_w - $float_w); 
  547.  
  548. if ( $cb_w < $float_x + $float_w - $old_x ) { 
  549. // TODO handle when floating elements don't fit 
  550.  
  551. $line_box->get_float_offsets(); 
  552.  
  553. if ( $child->_float_next_line ) { 
  554. $float_y += $line_box->h; 
  555.  
  556. $child->set_position($float_x, $float_y); 
  557. $child->move($float_x - $old_x, $float_y - $old_y, true); 
  558.  
  559. /** 
  560. * @param Frame_Decorator $block 
  561. */ 
  562. function reflow(Block_Frame_Decorator $block = null) { 
  563.  
  564. // Check if a page break is forced 
  565. $page = $this->_frame->get_root(); 
  566. $page->check_forced_page_break($this->_frame); 
  567.  
  568. // Bail if the page is full 
  569. if ( $page->is_full() ) { 
  570. return; 
  571.  
  572. // Generated content 
  573. $this->_set_content(); 
  574.  
  575. // Collapse margins if required 
  576. $this->_collapse_margins(); 
  577.  
  578. $style = $this->_frame->get_style(); 
  579. $cb = $this->_frame->get_containing_block(); 
  580.  
  581. if ( $style->position === "fixed" ) { 
  582. $cb = $this->_frame->get_root()->get_containing_block(); 
  583.  
  584. // Determine the constraints imposed by this frame: calculate the width 
  585. // of the content area: 
  586. list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width(); 
  587.  
  588. // Store the calculated properties 
  589. $style->width = $w . "pt"; 
  590. $style->margin_left = $left_margin."pt"; 
  591. $style->margin_right = $right_margin."pt"; 
  592. $style->left = $left ."pt"; 
  593. $style->right = $right . "pt"; 
  594.  
  595. // Update the position 
  596. $this->_frame->position(); 
  597. list($x, $y) = $this->_frame->get_position(); 
  598.  
  599. // Adjust the first line based on the text-indent property 
  600. $indent = $style->length_in_pt($style->text_indent, $cb["w"]); 
  601. $this->_frame->increase_line_width($indent); 
  602.  
  603. // Determine the content edge 
  604. $top = $style->length_in_pt(array($style->margin_top,  
  605. $style->padding_top,  
  606. $style->border_top_width), $cb["h"]); 
  607.  
  608. $bottom = $style->length_in_pt(array($style->border_bottom_width,  
  609. $style->margin_bottom,  
  610. $style->padding_bottom), $cb["h"]); 
  611.  
  612. $cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width,  
  613. $style->padding_left), $cb["w"]); 
  614.  
  615. $cb_y = $y + $top; 
  616.  
  617. $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y; 
  618.  
  619. // Set the y position of the first line in this block 
  620. $line_box = $this->_frame->get_current_line_box(); 
  621. $line_box->y = $cb_y; 
  622. $line_box->get_float_offsets(); 
  623.  
  624. // Set the containing blocks and reflow each child 
  625. foreach ( $this->_frame->get_children() as $child ) { 
  626.  
  627. // Bail out if the page is full 
  628. if ( $page->is_full() ) { 
  629. break; 
  630.  
  631. $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); 
  632.  
  633. $this->process_clear($child); 
  634.  
  635. $child->reflow($this->_frame); 
  636.  
  637. // Don't add the child to the line if a page break has occurred 
  638. if ( $page->check_page_break($child) ) { 
  639. break; 
  640.  
  641. $this->process_float($child, $cb_x, $w); 
  642.  
  643. // Determine our height 
  644. list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height(); 
  645. $style->height = $height; 
  646. $style->margin_top = $margin_top; 
  647. $style->margin_bottom = $margin_bottom; 
  648. $style->top = $top; 
  649. $style->bottom = $bottom; 
  650.  
  651. $needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto")); 
  652.  
  653. // Absolute positioning measurement 
  654. if ( $needs_reposition ) { 
  655. $orig_style = $this->_frame->get_original_style(); 
  656. if ( $orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto") ) { 
  657. $width = 0; 
  658. foreach ($this->_frame->get_line_boxes() as $line) { 
  659. $width = max($line->w, $width); 
  660. $style->width = $width; 
  661.  
  662. $style->left = $orig_style->left; 
  663. $style->right = $orig_style->right; 
  664.  
  665. $this->_text_align(); 
  666. $this->vertical_align(); 
  667.  
  668. // Absolute positioning 
  669. if ( $needs_reposition ) { 
  670. list($x, $y) = $this->_frame->get_position(); 
  671. $this->_frame->position(); 
  672. list($new_x, $new_y) = $this->_frame->get_position(); 
  673. $this->_frame->move($new_x-$x, $new_y-$y, true); 
  674.  
  675. if ( $block && $this->_frame->is_in_flow() ) { 
  676. $block->add_frame_to_line($this->_frame); 
  677.  
  678. // May be inline-block 
  679. if ( $style->display === "block" ) { 
  680. $block->add_line();