1<?php 2 3class StrategyWidthAbsolutePositioned { 4 function StrategyWidthAbsolutePositioned() { 5 } 6 7 /** 8 * See also CSS 2.1, p 10.3.7 Absolutely positioned, non-replaced 9 * elements 10 */ 11 function apply(&$box, &$context) { 12 $containing_block =& $box->_get_containing_block(); 13 $containing_block_width = $containing_block['right'] - $containing_block['left']; 14 15 $right =& $box->get_css_property(CSS_RIGHT); 16 $left =& $box->get_css_property(CSS_LEFT); 17 $wc =& $box->get_css_property(CSS_WIDTH); 18 19 // For the purposes of this section and the next, the term "static 20 // position" (of an element) refers, roughly, to the position an 21 // element would have had in the normal flow. More precisely: 22 // 23 // * The static position for 'left' is the distance from the left 24 // edge of the containing block to the left margin edge of a 25 // hypothetical box that would have been the first box of the 26 // element if its 'position' property had been 'static' and 27 // 'float' had been 'none'. The value is negative if the 28 // hypothetical box is to the left of the containing block. 29 // 30 // * The static position for 'right' is the distance from the 31 // right edge of the containing block to the right margin edge 32 // of the same hypothetical box as above. The value is positive 33 // if the hypothetical box is to the left of the containing 34 // block's edge. 35 // 36 // For the purposes of calculating the static position, the 37 // containing block of fixed positioned elements is the initial 38 // containing block instead of the viewport, and all scrollable 39 // boxes should be assumed to be scrolled to their origin. 40 // 41 // @todo: implement 42 $static_left = 0; 43 $static_right = 0; 44 45 // Calculation of the shrink-to-fit width is similar to 46 // calculating the width of a table cell using the automatic table 47 // layout algorithm. Roughly: calculate the preferred width by 48 // formatting the content without breaking lines other than where 49 // explicit line breaks occur, and also calculate the preferred 50 // minimum width, e.g., by trying all possible line breaks. CSS 51 // 2.1 does not define the exact algorithm. Thirdly, calculate the 52 // available width: this is found by solving for 'width' after 53 // setting 'left' (in case 1) or 'right' (in case 3) to 0. 54 // 55 // Then the shrink-to-fit width is: min(max(preferred minimum 56 // width, available width), preferred width). 57 $preferred_minimum_width = $box->get_preferred_minimum_width($context); 58 $available_width = $containing_block_width - 59 ($left->isAuto() ? 0 : $left->getPoints($containing_block_width)) - 60 ($right->isAuto() ? 0 : $right->getPoints($containing_block_width)) - 61 $box->_get_hor_extra(); 62 $preferred_width = $box->get_preferred_width($context); 63 64 $shrink_to_fit_width = min(max($preferred_minimum_width, 65 $available_width), 66 $preferred_width); 67 68 // The constraint that determines the used values for these 69 // elements is: 70 // 71 // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 72 // 'width' + 'padding-right' + 'border-right-width' + 73 // 'margin-right' + 'right' + scrollbar width (if any) = width of 74 // containing block 75 76 // If all three of 'left', 'width', and 'right' are 'auto': First 77 // set any 'auto' values for 'margin-left' and 'margin-right' to 78 // 0. Then, if the 'direction' property of the containing block is 79 // 'ltr' set 'left' to the static position and apply rule number 80 // three below; otherwise, set 'right' to the static position and 81 // apply rule number one below. 82 if ($left->isAuto() && $right->isAuto() && $wc->isNull()) { 83 // @todo: support 'direction' property for the containing block 84 $box->setCSSProperty(CSS_LEFT, ValueLeft::fromString('0')); 85 }; 86 87 // If none of the three is 'auto': If both 'margin-left' and 88 // 'margin-right' are 'auto', solve the equation under the extra 89 // constraint that the two margins get equal values, unless this 90 // would make them negative, in which case when direction of the 91 // containing block is 'ltr' ('rtl'), set 'margin-left' 92 // ('margin-right') to zero and solve for 'margin-right' 93 // ('margin-left'). If one of 'margin-left' or 'margin-right' is 94 // 'auto', solve the equation for that value. If the values are 95 // over-constrained, ignore the value for 'left' (in case the 96 // 'direction' property of the containing block is 'rtl') or 97 // 'right' (in case 'direction' is 'ltr') and solve for that 98 // value. 99 if (!$left->isAuto() && !$right->isAuto() && !$wc->isNull()) { 100 // @todo: implement 101 $box->put_width($wc->apply($box->get_width(), 102 $containing_block_width)); 103 }; 104 105 // Otherwise, set 'auto' values for 'margin-left' and 106 // 'margin-right' to 0, and pick the one of the following six 107 // rules that applies. 108 109 // Case 1 ('left' and 'width' are 'auto' and 'right' is not 110 // 'auto', then the width is shrink-to-fit. Then solve for 'left') 111 if ($left->isAuto() && !$right->isAuto() && $wc->isNull()) { 112 $box->put_width($shrink_to_fit_width); 113 }; 114 115 // Case 2 ('left' and 'right' are 'auto' and 'width' is not 116 // 'auto', then if the 'direction' property of the containing 117 // block is 'ltr' set 'left' to the static position, otherwise set 118 // 'right' to the static position. Then solve for 'left' (if 119 // 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').) 120 if ($left->isAuto() && $right->isAuto() && !$wc->isNull()) { 121 // @todo: implement 'direction' support 122 $box->put_width($wc->apply($box->get_width(), 123 $containing_block_width)); 124 }; 125 126 // Case 3 ('width' and 'right' are 'auto' and 'left' is not 127 // 'auto', then the width is shrink-to-fit . Then solve for 128 // 'right') 129 if (!$left->isAuto() && $right->isAuto() && $wc->isNull()) { 130 $box->put_width($shrink_to_fit_width); 131 }; 132 133 // Case 4 ('left' is 'auto', 'width' and 'right' are not 'auto', 134 // then solve for 'left') 135 if ($left->isAuto() && !$right->isAuto() && !$wc->isNull()) { 136 $box->put_width($wc->apply($box->get_width(), 137 $containing_block_width)); 138 }; 139 140 // Case 5 ('width' is 'auto', 'left' and 'right' are not 'auto', 141 // then solve for 'width') 142 if (!$left->isAuto() && !$right->isAuto() && $wc->isNull()) { 143 $box->put_width($containing_block_width - 144 $left->getPoints($containing_block_width) - 145 $right->getPoints($containing_block_width)); 146 }; 147 148 // Case 6 ('right' is 'auto', 'left' and 'width' are not 'auto', 149 // then solve for 'right') 150 if (!$left->isAuto() && $right->isAuto() && !$wc->isNull()) { 151 $box->put_width($wc->apply($box->get_width(), 152 $containing_block_width)); 153 }; 154 155 /** 156 * After this we should remove width constraints or we may encounter problem 157 * in future when we'll try to call get_..._width functions for this box 158 * 159 * @todo Update the family of get_..._width function so that they would apply constraint 160 * using the containing block width, not "real" parent width 161 */ 162 $box->setCSSProperty(CSS_WIDTH, new WCConstant($box->get_width())); 163 } 164} 165 166?>