Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
// $Header: /cvsroot/html2ps/box.frame.php,v 1.24 2007/02/18 09:55:10 Konstantin Exp $
3
 
4
class FrameBox extends GenericContainerBox {
5
  function &create(&$root, &$pipeline) {
6
    $box =& new FrameBox($root, $pipeline);
7
    $box->readCSS($pipeline->get_current_css_state());
8
    return $box;
9
  }
10
 
11
  function reflow(&$parent, &$context) {
12
    // If frame contains no boxes (for example, the src link is broken)
13
    // we just return - no further processing will be done
14
    if (count($this->content) == 0) { return; };
15
 
16
    // First box contained in a frame should always fill all its height
17
    $this->content[0]->put_full_height($this->get_height());
18
 
19
    $hc = new HCConstraint(array($this->get_height(), false),
20
                           array($this->get_height(), false),
21
                           array($this->get_height(), false));
22
    $this->content[0]->put_height_constraint($hc);
23
 
24
    $context->push_collapsed_margin(0);
25
    $context->push_container_uid($this->uid);
26
 
27
    $this->reflow_content($context);
28
 
29
    $context->pop_collapsed_margin();
30
    $context->pop_container_uid();
31
  }
32
 
33
  /**
34
   * Reflow absolutely positioned block box. Note that according to CSS 2.1
35
   * the only types of boxes which could be absolutely positioned are
36
   * 'block' and 'table'
37
   *
38
   * @param FlowContext $context A flow context object containing the additional layout data.
39
   *
40
   * @link http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo CSS 2.1: Relationships between 'display', 'position', and 'float'
41
   */
42
  function reflow_absolute(&$context) {
43
    GenericFormattedBox::reflow($this->parent, $context);
44
 
45
    $position_strategy =& new StrategyPositionAbsolute();
46
    $position_strategy->apply($this);
47
 
48
    /**
49
     * As sometimes left/right values may not be set, we need to use the "fit" width here.
50
     * If box have a width constraint, 'get_max_width' will return constrained value;
51
     * othersise, an intrictic width will be returned.
52
     *
53
     * Note that get_max_width returns width _including_ external space line margins, borders and padding;
54
     * as we're setting the "internal" - content width, we must subtract "extra" space width from the
55
     * value received
56
     *
57
     * @see GenericContainerBox::get_max_width()
58
     */
59
 
60
    $this->put_width($this->get_max_width($context) - $this->_get_hor_extra());
61
 
62
    /**
63
     * Update the width, as it should be calculated based upon containing block width, not real parent.
64
     * After this we should remove width constraints or we may encounter problem
65
     * in future when we'll try to call get_..._width functions for this box
66
     *
67
     * @todo Update the family of get_..._width function so that they would apply constraint
68
     * using the containing block width, not "real" parent width
69
     */
70
    $wc = $this->get_css_property(CSS_WIDTH);
71
 
72
    $containing_block =& $this->_get_containing_block();
73
    $this->put_width($wc->apply($this->get_width(),
74
                                $containing_block['right'] - $containing_block['left']));
75
    $this->setCSSProperty(CSS_WIDTH, new WCNone());
76
 
77
    /**
78
     * Layout element's children
79
     */
80
    $this->reflow_content($context);
81
 
82
    /**
83
     * As absolute-positioned box generated new flow contexy, extend the height to fit all floats
84
     */
85
    $this->fitFloats($context);
86
 
87
    /**
88
     * If element have been positioned using 'right' or 'bottom' property,
89
     * we need to offset it, as we assumed it had zero width and height at
90
     * the moment we placed it
91
     */
92
    $right = $this->get_css_property(CSS_RIGHT);
93
    $left = $this->get_css_property(CSS_LEFT);
94
    if ($left->isAuto() && !$right->isAuto()) {
95
      $this->offset(-$this->get_width(), 0);
96
    };
97
 
98
    $bottom = $this->get_css_property(CSS_BOTTOM);
99
    $top = $this->get_css_property(CSS_TOP);
100
    if ($top->isAuto() && !$bottom->isAuto()) {
101
      $this->offset(0, $this->get_height());
102
    };
103
  }
104
 
105
  function FrameBox(&$root, &$pipeline) {
106
    $css_state =& $pipeline->get_current_css_state();
107
 
108
    // Inherit 'border' CSS value from parent (FRAMESET tag), if current FRAME
109
    // has no FRAMEBORDER attribute, and FRAMESET has one
110
    $parent = $root->parent();
111
    if (!$root->has_attribute('frameborder') &&
112
        $parent->has_attribute('frameborder')) {
113
      $parent_border = $css_state->get_propertyOnLevel(CSS_BORDER, CSS_PROPERTY_LEVEL_PARENT);
114
      $css_state->set_property(CSS_BORDER, $parent_border->copy());
115
    }
116
 
117
    $this->GenericContainerBox($root);
118
 
119
    // If NO src attribute specified, just return.
120
    if (!$root->has_attribute('src')) { return; };
121
 
122
    // Determine the fullly qualified URL of the frame content
123
    $src  = $root->get_attribute('src');
124
    $url  = $pipeline->guess_url($src);
125
    $data = $pipeline->fetch($url);
126
 
127
    /**
128
     * If framed page could not be fetched return immediately
129
     */
130
    if (is_null($data)) { return; };
131
 
132
    /**
133
     * Render only iframes containing HTML only
134
     *
135
     * Note that content-type header may contain additional information after the ';' sign
136
     */
137
    $content_type = $data->get_additional_data('Content-Type');
138
    $content_type_array = explode(';', $content_type);
139
    if ($content_type_array[0] != "text/html") { return; };
140
 
141
    $html = $data->get_content();
142
 
143
    // Remove control symbols if any
144
    $html = preg_replace('/[\x00-\x07]/', "", $html);
145
    $converter = Converter::create();
146
    $html = $converter->to_utf8($html, $data->detect_encoding());
147
    $html = html2xhtml($html);
148
    $tree = TreeBuilder::build($html);
149
 
150
    // Save current stylesheet, as each frame may load its own stylesheets
151
    //
152
    $pipeline->pushCSS();
153
    $css =& $pipeline->get_current_css();
154
    $css->scan_styles($tree, $pipeline);
155
 
156
    $frame_root = traverse_dom_tree_pdf($tree);
157
    $box_child  =& create_pdf_box($frame_root, $pipeline);
158
    $this->add_child($box_child);
159
 
160
    // Restore old stylesheet
161
    //
162
    $pipeline->pop_css();
163
 
164
    $pipeline->pop_base_url();
165
  }
166
 
167
  /**
168
   * Note that if both top and bottom are 'auto', box will use vertical coordinate
169
   * calculated using guess_corder in 'reflow' method which could be used if this
170
   * box had 'position: static'
171
   */
172
  function _positionAbsoluteVertically($containing_block) {
173
    $bottom = $this->get_css_property(CSS_BOTTOM);
174
    $top    = $this->get_css_property(CSS_TOP);
175
 
176
    if (!$top->isAuto()) {
177
      if ($top->isPercentage()) {
178
        $top_value = ($containing_block['top'] - $containing_block['bottom']) / 100 * $top->getPercentage();
179
      } else {
180
        $top_value = $top->getPoints();
181
      };
182
      $this->put_top($containing_block['top'] - $top_value - $this->get_extra_top());
183
    } elseif (!$bottom->isAuto()) {
184
      if ($bottom->isPercentage()) {
185
        $bottom_value = ($containing_block['top'] - $containing_block['bottom']) / 100 * $bottom->getPercentage();
186
      } else {
187
        $bottom_value = $bottom->getPoints();
188
      };
189
      $this->put_top($containing_block['bottom'] + $bottom_value + $this->get_extra_bottom());
190
    };
191
  }
192
 
193
  /**
194
   * Note that  if both  'left' and 'right'  are 'auto', box  will use
195
   * horizontal coordinate  calculated using guess_corder  in 'reflow'
196
   * method which could be used if this box had 'position: static'
197
   */
198
  function _positionAbsoluteHorizontally($containing_block) {
199
    $left  = $this->get_css_property(CSS_LEFT);
200
    $right = $this->get_css_property(CSS_RIGHT);
201
 
202
    if (!$left->isAuto()) {
203
      if ($left->isPercentage()) {
204
        $left_value = ($containing_block['right'] - $containing_block['left']) / 100 * $left->getPercentage();
205
      } else {
206
        $left_value = $left->getPoints();
207
      };
208
      $this->put_left($containing_block['left'] + $left_value + $this->get_extra_left());
209
    } elseif (!$right->isAuto()) {
210
      if ($right->isPercentage()) {
211
        $right_value = ($containing_block['right'] - $containing_block['left']) / 100 * $right->getPercentage();
212
      } else {
213
        $right_value = $right->getPoints();
214
      };
215
      $this->put_left($containing_block['right'] - $right_value - $this->get_extra_right());
216
    };
217
  }
218
}
219
 
220
class FramesetBox extends GenericContainerBox {
221
  var $rows;
222
  var $cols;
223
 
224
  function &create(&$root, &$pipeline) {
225
    $box =& new FramesetBox($root, $pipeline);
226
    $box->readCSS($pipeline->get_current_css_state());
227
    return $box;
228
  }
229
 
230
  function FramesetBox(&$root, $pipeline) {
231
    $this->GenericContainerBox($root);
232
    $this->create_content($root, $pipeline);
233
 
234
    // Now determine the frame layout inside the frameset
235
    $this->rows = $root->has_attribute('rows') ? $root->get_attribute('rows') : "100%";
236
    $this->cols = $root->has_attribute('cols') ? $root->get_attribute('cols') : "100%";
237
  }
238
 
239
  function reflow(&$parent, &$context) {
240
    $viewport =& $context->get_viewport();
241
 
242
    // Frameset always fill all available space in viewport
243
    $this->put_left($viewport->get_left() + $this->get_extra_left());
244
    $this->put_top($viewport->get_top() - $this->get_extra_top());
245
 
246
    $this->put_full_width($viewport->get_width());
247
    $this->setCSSProperty(CSS_WIDTH, new WCConstant($viewport->get_width()));
248
 
249
    $this->put_full_height($viewport->get_height());
250
    $this->put_height_constraint(new WCConstant($viewport->get_height()));
251
 
252
    // Parse layout-control values
253
    $rows = guess_lengths($this->rows, $this->get_height());
254
    $cols = guess_lengths($this->cols, $this->get_width());
255
 
256
    // Now reflow all frames in frameset
257
    $cur_col = 0;
258
    $cur_row = 0;
259
    for ($i=0; $i < count($this->content); $i++) {
260
      // Had we run out of cols/rows?
261
      if ($cur_row >= count($rows)) {
262
        // In valid HTML we never should get here, but someone can provide less frame cells
263
        // than frames. Extra frames will not be rendered at all
264
        return;
265
      }
266
 
267
      $frame =& $this->content[$i];
268
 
269
      /**
270
       * Depending on the source HTML, FramesetBox may contain some non-frame boxes;
271
       * we'll just ignore them
272
       */
273
      if (!is_a($frame, "FramesetBox") &&
274
          !is_a($frame, "FrameBox")) {
275
        continue;
276
      };
277
 
278
      // Guess frame size and position
279
      $frame->put_left($this->get_left() + array_sum(array_slice($cols, 0, $cur_col)) + $frame->get_extra_left());
280
      $frame->put_top($this->get_top()   - array_sum(array_slice($rows, 0, $cur_row)) - $frame->get_extra_top());
281
 
282
      $frame->put_full_width($cols[$cur_col]);
283
      $frame->setCSSProperty(CSS_WIDTH, new WCConstant($frame->get_width()));
284
 
285
      $frame->put_full_height($rows[$cur_row]);
286
      $frame->put_height_constraint(new WCConstant($frame->get_height()));
287
 
288
      // Reflow frame contents
289
      $context->push_viewport(FlowViewport::create($frame));
290
      $frame->reflow($this, $context);
291
      $context->pop_viewport();
292
 
293
      // Move to the next frame position
294
      // Next columns
295
      $cur_col ++;
296
      if ($cur_col >= count($cols)) {
297
        // Next row
298
        $cur_col = 0;
299
        $cur_row ++;
300
      }
301
    }
302
  }
303
}
304
?>