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?>