Application->InitParser(); $this->Application->Parser->SetParams($template_params); if ($is_content) { $xml = $this->Application->Parser->Parse($template); } else { $xml = $this->Application->Parser->Run($template); } /** @var kXMLHelper $xml_helper */ $xml_helper =& $this->Application->recallObject('kXMLHelper'); $doc = $xml_helper->Parse($xml_helper->ConvertHTMLEntities($xml), kXMLHelper::XML_WITH_TEXT_NODES); if ($doc->Name == 'ERROR') { echo 'BAD TEMPLATE'; exit; } // $this->Application->Debugger->profileStart('pdf_init', 'Initializing PDF'); $this->InitPDF($doc); // $this->Application->Debugger->profileFinish('pdf_init'); // $this->Application->Debugger->profileStart('process_nodes', 'Processing nodes'); $this->ProcessNode($doc); // $this->Application->Debugger->profileFinish('process_nodes'); if (defined('PDF_DEBUG_DUMP_ONLY')) { $this->DimensionsMode = kPDFHelper::DM_NORMAL ; $this->Application->Debugger->profileStart('laying_out', 'Laying out nodes'); // $this->CurPDFElem->LayoutChildren(); $this->Application->Debugger->profileFinish('laying_out'); $this->Application->Debugger->profileStart('rendering', 'rendering'); // $this->Render(); $this->Application->Debugger->profileFinish('rendering'); // echo $this->CurPDFElem->DumpStructure(); exit; } $this->Render(); return $this->PDF->GetPDFString(); // exit; } function InitPDF($doc) { $this->PDF = new kTCPDFRenderer(); $this->Stylesheet = new kPDFStylesheet(); $this->CurPDFElem = kPDFElemFactory::CreateFromNode($doc, $this); $this->Document = $this->CurPDFElem; // $this->CurPDFElem = new kPDFPage($page1, new kXMLNode('_NONE_', array('style' => 'display: block; width: '.$page1->getWidth().';')), $this); $this->CurPDFElem->Init(); $this->CurPDFElem->SetCSSProperty('width', $this->PDF->getWidth()); $this->CurPDFElem->SetCSSProperty('height', $this->PDF->getHeight()); $this->PDF->SetFont('helvetica', $this->PtPerEm); } function Render() { $this->DimensionsMode = kPDFHelper::DM_NORMAL ; $this->CurPDFElem->LayoutChildren(); $this->PageBottom = $this->PDF->getHeight() - $this->Document->GetCSSProperty('margin-bottom'); // margin $this->CurPDFElem->DrawAt($this->PDF, 0, 0); } function ProcessHead($node) { if ($node->Name == 'STYLE') { $css = $node->Data; $tokens = $this->Stylesheet->GetTokens($node->Data); $this->Stylesheet->ParseTokens($tokens); } foreach($node->Children as $child) { $this->ProcessHead($child); } } function ProcessNode($node) { $children = count($node->Children); foreach($node->Children as $child) { if ($child->Name == 'HEAD') { $this->ProcessHead($child); continue; } $elem = kPDFElemFactory::CreateFromNode($child, $this); if (!$elem) continue; $display = $elem->GetDisplayLevel(); if ($display == 'none') continue; // http://manual.prod.intechnic.lv/css21/visuren.html#anonymous-block-level if ($display == 'block' && $this->CurPDFElem->GetDisplayLevel() == 'inline') { $this->CurPDFElem->Closed(); $this->CurPDFElem = $this->CurPDFElem->GetContainingBlock(); } $current = $this->CurPDFElem; $line = false; if ($display == 'inline' && !($this->CurPDFElem instanceof kPDFLine) ) { $this->CurPDFElem = $this->CurPDFElem->GetLineBox(); $line = $this->CurPDFElem; } $this->CurPDFElem = $this->CurPDFElem->AddChild( $elem ); $this->ProcessNode($child); $this->CurPDFElem = $current; } $this->CurPDFElem->Closed(); } } class kPDFElemFactory { static function CreateFromNode($node, $helper) { /* @todo Create elements, based on their display, rather than tag name - pure CSS rendering */ switch ($node->Name) { case '_TEXT_': // $DOMNode = $node->Parent; $elem = new kPDFTextElement($node->Data, $node, $helper); if ($elem->CSSSpecifiedProperties['WHITE-SPACE'] == 'normal' && trim($node->Data) == '') { return false; } return $elem; break; case 'TR': return new kPDFTableRow($node, $helper); case 'BR': return new kPDFTextElement($node->Data, $node, $helper); case 'TABLE': return new kPDFTable($node, $helper); case 'IMG': return new kPDFImage($node, $helper); default: return new kPDFElement($node, $helper); break; } } } class kPDFElement { public $Parent; protected $Font; protected $FontSize; public $Children = array(); public $Position = 0; public $FirstChild; public $LastChild; public $ContentHeight = 0; public $Style; public $CurX = 0; public $CurY = 0; public $Baseline = 0; public $Ascent; public $Descent; public $Gap; public $Node; public $Helper; public $CSSSpecifiedProperties = array(); public $CSSComputedPoperties = array(); public $DirectStyle; public $IsClosed = false; public $LayedOut = false; public $WidthComputed = false; public $MinContentWidth = 0; public $MaxContentWidth = 0; public $CurLine_MinContentWidth = 0; public $CurLine_MaxContentWidth = 0; public $Spacers = 0; function __construct($node, $helper) { $this->Node = $node; $this->Helper = $helper; $this->ProcessCSS(); } function Init() { $this->ComputeCSSProperties(); } function Reset() { $this->CurX = 0; $this->CurY = 0; } function AddChild($child, $init=true, $after=null) { $node_count = count($this->Children); if (isset($after)) { $after_pos = $after->Position; for($i=$after_pos+1; $i<$node_count; $i++) { $this->Children[$i]->Position++; } array_splice($this->Children, $after_pos+1, 0, array($child)); $child->Position = $after_pos+1; } else { $child->Position = $node_count; $this->Children[] = $child; } if ($node_count == 0) { $this->FirstChild = $child; $this->LastChild = $child; } elseif ($child->Position == $node_count) { $this->LastChild = $child; } $child->Parent = $this; if ($init) $child->Init(); return $child; } public function Closed() { if ($this->LastChild && $this->LastChild instanceof kPDFLine && !$this->LastChild->IsClosed) { $this->LastChild->Closed(); } $this->ComputeWidthAndMargins(); $this->CalcMinMaxContentWidth(); $this->IsClosed = true; return ; } function RemoveChildren($start, $count=null) { return array_splice($this->Children, $start); } function &FindChildByProperty($property, $value) { $property = strtoupper($property); if (strtoupper($this->GetCSSProperty($property)) == strtoupper($value)) return $this; foreach ($this->Children as $elem) { $child =& $elem->FindChildByProperty($property, $value); if ($child !== false) { return $child; } } $false = false; return $false; } function LayoutChildren() { $this->ComputeWidthAndMargins(); $i = 0; $this->Reset(); while (isset($this->Children[$i])) { // can't use foreach here, because LayoutChildren() may add new children to current elem (wrapping) $child = $this->Children[$i]; $child->LayoutChildren(); $i++; } $this->CheckDimensions(); $this->ComputeHeight(); // $this->ComputeBaseline(); } public function ComputeHeight() { $display = $this->GetCSSProperty('display'); if ($display == 'inline') return ; $height = 0; // $this->GetCSSProperty('height'); /* $extra_height = $this->GetCSSProperty('margin-top') + $this->GetCSSProperty('margin-bottom') + $this->GetCSSProperty('padding-top') + $this->GetCSSProperty('padding-bottom') + $this->GetCSSProperty('border-top-width') + $this->GetCSSProperty('border-bottom-width');*/ foreach ($this->Children as $elem) { $dim = $elem->GetBoxDimensions(); $elem_height = $dim[1]; if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') { $height += $elem_height; } else { if ($elem_height > $height) { $height = $elem_height; } } } $this->SetCSSProperty('height', $height); } function &FindChild($name) { $name = strtoupper($name); if ($this->Node->Name == $name) return $this; foreach ($this->Children as $elem) { $child =& $elem->FindChild($name); if ($child !== false) { return $child; } } $false = false; return $false; } function DumpStructure($level=0) { $dump = ''; $tab = str_repeat(' ', $level*4); $dump .= $tab . get_class($this) . ' Node: ' . $this->Node->Name . " child of ".$this->Node->Parent->Name."
\n"; if ($this instanceof kPDFTextElement) { $dump .= $tab . 'Data: ' . $this->Data . "
\n"; } $dump .= $tab . 'Width: ' . $this->GetCSSProperty('width') . ' Height: ' . $this->GetCSSProperty('height') . " Ascent: " . $this->Ascent . "
\n"; $dump .= $tab . 'MinCW: ' . $this->MinContentWidth . ' MaxCW: ' . $this->MaxContentWidth . "
\n"; $dump .= $tab . 'Children:' . "
\n"; $i = 0; foreach ($this->Children as $elem) { $i++; $dump .= $tab . $i . "
\n"; $level++; $dump .= $elem->DumpStructure($level); $level--; } return $dump; } function DrawAt($page, $x=0, $y=0, $spacer_w=0) { if ($this->Node->Name == 'FOOTER') { $dim = $this->GetBoxDimensions(); $y = $this->Helper->PDF->GetHeight() - $dim[1]; } if ($this->GetDisplayLevel() == 'block' ) { $width = $this->GetCSSProperty('width'); $margin_left = $this->GetCSSProperty('margin-left'); $margin_right = $this->GetCSSProperty('margin-right'); $border_left = $this->GetCSSProperty('border-left-width'); $border_right = $this->GetCSSProperty('border-right-width'); $padding_left = $this->GetCSSProperty('padding-left'); $padding_right = $this->GetCSSProperty('padding-right'); $height = $this->GetCSSProperty('height'); $margin_top = $this->GetCSSProperty('margin-top'); $margin_bottom = $this->GetCSSProperty('margin-bottom'); $border_top = $this->GetCSSProperty('border-top-width'); $border_bottom = $this->GetCSSProperty('border-bottom-width'); $padding_top = $this->GetCSSProperty('padding-top'); $padding_bottom = $this->GetCSSProperty('padding-bottom'); $outer_width = $margin_left + $border_left + $padding_left + $width + $padding_right + $border_right + $margin_right; $outer_height = $margin_top + $border_top + $padding_top + $height + $padding_bottom + $border_bottom + $margin_bottom; if (defined('PDF_DEBUG_DRAW_BOXES')) { $page->SetFillColor( '#eeeeee' ); if ($this instanceof kPDFLine) { if (defined('PDF_DEBUG_DRAW_LINE_BOXES')) { $page->SetLineWidth(0.5); $page->SetLineColor( 'yellow' ); $page->SetFillColor( '#efefef' ); } } else { $page->SetLineWidth(0.1); $page->SetLineColor( '#0000ff' ); } // $page->DrawRectangle($x, $y, $x + $outer_width, $y - $outer_height, kPDFRenderer::SHAPE_DRAW_FILL_AND_STROKE); $page->SetFillColor( '#000000' ); $page->setFont('helvetica', 6); if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name)) { $page->drawText($this->Node->Name . "{$outer_width}x{$outer_height} ".get_class($this), $x+2, $y+8); } } } if ($this->GetDisplayLevel() == 'block' && !($this instanceof kPDFLine)) { // MARGINS if (defined('PDF_DEBUG_DRAW_MARGINS')) { $page->SetLineWidth(1); $page->SetLineColor( 'green' ); $page->DrawLine($x, $y, $x + $margin_left, $y); $page->DrawLine($x, $y, $x, $y + $margin_bottom); $page->SetLineWidth(0.3); $page->DrawLine($x + $margin_left, $y, $x + $margin_left, $y + 3); $page->DrawLine($x, $y + $margin_top, $x + 3, $y + $margin_top); } $x += $margin_left; $y += $margin_top; // BACKGROUND // http://manual.prod.intechnic.lv/css21/colors.html#q2 $body = false; if ($this->Node->Name == 'HTML' && $this->GetCSSProperty('background-color') == 'transparent') { // get BODY color $body = $this->FindChild('BODY'); if ($body !== false) { $background_color = $body->GetCSSProperty('background-color'); $body->SetCSSProperty('background-color', 'transparent'); } } else { $background_color = $this->GetCSSProperty('background-color'); } if ($background_color != 'transparent') { $page->SetFillColor( $background_color ); $x1 = $x + $border_left + $padding_left + $width + $padding_right + $border_right; $y1 = $y + ($border_top + $padding_top + $height + $padding_bottom + $border_bottom); $page->DrawRectangle($x, $y, $x1, $y1, kPDFRenderer::SHAPE_DRAW_FILL); } // BORDERS $x2 = $x + $border_left + $padding_left + $width + $padding_right + $border_right; $y2 = $y + ($border_top + $padding_top + $height + $padding_bottom + $border_bottom); if ($this->GetCSSProperty('border-top-style') != 'none' && $border_top > 0) { $page->SetLineWidth($this->GetCSSProperty('border-top-width')); $page->SetLineColor( $this->GetCSSProperty('border-top-color') ); $page->DrawLine($x+$border_left/2, $y+$border_top/2, $x2-$border_right/2, $y+$border_top/2); } if ($this->GetCSSProperty('border-right-style') != 'none' && $border_right > 0) { $page->SetLineWidth($this->GetCSSProperty('border-right-width')); $page->SetLineColor( $this->GetCSSProperty('border-right-color') ); $page->DrawLine($x2-$border_right/2, $y+$border_top/2, $x2-$border_right/2, $y2-$border_bottom/2); } if ($this->GetCSSProperty('border-bottom-style') != 'none' && $border_bottom > 0) { $page->SetLineWidth($this->GetCSSProperty('border-bottom-width')); $page->SetLineColor( $this->GetCSSProperty('border-bottom-color') ); $page->DrawLine($x+$border_left/2, $y2-$border_bottom/2, $x2-$border_right/2, $y2-$border_bottom/2); } if ($this->GetCSSProperty('border-left-style') != 'none' && $border_left > 0) { $page->SetLineWidth($this->GetCSSProperty('border-left-width')); $page->SetLineColor( $this->GetCSSProperty('border-left-color')); $page->DrawLine($x+$border_left/2, $y+$border_top/2, $x+$border_left/2, $y2-$border_bottom/2); } $x += $border_left; $y += $border_top; // PADDING $x += $this->GetCSSProperty('padding-left'); $y += $this->GetCSSProperty('padding-top'); if (defined('PDF_DRAW_CONTENT_AREA') && $this->Parent) { $page->SetFillColor( 'pink' ) ; $page->DrawRectangle($x, $y, $x + $width, $y + $height, kPDFRenderer::SHAPE_DRAW_FILL); } } $this->CurX = $x; $this->CurY = $y; // $max_width = $this->GetCSSProperty('max-width'); $this->TopLine = $y; $page->SetLineWidth(0.1); foreach ($this->Children as $elem) { $dim = $elem->GetBoxDimensions(); $align_offset_x = 0; $align_offset_y = 0; if ($elem->GetDisplayLevel() == 'inline') { if ($this->GetCSSProperty('vertical-align') == 'baseline') { $align_offset_y = $this->Ascent - $elem->Ascent; } } if (defined('PDF_DEBUG_DRAW_BASELINE')) { $page->SetLineWidth(0.5); $page->SetLineColor( '#ff0000' ); $page->DrawLine($this->CurX, $this->CurY + $elem->Ascent, $this->CurX + $dim[0], $this->CurY + $elem->Ascent); } if ($elem instanceof kPDFLine ) { $spacer_w = 0; switch ($elem->GetCSSProperty('text-align')) { case 'center': $align_offset_x = ($dim[0] - $elem->CurX)/2; break; case 'right': $align_offset_x = ($dim[0] - $elem->CurX); break; case 'justify': $spacer_w = $elem->LastLine ? 0 : ($dim[0] - $elem->CurX)/$elem->Spacers; } } if (defined('PDF_DEBUG_DRAW_ELEM_BORDERS')) { $page->SetLineWidth(0.1); $page->SetLineColor( '#bbbbbb' ); $page->SetFillColor( '#bbbbbb' ); $page->setFont('helvetica', 4); $page->DrawRectangle($this->CurX, $this->CurY + $align_offset_y, $this->CurX + $dim[0], $this->CurY + $align_offset_y + $dim[1], kPDFRenderer::SHAPE_DRAW_STROKE); if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name) && $elem->GetDisplayLevel() != 'block') { $page->drawText("w:{$dim[0]}x{$dim[1]}", $this->CurX + 2, $this->CurY + $align_offset_y + 6); } } $tmp_x = $this->CurX; $this->CheckPageBreak($page, $elem, $dim); $elem->DrawAt($page, $this->CurX + $align_offset_x, $this->CurY + $align_offset_y, $spacer_w); if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') { $this->CurY += $dim[1]; $this->CurX = $tmp_x; } else { $this->CurX = $this->CurX + $dim[0] + ($elem->Spacers*$spacer_w); } } if ($this->GetCSSProperty('PAGE-BREAK-AFTER') == 'always') { $this->Helper->PDF->NextPage(); $this->Parent->CurY = $this->Helper->Document->GetCSSProperty('margin-top'); } } function CheckPageBreak($page, $elem, $dim) { if (($this->GetCSSProperty('DISPLAY') != 'block' && $this->GetCSSProperty('DISPLAY') != 'table') || $elem->Node->Name == 'BODY' || $elem->Node->Name == 'HTML') return; if ($this->CurY + $dim[1] > $this->Helper->PageBottom) { $this->Helper->PDF->NextPage(); $this->CurY = $this->Helper->Document->FindChild('BODY')->GetCSSProperty('margin-top'); } } function GetBoxDimensions() { return array( $this->GetCSSProperty('margin-left') + $this->GetCSSProperty('border-left-width') + $this->GetCSSProperty('padding-left') + $this->GetCSSProperty('width') + $this->GetCSSProperty('padding-right') + $this->GetCSSProperty('border-right-width') + $this->GetCSSProperty('margin-right'), $this->GetCSSProperty('margin-top') + $this->GetCSSProperty('border-top-width') + $this->GetCSSProperty('padding-top') + $this->GetCSSProperty('height') + $this->GetCSSProperty('padding-bottom') + $this->GetCSSProperty('border-bottom-width') + $this->GetCSSProperty('margin-bottom'), ); } function GetLineBox($first=false) { if ($this instanceof kPDFLine ) { if ($first) { return $this->Parent->FirstChild; } else { return $this; } } if ($this->GetDisplayLevel() == 'block') { if ($this->LastChild instanceof kPDFLine ) { return $this->LastChild; } return $this->AddChild( new kPDFLine($this->Node, $this->Helper)); } //in-line box return $this->Parent->GetLineBox(); } function GetTable() { if ($this instanceof kPDFTable) { return $this; } if ($this->Parent) { return $this->Parent->GetTable(); } return false; } function GetDisplayLevel() { // http://manual.prod.intechnic.lv/css21/visuren.html#q5 $display = $this->GetCSSProperty('display'); if (!$display) $display = $this->CSSSpecifiedProperties['DISPLAY']; switch ($display) { case 'block': case 'list-item': case 'table': case 'table-cell': case 'table-row': case 'table': return 'block'; case 'run-in': // do special processing here: http://manual.prod.intechnic.lv/css21/visuren.html#run-in return 'block'; case 'none': return 'none'; } return 'inline'; } function ProcessCSS() { $supported_properties = array( 'DISPLAY', 'FONT-SIZE', // SHOULD BE FIRST, BECAUSE ALL EM UNITS RELY ON IT 'WIDTH','MAX-WIDTH','MIN-WIDTH', 'HEIGHT', 'COLOR', 'FONT-FAMILY', 'FONT-WEIGHT', 'FONT-STYLE', 'FONT-VARIANT', 'WHITE-SPACE', 'VERTICAL-ALIGN', 'MARGIN-LEFT', 'MARGIN-RIGHT', 'MARGIN-TOP', 'MARGIN-BOTTOM', 'BORDER-TOP-STYLE', 'BORDER-RIGHT-STYLE', 'BORDER-BOTTOM-STYLE', 'BORDER-LEFT-STYLE', 'BORDER-TOP-WIDTH', 'BORDER-RIGHT-WIDTH', 'BORDER-BOTTOM-WIDTH', 'BORDER-LEFT-WIDTH', 'BORDER-TOP-COLOR', 'BORDER-RIGHT-COLOR', 'BORDER-BOTTOM-COLOR', 'BORDER-LEFT-COLOR', 'PADDING-TOP', 'PADDING-RIGHT', 'PADDING-BOTTOM', 'PADDING-LEFT', 'BACKGROUND-COLOR', 'TEXT-ALIGN', 'TEXT-TRANSFORM', 'TABLE-LAYOUT', 'PAGE-BREAK-AFTER' ); $cascade = $this->Helper->Stylesheet->GetAllProperties($this->Node); foreach ($supported_properties as $property) { $value = false; // !!! The following needs to be fixed somehow - thereis no major need in cascading properties for kPDFTextElement and kPDFLine also... if (!($this instanceof kPDFTextElement) || ($this instanceof kPDFTextElement && $property != 'DISPLAY')) { $value = isset($cascade[$property]) ? $cascade[$property] : false; } if (!$value && kCSSDefaults::IsInherited($property)) { $value = $this->FindInheritedValue($property); } if (!$value) { $value = kCSSDefaults::GetDefaultValue($property); } $this->CSSSpecifiedProperties[$property] = $value; } $this->Node->CssProperties = $this->CSSSpecifiedProperties; } function FindInheritedValue($property) { $node = $this->Node; if (!$node->Parent) { return false; } do { $node = $node->Parent; $value = isset($node->ComputedCSSProperties[$property]) ? $node->ComputedCSSProperties[$property] : false; } while (!$value && $node->Parent); return $value; } function ComputeCSSProperties() { foreach ($this->CSSSpecifiedProperties as $property => $value) { $this->SetCSSProperty($property, $this->ComputeCSSProperty($property, $value)); } $this->ComputeWidthAndMargins(); /*if ($this->GetDisplayLevel() == 'inline') { $props = array( 'margin-top' => 0, 'margin-right' => 0, 'margin-bottom' => 0, 'margin-left' => 0, 'width' => 0, ); foreach ($props as $name => $value) { $this->SetCSSProperty($name, $value); } }*/ $this->Node->ComputedCSSProperties = $this->CSSComputedPoperties; } function ComputeWidthAndMargins() { if ($this->WidthComputed) return ; if ($this->GetDisplayLevel() == 'inline') { return; } if (!$this->Parent) { $this->WidthComputed = true; return ; } $cb = $this->GetContainingBlock(); $cb_width = $cb->GetCSSProperty('width'); // containing block width if (!$cb->WidthComputed) { // this means we are inside an element which width is not yet defined (nested TABLE for instance) return ; } if ($this instanceof kPDFLine) { // otherwise margins will be applied from line containing block to the line $this->SetCSSProperty('width', $cb_width); return; } // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block $width = $this->GetCSSProperty('width'); // may be auto $margin_left = $this->GetCSSProperty('margin-left'); // may be auto $margin_right = $this->GetCSSProperty('margin-right'); // may be auto $border_left = $this->GetCSSProperty('border-left-width'); $border_right = $this->GetCSSProperty('border-right-width'); $padding_left = $this->GetCSSProperty('padding-left'); $padding_right = $this->GetCSSProperty('padding-right'); if ($width == 'auto' && $this->Parent) { if ($margin_left == 'auto') { $margin_left = 0; } if ($margin_right == 'auto') { $margin_right = 0; } $width = $cb_width - $margin_left - $border_left - $padding_left - $padding_right - $border_right - $margin_right; } elseif ($margin_left != 'auto' && $margin_right != 'auto') { //over-constrained $margin_right = $cb_width - $width - $margin_left - $border_left - $padding_left - $padding_right - $border_right; } elseif ($margin_left == 'auto' && $margin_right == 'auto') { $margin_left = ($cb_width - $border_left - $padding_left - $width - $padding_right - $border_right)/2; $margin_right = $margin_left; } $this->SetCSSProperty('width', $width); $this->SetCSSProperty('margin-right', $margin_right); $this->SetCSSProperty('margin-left', $margin_left); $this->WidthComputed = true; } function ComputeCSSProperty($property, $value) { if ($property == 'FONT-WEIGHT') { if ($value == 'normal') { return 400; } if ($value == 'bold') { return 700; } if ($value == 'bolder') { if (!$this->Parent) { return 700; } else { return max($this->Parent->GetCSSProperty('font-weight') + 300, 900); } } if ($value == 'lighter') { if (!$this->Parent) { return 400; } else { return min($this->Parent->GetCSSProperty('font-weight') - 300, 100); } } if (!is_integer($value)) { return 400; } return $value; } if (preg_match('/([.0-9]+)em/i', $value, $regs)) { $cb = $this->GetContainingBlock(); if ($property == 'FONT-SIZE') { if (!$cb) { $value = $regs[1] * $this->Helper->PtPerEm; } else { $value = $cb->GetCSSProperty('font-size') * $regs[1]; } } else { if ($cb) { $value = $cb->GetCSSProperty('font-size') * $regs[1]; } } } elseif (preg_match('/([.0-9]+)(px)/i', $value, $regs)) { $value = $regs[1] * 72 / 96; } elseif (preg_match('/([.0-9]+)(pt)/i', $value, $regs)) { $value = $regs[1]; } elseif (preg_match('/([.0-9]+)%/i', $value, $regs)) { $cb = $this->GetContainingBlock(); if ($cb && ($property != 'WIDTH' || ($property == 'WIDTH' && $cb->WidthComputed))) { $value = $regs[1]/100 * $cb->GetCSSProperty($property); } } if ($property == 'FONT-SIZE' && preg_match('/(xx-small|x-small|small|medium|large|x-large|xx-large)/i', $value)) { switch (strtolower($value)) { case 'xx-small': return $this->Helper->PtPerEm * 0.5; case 'x-small': return $this->Helper->PtPerEm * 0.7; case 'small': return $this->Helper->PtPerEm * 0.8; case 'medium': return $this->Helper->PtPerEm; case 'large': return $this->Helper->PtPerEm * 1.2; case 'x-large': return $this->Helper->PtPerEm * 1.4; case 'xx-large': return $this->Helper->PtPerEm * 1.6; } } // elseif ($value == 'none') { // $value = 0; // } return $value; } function GetContainingBlock() { if (!$this->Parent) return false; $parent_display = $this->Parent->GetCSSProperty('display'); if (preg_match('/^(block|inline-block|table|table-cell|list-item)$/i', $parent_display)) { return $this->Parent; } return $this->Parent->GetContainingBlock(); } function GetCSSProperty($property) { $property = strtoupper($property); return isset($this->CSSComputedPoperties[$property]) ? $this->CSSComputedPoperties[$property] : false; } function SetCSSProperty($name, $value) { $this->CSSComputedPoperties[strtoupper($name)] = $value; } function CheckDimensions() { $this->ComputeBaseline(); } function ComputeBaseline() { if (!$this->Parent) return ; $display = $this->GetCSSProperty('display'); /*$dim = $this->GetBoxDimensions(); $this->Ascent = $dim[1];*/ if ($display == 'inline' || $display == 'table-cell' || $this instanceof kPDFLine) { if ($this->Parent->Ascent < $this->Ascent) { $this->Parent->Ascent = $this->Ascent; } if ($this->Parent->Descent < $this->Descent) { $this->Parent->Descent = $this->Descent; } if ($this->Parent->Gap < $this->Gap) { $this->Parent->Gap = $this->Gap; } $this->Parent->ComputeBaseline(); } } function ContentWidthNewLine() { if ($this->CurLine_MinContentWidth > $this->MinContentWidth) { $this->MinContentWidth = $this->CurLine_MinContentWidth; } if ($this->CurLine_MaxContentWidth > $this->MaxContentWidth) { $this->MaxContentWidth = $this->CurLine_MaxContentWidth; } $this->CurLine_MinContentWidth = 0; $this->CurLine_MaxContentWidth = 0; } function CalcMinMaxContentWidth() { if (!$this->Parent) return ; $this->ContentWidthNewLine(); $extra_width = $this->GetCSSProperty('margin-left') + $this->GetCSSProperty('margin-right') + $this->GetCSSProperty('padding-left') + $this->GetCSSProperty('padding-right') + $this->GetCSSProperty('border-left-width') + $this->GetCSSProperty('border-right-width'); // $extra_width = 0; $this->MinContentWidth += $extra_width; $this->MaxContentWidth += $extra_width; $display = $this->GetCSSProperty('display'); if (($display == 'inline' || $display == 'table-cell')) { $this->Parent->CurLine_MinContentWidth += $this->MinContentWidth; $this->Parent->CurLine_MaxContentWidth += $this->MaxContentWidth; if ($this->Node->Name == 'BR') { $this->Parent->ContentWidthNewLine(); } } else { if ($this->MinContentWidth > $this->Parent->MinContentWidth) { $this->Parent->MinContentWidth = $this->MinContentWidth; // $this->Parent->CalcMinMaxContentWidth(); } if ($this->MaxContentWidth > $this->Parent->MaxContentWidth) { $this->Parent->MaxContentWidth = $this->MaxContentWidth; // $this->Parent->CalcMinMaxContentWidth(); } } // $this->ContentWidthNewLine(); } } class kPDFLine extends kPDFElement { public $LastLine = true; function __construct($node, $helper) { $line_node = new kXMLNode('_LINE_', array('STYLE' => 'display: block')); // $line_node->SetParent($node); $node->AddChild($line_node); parent::__construct($line_node, $helper); } function Init() { parent::Init(); $this->SetCSSProperty('display', 'block'); $this->SetCSSProperty('margin-left', '0'); $this->SetCSSProperty('margin-right', '0'); $this->SetCSSProperty('margin-top', '0'); $this->SetCSSProperty('margin-bottom', '0'); $this->SetCSSProperty('padding-left', '0'); $this->SetCSSProperty('padding-right', '0'); $this->SetCSSProperty('padding-top', '0'); $this->SetCSSProperty('padding-bottom', '0'); } }