<?php
class WorkerInline extends WorkerPlugin
{
protected $_whitespace;
protected $_line_height;
protected $_font_family;
protected $_font_weight;
protected $_font_style;
protected $_font_size;
protected $_text_transform;
protected $_text_decoration;
protected $_text_align;
protected $_ascender;
protected $_descender;
protected $_space_width;
protected $_word_spacing;
protected $_href;
protected $_content = array();
protected $_pos = 0;
protected $_pos_backup = array();
public function save()
{
$this->_pos_backup[] = $this->_pos;
return count($this->_pos_backup)-1;
}
public function restore($id = null)
{
if ($id === null) $id = count($this->_pos_backup) - 1;
$this->_pos = $this->_pos_backup[$id];
}
public function is2ByteLength($word){
$Slen=strlen($word);
for ($i=0; $i<$Slen; $i++) {
$str_ord=ord($word[$i]);
if ($str_ord < 0xE1) continue;
else return true;
}
return false;
}
public function initializePost()
{
//Lithron::trace("Initializing InlineWorker for ".$this->DOMNode->nodeName." - Start", "Init");
$this->_whitespace = Property::get($this->DOMNode, "white-space");
$this->_line_height = Property::get($this->DOMNode, "line-height");
if ($this->_line_height == "normal") $this->_line_height = Property::get($this->DOMNode, "font-size") * 1.1;
$this->_font_family = Property::get($this->DOMNode, "font-family");
$this->_font_weight = Property::get($this->DOMNode, "font-weight");
$this->_font_style = Property::get($this->DOMNode, "font-style");
$this->_font_size = Property::get($this->DOMNode, "font-size");
$this->_text_transform = Property::get($this->DOMNode, "text-transform");
$this->_text_decoration = Property::get($this->DOMNode, "text-decoration");
$this->_text_align = Property::get($this->DOMNode, "text-align");
$this->_word_spacing = Property::get($this->DOMNode, "word-spacing");
if ($this->_word_spacing == "normal") $this->_word_spacing = 0;
$this->_ascender = $this->Lithron->getFontMetric($this->DOMNode, "ascender");
$this->_descender = $this->Lithron->getFontMetric($this->DOMNode, "descender");
$this->_space_width = $this->Lithron->getFontMetric($this->DOMNode, "spacewidth");
$_href = Property::get($this->DOMNode, "href");
// TODO - use a regexp here!
if (( (substr($_href,0,7) == "http://") || (substr($_href,0,7) == "mailto:")) && strstr($_href, " ") == null) {
$this->_href = $_href;
} elseif($_href) {
Lithron::log("Omitting malformed hyperlink: '".$_href."'", LOG_ERR);
}
$this->_space_width += $this->_word_spacing;
$sel = "";
if ($this->_font_weight != "normal") $sel .= $this->_font_weight;
if ($this->_font_style != "normal") $sel .= $this->_font_style;
if ($sel == "") $sel = "normal";
$handle = $this->Lithron->getFontHandle($this->Lithron->DummyPDF, "dummyhandle", $this->_font_family, $sel);
$q = "./child::text()";
$result = $this->XPath->query($q, $this->DOMNode);
$rnum = $result->length;
if ($rnum > 1)
throw new Exception("Assert - got no more than 1 textnode failed, got $rnum!");
elseif ($rnum == 0)
return;
$node = $result->item(0);
switch($this->_whitespace)
{
case "normal":
$words = preg_split("/([\s]+)/", $node->nodeValue, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($words as $word)
if (trim($word) == "")
$this->_content[] = LineBox::CMD_SPACE;
else
{
switch($this->_text_transform)
{
case "uppercase_sz":
$word = str_replace("Ã", "ss", $word);
// break left intentionally
case "uppercase":
$word = mb_convert_case($word, MB_CASE_UPPER, "UTF-8");
$word = str_replace("&NBSP;", " ", $word);
break;
case "lowercase":
$word = mb_convert_case($word, MB_CASE_LOWER, "UTF-8");
break;
case "capitalize":
$word = mb_convert_case($word, MB_CASE_TITLE, "UTF-8");
break;
}
if ($this->is2ByteLength($word)){
preg_match_all('/./u', $word, $chars);
foreach($chars[0] as $char)
$this->_content[] = array($char, $this->Lithron->DummyPDF->stringwidth($char, $handle, (float)$this->_font_size));
}
else
{
$this->_content[] = array($word, $this->Lithron->DummyPDF->stringwidth($word, $handle, (float)$this->_font_size));
}
}
break;
case "pre":
$lines = preg_split("/([\n\f])/", $node->nodeValue, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach($lines as $line)
switch($line)
{
case chr(0x0a):
$this->_content[] = LineBox::CMD_NEWLINE;
break;
case chr(0x0c):
$this->_content[] = LineBox::CMD_COLUMNBREAK;
break;
default:
$this->_content[] = array($line, $this->Lithron->DummyPDF->stringwidth($line, $handle, $this->_font_size));
}
break;
}
//Lithron::trace("Initializing InlineWorker for ".$this->DOMNode->nodeName." - End", "Init");
//echo "WS: {$this->_whitespace}, ASC: {$this->_ascender}, DESC: {$this->_descender}, LH: {$this->_line_height}<br>";
//var_dump($this->_content);
//echo "<hr>";
}
public function getLineHeight()
{
return $this->_lh;
}
public function getWord($pos)
{
$w = $this->_content[$pos][0];
if ($w == "%LX_PAGENUM%")
{
//echo "GETWORD ".$this->Lithron->CurrentPageNum."<br>";
$w = $this->Lithron->CurrentPageNum-1;
}
else if ($w == "%LX_ANCHOR%")
{
$w .= $this->propAnchorGet();
}
return $w;
}
public function getAscender()
{
return $this->_ascender;
}
public function getDescender()
{
return $this->_descender;
}
public function getTextAlign()
{
return $this->_text_align;
}
public function flowInto($lb)
{
if ($this->propAnchorSet() != "none")
{
//echo "SET ANCHOR ".$this->propAnchorSet()." TO ".$this->Lithron->CurrentPageNum."<br>";
$this->Lithron->Anchors[$this->propAnchorSet()] = $this->Lithron->CurrentPageNum-1;
}
$ret = LineBox::FLOW_OK;
do
{
if ($this->_pos >= count($this->_content))
{
//Lithron::trace("<b style=\"color:fuchsia;\">".$this->DOMNode->nodeName.".flowInto() - no more content</b>", "Layout", $this->Level);
$ret = LineBox::FLOW_DONE;
}
else
switch($this->_content[$this->_pos])
{
case LineBox::CMD_SPACE:
$lb->addAffectedInline($this);
if ($this->_text_decoration == "underline")
$lb->push(array(LineBox::CMD_UNDERLINE_ON));
else
$lb->push(array(LineBox::CMD_UNDERLINE_OFF));
$lb->push(array(LineBox::CMD_LINK, $this->_href));
$lb->push(array(LineBox::CMD_SPACE, $this->_space_width, $this));
$this->_pos++;
//Lithron::trace("<b style=\"color:fuchsia;\">".$this->DOMNode->nodeName.".flowInto() - pushed space</b>", "Layout", $this->Level);
break;
case LineBox::CMD_NEWLINE:
$lb->addAffectedInline($this);
$lb->ensureLineHeight($this->_line_height);
$ret = LineBox::FLOW_NEWLINE;
$this->_pos++;
break;
case LineBox::CMD_COLUMNBREAK:
$lb->addAffectedInline($this);
$ret = LineBox::FLOW_COLUMNBREAK;
$this->_pos++;
break;
default:
$w = $this->_content[$this->_pos][1];
if ($this->_content[$this->_pos][0] == "%LX_PAGENUM%")
{
$sel = "";
if ($this->_font_weight != "normal") $sel .= $this->_font_weight;
if ($this->_font_style != "normal") $sel .= $this->_font_style;
if ($sel == "") $sel = "normal";
$handle = $this->Lithron->getFontHandle($this->Lithron->DummyPDF, "dummyhandle", $this->_font_family, $sel);
$w = $this->Lithron->DummyPDF->stringwidth($this->Lithron->CurrentPageNum-1, $handle, $this->_font_size);
//echo "GETWIDTH ".$this->Lithron->CurrentPageNum."<br>";
}
elseif ($this->_content[$this->_pos][0] == "%LX_ANCHOR%")
{
}
if ($lb->canPush($w))
{
$lb->addAffectedInline($this);
if ($this->_text_decoration == "underline")
$lb->push(array(LineBox::CMD_UNDERLINE_ON));
else
$lb->push(array(LineBox::CMD_UNDERLINE_OFF));
$lb->push(array(LineBox::CMD_LINK, $this->_href));
$lb->push(array(LineBox::CMD_WORD, $w, $this, $this->_pos));
$lb->ensureLineHeight($this->_line_height);
$this->_pos++;
//Lithron::trace("<b style=\"color:fuchsia;\">".$this->DOMNode->nodeName.".flowInto() - pushed {$this->_content[$this->_pos-1][0]}</b>", "Layout", $this->Level);
}
else
$ret = Linebox::FLOW_FULL;
}
}
while($ret == LineBox::FLOW_OK);
//$msg = array(LineBox::FLOW_OK => "FLOW_OK", LineBox::FLOW_NEWLINE => "FLOW_NEWLINE", LineBox::FLOW_DONE => "FLOW_DONE", LineBox::FLOW_FULL => "FLOW_FULL",);
//Lithron::trace("<b style=\"color:orange;\">".$this->DOMNode->nodeName.".flowInto() - finished with ".$msg[$ret]."</b>", "Layout", $this->Level);
return $ret;
}
}
?>