vendor: Update dompdf to version 0.8.3

refs #3785
This commit is contained in:
Johannes Meyer 2019-06-27 09:39:41 +02:00
parent 3f7b317ced
commit 44c7c427e8
25 changed files with 431 additions and 220 deletions

View File

@ -2,15 +2,13 @@
set -eux set -eux
#GLOBIGNORE=$0; rm -rf * #GLOBIGNORE=$0; rm -rf *
#DOMPDF_VERSION=0.8.2 DOMPDF_VERSION=0.8.3
DOMPDF_VERSION=6a77a427984f97743018ace3e095fbf0edaaee29 # https://github.com/dompdf/dompdf/pull/1854
PHP_FONTLIB_VERSION=0.5.1 PHP_FONTLIB_VERSION=0.5.1
PHP_SVGLIB_VERSION=0.3.2 PHP_SVGLIB_VERSION=0.3.2
rm -rf lib/ src/ rm -rf lib/ src/
curl -LsS https://github.com/dompdf/dompdf/archive/"$DOMPDF_VERSION".tar.gz -o /tmp/dompdf.tar.gz curl -LsS https://github.com/dompdf/dompdf/archive/v"$DOMPDF_VERSION".tar.gz -o /tmp/dompdf.tar.gz
tar xf /tmp/dompdf.tar.gz --strip-components 1 dompdf-"$DOMPDF_VERSION"/{lib,src,LICENSE.LGPL} tar xf /tmp/dompdf.tar.gz --strip-components 1 dompdf-"$DOMPDF_VERSION"/{lib,src,LICENSE.LGPL}
rm /tmp/dompdf.tar.gz rm /tmp/dompdf.tar.gz
mv LICENSE.LGPL LICENSE mv LICENSE.LGPL LICENSE

View File

@ -464,28 +464,28 @@ class Cpdf
// Named with limited valid values // Named with limited valid values
case 'NonFullScreenPageMode': case 'NonFullScreenPageMode':
if (!in_array($v, array('UseNone', 'UseOutlines', 'UseThumbs', 'UseOC'))) { if (!in_array($v, array('UseNone', 'UseOutlines', 'UseThumbs', 'UseOC'))) {
continue 2; break;
} }
$o['info'][$k] = $v; $o['info'][$k] = $v;
break; break;
case 'Direction': case 'Direction':
if (!in_array($v, array('L2R', 'R2L'))) { if (!in_array($v, array('L2R', 'R2L'))) {
continue 2; break;
} }
$o['info'][$k] = $v; $o['info'][$k] = $v;
break; break;
case 'PrintScaling': case 'PrintScaling':
if (!in_array($v, array('None', 'AppDefault'))) { if (!in_array($v, array('None', 'AppDefault'))) {
continue 2; break;
} }
$o['info'][$k] = $v; $o['info'][$k] = $v;
break; break;
case 'Duplex': case 'Duplex':
if (!in_array($v, array('None', 'AppDefault'))) { if (!in_array($v, array('None', 'AppDefault'))) {
continue 2; break;
} }
$o['info'][$k] = $v; $o['info'][$k] = $v;
break; break;

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg">
<g>
<rect stroke="#666666" id="svg_1" height="60.499994" width="60.166667" y="1.666669" x="1.999998" stroke-width="1.5" fill="none"/>
<line stroke-linecap="null" stroke-linejoin="null" id="svg_3" y2="59.333253" x2="59.749916" y1="4.333415" x1="4.250079" stroke-width="1.5" stroke="#999999" fill="none"/>
<line stroke-linecap="null" stroke-linejoin="null" id="svg_4" y2="59.999665" x2="4.062838" y1="3.750342" x1="60.062164" stroke-width="1.5" stroke="#999999" fill="none"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 579 B

View File

@ -152,7 +152,7 @@ class CPDF implements Canvas
private $_page_text; private $_page_text;
/** /**
* Array of pages for accesing after rendering is initially complete * Array of pages for accessing after rendering is initially complete
* *
* @var array * @var array
*/ */
@ -275,7 +275,7 @@ class CPDF implements Canvas
/** /**
* Opens a new 'object' * Opens a new 'object'
* *
* While an object is open, all drawing actions are recored in the object, * While an object is open, all drawing actions are recorded in the object,
* as opposed to being drawn on the current page. Objects can be added * as opposed to being drawn on the current page. Objects can be added
* later to a specific page or to several pages. * later to a specific page or to several pages.
* *

View File

@ -49,14 +49,46 @@ class PDFLib implements Canvas
static $IN_MEMORY = true; static $IN_MEMORY = true;
/** /**
* @var Dompdf * Saves the major version of PDFLib for compatibility requests
*
* @var null|int
*/
static private $MAJOR_VERSION = null;
/**
* Transforms the list of native fonts into PDFLib compatible names (casesensitive)
*
* @var array
*/
static public $nativeFontsTpPDFLib = array(
"courier" => "Courier",
"courier-bold" => "Courier-Bold",
"courier-oblique" => "Courier-Oblique",
"courier-boldoblique" => "Courier-BoldOblique",
"helvetica" => "Helvetica",
"helvetica-bold" => "Helvetica-Bold",
"helvetica-oblique" => "Helvetica-Oblique",
"helvetica-boldoblique" => "Helvetica-BoldOblique",
"times" => "Times-Roman",
"times-roman" => "Times-Roman",
"times-bold" => "Times-Bold",
"times-italic" => "Times-Italic",
"times-bolditalic" => "Times-BoldItalic",
"symbol" => "Symbol",
"zapfdinbats" => "ZapfDingbats",
"zapfdingbats" => "ZapfDingbats",
);
/**
* @var \Dompdf\Dompdf
*/ */
private $_dompdf; private $_dompdf;
/** /**
* Instance of PDFLib class * Instance of PDFLib class
* *
* @var \PDFlib * @var \PDFLib
*/ */
private $_pdf; private $_pdf;
@ -116,6 +148,13 @@ class PDFLib implements Canvas
*/ */
private $_fonts; private $_fonts;
/**
* Cache of fontFile checks
*
* @var array
*/
private $_fontsFiles;
/** /**
* List of objects (templates) to add to multiple pages * List of objects (templates) to add to multiple pages
* *
@ -161,7 +200,7 @@ class PDFLib implements Canvas
/** /**
* Class constructor * Class constructor
* *
* @param mixed $paper The size of paper to use either a string (see {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}) or * @param string|array $paper The size of paper to use either a string (see {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}) or
* an array(xmin,ymin,xmax,ymax) * an array(xmin,ymin,xmax,ymax)
* @param string $orientation The orientation of the document (either 'landscape' or 'portrait') * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
* @param Dompdf $dompdf * @param Dompdf $dompdf
@ -170,7 +209,7 @@ class PDFLib implements Canvas
{ {
if (is_array($paper)) { if (is_array($paper)) {
$size = $paper; $size = $paper;
} else if (isset(self::$PAPER_SIZES[mb_strtolower($paper)])) { } elseif (isset(self::$PAPER_SIZES[mb_strtolower($paper)])) {
$size = self::$PAPER_SIZES[mb_strtolower($paper)]; $size = self::$PAPER_SIZES[mb_strtolower($paper)];
} else { } else {
$size = self::$PAPER_SIZES["letter"]; $size = self::$PAPER_SIZES["letter"];
@ -189,14 +228,25 @@ class PDFLib implements Canvas
$license = $dompdf->getOptions()->getPdflibLicense(); $license = $dompdf->getOptions()->getPdflibLicense();
if (strlen($license) > 0) { if (strlen($license) > 0) {
$this->_pdf->set_parameter("license", $license); $this->setPDFLibParameter("license", $license);
} }
$this->_pdf->set_parameter("textformat", "utf8"); $this->setPDFLibParameter("textformat", "utf8");
$this->_pdf->set_parameter("fontwarning", "false"); if ($this->getPDFLibMajorVersion() >= 7) {
$this->setPDFLibParameter("errorpolicy", "return");
// $this->_pdf->set_option('logging={filename=' . \APP_PATH . '/logs/pdflib.log classes={api=1 warning=2}}');
// $this->_pdf->set_option('errorpolicy=exception');
} else {
$this->setPDFLibParameter("fontwarning", "false");
}
// TODO: fetch PDFLib version information for the producer field $searchPath = $this->_dompdf->getOptions()->getFontDir();
$this->_pdf->set_info("Producer Addendum", sprintf("%s + PDFLib", $dompdf->version)); if (empty($searchPath) === false) {
$this->_pdf->set_option('searchpath={' . $searchPath . '}');
}
// fetch PDFLib version information for the producer field
$this->_pdf->set_info("Producer Addendum", sprintf("%s + PDFLib %s", $dompdf->version, $this->getPDFLibMajorVersion()));
// Silence pedantic warnings about missing TZ settings // Silence pedantic warnings about missing TZ settings
$tz = @date_default_timezone_get(); $tz = @date_default_timezone_get();
@ -291,6 +341,7 @@ class PDFLib implements Canvas
$ret = $this->_pdf->begin_template($this->_width, $this->_height); $ret = $this->_pdf->begin_template($this->_width, $this->_height);
$this->_pdf->save(); $this->_pdf->save();
$this->_objs[$ret] = array("start_page" => $this->_page_number); $this->_objs[$ret] = array("start_page" => $this->_page_number);
return $ret; return $ret;
} }
@ -332,7 +383,7 @@ class PDFLib implements Canvas
* - 'nextodd' add to all odd numbered pages from the next one * - 'nextodd' add to all odd numbered pages from the next one
* - 'nexteven' add to all even numbered pages from the next one * - 'nexteven' add to all even numbered pages from the next one
* *
* @param int $object the object handle returned by open_object() * @param int $object the object handle returned by open_object()
* @param string $where * @param string $where
*/ */
public function add_object($object, $where = 'all') public function add_object($object, $where = 'all')
@ -453,10 +504,10 @@ class PDFLib implements Canvas
/** /**
* Sets the line style * Sets the line style
* *
* @param float $width * @param float $width
* @param $cap * @param $cap
* @param string $join * @param string $join
* @param array $dash * @param array $dash
* *
* @return void * @return void
*/ */
@ -466,23 +517,43 @@ class PDFLib implements Canvas
$dash[] = $dash[0]; $dash[] = $dash[0];
} }
if (count($dash) > 1) { if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->setdashpattern("dasharray={" . implode(" ", $dash) . "}"); if (count($dash) > 1) {
$this->_pdf->set_graphics_option("dasharray={" . implode(" ", $dash) . "}");
} else {
$this->_pdf->set_graphics_option("dasharray=none");
}
} else { } else {
$this->_pdf->setdash(0, 0); if (count($dash) > 1) {
$this->_pdf->setdashpattern("dasharray={" . implode(" ", $dash) . "}");
} else {
$this->_pdf->setdash(0, 0);
}
} }
switch ($join) { switch ($join) {
case "miter": case "miter":
$this->_pdf->setlinejoin(0); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linejoin=0');
} else {
$this->_pdf->setlinejoin(0);
}
break; break;
case "round": case "round":
$this->_pdf->setlinejoin(1); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linejoin=1');
} else {
$this->_pdf->setlinejoin(1);
}
break; break;
case "bevel": case "bevel":
$this->_pdf->setlinejoin(2); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linejoin=2');
} else {
$this->_pdf->setlinejoin(2);
}
break; break;
default: default:
@ -491,15 +562,27 @@ class PDFLib implements Canvas
switch ($cap) { switch ($cap) {
case "butt": case "butt":
$this->_pdf->setlinecap(0); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linecap=0');
} else {
$this->_pdf->setlinecap(0);
}
break; break;
case "round": case "round":
$this->_pdf->setlinecap(1); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linecap=1');
} else {
$this->_pdf->setlinecap(1);
}
break; break;
case "square": case "square":
$this->_pdf->setlinecap(2); if ($this->getPDFLibMajorVersion() >= 9) {
$this->_pdf->set_graphics_option('linecap=2');
} else {
$this->_pdf->setlinecap(2);
}
break; break;
default: default:
@ -583,7 +666,7 @@ class PDFLib implements Canvas
*/ */
public function _set_fill_opacity($opacity, $mode = "Normal") public function _set_fill_opacity($opacity, $mode = "Normal")
{ {
if ($mode === "Normal") { if ($mode === "Normal" && is_null($opacity) === false) {
$this->_set_gstate("opacityfill=$opacity"); $this->_set_gstate("opacityfill=$opacity");
} }
} }
@ -596,7 +679,7 @@ class PDFLib implements Canvas
*/ */
public function _set_stroke_opacity($opacity, $mode = "Normal") public function _set_stroke_opacity($opacity, $mode = "Normal")
{ {
if ($mode === "Normal") { if ($mode === "Normal" && is_null($opacity) === false) {
$this->_set_gstate("opacitystroke=$opacity"); $this->_set_gstate("opacitystroke=$opacity");
} }
} }
@ -609,7 +692,7 @@ class PDFLib implements Canvas
*/ */
public function set_opacity($opacity, $mode = "Normal") public function set_opacity($opacity, $mode = "Normal")
{ {
if ($mode === "Normal") { if ($mode === "Normal" && is_null($opacity) === false) {
$this->_set_gstate("opacityfill=$opacity opacitystroke=$opacity"); $this->_set_gstate("opacityfill=$opacity opacitystroke=$opacity");
$this->_current_opacity = $opacity; $this->_current_opacity = $opacity;
} }
@ -627,6 +710,7 @@ class PDFLib implements Canvas
$gstate = $this->_pdf->create_gstate($gstate_options); $gstate = $this->_pdf->create_gstate($gstate_options);
$this->_gstates[$gstate] = $gstate_options; $this->_gstates[$gstate] = $gstate_options;
} }
return $this->_pdf->set_gstate($gstate); return $this->_pdf->set_gstate($gstate);
} }
@ -644,7 +728,7 @@ class PDFLib implements Canvas
* fitwindow Fit the complete page to the window. * fitwindow Fit the complete page to the window.
* fixed * fixed
*/ */
//$this->_pdf->set_parameter("openaction", $view); //$this->setPDFLibParameter("openaction", $view);
} }
/** /**
@ -658,48 +742,17 @@ class PDFLib implements Canvas
*/ */
protected function _load_font($font, $encoding = null, $options = "") protected function _load_font($font, $encoding = null, $options = "")
{ {
// Set up font paths // Fix for PDFLibs case-sensitive font names
if ($this->_pdf->get_parameter("FontOutline", 1) === "") { $baseFont = basename($font);
$families = $this->_dompdf->getFontMetrics()->getFontFamilies(); $isNativeFont = false;
foreach ($families as $files) { if (isset(self::$nativeFontsTpPDFLib[$baseFont])) {
foreach ($files as $file) { $font = self::$nativeFontsTpPDFLib[$baseFont];
$face = basename($file); $isNativeFont = true;
$afm = null;
// Prefer ttfs to afms
if (file_exists("$file.ttf")) {
$outline = "$file.ttf";
} else if (file_exists("$file.TTF")) {
$outline = "$file.TTF";
} else if (file_exists("$file.pfb")) {
$outline = "$file.pfb";
if (file_exists("$file.afm")) {
$afm = "$file.afm";
}
} else if (file_exists("$file.PFB")) {
$outline = "$file.PFB";
if (file_exists("$file.AFM")) {
$afm = "$file.AFM";
}
} else {
continue;
}
$this->_pdf->set_parameter("FontOutline", "\{$face\}=\{$outline\}");
if (!is_null($afm)) {
$this->_pdf->set_parameter("FontAFM", "\{$face\}=\{$afm\}");
}
}
}
} }
// Check if the font is a native PDF font // Check if the font is a native PDF font
// Embed non-native fonts // Embed non-native fonts
$test = strtolower(basename($font)); $test = strtolower($baseFont);
if (in_array($test, DOMPDF::$nativeFonts)) { if (in_array($test, DOMPDF::$nativeFonts)) {
$font = basename($font); $font = basename($font);
} else { } else {
@ -718,13 +771,71 @@ class PDFLib implements Canvas
} }
$key = "$font:$encoding:$options"; $key = "$font:$encoding:$options";
if (isset($this->_fonts[$key])) { if (isset($this->_fonts[$key])) {
return $this->_fonts[$key]; return $this->_fonts[$key];
} else { }
// Native fonts are build in, just load it
if ($isNativeFont) {
$this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options); $this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options);
return $this->_fonts[$key]; return $this->_fonts[$key];
} }
$fontOutline = $this->getPDFLibParameter("FontOutline", 1);
if ($fontOutline === "" || $fontOutline <= 0) {
$families = $this->_dompdf->getFontMetrics()->getFontFamilies();
foreach ($families as $files) {
foreach ($files as $file) {
$face = basename($file);
$afm = null;
if (isset($this->_fontsFiles[$face])) {
continue;
}
// Prefer ttfs to afms
if (file_exists("$file.ttf")) {
$outline = "$file.ttf";
} elseif (file_exists("$file.TTF")) {
$outline = "$file.TTF";
} elseif (file_exists("$file.pfb")) {
$outline = "$file.pfb";
if (file_exists("$file.afm")) {
$afm = "$file.afm";
}
} elseif (file_exists("$file.PFB")) {
$outline = "$file.PFB";
if (file_exists("$file.AFM")) {
$afm = "$file.AFM";
}
} else {
continue;
}
$this->_fontsFiles[$face] = true;
if ($this->getPDFLibMajorVersion() >= 9) {
$this->setPDFLibParameter("FontOutline", '{' . "$face=$outline" . '}');
} else {
$this->setPDFLibParameter("FontOutline", "\{$face\}=\{$outline\}");
}
if (is_null($afm)) {
continue;
}
if ($this->getPDFLibMajorVersion() >= 9) {
$this->setPDFLibParameter("FontAFM", '{' . "$face=$afm" . '}');
} else {
$this->setPDFLibParameter("FontAFM", "\{$face\}=\{$afm\}");
}
}
}
}
$this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options);
return $this->_fonts[$key];
} }
/** /**
@ -759,7 +870,7 @@ class PDFLib implements Canvas
$this->_pdf->lineto($x2, $y2); $this->_pdf->lineto($x2, $y2);
$this->_pdf->stroke(); $this->_pdf->stroke();
$this->_set_line_transparency("Normal", $this->_current_opacity); $this->_set_stroke_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -802,7 +913,7 @@ class PDFLib implements Canvas
$this->_pdf->arc($x1, $y1, $r1, $astart, $aend); $this->_pdf->arc($x1, $y1, $r1, $astart, $aend);
$this->_pdf->stroke(); $this->_pdf->stroke();
$this->_set_line_transparency("Normal", $this->_current_opacity); $this->_set_stroke_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -812,7 +923,7 @@ class PDFLib implements Canvas
* @param float $h * @param float $h
* @param array $color * @param array $color
* @param float $width * @param float $width
* @param null $style * @param null $style
*/ */
public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
{ {
@ -824,7 +935,7 @@ class PDFLib implements Canvas
$this->_pdf->rect($x1, $y1, $w, $h); $this->_pdf->rect($x1, $y1, $w, $h);
$this->_pdf->stroke(); $this->_pdf->stroke();
$this->_set_line_transparency("Normal", $this->_current_opacity); $this->_set_stroke_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -843,7 +954,7 @@ class PDFLib implements Canvas
$this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h)); $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h));
$this->_pdf->fill(); $this->_pdf->fill();
$this->_set_fill_transparency("Normal", $this->_current_opacity); $this->_set_fill_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -874,7 +985,6 @@ class PDFLib implements Canvas
*/ */
public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
{ {
// @todo
$this->clipping_rectangle($x1, $y1, $w, $h); $this->clipping_rectangle($x1, $y1, $w, $h);
} }
@ -965,9 +1075,9 @@ class PDFLib implements Canvas
/** /**
* @param array $points * @param array $points
* @param array $color * @param array $color
* @param null $width * @param null $width
* @param null $style * @param null $style
* @param bool $fill * @param bool $fill
*/ */
public function polygon($points, $color, $width = null, $style = null, $fill = false) public function polygon($points, $color, $width = null, $style = null, $fill = false)
{ {
@ -994,8 +1104,8 @@ class PDFLib implements Canvas
$this->_pdf->closepath_stroke(); $this->_pdf->closepath_stroke();
} }
$this->_set_fill_transparency("Normal", $this->_current_opacity); $this->_set_fill_opacity($this->_current_opacity, "Normal");
$this->_set_line_transparency("Normal", $this->_current_opacity); $this->_set_stroke_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -1003,9 +1113,9 @@ class PDFLib implements Canvas
* @param float $y * @param float $y
* @param float $r * @param float $r
* @param array $color * @param array $color
* @param null $width * @param null $width
* @param null $style * @param null $style
* @param bool $fill * @param bool $fill
*/ */
public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
{ {
@ -1026,16 +1136,16 @@ class PDFLib implements Canvas
$this->_pdf->stroke(); $this->_pdf->stroke();
} }
$this->_set_fill_transparency("Normal", $this->_current_opacity); $this->_set_fill_opacity($this->_current_opacity, "Normal");
$this->_set_line_transparency("Normal", $this->_current_opacity); $this->_set_stroke_opacity($this->_current_opacity, "Normal");
} }
/** /**
* @param string $img_url * @param string $img_url
* @param float $x * @param float $x
* @param float $y * @param float $y
* @param int $w * @param int $w
* @param int $h * @param int $h
* @param string $resolution * @param string $resolution
*/ */
public function image($img_url, $x, $y, $w, $h, $resolution = "normal") public function image($img_url, $x, $y, $w, $h, $resolution = "normal")
@ -1056,15 +1166,15 @@ class PDFLib implements Canvas
} }
/** /**
* @param float $x * @param float $x
* @param float $y * @param float $y
* @param string $text * @param string $text
* @param string $font * @param string $font
* @param float $size * @param float $size
* @param array $color * @param array $color
* @param int $word_spacing * @param int $word_spacing
* @param int $char_spacing * @param int $char_spacing
* @param int $angle * @param int $angle
*/ */
public function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0, $char_spacing = 0, $angle = 0) public function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0, $char_spacing = 0, $angle = 0)
{ {
@ -1081,7 +1191,7 @@ class PDFLib implements Canvas
$this->_pdf->fit_textline($text, $x, $y, "rotate=$angle wordspacing=$word_spacing charspacing=$char_spacing "); $this->_pdf->fit_textline($text, $x, $y, "rotate=$angle wordspacing=$word_spacing charspacing=$char_spacing ");
$this->_set_fill_transparency("Normal", $this->_current_opacity); $this->_set_fill_opacity($this->_current_opacity, "Normal");
} }
/** /**
@ -1107,11 +1217,11 @@ class PDFLib implements Canvas
/** /**
* Add a link to the pdf * Add a link to the pdf
* *
* @param string $url The url to link to * @param string $url The url to link to
* @param float $x The x position of the link * @param float $x The x position of the link
* @param float $y The y position of the link * @param float $y The y position of the link
* @param float $width The width of the link * @param float $width The width of the link
* @param float $height The height of the link * @param float $height The height of the link
*/ */
public function add_link($url, $x, $y, $width, $height) public function add_link($url, $x, $y, $width, $height)
{ {
@ -1140,9 +1250,9 @@ class PDFLib implements Canvas
/** /**
* @param string $text * @param string $text
* @param string $font * @param string $font
* @param float $size * @param float $size
* @param int $word_spacing * @param int $word_spacing
* @param int $letter_spacing * @param int $letter_spacing
* @return mixed * @return mixed
*/ */
public function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0) public function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0)
@ -1163,7 +1273,7 @@ class PDFLib implements Canvas
/** /**
* @param string $font * @param string $font
* @param float $size * @param float $size
* @return float * @return float
*/ */
public function get_font_height($font, $size) public function get_font_height($font, $size)
@ -1177,17 +1287,19 @@ class PDFLib implements Canvas
// $desc is usually < 0, // $desc is usually < 0,
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio(); $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
return $size * ($asc - $desc) * $ratio; return $size * ($asc - $desc) * $ratio;
} }
/** /**
* @param string $font * @param string $font
* @param float $size * @param float $size
* @return float * @return float
*/ */
public function get_font_baseline($font, $size) public function get_font_baseline($font, $size)
{ {
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio(); $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
return $this->get_font_height($font, $size) / $ratio * 1.1; return $this->get_font_height($font, $size) / $ratio * 1.1;
} }
@ -1199,15 +1311,15 @@ class PDFLib implements Canvas
* *
* See {@link Style::munge_color()} for the format of the color array. * See {@link Style::munge_color()} for the format of the color array.
* *
* @param float $x * @param float $x
* @param float $y * @param float $y
* @param string $text the text to write * @param string $text the text to write
* @param string $font the font file to use * @param string $font the font file to use
* @param float $size the font size, in points * @param float $size the font size, in points
* @param array $color * @param array $color
* @param float $word_space word spacing adjustment * @param float $word_space word spacing adjustment
* @param float $char_space char spacing adjustment * @param float $char_space char spacing adjustment
* @param float $angle angle to write the text at, measured CW starting from the x-axis * @param float $angle angle to write the text at, measured CW starting from the x-axis
*/ */
public function page_text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) public function page_text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
{ {
@ -1296,7 +1408,7 @@ class PDFLib implements Canvas
* Streams the PDF to the client. * Streams the PDF to the client.
* *
* @param string $filename The filename to present to the client. * @param string $filename The filename to present to the client.
* @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1). * @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
* @throws Exception * @throws Exception
*/ */
public function stream($filename = "document.pdf", $options = array()) public function stream($filename = "document.pdf", $options = array())
@ -1305,15 +1417,19 @@ class PDFLib implements Canvas
die("Unable to stream pdf: headers already sent"); die("Unable to stream pdf: headers already sent");
} }
if (!isset($options["compress"])) $options["compress"] = true; if (!isset($options["compress"])) {
if (!isset($options["Attachment"])) $options["Attachment"] = true; $options["compress"] = true;
}
if (!isset($options["Attachment"])) {
$options["Attachment"] = true;
}
$this->_add_page_text(); $this->_add_page_text();
if ($options["compress"]) { if ($options["compress"]) {
$this->_pdf->set_value("compress", 6); $this->setPDFLibValue("compress", 6);
} else { } else {
$this->_pdf->set_value("compress", 0); $this->setPDFLibValue("compress", 0);
} }
$this->_close(); $this->_close();
@ -1372,14 +1488,16 @@ class PDFLib implements Canvas
*/ */
public function output($options = array()) public function output($options = array())
{ {
if (!isset($options["compress"])) $options["compress"] = true; if (!isset($options["compress"])) {
$options["compress"] = true;
}
$this->_add_page_text(); $this->_add_page_text();
if ($options["compress"]) { if ($options["compress"]) {
$this->_pdf->set_value("compress", 6); $this->setPDFLibValue("compress", 6);
} else { } else {
$this->_pdf->set_value("compress", 0); $this->setPDFLibValue("compress", 0);
} }
$this->_close(); $this->_close();
@ -1402,6 +1520,78 @@ class PDFLib implements Canvas
return $data; return $data;
} }
/**
* @param string $keyword
* @param string $optlist
* @return mixed
*/
protected function getPDFLibParameter($keyword, $optlist = "")
{
if ($this->getPDFLibMajorVersion() >= 9) {
return $this->_pdf->get_option($keyword, "");
}
return $this->_pdf->get_parameter($keyword, $optlist);
}
/**
* @param string $keyword
* @param string $value
* @return mixed
*/
protected function setPDFLibParameter($keyword, $value)
{
if ($this->getPDFLibMajorVersion() >= 9) {
return $this->_pdf->set_option($keyword . "=" . $value);
}
return $this->_pdf->set_parameter($keyword, $value);
}
/**
* @param string $keyword
* @param string $optlist
* @return mixed
*/
protected function getPDFLibValue($keyword, $optlist = "")
{
if ($this->getPDFLibMajorVersion() >= 9) {
return $this->getPDFLibParameter($keyword, $optlist);
}
return $this->_pdf->get_value($keyword);
}
/**
* @param string $keyword
* @param string $value
* @return mixed
*/
protected function setPDFLibValue($keyword, $value)
{
if ($this->getPDFLibMajorVersion() >= 9) {
return $this->setPDFLibParameter($keyword, $value);
}
return $this->_pdf->set_value($keyword, $value);
}
/**
* @return int
*/
private function getPDFLibMajorVersion()
{
if (is_null(self::$MAJOR_VERSION)) {
if (method_exists($this->_pdf, "get_option")) {
self::$MAJOR_VERSION = abs(intval($this->_pdf->get_option("major", "")));
} else {
self::$MAJOR_VERSION = abs(intval($this->_pdf->get_value("major", "")));
}
}
return self::$MAJOR_VERSION;
}
} }
// Workaround for idiotic limitation on statics... // Workaround for idiotic limitation on statics...

View File

@ -46,7 +46,7 @@ class CanvasFactory
} }
else { else {
if ($backend === "gd") { if ($backend === "gd" && extension_loaded('gd')) {
$class = "Dompdf\\Adapter\\GD"; $class = "Dompdf\\Adapter\\GD";
} else { } else {
$class = "Dompdf\\Adapter\\CPDF"; $class = "Dompdf\\Adapter\\CPDF";

View File

@ -776,7 +776,7 @@ class Style
* For easier finding all assignments, attempted to allowing only explicite assignment: * For easier finding all assignments, attempted to allowing only explicite assignment:
* Very many uses, e.g. AbstractFrameReflower.php -> for now leave as it is * Very many uses, e.g. AbstractFrameReflower.php -> for now leave as it is
* function __set($prop, $val) { * function __set($prop, $val) {
* throw new Exception("Implicite replacement of assignment by __set. Not good."); * throw new Exception("Implicit replacement of assignment by __set. Not good.");
* } * }
* function props_set($prop, $val) { ... } * function props_set($prop, $val) { ... }
* *
@ -1590,7 +1590,7 @@ class Style
Only for combined attributes extra treatment needed. See below. Only for combined attributes extra treatment needed. See below.
div { border: 1px red; } div { border: 1px red; }
div { border: solid; } // Not combined! Only one occurence of same style per context div { border: solid; } // Not combined! Only one occurrence of same style per context
// //
div { border: 1px red; } div { border: 1px red; }
div a { border: solid; } // Adding to border style ok by inheritance div a { border: solid; } // Adding to border style ok by inheritance
@ -1608,13 +1608,13 @@ class Style
At individual property like border-top-width need to check whether overriding value is also !important. At individual property like border-top-width need to check whether overriding value is also !important.
Also store the !important condition for later overrides. Also store the !important condition for later overrides.
Since not known who is initiating the override, need to get passed !important as parameter. Since not known who is initiating the override, need to get passed !important as parameter.
!important Paramter taken as in the original style in the css file. !important Parameter taken as in the original style in the css file.
When property border !important given, do not mark subsets like border_style as important. Only When property border !important given, do not mark subsets like border_style as important. Only
individual properties. individual properties.
Note: Note:
Setting individual property directly from css with e.g. set_border_top_style() is not needed, because Setting individual property directly from css with e.g. set_border_top_style() is not needed, because
missing set funcions handled by a generic handler __set(), including the !important. missing set functions handled by a generic handler __set(), including the !important.
Setting individual property of as sub-property is handled below. Setting individual property of as sub-property is handled below.
Implementation see at _set_style_side_type() Implementation see at _set_style_side_type()
@ -1969,7 +1969,7 @@ class Style
* *
* Other than with border and list, existing partial attributes should * Other than with border and list, existing partial attributes should
* reset when starting here, even when not mentioned. * reset when starting here, even when not mentioned.
* If individual attribute is !important and explicite or implicite replacement is not, * If individual attribute is !important and explicit or implicit replacement is not,
* keep individual attribute * keep individual attribute
* *
* require whitespace as delimiters for single value attributes * require whitespace as delimiters for single value attributes
@ -1978,7 +1978,7 @@ class Style
* font-style, font-variant, font-weight, font-size, line-height, font-family * font-style, font-variant, font-weight, font-size, line-height, font-family
* *
* missing font-size and font-family might be not allowed, but accept it here and * missing font-size and font-family might be not allowed, but accept it here and
* use default (medium size, enpty font name) * use default (medium size, empty font name)
* *
* @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style
* @param $val * @param $val
@ -2172,7 +2172,7 @@ class Style
// FIXME: handle partial values // FIXME: handle partial values
//For consistency of individal and combined properties, and with ie8 and firefox3 //For consistency of individual and combined properties, and with ie8 and firefox3
//reset all attributes, even if only partially given //reset all attributes, even if only partially given
$this->_set_style_side_type('border', $side, '_style', self::$_defaults['border_' . $side . '_style'], $important); $this->_set_style_side_type('border', $side, '_style', self::$_defaults['border_' . $side . '_style'], $important);
$this->_set_style_side_type('border', $side, '_width', self::$_defaults['border_' . $side . '_width'], $important); $this->_set_style_side_type('border', $side, '_width', self::$_defaults['border_' . $side . '_width'], $important);
@ -2544,7 +2544,7 @@ class Style
//On setting or merging or inheriting list_style_image as well as list_style_type, //On setting or merging or inheriting list_style_image as well as list_style_type,
//and url exists, then url has precedence, otherwise fall back to list_style_type //and url exists, then url has precedence, otherwise fall back to list_style_type
//Firefox is wrong here (list_style_image gets overwritten on explicite list_style_type) //Firefox is wrong here (list_style_image gets overwritten on explicit list_style_type)
//Internet Explorer 7/8 and dompdf is right. //Internet Explorer 7/8 and dompdf is right.
if (mb_substr($value, 0, 3) === "url") { if (mb_substr($value, 0, 3) === "url") {

View File

@ -172,8 +172,12 @@ class Stylesheet
$this->setFontMetrics($dompdf->getFontMetrics()); $this->setFontMetrics($dompdf->getFontMetrics());
$this->_styles = array(); $this->_styles = array();
$this->_loaded_files = array(); $this->_loaded_files = array();
list($this->_protocol, $this->_base_host, $this->_base_path) = Helpers::explode_url($_SERVER["SCRIPT_FILENAME"]); $script = __FILE__;
$this->_page_styles = array("base" => null); if(isset($_SERVER["SCRIPT_FILENAME"])){
$script = $_SERVER["SCRIPT_FILENAME"];
}
list($this->_protocol, $this->_base_host, $this->_base_path) = Helpers::explode_url($script);
$this->_page_styles = array("base" => new Style($this));
} }
/** /**
@ -281,7 +285,7 @@ class Stylesheet
} }
/** /**
* lookup a specifc Style collection * lookup a specific Style collection
* *
* lookup() returns the Style collection specified by $key, or null if the Style is * lookup() returns the Style collection specified by $key, or null if the Style is
* not found. * not found.
@ -441,7 +445,7 @@ class Stylesheet
* @param bool $first_pass * @param bool $first_pass
* *
* @throws Exception * @throws Exception
* @return string * @return array
*/ */
private function _css_selector_to_xpath($selector, $first_pass = false) private function _css_selector_to_xpath($selector, $first_pass = false)
{ {
@ -566,7 +570,7 @@ class Stylesheet
break; break;
case "+": case "+":
// All sibling elements that folow the current token // All sibling elements that follow the current token
if (mb_substr($query, -1, 1) !== "/") { if (mb_substr($query, -1, 1) !== "/") {
$query .= "/"; $query .= "/";
} }
@ -1261,7 +1265,7 @@ class Stylesheet
throw new Exception("Error parsing css file: preg_match_all() failed."); throw new Exception("Error parsing css file: preg_match_all() failed.");
} }
// After matching, the array indicies are set as follows: // After matching, the array indices are set as follows:
// //
// [0] => complete text of match // [0] => complete text of match
// [1] => contains '@import ...;' or '@media {' if applicable // [1] => contains '@import ...;' or '@media {' if applicable
@ -1357,7 +1361,7 @@ class Stylesheet
$key = $page_selector; $key = $page_selector;
default: default:
continue 3; break 2;
} }
// Store the style for later... // Store the style for later...
@ -1556,7 +1560,7 @@ class Stylesheet
foreach ($properties as $prop) { foreach ($properties as $prop) {
// If the $prop contains an url, the regex may be wrong // If the $prop contains an url, the regex may be wrong
// @todo: fix the regex so that it works everytime // @todo: fix the regex so that it works every time
/*if (strpos($prop, "url(") === false) { /*if (strpos($prop, "url(") === false) {
if (preg_match("/([a-z-]+)\s*:\s*[^:]+$/i", $prop, $m)) if (preg_match("/([a-z-]+)\s*:\s*[^:]+$/i", $prop, $m))
$prop = $m[0]; $prop = $m[0];

View File

@ -107,7 +107,7 @@ class Dompdf
/** /**
* Desired paper size ('letter', 'legal', 'A4', etc.) * Desired paper size ('letter', 'legal', 'A4', etc.)
* *
* @var string * @var string|array
*/ */
private $paperSize; private $paperSize;
@ -273,6 +273,11 @@ class Dompdf
{ {
mb_internal_encoding('UTF-8'); mb_internal_encoding('UTF-8');
if (version_compare(PHP_VERSION, '7.0.0') >= 0)
{
ini_set('pcre.jit', 0);
}
if (isset($options) && $options instanceof Options) { if (isset($options) && $options instanceof Options) {
$this->setOptions($options); $this->setOptions($options);
} elseif (is_array($options)) { } elseif (is_array($options)) {
@ -397,8 +402,8 @@ class Dompdf
} }
/** /**
* @param $str * @param string $str
* @param null $encoding * @param string $encoding
* @deprecated * @deprecated
*/ */
public function load_html($str, $encoding = 'UTF-8') public function load_html($str, $encoding = 'UTF-8')
@ -607,7 +612,7 @@ class Dompdf
if (!$accept) { if (!$accept) {
//found at least one mediatype, but none of the accepted ones //found at least one mediatype, but none of the accepted ones
//Skip this css file. //Skip this css file.
continue 2; break;
} }
} }
@ -628,7 +633,7 @@ class Dompdf
($media = $tag->getAttribute("media")) && ($media = $tag->getAttribute("media")) &&
!in_array($media, $acceptedmedia) !in_array($media, $acceptedmedia)
) { ) {
continue 2; break;
} }
$css = ""; $css = "";
@ -1030,7 +1035,7 @@ class Dompdf
/** /**
* Sets the paper size & orientation * Sets the paper size & orientation
* *
* @param string $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES} * @param string|array $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}
* @param string $orientation 'portrait' or 'landscape' * @param string $orientation 'portrait' or 'landscape'
* @return $this * @return $this
*/ */

View File

@ -125,7 +125,7 @@ class FontMetrics
$fontDir = $this->getOptions()->getFontDir(); $fontDir = $this->getOptions()->getFontDir();
$rootDir = $this->getOptions()->getRootDir(); $rootDir = $this->getOptions()->getRootDir();
// FIXME: tempoarary define constants for cache files <= v0.6.2 // FIXME: temporarily define constants for cache files <= v0.6.2
if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); } if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); }
if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); } if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); }
@ -186,7 +186,6 @@ class FontMetrics
$fontDir = $this->getOptions()->getFontDir(); $fontDir = $this->getOptions()->getFontDir();
$remoteHash = md5($remoteFile); $remoteHash = md5($remoteFile);
$localFile = $fontDir . DIRECTORY_SEPARATOR . $remoteHash; $localFile = $fontDir . DIRECTORY_SEPARATOR . $remoteHash;
$localTempFile = @tempnam($this->options->get("tempDir"), "dompdf-font-");
$cacheEntry = $localFile; $cacheEntry = $localFile;
$localFile .= ".".strtolower(pathinfo(parse_url($remoteFile, PHP_URL_PATH),PATHINFO_EXTENSION)); $localFile .= ".".strtolower(pathinfo(parse_url($remoteFile, PHP_URL_PATH),PATHINFO_EXTENSION));
@ -198,6 +197,8 @@ class FontMetrics
if (false === $remoteFileContent) { if (false === $remoteFileContent) {
return false; return false;
} }
$localTempFile = @tempnam($this->options->get("tempDir"), "dompdf-font-");
file_put_contents($localTempFile, $remoteFileContent); file_put_contents($localTempFile, $remoteFileContent);
$font = Font::load($localTempFile); $font = Font::load($localTempFile);

View File

@ -148,7 +148,7 @@ class Frame
protected $_is_cache = array(); protected $_is_cache = array();
/** /**
* Tells wether the frame was already pushed to the next page * Tells whether the frame was already pushed to the next page
* *
* @var bool * @var bool
*/ */
@ -160,7 +160,7 @@ class Frame
public $_float_next_line = false; public $_float_next_line = false;
/** /**
* Tells wether the frame was split * Tells whether the frame was split
* *
* @var bool * @var bool
*/ */

View File

@ -22,7 +22,7 @@ use Dompdf\Frame;
* *
* The FrameTree consists of {@link Frame} objects each tied to specific * The FrameTree consists of {@link Frame} objects each tied to specific
* DOMNode objects in a specific DomDocument. The FrameTree has the same * DOMNode objects in a specific DomDocument. The FrameTree has the same
* structure as the DomDocument, but adds additional capabalities for * structure as the DomDocument, but adds additional capabilities for
* styling and layout. * styling and layout.
* *
* @package dompdf * @package dompdf
@ -90,7 +90,7 @@ class FrameTree
} }
/** /**
* Returns the DOMDocument object representing the curent html document * Returns the DOMDocument object representing the current html document
* *
* @return DOMDocument * @return DOMDocument
*/ */

View File

@ -83,7 +83,7 @@ abstract class AbstractFrameDecorator extends Frame
private $_positionned_parent; private $_positionned_parent;
/** /**
* Cache for the get_parent wehile loop results * Cache for the get_parent while loop results
* *
* @var Frame * @var Frame
*/ */
@ -438,6 +438,7 @@ abstract class AbstractFrameDecorator extends Frame
} }
/** /**
* @param bool $use_cache
* @return AbstractFrameDecorator * @return AbstractFrameDecorator
*/ */
function get_parent($use_cache = true) function get_parent($use_cache = true)

View File

@ -48,7 +48,7 @@ class ListBullet extends AbstractFrameDecorator
return 0; return 0;
} }
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; return $style->font_size * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
} }
/** /**
@ -64,7 +64,7 @@ class ListBullet extends AbstractFrameDecorator
return 0; return 0;
} }
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; return $style->font_size * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
} }
/** /**

View File

@ -169,7 +169,6 @@ class Page extends AbstractFrameDecorator
*/ */
function check_forced_page_break(Frame $frame) function check_forced_page_break(Frame $frame)
{ {
// Skip check if page is already split // Skip check if page is already split
if ($this->_page_full) { if ($this->_page_full) {
return null; return null;
@ -195,9 +194,10 @@ class Page extends AbstractFrameDecorator
// Prevent cascading splits // Prevent cascading splits
$frame->split(null, true); $frame->split(null, true);
// We have to grab the style again here because split() resets // We have to grab the style again here because split() resets
// $frame->style to the frame's orignal style. // $frame->style to the frame's original style.
$frame->get_style()->page_break_before = "auto"; $frame->get_style()->page_break_before = "auto";
$this->_page_full = true; $this->_page_full = true;
$frame->_already_pushed = true;
return true; return true;
} }
@ -207,6 +207,7 @@ class Page extends AbstractFrameDecorator
$frame->split(null, true); $frame->split(null, true);
$prev->get_style()->page_break_after = "auto"; $prev->get_style()->page_break_after = "auto";
$this->_page_full = true; $this->_page_full = true;
$frame->_already_pushed = true;
return true; return true;
} }
@ -217,6 +218,7 @@ class Page extends AbstractFrameDecorator
$frame->split(null, true); $frame->split(null, true);
$prev_last_child->get_style()->page_break_after = "auto"; $prev_last_child->get_style()->page_break_after = "auto";
$this->_page_full = true; $this->_page_full = true;
$frame->_already_pushed = true;
return true; return true;
} }
@ -235,6 +237,10 @@ class Page extends AbstractFrameDecorator
* break occurs here, the used values of the relevant * break occurs here, the used values of the relevant
* 'margin-top' and 'margin-bottom' properties are set to '0'. * 'margin-top' and 'margin-bottom' properties are set to '0'.
* 2. Between line boxes inside a block box. * 2. Between line boxes inside a block box.
* 3. Between the content edge of a block container box and the
* outer edges of its child content (margin edges of block-level
* children or line box edges for inline-level children) if there
* is a (non-zero) gap between them.
* *
* These breaks are subject to the following rules: * These breaks are subject to the following rules:
* *
@ -284,7 +290,7 @@ class Page extends AbstractFrameDecorator
if (in_array($display, $block_types)) { if (in_array($display, $block_types)) {
// Avoid breaks within table-cells // Avoid breaks within table-cells
if ($this->_in_table) { if ($this->_in_table > ($display === "table" ? 1 : 0)) {
Helpers::dompdf_debug("page-break", "In table: " . $this->_in_table); Helpers::dompdf_debug("page-break", "In table: " . $this->_in_table);
return false; return false;
@ -330,10 +336,14 @@ class Page extends AbstractFrameDecorator
return false; return false;
} }
// If the frame is the first block-level frame, use the value from // If the frame is the first block-level frame, only allow a page
// $frame's parent instead. // break if there is a (non-zero) gap between the frame and its
// parent
if (!$prev && $parent) { if (!$prev && $parent) {
return $this->_page_break_allowed($parent); Helpers::dompdf_debug("page-break", "First block level frame, checking gap");
return $frame->get_style()->length_in_pt($frame->get_style()->margin_top) != 0
|| $parent->get_style()->length_in_pt($parent->get_style()->padding_top) != 0;
} }
Helpers::dompdf_debug("page-break", "block: break allowed"); Helpers::dompdf_debug("page-break", "block: break allowed");
@ -414,7 +424,7 @@ class Page extends AbstractFrameDecorator
$p = $p->find_block_parent(); $p = $p->find_block_parent();
} }
// Avoid breaking after the first row of a table // Avoid breaking before the first row of a table
if ($table && $table->get_first_child() === $frame || $table->get_first_child()->get_first_child() === $frame) { if ($table && $table->get_first_child() === $frame || $table->get_first_child()->get_first_child() === $frame) {
Helpers::dompdf_debug("page-break", "table: first-row"); Helpers::dompdf_debug("page-break", "table: first-row");
@ -459,27 +469,10 @@ class Page extends AbstractFrameDecorator
*/ */
function check_page_break(Frame $frame) function check_page_break(Frame $frame)
{ {
//FIXME: should not need to do this since we're tracking table status in `$this->_in_table` if ($this->_page_full || $frame->_already_pushed) {
$p = $frame;
$in_table = false;
while ($p) {
if ($p->is_table()) { $in_table = true; break; }
$p = $p->get_parent();
}
// Do not split if we have already or if the frame was already
// pushed to the next page (prevents infinite loops)
if ($in_table) {
if ($this->_page_full && $frame->_already_pushed) {
return false;
}
} elseif ($this->_page_full || $frame->_already_pushed) {
return false; return false;
} }
//FIXME: work-around for infinite loop due to tables
if ($in_table && $frame->_already_pushed) {
return false;
}
$p = $frame; $p = $frame;
do { do {
$display = $p->get_style()->display; $display = $p->get_style()->display;
@ -488,22 +481,12 @@ class Page extends AbstractFrameDecorator
} }
} while ($p = $p->get_parent()); } while ($p = $p->get_parent());
// If the frame is absolute of fixed it shouldn't break // If the frame is absolute or fixed it shouldn't break
$p = $frame; $p = $frame;
do { do {
if ($p->is_absolute()) { if ($p->is_absolute()) {
return false; return false;
} }
// FIXME If the row is taller than the page and
// if it the first of the page, we don't break
$display = $p->get_style()->display;
if ($display === "table-row"
&& !$p->get_prev_sibling()
&& $p->get_margin_height() > $this->get_margin_height()
) {
return false;
}
} while ($p = $p->get_parent()); } while ($p = $p->get_parent());
$margin_height = $frame->get_margin_height(); $margin_height = $frame->get_margin_height();
@ -519,7 +502,6 @@ class Page extends AbstractFrameDecorator
$p = $p->get_parent(); $p = $p->get_parent();
} }
// Check if $frame flows off the page // Check if $frame flows off the page
if ($max_y <= $this->_bottom_page_margin) { if ($max_y <= $this->_bottom_page_margin) {
// no: do nothing // no: do nothing
@ -532,6 +514,7 @@ class Page extends AbstractFrameDecorator
// yes: determine page break location // yes: determine page break location
$iter = $frame; $iter = $frame;
$flg = false; $flg = false;
$pushed_flg = false;
$in_table = $this->_in_table; $in_table = $this->_in_table;
@ -544,11 +527,14 @@ class Page extends AbstractFrameDecorator
break; break;
} }
if ($this->_page_break_allowed($iter)) { if ($iter->_already_pushed) {
$pushed_flg = true;
} elseif ($this->_page_break_allowed($iter)) {
Helpers::dompdf_debug("page-break", "break allowed, splitting."); Helpers::dompdf_debug("page-break", "break allowed, splitting.");
$iter->split(null, true); $iter->split(null, true);
$this->_page_full = true; $this->_page_full = true;
$this->_in_table = $in_table; $this->_in_table = $in_table;
$iter->_already_pushed = true;
$frame->_already_pushed = true; $frame->_already_pushed = true;
return true; return true;
@ -562,9 +548,15 @@ class Page extends AbstractFrameDecorator
} }
$iter = $next; $iter = $next;
$pushed_flg = false;
continue; continue;
} }
if ($pushed_flg) {
// The frame was already pushed, avoid breaking on a previous page
break;
}
if ($next = $iter->get_prev_sibling()) { if ($next = $iter->get_prev_sibling()) {
Helpers::dompdf_debug("page-break", "following prev sibling."); Helpers::dompdf_debug("page-break", "following prev sibling.");
@ -608,6 +600,7 @@ class Page extends AbstractFrameDecorator
if ($iter) { if ($iter) {
$iter->split(null, true); $iter->split(null, true);
$iter->_already_pushed = true;
} else { } else {
return false; return false;
} }

View File

@ -116,7 +116,7 @@ abstract class AbstractFrameReflower
} }
// Collapse our first child's margin, if there is no border or padding // Collapse our first child's margin, if there is no border or padding
if ($style->get_border_top_width() == 0 && $style->length_in_pt($style->padding_top) == 0) { if ($style->border_top_width == 0 && $style->length_in_pt($style->padding_top) == 0) {
$f = $this->_frame->get_first_child(); $f = $this->_frame->get_first_child();
if ( $f && !$f->is_block() && !$f->is_table() ) { if ( $f && !$f->is_block() && !$f->is_table() ) {
while ( $f = $f->get_next_sibling() ) { while ( $f = $f->get_next_sibling() ) {
@ -143,7 +143,7 @@ abstract class AbstractFrameReflower
} }
// Collapse our last child's margin, if there is no border or padding // Collapse our last child's margin, if there is no border or padding
if ($style->get_border_bottom_width() == 0 && $style->length_in_pt($style->padding_bottom) == 0) { if ($style->border_bottom_width == 0 && $style->length_in_pt($style->padding_bottom) == 0) {
$l = $this->_frame->get_last_child(); $l = $this->_frame->get_last_child();
if ( $l && !$l->is_block() && !$l->is_table() ) { if ( $l && !$l->is_block() && !$l->is_table() ) {
while ( $l = $l->get_prev_sibling() ) { while ( $l = $l->get_prev_sibling() ) {
@ -398,7 +398,7 @@ abstract class AbstractFrameReflower
continue; continue;
} }
preg_match('/(counters?)(^\()*?\(\s*([^\s,]+)\s*(,\s*["\']?([^"\'\)]+)["\']?\s*(,\s*([^\s)]+)\s*)?)?\)/i', $match[1], $args); preg_match('/(counters?)(^\()*?\(\s*([^\s,]+)\s*(,\s*["\']?([^"\'\)]*)["\']?\s*(,\s*([^\s)]+)\s*)?)?\)/i', $match[1], $args);
$counter_id = $args[3]; $counter_id = $args[3];
if (strtolower($args[1]) == 'counter') { if (strtolower($args[1]) == 'counter') {
// counter(name [,style]) // counter(name [,style])

View File

@ -604,7 +604,7 @@ class Block extends AbstractFrameReflower
break; break;
case "text-top": // FIXME: this should be the height of the frame minus the height of the text case "text-top": // FIXME: this should be the height of the frame minus the height of the text
$y_offset = $height - (float)$style->length_in_pt($style->get_line_height(), $style->font_size); $y_offset = $height - (float)$style->length_in_pt($style->line_height, $style->font_size);
break; break;
case "top": case "top":

View File

@ -447,7 +447,7 @@ class Table extends AbstractFrameReflower
$style->margin_right = sprintf("%Fpt", $right);; $style->margin_right = sprintf("%Fpt", $right);;
} else { } else {
if ($left === "auto") { if ($left === "auto") {
$left = (float)$style->length_in_pt($cb["w"] - $right - $width, $cb["w"]); $left = (float)$style->length_in_pt($cb["w"], $cb["w"]) - (float)$style->length_in_pt($right, $cb["w"]) - (float)$style->length_in_pt($width, $cb["w"]);
} }
if ($right === "auto") { if ($right === "auto") {
$left = (float)$style->length_in_pt($left, $cb["w"]); $left = (float)$style->length_in_pt($left, $cb["w"]);

View File

@ -467,9 +467,18 @@ class Text extends AbstractFrameReflower
$style->border_right_width, $style->border_right_width,
$style->margin_right), $line_width); $style->margin_right), $line_width);
$min += $delta; $min += $delta;
$min_word = $min;
$max += $delta; $max += $delta;
return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max); if ($style->word_wrap === 'break-word') {
// If it is allowed to break words, the min width is the widest character.
// But for performance reasons, we only check the first character.
$char = mb_substr($str, 0, 1);
$min_char = $this->getFontMetrics()->getTextWidth($char, $font, $size, $word_spacing, $char_spacing);
$min = $delta + $min_char;
}
return $this->_min_max_cache = array($min, $max, $min_word, "min" => $min, "max" => $max, 'min_word' => $min_word);
} }
/** /**

View File

@ -63,7 +63,7 @@ class Helpers
} }
// Is the url already fully qualified, a Data URI, or a reference to a named anchor? // Is the url already fully qualified, a Data URI, or a reference to a named anchor?
if (mb_strpos($url, "://") !== false || mb_substr($url, 0, 1) === "#" || mb_strpos($url, "data:") === 0 || mb_strpos($url, "mailto:") === 0) { if (mb_strpos($url, "://") !== false || mb_substr($url, 0, 1) === "#" || mb_strpos($url, "data:") === 0 || mb_strpos($url, "mailto:") === 0 || mb_strpos($url, "tel:") === 0) {
return $url; return $url;
} }
@ -583,6 +583,7 @@ class Helpers
* getimagesize doesn't give a good size for 32bit BMP image v5 * getimagesize doesn't give a good size for 32bit BMP image v5
* *
* @param string $filename * @param string $filename
* @param resource $context
* @return array The same format as getimagesize($filename) * @return array The same format as getimagesize($filename)
*/ */
public static function dompdf_getimagesize($filename, $context = null) public static function dompdf_getimagesize($filename, $context = null)

View File

@ -34,7 +34,7 @@ class Cache
* *
* @var string * @var string
*/ */
public static $broken_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAA3NCSVQICAjb4U/gAAAAHlBMVEWZmZn////g4OCkpKS1tbXv7++9vb2tra3m5ub5+fkFnN6oAAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M0BrLToAAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNC8xMi8xMRPnI58AAAGZSURBVEiJhZbPasMwDMbTw2DHKhDQcbDQPsEge4BAjg0Mxh5gkBcY7Niwkpx32PvOjv9JspX60It/+fxJsqxW1b11gN11rA7N3v6vAd5nfR9fDYCTDiyzAeA6qgKd9QDNoAtsAKyKCxzAAfhdBuyHGwC3oovNvQOaxxJwnSNg3ZQFAlBy4ax7AG6ZBLrgA5Cn038SAPgREiaJHJASwXYEhEQQIACyikTTCWCBJJoANBfpPAKQdBLHFMBYkctcBKIE9lAGggt6gRjgA2GV44CL7m1WgS08fAAdsPHxyyMAIyHujgRwEldHArCKy5cBz90+gNOyf8TTyKOUQN2LPEmgnWWPcKD+sr+rnuqTK1avAcHfRSv3afTgVAbqmCPiggLtGM8aSkBNOidVjADrmIDYebT1PoGsWJEE8Oc0b96aZoe4iMBZPiADB6RAzEUA2vwRmyiAL3Lfv6MBSEmUEg7ALt/3LhxwLgj4QNw4UCbKEsaBNpPsyRbgVRASFig78BIGyJNIJQyQTwIi0RvgT98H+Mi6W67j3X8H/427u5bfpQGVAAAAAElFTkSuQmCC"; public static $broken_image = "data:image/svg+xml;charset=utf8,%3C?xml version='1.0'?%3E%3Csvg width='64' height='64' xmlns='http://www.w3.org/2000/svg'%3E%3Cg%3E%3Crect stroke='%23666666' id='svg_1' height='60.499994' width='60.166667' y='1.666669' x='1.999998' stroke-width='1.5' fill='none'/%3E%3Cline stroke-linecap='null' stroke-linejoin='null' id='svg_3' y2='59.333253' x2='59.749916' y1='4.333415' x1='4.250079' stroke-width='1.5' stroke='%23999999' fill='none'/%3E%3Cline stroke-linecap='null' stroke-linejoin='null' id='svg_4' y2='59.999665' x2='4.062838' y1='3.750342' x1='60.062164' stroke-width='1.5' stroke='%23999999' fill='none'/%3E%3C/g%3E%3C/svg%3E";
public static $error_message = "Image not found or type unknown"; public static $error_message = "Image not found or type unknown";
@ -181,6 +181,6 @@ class Cache
} }
} }
if (file_exists(realpath(__DIR__ . "/../../lib/res/broken_image.png"))) { if (file_exists(realpath(__DIR__ . "/../../lib/res/broken_image.svg"))) {
Cache::$broken_image = realpath(__DIR__ . "/../../lib/res/broken_image.png"); Cache::$broken_image = realpath(__DIR__ . "/../../lib/res/broken_image.svg");
} }

View File

@ -13,7 +13,7 @@ class Options
/** /**
* The location of a temporary directory. * The location of a temporary directory.
* *
* The directory specified must be writeable by the webserver process. * The directory specified must be writable by the webserver process.
* The temporary directory is required to download remote images and when * The temporary directory is required to download remote images and when
* using the PFDLib back end. * using the PFDLib back end.
* *
@ -112,7 +112,7 @@ class Options
* Image DPI setting * Image DPI setting
* *
* This setting determines the default DPI setting for images and fonts. The * This setting determines the default DPI setting for images and fonts. The
* DPI may be overridden for inline images by explictly setting the * DPI may be overridden for inline images by explicitly setting the
* image's width & height style attributes (i.e. if the image's native * image's width & height style attributes (i.e. if the image's native
* width is 600 pixels and you specify the image's width as 72 points, * width is 600 pixels and you specify the image's width as 72 points,
* the image will have a DPI of 600 in the rendered PDF. The DPI of * the image will have a DPI of 600 in the rendered PDF. The DPI of
@ -267,7 +267,7 @@ class Options
* *
* @link http://www.pdflib.com * @link http://www.pdflib.com
* *
* If pdflib present in web server and auto or selected explicitely above, * If pdflib present in web server and auto or selected explicitly above,
* a real license code must exist! * a real license code must exist!
* *
* @var string * @var string

View File

@ -41,7 +41,7 @@ class ListBullet extends AbstractPositioner
$n = $frame->get_next_sibling(); $n = $frame->get_next_sibling();
if ($n) { if ($n) {
$style = $n->get_style(); $style = $n->get_style();
$line_height = $style->length_in_pt($style->line_height, $style->get_font_size()); $line_height = $style->length_in_pt($style->line_height, $style->font_size);
$offset = (float)$style->length_in_pt($line_height, $n->get_containing_block("h")) - $frame->get_height(); $offset = (float)$style->length_in_pt($line_height, $n->get_containing_block("h")) - $frame->get_height();
$y += $offset / 2; $y += $offset / 2;
} }
@ -66,7 +66,7 @@ class ListBullet extends AbstractPositioner
// For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing // For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing
/*$style = $p->get_style(); /*$style = $p->get_style();
$font_size = $style->get_font_size(); $font_size = $style->font_size;
$line_height = (float)$style->length_in_pt($style->line_height, $font_size); $line_height = (float)$style->length_in_pt($style->line_height, $font_size);
$y += ($line_height - $font_size) / 2; */ $y += ($line_height - $font_size) / 2; */

View File

@ -134,7 +134,7 @@ class ListBullet extends AbstractRenderer
function render(Frame $frame) function render(Frame $frame)
{ {
$style = $frame->get_style(); $style = $frame->get_style();
$font_size = $style->get_font_size(); $font_size = $style->font_size;
$line_height = (float)$style->length_in_pt($style->line_height, $frame->get_containing_block("h")); $line_height = (float)$style->length_in_pt($style->line_height, $frame->get_containing_block("h"));
$this->_set_opacity($frame->get_opacity($style->opacity)); $this->_set_opacity($frame->get_opacity($style->opacity));

View File

@ -69,7 +69,8 @@ class Text extends AbstractRenderer
$x += (float)$style->length_in_pt(array($ml, $pl, $bl), $cb["w"]); $x += (float)$style->length_in_pt(array($ml, $pl, $bl), $cb["w"]);
$font = $style->font_family; $font = $style->font_family;
$size = $frame_font_size = $style->font_size; $size = $style->font_size;
$frame_font_size = $frame->get_dompdf()->getFontMetrics()->getFontHeight($font, $size);
$word_spacing = $frame->get_text_spacing() + (float)$style->length_in_pt($style->word_spacing); $word_spacing = $frame->get_text_spacing() + (float)$style->length_in_pt($style->word_spacing);
$char_spacing = (float)$style->length_in_pt($style->letter_spacing); $char_spacing = (float)$style->length_in_pt($style->letter_spacing);
$width = $style->width; $width = $style->width;
@ -113,7 +114,7 @@ class Text extends AbstractRenderer
} }
$descent = $size * $underline_position; $descent = $size * $underline_position;
$base = $size; $base = $frame_font_size;
// Handle text decoration: // Handle text decoration:
// http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration // http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration
@ -159,7 +160,7 @@ class Text extends AbstractRenderer
} }
if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines()) { if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines()) {
$text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $frame_font_size); $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size);
$this->_debug_layout(array($x, $y, $text_width + ($line->wc - 1) * $word_spacing, $frame_font_size), "orange", array(0.5, 0.5)); $this->_debug_layout(array($x, $y, $text_width + ($line->wc - 1) * $word_spacing, $frame_font_size), "orange", array(0.5, 0.5));
} }
} }