Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
class StrategyTableLayoutAuto {
4
  function StrategyTableLayoutAuto() {
5
  }
6
 
7
  function apply($table, &$context) {
8
    $width = $table->get_width();
9
    return $this->table_columns_fit($table, $width, $context);
10
  }
11
 
12
  function use_colspans(&$table, $widths, &$context, $width_fun, $minwc, $maxwc) {
13
    $colspans = $table->get_colspans();
14
 
15
    foreach ($colspans as $colspan) {
16
      $cell = $table->content[$colspan->row]->content[$colspan->column];
17
 
18
      // apply colspans to the corresponsing colspanned-cell dimension
19
      //
20
      $cell_width = $cell->$width_fun($context);
21
 
22
      // now select the pre-calculated widths of columns covered by this cell
23
      // select the list of resizable columns covered by this cell
24
      $spanned_widths = array();
25
      $spanned_resizable = array();
26
 
27
      for ($i=$colspan->column; $i < $colspan->column+$colspan->size; $i++) {
28
        $spanned_widths[] = $widths[$i];
29
        $spanned_resizable[] = ($minwc[$i] != $maxwc[$i]);
30
      }
31
 
32
      // Sometimes we may encounter the colspan over the empty columns (I mean ALL columns are empty); in this case
33
      // we need to make these columns reizable in order to fit colspanned cell contents
34
      //
35
      if (array_sum($spanned_widths) == 0) {
36
        for ($i=0; $i<count($spanned_widths); $i++) {
37
          $spanned_widths[$i] = EPSILON;
38
          $spanned_resizable[$i] = true;
39
        };
40
      };
41
 
42
      // The same problem may arise when all colspanned columns are not resizable; in this case we'll force all
43
      // of them to be resized
44
      $any_resizable = false;
45
      for ($i=0; $i<count($spanned_widths); $i++) {
46
        $any_resizable |= $spanned_resizable[$i];
47
      };
48
      if (!$any_resizable) {
49
        for ($i=0; $i<count($spanned_widths); $i++) {
50
          $spanned_resizable[$i] = true;
51
        };
52
      }
53
 
54
      // Expand resizable columns
55
      //
56
      $spanned_widths = expand_to_with_flags($cell_width,$spanned_widths,$spanned_resizable);
57
 
58
      // Store modified widths
59
      array_splice($widths, $colspan->column, $colspan->size, $spanned_widths);
60
    };
61
 
62
    return $widths;
63
  }
64
 
65
  /**
66
   * Fit table columns to the given width
67
   */
68
  function table_columns_fit(&$table, $width, &$context) {
69
    $minw = $table->get_table_columns_min_widths($context);
70
    $maxw = $table->get_table_columns_max_widths($context);
71
 
72
    $minw = $this->use_colspans($table, $minw, $context, 'get_min_width', $minw, $maxw);
73
    $maxw = $this->use_colspans($table, $maxw, $context, 'get_max_width', $minw, $maxw);
74
 
75
    // Store number of columns
76
    $columns = count($minw);
77
 
78
    // Apply column width constraints
79
    $minwc = array();
80
    $maxwc = array();
81
 
82
    $cellpadding = $table->get_css_property(CSS_HTML2PS_CELLPADDING);
83
    $cellspacing = $table->get_css_property(CSS_HTML2PS_CELLSPACING);
84
 
85
    for ($i=0; $i<count($minw); $i++) {
86
      $cwc = $table->get_cwc($i);
87
 
88
      // Do not allow constrained max width be less than min width
89
      // Do not allow constrained min width be less than min width
90
      //
91
      $table_width = $table->get_width();
92
 
93
      $extra = 2*$cellpadding->getPoints() + $cellspacing->getPoints();
94
 
95
      $minwc[$i] = max($minw[$i], $cwc->apply($minw[$i]-$extra, $table_width) + $extra);
96
      $maxwc[$i] = max($minw[$i], $cwc->apply($maxw[$i]-$extra, $table_width) + $extra);
97
    };
98
 
99
    $minwc = $table->normalize_min_widths($width, $minw, $minwc);
100
    $minwc = $table->_table_apply_colspans($minwc, $context, 'get_min_width', $minwc, $maxwc);
101
 
102
    // We need to normalize widths for the case of colspans width is too big; for example:
103
    // <table><tr><td width="100">
104
    // <table><tr><td width="150">TEXT<td>TEXT<tr><td colspan="2" width="200">
105
    // in this case table SHOULD NOT be expanded over the 100px!
106
    //
107
    // $minwc = $table->normalize_min_widths($width, $minw, $minwc);
108
    $maxwc = $table->_table_apply_colspans($maxwc, $context, 'get_max_width', $minwc, $maxwc);
109
 
110
    // Calculate actual widths
111
    $widths = array();
112
    // Calculate widths for all constrained columns
113
    for ($i=0; $i < $columns; $i++) {
114
      if ($table->is_constrained_column($i)) {
115
        $widths[$i] = $minwc[$i];
116
      }
117
    }
118
 
119
    // Quick fix for overconstrained tables: if table have width attribute AND its value is less than sum
120
    // of constrained columns widths plus minimal widths of uncostrained columns, then we'll expand the width of table
121
    // to fit all columns
122
    // 1. calculate sum of constrained column widths
123
    // 2. calculate sum of unconstrained column minimal widths
124
    $sum_cw = 0;
125
    $sum_ucw = 0;
126
    for ($i=0; $i < $columns; $i++) {
127
      if ($table->is_constrained_column($i)) {
128
        $sum_cw += $widths[$i];
129
      } else {
130
        $sum_ucw += $minwc[$i];
131
      }
132
    }
133
 
134
    // 3. compare these widths with the table width and choose the maximal value
135
    $width = max($width, $sum_cw + $sum_ucw);
136
 
137
    // Second pass - disctribute the rest of the width
138
 
139
    // Explanation of the stuff below (I've really had problems with this small piece of code, especially
140
    // when I was trying to fix "bugs" inside it)
141
    //
142
    // First of all, no column can be narrower than it minimal width (determined by its content)
143
    // Note that constrained columns have their widths distributed above, so we can exclude them for now
144
    // (just throw them out and imagine that table does not contain any width-constrained cols)
145
    //
146
    // Second, the relative widths of columns will have _appoximately_ the same ratio as
147
    // their maximal content widths. (In exception of cases where the first rule will take place -
148
    // say for the table containing two columns with the VERY long text in the first and one or two words
149
    // in the second)
150
    //
151
    // In general, this approach can be inoptimal in case of _very_ different font sizes
152
    // inside the cells, of, say big images; nevertheless, it will give a good approximate
153
    // AND still fast enough (unlike fully correct methods involving evaluation of the content height of the cell)
154
    //
155
    // Thus, we do the following:
156
    // - calculate the ratio of current column MAXIMAL ($current_max) width to the sum of MAXIMAL widths of all columns left
157
    //   (inluding current) second rule applied. Note that we need remember about column spans and select
158
    //   maxw or maxwc in order.
159
    // - then check if the rest of width will be too small for other columns to fit and decrease current columns
160
    //   width (see MIN function call)
161
    // - then check again if our width will be too small for current column to fit (and expand if nesessary) -
162
    //   MAX function call
163
    for ($i=0; $i < $columns; $i++) {
164
      if (!$table->is_constrained_column($i)) {
165
        // Get undistributed width (total table width - width of constrained columns)
166
        $rest = $width - array_sum($widths);
167
        // get max width of column being processed
168
        // If width is equal to zero, use max constrained width, as this column could be covered by colspan;
169
        // If not, we lose nothing, because all constrained columns are already processed earlier, and no more
170
        // columns except these two types can have different constrained and raw widths
171
        $current_max = max($maxw[$i], $maxwc[$i]);
172
 
173
        // Get sum of maximal constrained widths of unplaced columns
174
        $sum_max_cw = 0;
175
        $sum_min_cw = 0;
176
        for ($j=0; $j<$columns; $j++) {
177
          if (!isset($widths[$j])) {
178
            $sum_max_cw += max($maxw[$j], $maxwc[$j]);
179
            $sum_min_cw += max($minw[$j], $minwc[$j]);
180
          };
181
        };
182
 
183
        // If some unplaced columns have maximal (constrained width) greater zero
184
        if ($sum_max_cw > 0) {
185
          $current_max = min($current_max * $rest / $sum_max_cw, $rest - $sum_min_cw + max($minwc[$i], $minw[$i]));
186
        };
187
 
188
        // Check for minimal width (either unconstrained or constrained) of current column
189
        $current_max = max($current_max, $minw[$i] == 0 ? $minwc[$i] : $minw[$i]);
190
        // Store calculated width
191
        $widths[$i] = $current_max;
192
      }
193
    }
194
 
195
    // Process the case of a lone empty table cell (used, for example, for its background color)
196
    // as we're using floating point numbers, we cannot use equals sign
197
    if (array_sum($widths) < EPSILON) {
198
      for ($i=0; $i<count($widths); $i++) {
199
        $widths[$i] = 0.01;
200
      };
201
    };
202
 
203
    // now - the last attempt; if total width is less than box width, then we have a situation when either
204
    // all columns AND table are width constrained or the HTML similar to the following:
205
    //
206
    // <table cellpadding="0" width="100%" bgcolor="green"><tbody><tr>
207
    // <td colspan="2" bgcolor="yellow"></td>
208
    // <td style="width: 100px;" bgcolor="cyan">TEXT
209
    //
210
    // e.g. empty column (with zero width) and fixed-width column.
211
    //
212
    $wc = $table->get_css_property(CSS_WIDTH);
213
    if (!$wc->isNull()) {
214
      if (array_sum($widths) < $width) {
215
        // Let's make zero-width columns
216
        // non-zero width (so that they columd be expanded) and re-try expanding columns
217
        //
218
        for ($i=0; $i<count($widths); $i++) {
219
          if ($widths[$i] == 0) { $widths[$i] = EPSILON; };
220
        };
221
 
222
        // Now, if there's at least one non-costrained columns, try expanding them again
223
        $flags = $table->get_non_constrained_width_flags();
224
        if (!any_flag_set($flags)) {
225
          $flags = $table->get_non_constant_constrained_width_flags();
226
          if (!any_flag_set($flags)) {
227
            $flags = $table->get_non_image_constrained_width_flags();
228
            if (!any_flag_set($flags)) {
229
              for ($i=0; $i<count($flags); $i++) { $flags[$i] = true; };
230
            };
231
          };
232
        };
233
 
234
        $widths = expand_to_with_flags($width,
235
                                       $widths,
236
                                       $flags);
237
      };
238
 
239
      // in case of overconstrained table (e.g. two columns with 20% widths), expand them
240
      $widths = expand_to($width, $widths);
241
    };
242
 
243
    $table->put_full_width(array_sum($widths));
244
 
245
    // Now we need to sort array by key keeping key-value associations in order for array_slice to work correctly
246
    ksort($widths, SORT_NUMERIC);
247
 
248
    return $widths;
249
  }
250
}
251
 
252
?>