PageRenderTime 59ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/app/protected/extensions/pdf/dompdf/include/style.cls.php

https://bitbucket.org/sanbrar/zurmo_invoice
PHP | 2211 lines | 1883 code | 86 blank | 242 comment | 51 complexity | eef53db13ac961ba57c366ca4376158d MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, BSD-2-Clause, GPL-3.0

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

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

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