Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Wed, Apr 30, 8:59 AM

in-portal

Index: branches/5.1.x/core/units/pdf/pdf_helper.php
===================================================================
--- branches/5.1.x/core/units/pdf/pdf_helper.php (revision 13901)
+++ branches/5.1.x/core/units/pdf/pdf_helper.php (revision 13902)
@@ -1,1012 +1,1026 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
//define('PDF_DEBUG_NO_TEXT', 1); // do not draw text
//define('PDF_DEBUG_DUMP_ONLY', 1); // output elements dump and exit
//define('PDF_DEBUG_DRAW_BOXES', 1); //
//define('PDF_DEBUG_DRAW_BASELINE', 1); //
//define('PDF_DEBUG_DRAW_BOX_INFO', '/.*/'); //
//define('PDF_DEBUG_DRAW_BOX_INFO', '/(td|img)/i'); //
//define('PDF_DEBUG_DRAW_MARGINS', 1); //
//define('PDF_DEBUG_DRAW_ELEM_BORDERS', 1);
//define('PDF_DEBUG_DRAW_LINE_BOXES', 1);
//define('PDF_DRAW_CONTENT_AREA', 1);
require_once FULL_PATH.'/core/units/pdf/pdf_styles.php';
require_once FULL_PATH.'/core/units/pdf/pdf_text.php';
require_once FULL_PATH.'/core/units/pdf/pdf_table.php';
require_once FULL_PATH.'/core/units/pdf/pdf_image.php';
require_once FULL_PATH.'/core/units/pdf/pdf_renderer.php';
require_once FULL_PATH.'/core/units/pdf/pdf_renderer_tcpdf.php';
class kPDFHelper extends kHelper {
/**
* Enter description here...
*
* @var kPDFRenderer
*/
var $PDF;
var $CurPDFElem;
var $DimensionsMode = 1;
var $Stylesheet;
var $PtPerEm = 10;
public $Document = null;
const DM_NORMAL = 0;
const DM_SKIP = 1;
- function BuildFromTemplate($template, $template_params = Array ())
+ /**
+ * Allows to convert given template contents into pdf document
+ *
+ * @param string $template (template name OR it's contents, see $raw_template)
+ * @param Array $template_params
+ * @param bool $is_content
+ * @return string
+ */
+ function BuildFromTemplate($template, $template_params = Array (), $is_content = false)
{
$this->Application->InitParser();
$this->Application->Parser->SetParams($template_params);
- $xml = $this->Application->Parser->Run($template);
+
+ if ($is_content) {
+ $xml = $this->Application->Parser->Parse($template);
+ }
+ else {
+ $xml = $this->Application->Parser->Run($template);
+ }
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$doc = $xml_helper->Parse($xml_helper->ConvertHTMLEntities($xml), 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('&nbsp;', $level*4);
$dump .= $tab . get_class($this) . ' Node: ' . $this->Node->Name . " child of ".$this->Node->Parent->Name."<br>\n";
if ($this instanceof kPDFTextElement) {
$dump .= $tab . 'Data: ' . $this->Data . "<br>\n";
}
$dump .= $tab . 'Width: ' . $this->GetCSSProperty('width') . ' Height: ' . $this->GetCSSProperty('height') . " Ascent: " . $this->Ascent . "<br>\n";
$dump .= $tab . 'MinCW: ' . $this->MinContentWidth . ' MaxCW: ' . $this->MaxContentWidth . "<br>\n";
$dump .= $tab . 'Children:' . "<br>\n";
$i = 0;
foreach ($this->Children as $elem)
{
$i++;
$dump .= $tab . $i . "<br>\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');
}
}
\ No newline at end of file

Event Timeline