| 1 |
lars |
1 |
<?php
|
|
|
2 |
// $Header: /cvsroot/html2ps/box.text.php,v 1.56 2007/05/07 12:15:53 Konstantin Exp $
|
|
|
3 |
|
|
|
4 |
require_once(HTML2PS_DIR.'box.inline.simple.php');
|
|
|
5 |
|
|
|
6 |
// TODO: from my POV, it wll be better to pass the font- or CSS-controlling object to the constructor
|
|
|
7 |
// instead of using globally visible functions in 'show'.
|
|
|
8 |
|
|
|
9 |
class TextBox extends SimpleInlineBox {
|
|
|
10 |
var $words;
|
|
|
11 |
var $encodings;
|
|
|
12 |
var $hyphens;
|
|
|
13 |
var $_widths;
|
|
|
14 |
var $_word_widths;
|
|
|
15 |
var $_wrappable;
|
|
|
16 |
var $wrapped;
|
|
|
17 |
|
|
|
18 |
function TextBox() {
|
|
|
19 |
$this->SimpleInlineBox();
|
|
|
20 |
|
|
|
21 |
$this->words = array();
|
|
|
22 |
$this->encodings = array();
|
|
|
23 |
$this->hyphens = array();
|
|
|
24 |
$this->_word_widths = array();
|
|
|
25 |
$this->_wrappable = array();
|
|
|
26 |
$this->wrapped = null;
|
|
|
27 |
$this->_widths = array();
|
|
|
28 |
|
|
|
29 |
$this->font_size = 0;
|
|
|
30 |
$this->ascender = 0;
|
|
|
31 |
$this->descender = 0;
|
|
|
32 |
$this->width = 0;
|
|
|
33 |
$this->height = 0;
|
|
|
34 |
}
|
|
|
35 |
|
|
|
36 |
/**
|
|
|
37 |
* Check if given subword contains soft hyphens and calculate
|
|
|
38 |
*/
|
|
|
39 |
function _make_wrappable(&$driver, $base_width, $font_name, $font_size, $subword_index) {
|
|
|
40 |
$hyphens = $this->hyphens[$subword_index];
|
|
|
41 |
$wrappable = array();
|
|
|
42 |
|
|
|
43 |
foreach ($hyphens as $hyphen) {
|
|
|
44 |
$subword_wrappable_index = $hyphen;
|
|
|
45 |
$subword_wrappable_width = $base_width + $driver->stringwidth(substr($this->words[$subword_index], 0, $subword_wrappable_index),
|
|
|
46 |
$font_name,
|
|
|
47 |
$this->encodings[$subword_index],
|
|
|
48 |
$font_size);
|
|
|
49 |
$subword_full_width = $subword_wrappable_width + $driver->stringwidth('-',
|
|
|
50 |
$font_name,
|
|
|
51 |
"iso-8859-1",
|
|
|
52 |
$font_size);
|
|
|
53 |
|
|
|
54 |
$wrappable[] = array($subword_index, $subword_wrappable_index, $subword_wrappable_width, $subword_full_width);
|
|
|
55 |
};
|
|
|
56 |
return $wrappable;
|
|
|
57 |
}
|
|
|
58 |
|
|
|
59 |
function get_content() {
|
|
|
60 |
return join('', array_map(array($this, 'get_content_callback'), $this->words, $this->encodings));
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
function get_content_callback($word, $encoding) {
|
|
|
64 |
$manager_encoding =& ManagerEncoding::get();
|
|
|
65 |
return $manager_encoding->to_utf8($word, $encoding);
|
|
|
66 |
}
|
|
|
67 |
|
|
|
68 |
function get_height() {
|
|
|
69 |
return $this->height;
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
function put_height($value) {
|
|
|
73 |
$this->height = $value;
|
|
|
74 |
}
|
|
|
75 |
|
|
|
76 |
// Apply 'line-height' CSS property; modifies the default_baseline value
|
|
|
77 |
// (NOT baseline, as it is calculated - and is overwritten - in the close_line
|
|
|
78 |
// method of container box
|
|
|
79 |
//
|
|
|
80 |
// Note that underline position (or 'descender' in terms of PDFLIB) -
|
|
|
81 |
// so, simple that space of text box under the baseline - is scaled too
|
|
|
82 |
// when 'line-height' is applied
|
|
|
83 |
//
|
|
|
84 |
function _apply_line_height() {
|
|
|
85 |
$height = $this->get_height();
|
|
|
86 |
$under = $height - $this->default_baseline;
|
|
|
87 |
|
|
|
88 |
$line_height = $this->get_css_property(CSS_LINE_HEIGHT);
|
|
|
89 |
|
|
|
90 |
if ($height > 0) {
|
|
|
91 |
$scale = $line_height->apply($this->ascender + $this->descender) / ($this->ascender + $this->descender);
|
|
|
92 |
} else {
|
|
|
93 |
$scale = 0;
|
|
|
94 |
};
|
|
|
95 |
|
|
|
96 |
// Calculate the height delta of the text box
|
|
|
97 |
|
|
|
98 |
$delta = $height * ($scale-1);
|
|
|
99 |
$this->put_height(($this->ascender + $this->descender)*$scale);
|
|
|
100 |
$this->default_baseline = $this->default_baseline + $delta/2;
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
function _get_font_name(&$viewport, $subword_index) {
|
|
|
104 |
if (isset($this->_cache[CACHE_TYPEFACE][$subword_index])) {
|
|
|
105 |
return $this->_cache[CACHE_TYPEFACE][$subword_index];
|
|
|
106 |
};
|
|
|
107 |
|
|
|
108 |
$font_resolver =& $viewport->get_font_resolver();
|
|
|
109 |
|
|
|
110 |
$font = $this->get_css_property(CSS_FONT);
|
|
|
111 |
|
|
|
112 |
$typeface = $font_resolver->get_typeface_name($font->family,
|
|
|
113 |
$font->weight,
|
|
|
114 |
$font->style,
|
|
|
115 |
$this->encodings[$subword_index]);
|
|
|
116 |
|
|
|
117 |
$this->_cache[CACHE_TYPEFACE][$subword_index] = $typeface;
|
|
|
118 |
|
|
|
119 |
return $typeface;
|
|
|
120 |
}
|
|
|
121 |
|
|
|
122 |
function add_subword($raw_subword, $encoding, $hyphens) {
|
|
|
123 |
$text_transform = $this->get_css_property(CSS_TEXT_TRANSFORM);
|
|
|
124 |
switch ($text_transform) {
|
|
|
125 |
case CSS_TEXT_TRANSFORM_CAPITALIZE:
|
|
|
126 |
$subword = ucwords($raw_subword);
|
|
|
127 |
break;
|
|
|
128 |
case CSS_TEXT_TRANSFORM_UPPERCASE:
|
|
|
129 |
$subword = strtoupper($raw_subword);
|
|
|
130 |
break;
|
|
|
131 |
case CSS_TEXT_TRANSFORM_LOWERCASE:
|
|
|
132 |
$subword = strtolower($raw_subword);
|
|
|
133 |
break;
|
|
|
134 |
case CSS_TEXT_TRANSFORM_NONE:
|
|
|
135 |
$subword = $raw_subword;
|
|
|
136 |
break;
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
$this->words[] = $subword;
|
|
|
140 |
$this->encodings[] = $encoding;
|
|
|
141 |
$this->hyphens[] = $hyphens;
|
|
|
142 |
}
|
|
|
143 |
|
|
|
144 |
function &create($text, $encoding, &$pipeline) {
|
|
|
145 |
$box =& TextBox::create_empty($pipeline);
|
|
|
146 |
$box->add_subword($text, $encoding, array());
|
|
|
147 |
return $box;
|
|
|
148 |
}
|
|
|
149 |
|
|
|
150 |
function &create_empty(&$pipeline) {
|
|
|
151 |
$box =& new TextBox();
|
|
|
152 |
$css_state = $pipeline->get_current_css_state();
|
|
|
153 |
|
|
|
154 |
$box->readCSS($css_state);
|
|
|
155 |
$css_state = $pipeline->get_current_css_state();
|
|
|
156 |
|
|
|
157 |
return $box;
|
|
|
158 |
}
|
|
|
159 |
|
|
|
160 |
function readCSS(&$state) {
|
|
|
161 |
parent::readCSS($state);
|
|
|
162 |
|
|
|
163 |
$this->_readCSSLengths($state,
|
|
|
164 |
array(CSS_TEXT_INDENT,
|
|
|
165 |
CSS_LETTER_SPACING));
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
// Inherited from GenericFormattedBox
|
|
|
169 |
function get_descender() {
|
|
|
170 |
return $this->descender;
|
|
|
171 |
}
|
|
|
172 |
|
|
|
173 |
function get_ascender() {
|
|
|
174 |
return $this->ascender;
|
|
|
175 |
}
|
|
|
176 |
|
|
|
177 |
function get_baseline() {
|
|
|
178 |
return $this->baseline;
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
function get_min_width_natural(&$context) {
|
|
|
182 |
return $this->get_full_width();
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
function get_min_width(&$context) {
|
|
|
186 |
return $this->get_full_width();
|
|
|
187 |
}
|
|
|
188 |
|
|
|
189 |
function get_max_width(&$context) {
|
|
|
190 |
return $this->get_full_width();
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
// Checks if current inline box should cause a line break inside the parent box
|
|
|
194 |
//
|
|
|
195 |
// @param $parent reference to a parent box
|
|
|
196 |
// @param $content flow context
|
|
|
197 |
// @return true if line break occurred; false otherwise
|
|
|
198 |
//
|
|
|
199 |
function maybe_line_break(&$parent, &$context) {
|
|
|
200 |
if (!$parent->line_break_allowed()) {
|
|
|
201 |
return false;
|
|
|
202 |
};
|
|
|
203 |
|
|
|
204 |
$last =& $parent->last_in_line();
|
|
|
205 |
if ($last) {
|
|
|
206 |
// Check if last box was a note call box. Punctuation marks
|
|
|
207 |
// after a note-call box should not be wrapped to new line,
|
|
|
208 |
// while "plain" words may be wrapped.
|
|
|
209 |
if ($last->is_note_call() && $this->is_punctuation()) {
|
|
|
210 |
return false;
|
|
|
211 |
};
|
|
|
212 |
};
|
|
|
213 |
|
|
|
214 |
// Calculate the x-coordinate of this box right edge
|
|
|
215 |
$right_x = $this->get_full_width() + $parent->_current_x;
|
|
|
216 |
|
|
|
217 |
$need_break = false;
|
|
|
218 |
|
|
|
219 |
// Check for right-floating boxes
|
|
|
220 |
// If upper-right corner of this inline box is inside of some float, wrap the line
|
|
|
221 |
$float = $context->point_in_floats($right_x, $parent->_current_y);
|
|
|
222 |
if ($float) {
|
|
|
223 |
$need_break = true;
|
|
|
224 |
};
|
|
|
225 |
|
|
|
226 |
// No floats; check if we had run out the right edge of container
|
|
|
227 |
// TODO: nobr-before, nobr-after
|
|
|
228 |
if (($right_x > $parent->get_right()+EPSILON)) {
|
|
|
229 |
// Now check if parent line box contains any other boxes;
|
|
|
230 |
// if not, we should draw this box unless we have a floating box to the left
|
|
|
231 |
|
|
|
232 |
$first = $parent->get_first();
|
|
|
233 |
|
|
|
234 |
$ti = $this->get_css_property(CSS_TEXT_INDENT);
|
|
|
235 |
$indent_offset = $ti->calculate($parent);
|
|
|
236 |
|
|
|
237 |
if ($parent->_current_x > $parent->get_left() + $indent_offset + EPSILON) {
|
|
|
238 |
$need_break = true;
|
|
|
239 |
};
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
// As close-line will not change the current-Y parent coordinate if no
|
|
|
243 |
// items were in the line box, we need to offset this explicitly in this case
|
|
|
244 |
//
|
|
|
245 |
if ($parent->line_box_empty() && $need_break) {
|
|
|
246 |
$parent->_current_y -= $this->get_height();
|
|
|
247 |
};
|
|
|
248 |
|
|
|
249 |
if ($need_break) {
|
|
|
250 |
// Check if current box contains soft hyphens and use them, breaking word into parts
|
|
|
251 |
$size = count($this->_wrappable);
|
|
|
252 |
if ($size > 0) {
|
|
|
253 |
$width_delta = $right_x - $parent->get_right();
|
|
|
254 |
if (!is_null($float)) {
|
|
|
255 |
$width_delta = $right_x - $float->get_left_margin();
|
|
|
256 |
};
|
|
|
257 |
|
|
|
258 |
$this->_find_soft_hyphen($parent, $width_delta);
|
|
|
259 |
};
|
|
|
260 |
|
|
|
261 |
$parent->close_line($context);
|
|
|
262 |
|
|
|
263 |
// Check if parent inline boxes have left padding/margins and add them to current_x
|
|
|
264 |
$element = $this->parent;
|
|
|
265 |
while (!is_null($element) && is_a($element,"GenericInlineBox")) {
|
|
|
266 |
$parent->_current_x += $element->get_extra_left();
|
|
|
267 |
$element = $element->parent;
|
|
|
268 |
};
|
|
|
269 |
};
|
|
|
270 |
|
|
|
271 |
return $need_break;
|
|
|
272 |
}
|
|
|
273 |
|
|
|
274 |
function _find_soft_hyphen(&$parent, $width_delta) {
|
|
|
275 |
/**
|
|
|
276 |
* Now we search for soft hyphen closest to the right margin
|
|
|
277 |
*/
|
|
|
278 |
$size = count($this->_wrappable);
|
|
|
279 |
for ($i=$size-1; $i>=0; $i--) {
|
|
|
280 |
$wrappable = $this->_wrappable[$i];
|
|
|
281 |
if ($this->get_width() - $wrappable[3] > $width_delta) {
|
|
|
282 |
$this->save_wrapped($wrappable, $parent, $context);
|
|
|
283 |
$parent->append_line($this);
|
|
|
284 |
return;
|
|
|
285 |
};
|
|
|
286 |
};
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
function save_wrapped($wrappable, &$parent, &$context) {
|
|
|
290 |
$this->wrapped = array($wrappable,
|
|
|
291 |
$parent->_current_x + $this->get_extra_left(),
|
|
|
292 |
$parent->_current_y - $this->get_extra_top());
|
|
|
293 |
}
|
|
|
294 |
|
|
|
295 |
function reflow(&$parent, &$context) {
|
|
|
296 |
// Check if we need a line break here (possilble several times in a row, if we
|
|
|
297 |
// have a long word and a floating box intersecting with this word
|
|
|
298 |
//
|
|
|
299 |
// To prevent infinite loop, we'll use a limit of 100 sequental line feeds
|
|
|
300 |
$i=0;
|
|
|
301 |
|
|
|
302 |
do { $i++; } while ($this->maybe_line_break($parent, $context) && $i < 100);
|
|
|
303 |
|
|
|
304 |
// Determine the baseline position and height of the text-box using line-height CSS property
|
|
|
305 |
$this->_apply_line_height();
|
|
|
306 |
|
|
|
307 |
// set default baseline
|
|
|
308 |
$this->baseline = $this->default_baseline;
|
|
|
309 |
|
|
|
310 |
// append current box to parent line box
|
|
|
311 |
$parent->append_line($this);
|
|
|
312 |
|
|
|
313 |
// Determine coordinates of upper-left _margin_ corner
|
|
|
314 |
$this->guess_corner($parent);
|
|
|
315 |
|
|
|
316 |
// Offset parent current X coordinate
|
|
|
317 |
if (!is_null($this->wrapped)) {
|
|
|
318 |
$parent->_current_x += $this->get_full_width() - $this->wrapped[0][2];
|
|
|
319 |
} else {
|
|
|
320 |
$parent->_current_x += $this->get_full_width();
|
|
|
321 |
};
|
|
|
322 |
|
|
|
323 |
// Extends parents height
|
|
|
324 |
$parent->extend_height($this->get_bottom());
|
|
|
325 |
|
|
|
326 |
// Update the value of current collapsed margin; pure text (non-span)
|
|
|
327 |
// boxes always have zero margin
|
|
|
328 |
|
|
|
329 |
$context->pop_collapsed_margin();
|
|
|
330 |
$context->push_collapsed_margin( 0 );
|
|
|
331 |
}
|
|
|
332 |
|
|
|
333 |
function getWrappedWidthAndHyphen() {
|
|
|
334 |
return $this->wrapped[0][3];
|
|
|
335 |
}
|
|
|
336 |
|
|
|
337 |
function getWrappedWidth() {
|
|
|
338 |
return $this->wrapped[0][2];
|
|
|
339 |
}
|
|
|
340 |
|
|
|
341 |
function reflow_text(&$driver) {
|
|
|
342 |
$num_words = count($this->words);
|
|
|
343 |
|
|
|
344 |
/**
|
|
|
345 |
* Empty text box
|
|
|
346 |
*/
|
|
|
347 |
if ($num_words == 0) {
|
|
|
348 |
return true;
|
|
|
349 |
};
|
|
|
350 |
|
|
|
351 |
/**
|
|
|
352 |
* A simple assumption is made: fonts used for different encodings
|
|
|
353 |
* have equal ascender/descender values (while they have the same
|
|
|
354 |
* typeface, style and weight).
|
|
|
355 |
*/
|
|
|
356 |
$font_name = $this->_get_font_name($driver, 0);
|
|
|
357 |
|
|
|
358 |
/**
|
|
|
359 |
* Get font vertical metrics
|
|
|
360 |
*/
|
|
|
361 |
$ascender = $driver->font_ascender($font_name, $this->encodings[0]);
|
|
|
362 |
if (is_null($ascender)) {
|
|
|
363 |
error_log("TextBox::reflow_text: cannot get font ascender");
|
|
|
364 |
return null;
|
|
|
365 |
};
|
|
|
366 |
|
|
|
367 |
$descender = $driver->font_descender($font_name, $this->encodings[0]);
|
|
|
368 |
if (is_null($descender)) {
|
|
|
369 |
error_log("TextBox::reflow_text: cannot get font descender");
|
|
|
370 |
return null;
|
|
|
371 |
};
|
|
|
372 |
|
|
|
373 |
/**
|
|
|
374 |
* Setup box size
|
|
|
375 |
*/
|
|
|
376 |
$font = $this->get_css_property(CSS_FONT_SIZE);
|
|
|
377 |
$font_size = $font->getPoints();
|
|
|
378 |
|
|
|
379 |
// Both ascender and descender should make $font_size
|
|
|
380 |
// as it is not guaranteed that $ascender + $descender == 1,
|
|
|
381 |
// we should normalize the result
|
|
|
382 |
$koeff = $font_size / ($ascender + $descender);
|
|
|
383 |
$this->ascender = $ascender * $koeff;
|
|
|
384 |
$this->descender = $descender * $koeff;
|
|
|
385 |
|
|
|
386 |
$this->default_baseline = $this->ascender;
|
|
|
387 |
$this->height = $this->ascender + $this->descender;
|
|
|
388 |
|
|
|
389 |
/**
|
|
|
390 |
* Determine box width
|
|
|
391 |
*/
|
|
|
392 |
if ($font_size > 0) {
|
|
|
393 |
$width = 0;
|
|
|
394 |
|
|
|
395 |
for ($i=0; $i<$num_words; $i++) {
|
|
|
396 |
$font_name = $this->_get_font_name($driver, $i);
|
|
|
397 |
|
|
|
398 |
$current_width = $driver->stringwidth($this->words[$i],
|
|
|
399 |
$font_name,
|
|
|
400 |
$this->encodings[$i],
|
|
|
401 |
$font_size);
|
|
|
402 |
$this->_word_widths[] = $current_width;
|
|
|
403 |
|
|
|
404 |
// Add information about soft hyphens
|
|
|
405 |
$this->_wrappable = array_merge($this->_wrappable, $this->_make_wrappable($driver, $width, $font_name, $font_size, $i));
|
|
|
406 |
|
|
|
407 |
$width += $current_width;
|
|
|
408 |
};
|
|
|
409 |
|
|
|
410 |
$this->width = $width;
|
|
|
411 |
} else {
|
|
|
412 |
$this->width = 0;
|
|
|
413 |
};
|
|
|
414 |
|
|
|
415 |
$letter_spacing = $this->get_css_property(CSS_LETTER_SPACING);
|
|
|
416 |
|
|
|
417 |
if ($letter_spacing->getPoints() != 0) {
|
|
|
418 |
$this->_widths = array();
|
|
|
419 |
|
|
|
420 |
for ($i=0; $i<$num_words; $i++) {
|
|
|
421 |
$num_chars = strlen($this->words[$i]);
|
|
|
422 |
|
|
|
423 |
for ($j=0; $j<$num_chars; $j++) {
|
|
|
424 |
$this->_widths[] = $driver->stringwidth($this->words[$i]{$j},
|
|
|
425 |
$font_name,
|
|
|
426 |
$this->encodings[$i],
|
|
|
427 |
$font_size);
|
|
|
428 |
};
|
|
|
429 |
|
|
|
430 |
$this->width += $letter_spacing->getPoints()*$num_chars;
|
|
|
431 |
};
|
|
|
432 |
};
|
|
|
433 |
|
|
|
434 |
return true;
|
|
|
435 |
}
|
|
|
436 |
|
|
|
437 |
function show(&$driver) {
|
|
|
438 |
/**
|
|
|
439 |
* Check if font-size have been set to 0; in this case we should not draw this box at all
|
|
|
440 |
*/
|
|
|
441 |
$font_size = $this->get_css_property(CSS_FONT_SIZE);
|
|
|
442 |
if ($font_size->getPoints() == 0) {
|
|
|
443 |
return true;
|
|
|
444 |
}
|
|
|
445 |
|
|
|
446 |
// Check if current text box will be cut-off by the page edge
|
|
|
447 |
// Get Y coordinate of the top edge of the box
|
|
|
448 |
$top = $this->get_top_margin();
|
|
|
449 |
// Get Y coordinate of the bottom edge of the box
|
|
|
450 |
$bottom = $this->get_bottom_margin();
|
|
|
451 |
|
|
|
452 |
$top_inside = $top >= $driver->getPageBottom()-EPSILON;
|
|
|
453 |
$bottom_inside = $bottom >= $driver->getPageBottom()-EPSILON;
|
|
|
454 |
|
|
|
455 |
if (!$top_inside && !$bottom_inside) {
|
|
|
456 |
return true;
|
|
|
457 |
}
|
|
|
458 |
|
|
|
459 |
return $this->_showText($driver);
|
|
|
460 |
}
|
|
|
461 |
|
|
|
462 |
function _showText(&$driver) {
|
|
|
463 |
if (!is_null($this->wrapped)) {
|
|
|
464 |
return $this->_showTextWrapped($driver);
|
|
|
465 |
} else {
|
|
|
466 |
return $this->_showTextNormal($driver);
|
|
|
467 |
};
|
|
|
468 |
}
|
|
|
469 |
|
|
|
470 |
function _showTextWrapped(&$driver) {
|
|
|
471 |
// draw generic box
|
|
|
472 |
parent::show($driver);
|
|
|
473 |
|
|
|
474 |
$font_size = $this->get_css_property(CSS_FONT_SIZE);
|
|
|
475 |
|
|
|
476 |
$decoration = $this->get_css_property(CSS_TEXT_DECORATION);
|
|
|
477 |
|
|
|
478 |
// draw text decoration
|
|
|
479 |
$driver->decoration($decoration['U'],
|
|
|
480 |
$decoration['O'],
|
|
|
481 |
$decoration['T']);
|
|
|
482 |
|
|
|
483 |
$letter_spacing = $this->get_css_property(CSS_LETTER_SPACING);
|
|
|
484 |
|
|
|
485 |
// Output text with the selected font
|
|
|
486 |
// note that we're using $default_baseline;
|
|
|
487 |
// the alignment offset - the difference between baseline and default_baseline values
|
|
|
488 |
// is taken into account inside the get_top/get_bottom functions
|
|
|
489 |
//
|
|
|
490 |
$current_char = 0;
|
|
|
491 |
|
|
|
492 |
$left = $this->wrapped[1];
|
|
|
493 |
$top = $this->get_top() - $this->default_baseline;
|
|
|
494 |
$num_words = count($this->words);
|
|
|
495 |
|
|
|
496 |
/**
|
|
|
497 |
* First part of wrapped word (before hyphen)
|
|
|
498 |
*/
|
|
|
499 |
for ($i=0; $i<$this->wrapped[0][0]; $i++) {
|
|
|
500 |
// Activate font
|
|
|
501 |
$status = $driver->setfont($this->_get_font_name($driver, $i),
|
|
|
502 |
$this->encodings[$i],
|
|
|
503 |
$font_size->getPoints());
|
|
|
504 |
if (is_null($status)) {
|
|
|
505 |
error_log("TextBox::show: setfont call failed");
|
|
|
506 |
return null;
|
|
|
507 |
};
|
|
|
508 |
|
|
|
509 |
$driver->show_xy($this->words[$i],
|
|
|
510 |
$left,
|
|
|
511 |
$this->wrapped[2] - $this->default_baseline);
|
|
|
512 |
$left += $this->_word_widths[$i];
|
|
|
513 |
};
|
|
|
514 |
|
|
|
515 |
$index = $this->wrapped[0][0];
|
|
|
516 |
|
|
|
517 |
$status = $driver->setfont($this->_get_font_name($driver, $index),
|
|
|
518 |
$this->encodings[$index],
|
|
|
519 |
$font_size->getPoints());
|
|
|
520 |
if (is_null($status)) {
|
|
|
521 |
error_log("TextBox::show: setfont call failed");
|
|
|
522 |
return null;
|
|
|
523 |
};
|
|
|
524 |
|
|
|
525 |
$driver->show_xy(substr($this->words[$index],0,$this->wrapped[0][1])."-",
|
|
|
526 |
$left,
|
|
|
527 |
$this->wrapped[2] - $this->default_baseline);
|
|
|
528 |
|
|
|
529 |
/**
|
|
|
530 |
* Second part of wrapped word (after hyphen)
|
|
|
531 |
*/
|
|
|
532 |
|
|
|
533 |
$left = $this->get_left();
|
|
|
534 |
$top = $this->get_top();
|
|
|
535 |
$driver->show_xy(substr($this->words[$index],$this->wrapped[0][1]),
|
|
|
536 |
$left,
|
|
|
537 |
$top - $this->default_baseline);
|
|
|
538 |
|
|
|
539 |
$size = count($this->words);
|
|
|
540 |
for ($i = $this->wrapped[0][0]+1; $i<$size; $i++) {
|
|
|
541 |
// Activate font
|
|
|
542 |
$status = $driver->setfont($this->_get_font_name($driver, $i),
|
|
|
543 |
$this->encodings[$i],
|
|
|
544 |
$font_size->getPoints());
|
|
|
545 |
if (is_null($status)) {
|
|
|
546 |
error_log("TextBox::show: setfont call failed");
|
|
|
547 |
return null;
|
|
|
548 |
};
|
|
|
549 |
|
|
|
550 |
$driver->show_xy($this->words[$i],
|
|
|
551 |
$left,
|
|
|
552 |
$top - $this->default_baseline);
|
|
|
553 |
|
|
|
554 |
$left += $this->_word_widths[$i];
|
|
|
555 |
};
|
|
|
556 |
|
|
|
557 |
return true;
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
function _showTextNormal(&$driver) {
|
|
|
561 |
// draw generic box
|
|
|
562 |
parent::show($driver);
|
|
|
563 |
|
|
|
564 |
$font_size = $this->get_css_property(CSS_FONT_SIZE);
|
|
|
565 |
|
|
|
566 |
$decoration = $this->get_css_property(CSS_TEXT_DECORATION);
|
|
|
567 |
|
|
|
568 |
// draw text decoration
|
|
|
569 |
$driver->decoration($decoration['U'],
|
|
|
570 |
$decoration['O'],
|
|
|
571 |
$decoration['T']);
|
|
|
572 |
|
|
|
573 |
$letter_spacing = $this->get_css_property(CSS_LETTER_SPACING);
|
|
|
574 |
|
|
|
575 |
if ($letter_spacing->getPoints() == 0) {
|
|
|
576 |
// Output text with the selected font
|
|
|
577 |
// note that we're using $default_baseline;
|
|
|
578 |
// the alignment offset - the difference between baseline and default_baseline values
|
|
|
579 |
// is taken into account inside the get_top/get_bottom functions
|
|
|
580 |
//
|
|
|
581 |
$size = count($this->words);
|
|
|
582 |
$left = $this->get_left();
|
|
|
583 |
|
|
|
584 |
for ($i=0; $i<$size; $i++) {
|
|
|
585 |
// Activate font
|
|
|
586 |
$status = $driver->setfont($this->_get_font_name($driver, $i),
|
|
|
587 |
$this->encodings[$i],
|
|
|
588 |
$font_size->getPoints());
|
|
|
589 |
if (is_null($status)) {
|
|
|
590 |
error_log("TextBox::show: setfont call failed");
|
|
|
591 |
return null;
|
|
|
592 |
};
|
|
|
593 |
|
|
|
594 |
$driver->show_xy($this->words[$i],
|
|
|
595 |
$left,
|
|
|
596 |
$this->get_top() - $this->default_baseline);
|
|
|
597 |
|
|
|
598 |
$left += $this->_word_widths[$i];
|
|
|
599 |
};
|
|
|
600 |
} else {
|
|
|
601 |
$current_char = 0;
|
|
|
602 |
|
|
|
603 |
$left = $this->get_left();
|
|
|
604 |
$top = $this->get_top() - $this->default_baseline;
|
|
|
605 |
$num_words = count($this->words);
|
|
|
606 |
|
|
|
607 |
for ($i=0; $i<$num_words; $i++) {
|
|
|
608 |
$num_chars = strlen($this->words[$i]);
|
|
|
609 |
|
|
|
610 |
for ($j=0; $j<$num_chars; $j++) {
|
|
|
611 |
$status = $driver->setfont($this->_get_font_name($driver, $i),
|
|
|
612 |
$this->encodings[$i],
|
|
|
613 |
$font_size->getPoints());
|
|
|
614 |
|
|
|
615 |
$driver->show_xy($this->words[$i]{$j}, $left, $top);
|
|
|
616 |
$left += $this->_widths[$current_char] + $letter_spacing->getPoints();
|
|
|
617 |
$current_char++;
|
|
|
618 |
};
|
|
|
619 |
};
|
|
|
620 |
};
|
|
|
621 |
|
|
|
622 |
return true;
|
|
|
623 |
}
|
|
|
624 |
|
|
|
625 |
function show_fixed(&$driver) {
|
|
|
626 |
$font_size = $this->get_css_property(CSS_FONT_SIZE);
|
|
|
627 |
|
|
|
628 |
// Check if font-size have been set to 0; in this case we should not draw this box at all
|
|
|
629 |
if ($font_size->getPoints() == 0) {
|
|
|
630 |
return true;
|
|
|
631 |
}
|
|
|
632 |
|
|
|
633 |
return $this->_showText($driver);
|
|
|
634 |
}
|
|
|
635 |
|
|
|
636 |
function offset($dx, $dy) {
|
|
|
637 |
parent::offset($dx, $dy);
|
|
|
638 |
|
|
|
639 |
// Note that horizonal offset should be called explicitly from text-align routines
|
|
|
640 |
// otherwise wrapped part will be offset twice (as offset is called both for
|
|
|
641 |
// wrapped and non-wrapped parts).
|
|
|
642 |
if (!is_null($this->wrapped)) {
|
|
|
643 |
$this->offset_wrapped($dx, $dy);
|
|
|
644 |
};
|
|
|
645 |
}
|
|
|
646 |
|
|
|
647 |
function offset_wrapped($dx, $dy) {
|
|
|
648 |
$this->wrapped[1] += $dx;
|
|
|
649 |
$this->wrapped[2] += $dy;
|
|
|
650 |
}
|
|
|
651 |
|
|
|
652 |
function reflow_whitespace(&$linebox_started, &$previous_whitespace) {
|
|
|
653 |
$linebox_started = true;
|
|
|
654 |
$previous_whitespace = false;
|
|
|
655 |
return;
|
|
|
656 |
}
|
|
|
657 |
|
|
|
658 |
function is_null() { return false; }
|
|
|
659 |
}
|
|
|
660 |
?>
|