PageRenderTime 63ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/dompdf/dompdf/src/Css/Style.php

https://bitbucket.org/openemr/openemr
PHP | 2582 lines | 2245 code | 90 blank | 247 comment | 52 complexity | 60f6f2aaa78a6d789b0f94fab415bb3f MD5 | raw file
Possible License(s): Apache-2.0, AGPL-1.0, GPL-2.0, LGPL-3.0, BSD-3-Clause, Unlicense, MPL-2.0, GPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @package dompdf
  4. * @link http://dompdf.github.com/
  5. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  6. * @author Helmut Tischer <htischer@weihenstephan.org>
  7. * @author Fabien MĂŠnager <fabien.menager@gmail.com>
  8. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  9. */
  10. namespace Dompdf\Css;
  11. use Dompdf\Adapter\CPDF;
  12. use Dompdf\Exception;
  13. use Dompdf\Helpers;
  14. use Dompdf\FontMetrics;
  15. use Dompdf\Frame;
  16. /**
  17. * Represents CSS properties.
  18. *
  19. * The Style class is responsible for handling and storing CSS properties.
  20. * It includes methods to resolve colors and lengths, as well as getters &
  21. * setters for many CSS properites.
  22. *
  23. * Actual CSS parsing is performed in the {@link Stylesheet} class.
  24. *
  25. * @package dompdf
  26. */
  27. class Style
  28. {
  29. const CSS_IDENTIFIER = "-?[_a-zA-Z]+[_a-zA-Z0-9-]*";
  30. const CSS_INTEGER = "-?\d+";
  31. /**
  32. * Default font size, in points.
  33. *
  34. * @var float
  35. */
  36. static $default_font_size = 12;
  37. /**
  38. * Default line height, as a fraction of the font size.
  39. *
  40. * @var float
  41. */
  42. static $default_line_height = 1.2;
  43. /**
  44. * Default "absolute" font sizes relative to the default font-size
  45. * http://www.w3.org/TR/css3-fonts/#font-size-the-font-size-property
  46. * @var array<float>
  47. */
  48. static $font_size_keywords = array(
  49. "xx-small" => 0.6, // 3/5
  50. "x-small" => 0.75, // 3/4
  51. "small" => 0.889, // 8/9
  52. "medium" => 1, // 1
  53. "large" => 1.2, // 6/5
  54. "x-large" => 1.5, // 3/2
  55. "xx-large" => 2.0, // 2/1
  56. );
  57. /**
  58. * List of all inline types. Should really be a constant.
  59. *
  60. * @var array
  61. */
  62. static $INLINE_TYPES = array("inline");
  63. /**
  64. * List of all block types. Should really be a constant.
  65. *
  66. * @var array
  67. */
  68. static $BLOCK_TYPES = array("block", "inline-block", "table-cell", "list-item");
  69. /**
  70. * List of all positionned types. Should really be a constant.
  71. *
  72. * @var array
  73. */
  74. static $POSITIONNED_TYPES = array("relative", "absolute", "fixed");
  75. /**
  76. * List of all table types. Should really be a constant.
  77. *
  78. * @var array;
  79. */
  80. static $TABLE_TYPES = array("table", "inline-table");
  81. /**
  82. * List of valid border styles. Should also really be a constant.
  83. *
  84. * @var array
  85. */
  86. static $BORDER_STYLES = array("none", "hidden", "dotted", "dashed", "solid",
  87. "double", "groove", "ridge", "inset", "outset");
  88. /**
  89. * Default style values.
  90. *
  91. * @link http://www.w3.org/TR/CSS21/propidx.html
  92. *
  93. * @var array
  94. */
  95. static protected $_defaults = null;
  96. /**
  97. * List of inherited properties
  98. *
  99. * @link http://www.w3.org/TR/CSS21/propidx.html
  100. *
  101. * @var array
  102. */
  103. static protected $_inherited = null;
  104. /**
  105. * Caches method_exists result
  106. *
  107. * @var array<bool>
  108. */
  109. static protected $_methods_cache = array();
  110. /**
  111. * The stylesheet this style belongs to
  112. *
  113. * @see Stylesheet
  114. * @var Stylesheet
  115. */
  116. protected $_stylesheet; // stylesheet this style is attached to
  117. /**
  118. * Main array of all CSS properties & values
  119. *
  120. * @var array
  121. */
  122. protected $_props;
  123. /* var instead of protected would allow access outside of class */
  124. protected $_important_props;
  125. /**
  126. * Cached property values
  127. *
  128. * @var array
  129. */
  130. protected $_prop_cache;
  131. /**
  132. * Font size of parent element in document tree. Used for relative font
  133. * size resolution.
  134. *
  135. * @var float
  136. */
  137. protected $_parent_font_size; // Font size of parent element
  138. protected $_font_family;
  139. /**
  140. * @var Frame
  141. */
  142. protected $_frame;
  143. /**
  144. * The origin of the style
  145. *
  146. * @var int
  147. */
  148. protected $_origin = Stylesheet::ORIG_AUTHOR;
  149. // private members
  150. /**
  151. * True once the font size is resolved absolutely
  152. *
  153. * @var bool
  154. */
  155. private $__font_size_calculated; // Cache flag
  156. /**
  157. * The computed border radius
  158. */
  159. private $_computed_border_radius = null;
  160. /**
  161. * @var bool
  162. */
  163. public $_has_border_radius = false;
  164. /**
  165. * @var FontMetrics
  166. */
  167. private $fontMetrics;
  168. /**
  169. * Class constructor
  170. *
  171. * @param Stylesheet $stylesheet the stylesheet this Style is associated with.
  172. * @param int $origin
  173. */
  174. public function __construct(Stylesheet $stylesheet, $origin = Stylesheet::ORIG_AUTHOR)
  175. {
  176. $this->setFontMetrics($stylesheet->getFontMetrics());
  177. $this->_props = array();
  178. $this->_important_props = array();
  179. $this->_stylesheet = $stylesheet;
  180. $this->_origin = $origin;
  181. $this->_parent_font_size = null;
  182. $this->__font_size_calculated = false;
  183. if (!isset(self::$_defaults)) {
  184. // Shorthand
  185. $d =& self::$_defaults;
  186. // All CSS 2.1 properties, and their default values
  187. $d["azimuth"] = "center";
  188. $d["background_attachment"] = "scroll";
  189. $d["background_color"] = "transparent";
  190. $d["background_image"] = "none";
  191. $d["background_image_resolution"] = "normal";
  192. $d["_dompdf_background_image_resolution"] = $d["background_image_resolution"];
  193. $d["background_position"] = "0% 0%";
  194. $d["background_repeat"] = "repeat";
  195. $d["background"] = "";
  196. $d["border_collapse"] = "separate";
  197. $d["border_color"] = "";
  198. $d["border_spacing"] = "0";
  199. $d["border_style"] = "";
  200. $d["border_top"] = "";
  201. $d["border_right"] = "";
  202. $d["border_bottom"] = "";
  203. $d["border_left"] = "";
  204. $d["border_top_color"] = "";
  205. $d["border_right_color"] = "";
  206. $d["border_bottom_color"] = "";
  207. $d["border_left_color"] = "";
  208. $d["border_top_style"] = "none";
  209. $d["border_right_style"] = "none";
  210. $d["border_bottom_style"] = "none";
  211. $d["border_left_style"] = "none";
  212. $d["border_top_width"] = "medium";
  213. $d["border_right_width"] = "medium";
  214. $d["border_bottom_width"] = "medium";
  215. $d["border_left_width"] = "medium";
  216. $d["border_width"] = "medium";
  217. $d["border_bottom_left_radius"] = "";
  218. $d["border_bottom_right_radius"] = "";
  219. $d["border_top_left_radius"] = "";
  220. $d["border_top_right_radius"] = "";
  221. $d["border_radius"] = "";
  222. $d["border"] = "";
  223. $d["bottom"] = "auto";
  224. $d["caption_side"] = "top";
  225. $d["clear"] = "none";
  226. $d["clip"] = "auto";
  227. $d["color"] = "#000000";
  228. $d["content"] = "normal";
  229. $d["counter_increment"] = "none";
  230. $d["counter_reset"] = "none";
  231. $d["cue_after"] = "none";
  232. $d["cue_before"] = "none";
  233. $d["cue"] = "";
  234. $d["cursor"] = "auto";
  235. $d["direction"] = "ltr";
  236. $d["display"] = "inline";
  237. $d["elevation"] = "level";
  238. $d["empty_cells"] = "show";
  239. $d["float"] = "none";
  240. $d["font_family"] = $stylesheet->get_dompdf()->get_option("default_font");
  241. $d["font_size"] = "medium";
  242. $d["font_style"] = "normal";
  243. $d["font_variant"] = "normal";
  244. $d["font_weight"] = "normal";
  245. $d["font"] = "";
  246. $d["height"] = "auto";
  247. $d["image_resolution"] = "normal";
  248. $d["_dompdf_image_resolution"] = $d["image_resolution"];
  249. $d["_dompdf_keep"] = "";
  250. $d["left"] = "auto";
  251. $d["letter_spacing"] = "normal";
  252. $d["line_height"] = "normal";
  253. $d["list_style_image"] = "none";
  254. $d["list_style_position"] = "outside";
  255. $d["list_style_type"] = "disc";
  256. $d["list_style"] = "";
  257. $d["margin_right"] = "0";
  258. $d["margin_left"] = "0";
  259. $d["margin_top"] = "0";
  260. $d["margin_bottom"] = "0";
  261. $d["margin"] = "";
  262. $d["max_height"] = "none";
  263. $d["max_width"] = "none";
  264. $d["min_height"] = "0";
  265. $d["min_width"] = "0";
  266. $d["opacity"] = "1.0"; // CSS3
  267. $d["orphans"] = "2";
  268. $d["outline_color"] = ""; // "invert" special color is not supported
  269. $d["outline_style"] = "none";
  270. $d["outline_width"] = "medium";
  271. $d["outline"] = "";
  272. $d["overflow"] = "visible";
  273. $d["padding_top"] = "0";
  274. $d["padding_right"] = "0";
  275. $d["padding_bottom"] = "0";
  276. $d["padding_left"] = "0";
  277. $d["padding"] = "";
  278. $d["page_break_after"] = "auto";
  279. $d["page_break_before"] = "auto";
  280. $d["page_break_inside"] = "auto";
  281. $d["pause_after"] = "0";
  282. $d["pause_before"] = "0";
  283. $d["pause"] = "";
  284. $d["pitch_range"] = "50";
  285. $d["pitch"] = "medium";
  286. $d["play_during"] = "auto";
  287. $d["position"] = "static";
  288. $d["quotes"] = "";
  289. $d["richness"] = "50";
  290. $d["right"] = "auto";
  291. $d["size"] = "auto"; // @page
  292. $d["speak_header"] = "once";
  293. $d["speak_numeral"] = "continuous";
  294. $d["speak_punctuation"] = "none";
  295. $d["speak"] = "normal";
  296. $d["speech_rate"] = "medium";
  297. $d["stress"] = "50";
  298. $d["table_layout"] = "auto";
  299. $d["text_align"] = "left";
  300. $d["text_decoration"] = "none";
  301. $d["text_indent"] = "0";
  302. $d["text_transform"] = "none";
  303. $d["top"] = "auto";
  304. $d["transform"] = "none"; // CSS3
  305. $d["transform_origin"] = "50% 50%"; // CSS3
  306. $d["_webkit_transform"] = $d["transform"]; // CSS3
  307. $d["_webkit_transform_origin"] = $d["transform_origin"]; // CSS3
  308. $d["unicode_bidi"] = "normal";
  309. $d["vertical_align"] = "baseline";
  310. $d["visibility"] = "visible";
  311. $d["voice_family"] = "";
  312. $d["volume"] = "medium";
  313. $d["white_space"] = "normal";
  314. $d["word_wrap"] = "normal";
  315. $d["widows"] = "2";
  316. $d["width"] = "auto";
  317. $d["word_spacing"] = "normal";
  318. $d["z_index"] = "auto";
  319. // for @font-face
  320. $d["src"] = "";
  321. $d["unicode_range"] = "";
  322. // Properties that inherit by default
  323. self::$_inherited = array(
  324. "azimuth",
  325. "background_image_resolution",
  326. "border_collapse",
  327. "border_spacing",
  328. "caption_side",
  329. "color",
  330. "cursor",
  331. "direction",
  332. "elevation",
  333. "empty_cells",
  334. "font_family",
  335. "font_size",
  336. "font_style",
  337. "font_variant",
  338. "font_weight",
  339. "font",
  340. "image_resolution",
  341. "letter_spacing",
  342. "line_height",
  343. "list_style_image",
  344. "list_style_position",
  345. "list_style_type",
  346. "list_style",
  347. "orphans",
  348. "page_break_inside",
  349. "pitch_range",
  350. "pitch",
  351. "quotes",
  352. "richness",
  353. "speak_header",
  354. "speak_numeral",
  355. "speak_punctuation",
  356. "speak",
  357. "speech_rate",
  358. "stress",
  359. "text_align",
  360. "text_indent",
  361. "text_transform",
  362. "visibility",
  363. "voice_family",
  364. "volume",
  365. "white_space",
  366. "word_wrap",
  367. "widows",
  368. "word_spacing",
  369. );
  370. }
  371. }
  372. /**
  373. * "Destructor": forcibly free all references held by this object
  374. */
  375. function dispose()
  376. {
  377. }
  378. function set_frame(Frame $frame)
  379. {
  380. $this->_frame = $frame;
  381. }
  382. function get_frame()
  383. {
  384. return $this->_frame;
  385. }
  386. function set_origin($origin)
  387. {
  388. $this->_origin = $origin;
  389. }
  390. function get_origin()
  391. {
  392. return $this->_origin;
  393. }
  394. /**
  395. * returns the {@link Stylesheet} this Style is associated with.
  396. *
  397. * @return Stylesheet
  398. */
  399. function get_stylesheet()
  400. {
  401. return $this->_stylesheet;
  402. }
  403. /**
  404. * Converts any CSS length value into an absolute length in points.
  405. *
  406. * length_in_pt() takes a single length (e.g. '1em') or an array of
  407. * lengths and returns an absolute length. If an array is passed, then
  408. * the return value is the sum of all elements.
  409. *
  410. * If a reference size is not provided, the default font size is used
  411. * ({@link Style::$default_font_size}).
  412. *
  413. * @param float|array $length the length or array of lengths to resolve
  414. * @param float $ref_size an absolute reference size to resolve percentage lengths
  415. * @return float
  416. */
  417. function length_in_pt($length, $ref_size = null)
  418. {
  419. static $cache = array();
  420. if (!is_array($length)) {
  421. $length = array($length);
  422. }
  423. if (!isset($ref_size)) {
  424. $ref_size = self::$default_font_size;
  425. }
  426. $key = implode("@", $length) . "/$ref_size";
  427. if (isset($cache[$key])) {
  428. return $cache[$key];
  429. }
  430. $ret = 0;
  431. foreach ($length as $l) {
  432. if ($l === "auto") {
  433. return "auto";
  434. }
  435. if ($l === "none") {
  436. return "none";
  437. }
  438. // Assume numeric values are already in points
  439. if (is_numeric($l)) {
  440. $ret += $l;
  441. continue;
  442. }
  443. if ($l === "normal") {
  444. $ret += $ref_size;
  445. continue;
  446. }
  447. // Border lengths
  448. if ($l === "thin") {
  449. $ret += 0.5;
  450. continue;
  451. }
  452. if ($l === "medium") {
  453. $ret += 1.5;
  454. continue;
  455. }
  456. if ($l === "thick") {
  457. $ret += 2.5;
  458. continue;
  459. }
  460. if (($i = mb_strpos($l, "px")) !== false) {
  461. $dpi = $this->_stylesheet->get_dompdf()->get_option("dpi");
  462. $ret += (mb_substr($l, 0, $i) * 72) / $dpi;
  463. continue;
  464. }
  465. if (($i = mb_strpos($l, "pt")) !== false) {
  466. $ret += (float)mb_substr($l, 0, $i);
  467. continue;
  468. }
  469. if (($i = mb_strpos($l, "%")) !== false) {
  470. $ret += (float)mb_substr($l, 0, $i) / 100 * $ref_size;
  471. continue;
  472. }
  473. if (($i = mb_strpos($l, "rem")) !== false) {
  474. $ret += (float)mb_substr($l, 0, $i) * $this->_stylesheet->get_dompdf()->get_tree()->get_root()->get_style()->font_size;
  475. continue;
  476. }
  477. if (($i = mb_strpos($l, "em")) !== false) {
  478. $ret += (float)mb_substr($l, 0, $i) * $this->__get("font_size");
  479. continue;
  480. }
  481. if (($i = mb_strpos($l, "cm")) !== false) {
  482. $ret += mb_substr($l, 0, $i) * 72 / 2.54;
  483. continue;
  484. }
  485. if (($i = mb_strpos($l, "mm")) !== false) {
  486. $ret += mb_substr($l, 0, $i) * 72 / 25.4;
  487. continue;
  488. }
  489. // FIXME: em:ex ratio?
  490. if (($i = mb_strpos($l, "ex")) !== false) {
  491. $ret += mb_substr($l, 0, $i) * $this->__get("font_size") / 2;
  492. continue;
  493. }
  494. if (($i = mb_strpos($l, "in")) !== false) {
  495. $ret += (float)mb_substr($l, 0, $i) * 72;
  496. continue;
  497. }
  498. if (($i = mb_strpos($l, "pc")) !== false) {
  499. $ret += (float)mb_substr($l, 0, $i) * 12;
  500. continue;
  501. }
  502. // Bogus value
  503. $ret += $ref_size;
  504. }
  505. return $cache[$key] = $ret;
  506. }
  507. /**
  508. * Set inherited properties in this style using values in $parent
  509. *
  510. * @param Style $parent
  511. *
  512. * @return Style
  513. */
  514. function inherit(Style $parent)
  515. {
  516. // Set parent font size
  517. $this->_parent_font_size = $parent->get_font_size();
  518. foreach (self::$_inherited as $prop) {
  519. //inherit the !important property also.
  520. //if local property is also !important, don't inherit.
  521. if (isset($parent->_props[$prop]) &&
  522. (!isset($this->_props[$prop]) ||
  523. (isset($parent->_important_props[$prop]) && !isset($this->_important_props[$prop]))
  524. )
  525. ) {
  526. if (isset($parent->_important_props[$prop])) {
  527. $this->_important_props[$prop] = true;
  528. }
  529. //see __set and __get, on all assignments clear cache!
  530. $this->_prop_cache[$prop] = null;
  531. $this->_props[$prop] = $parent->_props[$prop];
  532. }
  533. }
  534. foreach ($this->_props as $prop => $value) {
  535. if ($value === "inherit") {
  536. if (isset($parent->_important_props[$prop])) {
  537. $this->_important_props[$prop] = true;
  538. }
  539. //do not assign direct, but
  540. //implicite assignment through __set, redirect to specialized, get value with __get
  541. //This is for computing defaults if the parent setting is also missing.
  542. //Therefore do not directly assign the value without __set
  543. //set _important_props before that to be able to propagate.
  544. //see __set and __get, on all assignments clear cache!
  545. //$this->_prop_cache[$prop] = null;
  546. //$this->_props[$prop] = $parent->_props[$prop];
  547. //props_set for more obvious explicite assignment not implemented, because
  548. //too many implicite uses.
  549. // $this->props_set($prop, $parent->$prop);
  550. $this->__set($prop, $parent->__get($prop));
  551. }
  552. }
  553. return $this;
  554. }
  555. /**
  556. * Override properties in this style with those in $style
  557. *
  558. * @param Style $style
  559. */
  560. function merge(Style $style)
  561. {
  562. //treat the !important attribute
  563. //if old rule has !important attribute, override with new rule only if
  564. //the new rule is also !important
  565. foreach ($style->_props as $prop => $val) {
  566. if (isset($style->_important_props[$prop])) {
  567. $this->_important_props[$prop] = true;
  568. //see __set and __get, on all assignments clear cache!
  569. $this->_prop_cache[$prop] = null;
  570. $this->_props[$prop] = $val;
  571. } else if (!isset($this->_important_props[$prop])) {
  572. //see __set and __get, on all assignments clear cache!
  573. $this->_prop_cache[$prop] = null;
  574. $this->_props[$prop] = $val;
  575. }
  576. }
  577. if (isset($style->_props["font_size"])) {
  578. $this->__font_size_calculated = false;
  579. }
  580. }
  581. /**
  582. * Returns an array(r, g, b, "r"=> r, "g"=>g, "b"=>b, "hex"=>"#rrggbb")
  583. * based on the provided CSS color value.
  584. *
  585. * @param string $color
  586. * @return array
  587. */
  588. function munge_color($color)
  589. {
  590. return Color::parse($color);
  591. }
  592. /* direct access to _important_props array from outside would work only when declared as
  593. * 'var $_important_props;' instead of 'protected $_important_props;'
  594. * Don't call _set/__get on missing attribute. Therefore need a special access.
  595. * Assume that __set will be also called when this is called, so do not check validity again.
  596. * Only created, if !important exists -> always set true.
  597. */
  598. function important_set($prop)
  599. {
  600. $prop = str_replace("-", "_", $prop);
  601. $this->_important_props[$prop] = true;
  602. }
  603. function important_get($prop)
  604. {
  605. return isset($this->_important_props[$prop]);
  606. }
  607. /**
  608. * PHP5 overloaded setter
  609. *
  610. * This function along with {@link Style::__get()} permit a user of the
  611. * Style class to access any (CSS) property using the following syntax:
  612. * <code>
  613. * Style->margin_top = "1em";
  614. * echo (Style->margin_top);
  615. * </code>
  616. *
  617. * __set() automatically calls the provided set function, if one exists,
  618. * otherwise it sets the property directly. Typically, __set() is not
  619. * called directly from outside of this class.
  620. *
  621. * On each modification clear cache to return accurate setting.
  622. * Also affects direct settings not using __set
  623. * For easier finding all assignments, attempted to allowing only explicite assignment:
  624. * Very many uses, e.g. AbstractFrameReflower.php -> for now leave as it is
  625. * function __set($prop, $val) {
  626. * throw new Exception("Implicite replacement of assignment by __set. Not good.");
  627. * }
  628. * function props_set($prop, $val) { ... }
  629. *
  630. * @param string $prop the property to set
  631. * @param mixed $val the value of the property
  632. *
  633. */
  634. function __set($prop, $val)
  635. {
  636. $prop = str_replace("-", "_", $prop);
  637. $this->_prop_cache[$prop] = null;
  638. if (!isset(self::$_defaults[$prop])) {
  639. global $_dompdf_warnings;
  640. $_dompdf_warnings[] = "'$prop' is not a valid CSS2 property.";
  641. return;
  642. }
  643. if ($prop !== "content" && is_string($val) && strlen($val) > 5 && mb_strpos($val, "url") === false) {
  644. $val = mb_strtolower(trim(str_replace(array("\n", "\t"), array(" "), $val)));
  645. $val = preg_replace("/([0-9]+) (pt|px|pc|em|ex|in|cm|mm|%)/S", "\\1\\2", $val);
  646. }
  647. $method = "set_$prop";
  648. if (!isset(self::$_methods_cache[$method])) {
  649. self::$_methods_cache[$method] = method_exists($this, $method);
  650. }
  651. if (self::$_methods_cache[$method]) {
  652. $this->$method($val);
  653. } else {
  654. $this->_props[$prop] = $val;
  655. }
  656. }
  657. /**
  658. * PHP5 overloaded getter
  659. * Along with {@link Style::__set()} __get() provides access to all CSS
  660. * properties directly. Typically __get() is not called directly outside
  661. * of this class.
  662. * On each modification clear cache to return accurate setting.
  663. * Also affects direct settings not using __set
  664. *
  665. * @param string $prop
  666. *
  667. * @throws Exception
  668. * @return mixed
  669. */
  670. function __get($prop)
  671. {
  672. if (!isset(self::$_defaults[$prop])) {
  673. throw new Exception("'$prop' is not a valid CSS2 property.");
  674. }
  675. if (isset($this->_prop_cache[$prop]) && $this->_prop_cache[$prop] != null) {
  676. return $this->_prop_cache[$prop];
  677. }
  678. $method = "get_$prop";
  679. // Fall back on defaults if property is not set
  680. if (!isset($this->_props[$prop])) {
  681. $this->_props[$prop] = self::$_defaults[$prop];
  682. }
  683. if (!isset(self::$_methods_cache[$method])) {
  684. self::$_methods_cache[$method] = method_exists($this, $method);
  685. }
  686. if (self::$_methods_cache[$method]) {
  687. return $this->_prop_cache[$prop] = $this->$method();
  688. }
  689. return $this->_prop_cache[$prop] = $this->_props[$prop];
  690. }
  691. function get_font_family_raw()
  692. {
  693. return trim($this->_props["font_family"], " \t\n\r\x0B\"'");
  694. }
  695. /**
  696. * Getter for the 'font-family' CSS property.
  697. * Uses the {@link FontMetrics} class to resolve the font family into an
  698. * actual font file.
  699. *
  700. * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-family
  701. * @throws Exception
  702. *
  703. * @return string
  704. */
  705. function get_font_family()
  706. {
  707. if (isset($this->_font_family)) {
  708. return $this->_font_family;
  709. }
  710. $DEBUGCSS = $this->_stylesheet->get_dompdf()->get_option("debugCss");
  711. // Select the appropriate font. First determine the subtype, then check
  712. // the specified font-families for a candidate.
  713. // Resolve font-weight
  714. $weight = $this->__get("font_weight");
  715. if (is_numeric($weight)) {
  716. if ($weight < 600) {
  717. $weight = "normal";
  718. } else {
  719. $weight = "bold";
  720. }
  721. } else if ($weight === "bold" || $weight === "bolder") {
  722. $weight = "bold";
  723. } else {
  724. $weight = "normal";
  725. }
  726. // Resolve font-style
  727. $font_style = $this->__get("font_style");
  728. if ($weight === "bold" && ($font_style === "italic" || $font_style === "oblique")) {
  729. $subtype = "bold_italic";
  730. } else if ($weight === "bold" && $font_style !== "italic" && $font_style !== "oblique") {
  731. $subtype = "bold";
  732. } else if ($weight !== "bold" && ($font_style === "italic" || $font_style === "oblique")) {
  733. $subtype = "italic";
  734. } else {
  735. $subtype = "normal";
  736. }
  737. // Resolve the font family
  738. if ($DEBUGCSS) {
  739. print "<pre>[get_font_family:";
  740. print '(' . $this->_props["font_family"] . '.' . $font_style . '.' . $this->__get("font_weight") . '.' . $weight . '.' . $subtype . ')';
  741. }
  742. $families = preg_split("/\s*,\s*/", $this->_props["font_family"]);
  743. $font = null;
  744. foreach ($families as $family) {
  745. //remove leading and trailing string delimiters, e.g. on font names with spaces;
  746. //remove leading and trailing whitespace
  747. $family = trim($family, " \t\n\r\x0B\"'");
  748. if ($DEBUGCSS) {
  749. print '(' . $family . ')';
  750. }
  751. $font = $this->getFontMetrics()->getFont($family, $subtype);
  752. if ($font) {
  753. if ($DEBUGCSS) print '(' . $font . ")get_font_family]\n</pre>";
  754. return $this->_font_family = $font;
  755. }
  756. }
  757. $family = null;
  758. if ($DEBUGCSS) {
  759. print '(default)';
  760. }
  761. $font = $this->getFontMetrics()->getFont($family, $subtype);
  762. if ($font) {
  763. if ($DEBUGCSS) print '(' . $font . ")get_font_family]\n</pre>";
  764. return $this->_font_family = $font;
  765. }
  766. throw new Exception("Unable to find a suitable font replacement for: '" . $this->_props["font_family"] . "'");
  767. }
  768. /**
  769. * Returns the resolved font size, in points
  770. *
  771. * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size
  772. * @return float
  773. */
  774. function get_font_size()
  775. {
  776. if ($this->__font_size_calculated) {
  777. return $this->_props["font_size"];
  778. }
  779. if (!isset($this->_props["font_size"])) {
  780. $fs = self::$_defaults["font_size"];
  781. } else {
  782. $fs = $this->_props["font_size"];
  783. }
  784. if (!isset($this->_parent_font_size)) {
  785. $this->_parent_font_size = self::$default_font_size;
  786. }
  787. switch ((string)$fs) {
  788. case "xx-small":
  789. case "x-small":
  790. case "small":
  791. case "medium":
  792. case "large":
  793. case "x-large":
  794. case "xx-large":
  795. $fs = self::$default_font_size * self::$font_size_keywords[$fs];
  796. break;
  797. case "smaller":
  798. $fs = 8 / 9 * $this->_parent_font_size;
  799. break;
  800. case "larger":
  801. $fs = 6 / 5 * $this->_parent_font_size;
  802. break;
  803. default:
  804. break;
  805. }
  806. // Ensure relative sizes resolve to something
  807. if (($i = mb_strpos($fs, "em")) !== false) {
  808. $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size;
  809. } else if (($i = mb_strpos($fs, "ex")) !== false) {
  810. $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size;
  811. } else {
  812. $fs = $this->length_in_pt($fs);
  813. }
  814. //see __set and __get, on all assignments clear cache!
  815. $this->_prop_cache["font_size"] = null;
  816. $this->_props["font_size"] = $fs;
  817. $this->__font_size_calculated = true;
  818. return $this->_props["font_size"];
  819. }
  820. /**
  821. * @link http://www.w3.org/TR/CSS21/text.html#propdef-word-spacing
  822. * @return float
  823. */
  824. function get_word_spacing()
  825. {
  826. if ($this->_props["word_spacing"] === "normal") {
  827. return 0;
  828. }
  829. return $this->_props["word_spacing"];
  830. }
  831. /**
  832. * @link http://www.w3.org/TR/CSS21/text.html#propdef-letter-spacing
  833. * @return float
  834. */
  835. function get_letter_spacing()
  836. {
  837. if ($this->_props["letter_spacing"] === "normal") {
  838. return 0;
  839. }
  840. return $this->_props["letter_spacing"];
  841. }
  842. /**
  843. * @link http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height
  844. * @return float
  845. */
  846. function get_line_height()
  847. {
  848. $line_height = $this->_props["line_height"];
  849. if ($line_height === "normal") {
  850. return self::$default_line_height * $this->get_font_size();
  851. }
  852. if (is_numeric($line_height)) {
  853. return $this->length_in_pt($line_height . "em", $this->get_font_size());
  854. }
  855. return $this->length_in_pt($line_height, $this->_parent_font_size);
  856. }
  857. /**
  858. * Returns the color as an array
  859. *
  860. * The array has the following format:
  861. * <code>array(r,g,b, "r" => r, "g" => g, "b" => b, "hex" => "#rrggbb")</code>
  862. *
  863. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color
  864. * @return array
  865. */
  866. function get_color()
  867. {
  868. return $this->munge_color($this->_props["color"]);
  869. }
  870. /**
  871. * Returns the background color as an array
  872. *
  873. * The returned array has the same format as {@link Style::get_color()}
  874. *
  875. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color
  876. * @return array
  877. */
  878. function get_background_color()
  879. {
  880. return $this->munge_color($this->_props["background_color"]);
  881. }
  882. /**
  883. * Returns the background position as an array
  884. *
  885. * The returned array has the following format:
  886. * <code>array(x,y, "x" => x, "y" => y)</code>
  887. *
  888. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position
  889. * @return array
  890. */
  891. function get_background_position()
  892. {
  893. $tmp = explode(" ", $this->_props["background_position"]);
  894. switch ($tmp[0]) {
  895. case "left":
  896. $x = "0%";
  897. break;
  898. case "right":
  899. $x = "100%";
  900. break;
  901. case "top":
  902. $y = "0%";
  903. break;
  904. case "bottom":
  905. $y = "100%";
  906. break;
  907. case "center":
  908. $x = "50%";
  909. $y = "50%";
  910. break;
  911. default:
  912. $x = $tmp[0];
  913. break;
  914. }
  915. if (isset($tmp[1])) {
  916. switch ($tmp[1]) {
  917. case "left":
  918. $x = "0%";
  919. break;
  920. case "right":
  921. $x = "100%";
  922. break;
  923. case "top":
  924. $y = "0%";
  925. break;
  926. case "bottom":
  927. $y = "100%";
  928. break;
  929. case "center":
  930. if ($tmp[0] === "left" || $tmp[0] === "right" || $tmp[0] === "center") {
  931. $y = "50%";
  932. } else {
  933. $x = "50%";
  934. }
  935. break;
  936. default:
  937. $y = $tmp[1];
  938. break;
  939. }
  940. } else {
  941. $y = "50%";
  942. }
  943. if (!isset($x)) {
  944. $x = "0%";
  945. }
  946. if (!isset($y)) {
  947. $y = "0%";
  948. }
  949. return array(
  950. 0 => $x, "x" => $x,
  951. 1 => $y, "y" => $y,
  952. );
  953. }
  954. /**
  955. * Returns the background as it is currently stored
  956. *
  957. * (currently anyway only for completeness.
  958. * not used for further processing)
  959. *
  960. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment
  961. * @return string
  962. */
  963. function get_background_attachment()
  964. {
  965. return $this->_props["background_attachment"];
  966. }
  967. /**
  968. * Returns the background_repeat as it is currently stored
  969. *
  970. * (currently anyway only for completeness.
  971. * not used for further processing)
  972. *
  973. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat
  974. * @return string
  975. */
  976. function get_background_repeat()
  977. {
  978. return $this->_props["background_repeat"];
  979. }
  980. /**
  981. * Returns the background as it is currently stored
  982. *
  983. * (currently anyway only for completeness.
  984. * not used for further processing, but the individual get_background_xxx)
  985. *
  986. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background
  987. * @return string
  988. */
  989. function get_background()
  990. {
  991. return $this->_props["background"];
  992. }
  993. /**#@+
  994. * Returns the border color as an array
  995. *
  996. * See {@link Style::get_color()}
  997. *
  998. * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties
  999. * @return array
  1000. */
  1001. function get_border_top_color()
  1002. {
  1003. if ($this->_props["border_top_color"] === "") {
  1004. //see __set and __get, on all assignments clear cache!
  1005. $this->_prop_cache["border_top_color"] = null;
  1006. $this->_props["border_top_color"] = $this->__get("color");
  1007. }
  1008. return $this->munge_color($this->_props["border_top_color"]);
  1009. }
  1010. function get_border_right_color()
  1011. {
  1012. if ($this->_props["border_right_color"] === "") {
  1013. //see __set and __get, on all assignments clear cache!
  1014. $this->_prop_cache["border_right_color"] = null;
  1015. $this->_props["border_right_color"] = $this->__get("color");
  1016. }
  1017. return $this->munge_color($this->_props["border_right_color"]);
  1018. }
  1019. function get_border_bottom_color()
  1020. {
  1021. if ($this->_props["border_bottom_color"] === "") {
  1022. //see __set and __get, on all assignments clear cache!
  1023. $this->_prop_cache["border_bottom_color"] = null;
  1024. $this->_props["border_bottom_color"] = $this->__get("color");
  1025. }
  1026. return $this->munge_color($this->_props["border_bottom_color"]);
  1027. }
  1028. function get_border_left_color()
  1029. {
  1030. if ($this->_props["border_left_color"] === "") {
  1031. //see __set and __get, on all assignments clear cache!
  1032. $this->_prop_cache["border_left_color"] = null;
  1033. $this->_props["border_left_color"] = $this->__get("color");
  1034. }
  1035. return $this->munge_color($this->_props["border_left_color"]);
  1036. }
  1037. /**#@-*/
  1038. /**#@+
  1039. * Returns the border width, as it is currently stored
  1040. *
  1041. * @link http://www.w3.org/TR/CSS21/box.html#border-width-properties
  1042. * @return float|string
  1043. */
  1044. function get_border_top_width()
  1045. {
  1046. $style = $this->__get("border_top_style");
  1047. return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_top_width"]) : 0;
  1048. }
  1049. function get_border_right_width()
  1050. {
  1051. $style = $this->__get("border_right_style");
  1052. return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_right_width"]) : 0;
  1053. }
  1054. function get_border_bottom_width()
  1055. {
  1056. $style = $this->__get("border_bottom_style");
  1057. return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_bottom_width"]) : 0;
  1058. }
  1059. function get_border_left_width()
  1060. {
  1061. $style = $this->__get("border_left_style");
  1062. return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_left_width"]) : 0;
  1063. }
  1064. /**#@-*/
  1065. /**
  1066. * Return an array of all border properties.
  1067. *
  1068. * The returned array has the following structure:
  1069. * <code>
  1070. * array("top" => array("width" => [border-width],
  1071. * "style" => [border-style],
  1072. * "color" => [border-color (array)]),
  1073. * "bottom" ... )
  1074. * </code>
  1075. *
  1076. * @return array
  1077. */
  1078. function get_border_properties()
  1079. {
  1080. return array(
  1081. "top" => array(
  1082. "width" => $this->__get("border_top_width"),
  1083. "style" => $this->__get("border_top_style"),
  1084. "color" => $this->__get("border_top_color"),
  1085. ),
  1086. "bottom" => array(
  1087. "width" => $this->__get("border_bottom_width"),
  1088. "style" => $this->__get("border_bottom_style"),
  1089. "color" => $this->__get("border_bottom_color"),
  1090. ),
  1091. "right" => array(
  1092. "width" => $this->__get("border_right_width"),
  1093. "style" => $this->__get("border_right_style"),
  1094. "color" => $this->__get("border_right_color"),
  1095. ),
  1096. "left" => array(
  1097. "width" => $this->__get("border_left_width"),
  1098. "style" => $this->__get("border_left_style"),
  1099. "color" => $this->__get("border_left_color"),
  1100. ),
  1101. );
  1102. }
  1103. /**
  1104. * Return a single border property
  1105. *
  1106. * @param string $side
  1107. *
  1108. * @return mixed
  1109. */
  1110. protected function _get_border($side)
  1111. {
  1112. $color = $this->__get("border_" . $side . "_color");
  1113. return $this->__get("border_" . $side . "_width") . " " .
  1114. $this->__get("border_" . $side . "_style") . " " . $color["hex"];
  1115. }
  1116. /**#@+
  1117. * Return full border properties as a string
  1118. *
  1119. * Border properties are returned just as specified in CSS:
  1120. * <pre>[width] [style] [color]</pre>
  1121. * e.g. "1px solid blue"
  1122. *
  1123. * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties
  1124. * @return string
  1125. */
  1126. function get_border_top()
  1127. {
  1128. return $this->_get_border("top");
  1129. }
  1130. function get_border_right()
  1131. {
  1132. return $this->_get_border("right");
  1133. }
  1134. function get_border_bottom()
  1135. {
  1136. return $this->_get_border("bottom");
  1137. }
  1138. function get_border_left()
  1139. {
  1140. return $this->_get_border("left");
  1141. }
  1142. /**#@-*/
  1143. function get_computed_border_radius($w, $h)
  1144. {
  1145. if (!empty($this->_computed_border_radius)) {
  1146. return $this->_computed_border_radius;
  1147. }
  1148. $rTL = $this->__get("border_top_left_radius");
  1149. $rTR = $this->__get("border_top_right_radius");
  1150. $rBL = $this->__get("border_bottom_left_radius");
  1151. $rBR = $this->__get("border_bottom_right_radius");
  1152. if ($rTL + $rTR + $rBL + $rBR == 0) {
  1153. return $this->_computed_border_radius = array(
  1154. 0, 0, 0, 0,
  1155. "top-left" => 0,
  1156. "top-right" => 0,
  1157. "bottom-right" => 0,
  1158. "bottom-left" => 0,
  1159. );
  1160. }
  1161. $t = $this->__get("border_top_width");
  1162. $r = $this->__get("border_right_width");
  1163. $b = $this->__get("border_bottom_width");
  1164. $l = $this->__get("border_left_width");
  1165. $rTL = min($rTL, $h - $rBL - $t / 2 - $b / 2, $w - $rTR - $l / 2 - $r / 2);
  1166. $rTR = min($rTR, $h - $rBR - $t / 2 - $b / 2, $w - $rTL - $l / 2 - $r / 2);
  1167. $rBL = min($rBL, $h - $rTL - $t / 2 - $b / 2, $w - $rBR - $l / 2 - $r / 2);
  1168. $rBR = min($rBR, $h - $rTR - $t / 2 - $b / 2, $w - $rBL - $l / 2 - $r / 2);
  1169. return $this->_computed_border_radius = array(
  1170. $rTL, $rTR, $rBR, $rBL,
  1171. "top-left" => $rTL,
  1172. "top-right" => $rTR,
  1173. "bottom-right" => $rBR,
  1174. "bottom-left" => $rBL,
  1175. );
  1176. }
  1177. /**#@-*/
  1178. /**
  1179. * Returns the outline color as an array
  1180. *
  1181. * See {@link Style::get_color()}
  1182. *
  1183. * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties
  1184. * @return array
  1185. */
  1186. function get_outline_color()
  1187. {
  1188. if ($this->_props["outline_color"] === "") {
  1189. //see __set and __get, on all assignments clear cache!
  1190. $this->_prop_cache["outline_color"] = null;
  1191. $this->_props["outline_color"] = $this->__get("color");
  1192. }
  1193. return $this->munge_color($this->_props["outline_color"]);
  1194. }
  1195. /**#@+
  1196. * Returns the outline width, as it is currently stored
  1197. * @return float|string
  1198. */
  1199. function get_outline_width()
  1200. {
  1201. $style = $this->__get("outline_style");
  1202. return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["outline_width"]) : 0;
  1203. }
  1204. /**#@+
  1205. * Return full outline properties as a string
  1206. *
  1207. * Outline properties are returned just as specified in CSS:
  1208. * <pre>[width] [style] [color]</pre>
  1209. * e.g. "1px solid blue"
  1210. *
  1211. * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties
  1212. * @return string
  1213. */
  1214. function get_outline()
  1215. {
  1216. $color = $this->__get("outline_color");
  1217. return
  1218. $this->__get("outline_width") . " " .
  1219. $this->__get("outline_style") . " " .
  1220. $color["hex"];
  1221. }
  1222. /**#@-*/
  1223. /**
  1224. * Returns border spacing as an array
  1225. *
  1226. * The array has the format (h_space,v_space)
  1227. *
  1228. * @link http://www.w3.org/TR/CSS21/tables.html#propdef-border-spacing
  1229. * @return array
  1230. */
  1231. function get_border_spacing()
  1232. {
  1233. $arr = explode(" ", $this->_props["border_spacing"]);
  1234. if (count($arr) == 1) {
  1235. $arr[1] = $arr[0];
  1236. }
  1237. return $arr;
  1238. }
  1239. /*==============================*/
  1240. /*
  1241. !important attribute
  1242. For basic functionality of the !important attribute with overloading
  1243. of several styles of an element, changes in inherit(), merge() and _parse_properties()
  1244. are sufficient [helpers var $_important_props, __construct(), important_set(), important_get()]
  1245. Only for combined attributes extra treatment needed. See below.
  1246. div { border: 1px red; }
  1247. div { border: solid; } // Not combined! Only one occurence of same style per context
  1248. //
  1249. div { border: 1px red; }
  1250. div a { border: solid; } // Adding to border style ok by inheritance
  1251. //
  1252. div { border-style: solid; } // Adding to border style ok because of different styles
  1253. div { border: 1px red; }
  1254. //
  1255. div { border-style: solid; !important} // border: overrides, even though not !important
  1256. div { border: 1px dashed red; }
  1257. //
  1258. div { border: 1px red; !important }
  1259. div a { border-style: solid; } // Need to override because not set
  1260. Special treatment:
  1261. At individual property like border-top-width need to check whether overriding value is also !important.
  1262. Also store the !important condition for later overrides.
  1263. Since not known who is initiating the override, need to get passed !important as parameter.
  1264. !important Paramter taken as in the original style in the css file.
  1265. When property border !important given, do not mark subsets like border_style as important. Only
  1266. individual properties.
  1267. Note:
  1268. Setting individual property directly from css with e.g. set_border_top_style() is not needed, because
  1269. missing set funcions handled by a generic handler __set(), including the !important.
  1270. Setting individual property of as sub-property is handled below.
  1271. Implementation see at _set_style_side_type()
  1272. Callers _set_style_sides_type(), _set_style_type, _set_style_type_important()
  1273. Related functionality for background, padding, margin, font, list_style
  1274. */
  1275. /* Generalized set function for individual attribute of combined style.
  1276. * With check for !important
  1277. * Applicable for background, border, padding, margin, font, list_style
  1278. * Note: $type has a leading underscore (or is empty), the others not.
  1279. */
  1280. protected function _set_style_side_type($style, $side, $type, $val, $important)
  1281. {
  1282. $prop = $style . '_' . $side . $type;
  1283. if (!isset($this->_important_props[$prop]) || $important) {
  1284. //see __set and __get, on all assignments clear cache!
  1285. $this->_prop_cache[$prop] = null;
  1286. if ($important) {
  1287. $this->_important_props[$prop] = true;
  1288. }
  1289. $this->_props[$prop] = $val;
  1290. }
  1291. }
  1292. protected function _set_style_sides_type($style, $top, $right, $bottom, $left, $type, $important)
  1293. {
  1294. $this->_set_style_side_type($style, 'top', $type, $top, $important);
  1295. $this->_set_style_side_type($style, 'right', $type, $right, $important);
  1296. $this->_set_style_side_type($style, 'bottom', $type, $bottom, $important);
  1297. $this->_set_style_side_type($style, 'left', $type, $left, $important);
  1298. }
  1299. protected function _set_style_type($style, $type, $val, $important)
  1300. {
  1301. $val = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces
  1302. $arr = explode(" ", $val);
  1303. switch (count($arr)) {
  1304. case 1:
  1305. $this->_set_style_sides_type($style, $arr[0], $arr[0], $arr[0], $arr[0], $type, $important);
  1306. break;
  1307. case 2:
  1308. $this->_set_style_sides_type($style, $arr[0], $arr[1], $arr[0], $arr[1], $type, $important);
  1309. break;
  1310. case 3:
  1311. $this->_set_style_sides_type($style, $arr[0], $arr[1], $arr[2], $arr[1], $type, $important);
  1312. break;
  1313. case 4:
  1314. $this->_set_style_sides_type($style, $arr[0], $arr[1], $arr[2], $arr[3], $type, $important);
  1315. break;
  1316. }
  1317. //see __set and __get, on all assignments clear cache!
  1318. $this->_prop_cache[$style . $type] = null;
  1319. $this->_props[$style . $type] = $val;
  1320. }
  1321. protected function _set_style_type_important($style, $type, $val)
  1322. {
  1323. $this->_set_style_type($style, $type, $val, isset($this->_important_props[$style . $type]));
  1324. }
  1325. /* Anyway only called if _important matches and is assigned
  1326. * E.g. _set_style_side_type($style,$side,'',str_replace("none", "0px", $val),isset($this->_important_props[$style.'_'.$side]));
  1327. */
  1328. protected function _set_style_side_width_important($style, $side, $val)
  1329. {
  1330. //see __set and __get, on all assignments clear cache!
  1331. $this->_prop_cache[$style . '_' . $side] = null;
  1332. $this->_props[$style . '_' . $side] = str_replace("none", "0px", $val);
  1333. }
  1334. protected function _set_style($style, $val, $important)
  1335. {
  1336. if (!isset($this->_important_props[$style]) || $important) {
  1337. if ($important) {
  1338. $this->_important_props[$style] = true;
  1339. }
  1340. //see __set and __get, on all assignments clear cache!
  1341. $this->_prop_cache[$style] = null;
  1342. $this->_props[$style] = $val;
  1343. }
  1344. }
  1345. protected function _image($val)
  1346. {
  1347. $DEBUGCSS = $this->_stylesheet->get_dompdf()->get_option("debugCss");
  1348. $parsed_url = "none";
  1349. if (mb_strpos($val, "url") === false) {
  1350. $path = "none"; //Don't resolve no image -> otherwise would prefix path and no longer recognize as none
  1351. } else {
  1352. $val = preg_replace("/url\(['\"]?([^'\")]+)['\"]?\)/", "\\1", trim($val));
  1353. // Resolve the url now in the context of the current stylesheet
  1354. $parsed_url = Helpers::explode_url($val);
  1355. if ($parsed_url["protocol"] == "" && $this->_stylesheet->get_protocol() == "") {
  1356. if ($parsed_url["path"][0] === '/' || $parsed_url["path"][0] === '\\') {
  1357. $path = $_SERVER["DOCUMENT_ROOT"] . '/';
  1358. } else {
  1359. $path = $this->_stylesheet->get_base_path();
  1360. }
  1361. $path .= $parsed_url["path"] . $parsed_url["file"];
  1362. $path = realpath($path);
  1363. // If realpath returns FALSE then specifically state that there is no background image
  1364. if (!$path) {
  1365. $path = 'none';
  1366. }
  1367. } else {
  1368. $path = Helpers::build_url($this->_stylesheet->get_protocol(),
  1369. $this->_stylesheet->get_host(),
  1370. $this->_stylesheet->get_base_path(),
  1371. $val);
  1372. }
  1373. }
  1374. if ($DEBUGCSS) {
  1375. print "<pre>[_image\n";
  1376. print_r($parsed_url);
  1377. print $this->_stylesheet->get_protocol() . "\n" . $this->_stylesheet->get_base_path() . "\n" . $path . "\n";
  1378. print "_image]</pre>";;
  1379. }
  1380. return $path;
  1381. }
  1382. /*======================*/
  1383. /**
  1384. * Sets color
  1385. *
  1386. * The color parameter can be any valid CSS color value
  1387. *
  1388. * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color
  1389. * @param string $color
  1390. */
  1391. function set_color($color)
  1392. {

Large files files are truncated, but you can click here to view the full file