PageRenderTime 66ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/vendor/cssmin.php

https://github.com/kbsali/sfAssetsManagerPlugin
PHP | 1739 lines | 1348 code | 1 blank | 390 comment | 205 complexity | 393cf5abb62e145f29fa25277e7a6531 MD5 | raw file
Possible License(s): BSD-3-Clause

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

  1. <?php
  2. /**
  3. * CssMin - A (simple) css minifier with benefits
  4. *
  5. * --
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
  8. * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  9. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  10. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  11. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  12. * --
  13. *
  14. * @package CssMin
  15. * @link http://code.google.com/p/cssmin/
  16. * @author Joe Scylla <joe.scylla@gmail.com>
  17. * @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
  18. * @license http://opensource.org/licenses/mit-license.php MIT License
  19. * @version 2.0.2.1 (2011-02-18)
  20. */
  21. class CssMin
  22. {
  23. /**
  24. * Null-Token.
  25. *
  26. * @var integer
  27. */
  28. const T_NULL = 0;
  29. /**
  30. * State: Is in document
  31. *
  32. * @var integer
  33. */
  34. const T_DOCUMENT = 1;
  35. /**
  36. * Token: Comment
  37. *
  38. * @var integer
  39. */
  40. const T_COMMENT = 2;
  41. /**
  42. * Token: Generic at-rule
  43. *
  44. * @var integer
  45. */
  46. const T_AT_RULE = 3;
  47. /**
  48. * Token: Generic at-rule
  49. *
  50. * @var integer
  51. */
  52. const T_AT_IMPORT = 22;
  53. /**
  54. * Token: Start of @media block
  55. *
  56. * @var integer
  57. */
  58. const T_AT_MEDIA_START = 4;
  59. /**
  60. * State: Is in @media block
  61. *
  62. * @var integer
  63. */
  64. const T_AT_MEDIA = 5;
  65. /**
  66. * Token: End of @media block
  67. *
  68. * @var integer
  69. */
  70. const T_AT_MEDIA_END = 6;
  71. /**
  72. * Token: Start of @font-face block
  73. *
  74. * @var integer
  75. */
  76. const T_AT_FONT_FACE_START = 7;
  77. /**
  78. * State: Is in @font-face block
  79. *
  80. * @var integer
  81. */
  82. const T_AT_FONT_FACE = 8;
  83. /**
  84. * Token: @font-face declaration
  85. *
  86. * @var integer
  87. */
  88. const T_FONT_FACE_DECLARATION = 9;
  89. /**
  90. * Token: End of @font-face block
  91. *
  92. * @var integer
  93. */
  94. const T_AT_FONT_FACE_END = 10;
  95. /**
  96. * Token: Start of @page block
  97. *
  98. * @var integer
  99. */
  100. const T_AT_PAGE_START = 11;
  101. /**
  102. * State: Is in @page block
  103. *
  104. * @var integer
  105. */
  106. const T_AT_PAGE = 12;
  107. /**
  108. * Token: @page declaration
  109. *
  110. * @var integer
  111. */
  112. const T_PAGE_DECLARATION = 13;
  113. /**
  114. * Token: End of @page block
  115. *
  116. * @var integer
  117. */
  118. const T_AT_PAGE_END = 14;
  119. /**
  120. * Token: Start of ruleset
  121. *
  122. * @var integer
  123. */
  124. const T_RULESET_START = 15;
  125. /**
  126. * Token: Ruleset selectors
  127. *
  128. * @var integer
  129. */
  130. const T_SELECTORS = 16;
  131. /**
  132. * Token: Start of declarations
  133. *
  134. * @var integer
  135. */
  136. const T_DECLARATIONS_START = 17;
  137. /**
  138. * State: Is in declarations
  139. *
  140. * @var integer
  141. */
  142. const T_DECLARATIONS = 18;
  143. /**
  144. * Token: Declaration
  145. *
  146. * @var integer
  147. */
  148. const T_DECLARATION = 19;
  149. /**
  150. * Token: End of declarations
  151. *
  152. * @var integer
  153. */
  154. const T_DECLARATIONS_END = 20;
  155. /**
  156. * Token: End of ruleset
  157. *
  158. * @var integer
  159. */
  160. const T_RULESET_END = 21;
  161. /**
  162. * Token: Start of @variables block
  163. *
  164. * @var integer
  165. */
  166. const T_AT_VARIABLES_START = 100;
  167. /**
  168. * State: Is in @variables block
  169. *
  170. * @var integer
  171. */
  172. const T_AT_VARIABLES = 101;
  173. /**
  174. * Token: @variables declaration
  175. *
  176. * @var integer
  177. */
  178. const T_VARIABLE_DECLARATION = 102;
  179. /**
  180. * Token: End of @variables block
  181. *
  182. * @var integer
  183. */
  184. const T_AT_VARIABLES_END = 103;
  185. /**
  186. * State: Is in string
  187. *
  188. * @var integer
  189. */
  190. const T_STRING = 253;
  191. /**
  192. * State: Is in url string property
  193. *
  194. * @var integer
  195. */
  196. const T_STRING_URL = 254;
  197. /**
  198. * State: Is in expression string property
  199. *
  200. * @var integer
  201. */
  202. const T_STRING_EXPRESSION = 255;
  203. /**
  204. * Default configuration.
  205. *
  206. * @var array
  207. */
  208. private static $defaultConfiguration = array
  209. (
  210. "remove-empty-blocks" => true,
  211. "remove-empty-rulesets" => true,
  212. "remove-last-semicolons" => true,
  213. "convert-css3-properties" => false,
  214. "convert-font-weight-values" => false,
  215. "convert-named-color-values" => false,
  216. "convert-hsl-color-values" => false,
  217. "convert-rgb-color-values" => false,
  218. "compress-color-values" => false,
  219. "compress-unit-values" => false,
  220. "emulate-css3-variables" => true,
  221. "import-imports" => false,
  222. "import-base-path" => null,
  223. "import-remove-invalid" => false
  224. );
  225. /**
  226. * Css color transformations table. Used to convert named colors to hexadecimal notation.
  227. *
  228. * @var array
  229. */
  230. private static $colorTransformations = array
  231. (
  232. "aliceblue" => "#f0f8ff",
  233. "antiquewhite" => "#faebd7",
  234. "aqua" => "#0ff",
  235. "aquamarine" => "#7fffd4",
  236. "azure" => "#f0ffff",
  237. "beige" => "#f5f5dc",
  238. "black" => "#000",
  239. "blue" => "#00f",
  240. "blueviolet" => "#8a2be2",
  241. "brown" => "#a52a2a",
  242. "burlywood" => "#deb887",
  243. "cadetblue" => "#5f9ea0",
  244. "chartreuse" => "#7fff00",
  245. "chocolate" => "#d2691e",
  246. "coral" => "#ff7f50",
  247. "cornflowerblue" => "#6495ed",
  248. "cornsilk" => "#fff8dc",
  249. "crimson" => "#dc143c",
  250. "darkblue" => "#00008b",
  251. "darkcyan" => "#008b8b",
  252. "darkgoldenrod" => "#b8860b",
  253. "darkgray" => "#a9a9a9",
  254. "darkgreen" => "#006400",
  255. "darkkhaki" => "#bdb76b",
  256. "darkmagenta" => "#8b008b",
  257. "darkolivegreen" => "#556b2f",
  258. "darkorange" => "#ff8c00",
  259. "darkorchid" => "#9932cc",
  260. "darkred" => "#8b0000",
  261. "darksalmon" => "#e9967a",
  262. "darkseagreen" => "#8fbc8f",
  263. "darkslateblue" => "#483d8b",
  264. "darkslategray" => "#2f4f4f",
  265. "darkturquoise" => "#00ced1",
  266. "darkviolet" => "#9400d3",
  267. "deeppink" => "#ff1493",
  268. "deepskyblue" => "#00bfff",
  269. "dimgray" => "#696969",
  270. "dodgerblue" => "#1e90ff",
  271. "firebrick" => "#b22222",
  272. "floralwhite" => "#fffaf0",
  273. "forestgreen" => "#228b22",
  274. "fuchsia" => "#f0f",
  275. "gainsboro" => "#dcdcdc",
  276. "ghostwhite" => "#f8f8ff",
  277. "gold" => "#ffd700",
  278. "goldenrod" => "#daa520",
  279. "gray" => "#808080",
  280. "green" => "#008000",
  281. "greenyellow" => "#adff2f",
  282. "honeydew" => "#f0fff0",
  283. "hotpink" => "#ff69b4",
  284. "indianred" => "#cd5c5c",
  285. "indigo" => "#4b0082",
  286. "ivory" => "#fffff0",
  287. "khaki" => "#f0e68c",
  288. "lavender" => "#e6e6fa",
  289. "lavenderblush" => "#fff0f5",
  290. "lawngreen" => "#7cfc00",
  291. "lemonchiffon" => "#fffacd",
  292. "lightblue" => "#add8e6",
  293. "lightcoral" => "#f08080",
  294. "lightcyan" => "#e0ffff",
  295. "lightgoldenrodyellow" => "#fafad2",
  296. "lightgreen" => "#90ee90",
  297. "lightgrey" => "#d3d3d3",
  298. "lightpink" => "#ffb6c1",
  299. "lightsalmon" => "#ffa07a",
  300. "lightseagreen" => "#20b2aa",
  301. "lightskyblue" => "#87cefa",
  302. "lightslategray" => "#789",
  303. "lightsteelblue" => "#b0c4de",
  304. "lightyellow" => "#ffffe0",
  305. "lime" => "#0f0",
  306. "limegreen" => "#32cd32",
  307. "linen" => "#faf0e6",
  308. "maroon" => "#800000",
  309. "mediumaquamarine" => "#66cdaa",
  310. "mediumblue" => "#0000cd",
  311. "mediumorchid" => "#ba55d3",
  312. "mediumpurple" => "#9370db",
  313. "mediumseagreen" => "#3cb371",
  314. "mediumslateblue" => "#7b68ee",
  315. "mediumspringgreen" => "#00fa9a",
  316. "mediumturquoise" => "#48d1cc",
  317. "mediumvioletred" => "#c71585",
  318. "midnightblue" => "#191970",
  319. "mintcream" => "#f5fffa",
  320. "mistyrose" => "#ffe4e1",
  321. "moccasin" => "#ffe4b5",
  322. "navajowhite" => "#ffdead",
  323. "navy" => "#000080",
  324. "oldlace" => "#fdf5e6",
  325. "olive" => "#808000",
  326. "olivedrab" => "#6b8e23",
  327. "orange" => "#ffa500",
  328. "orangered" => "#ff4500",
  329. "orchid" => "#da70d6",
  330. "palegoldenrod" => "#eee8aa",
  331. "palegreen" => "#98fb98",
  332. "paleturquoise" => "#afeeee",
  333. "palevioletred" => "#db7093",
  334. "papayawhip" => "#ffefd5",
  335. "peachpuff" => "#ffdab9",
  336. "peru" => "#cd853f",
  337. "pink" => "#ffc0cb",
  338. "plum" => "#dda0dd",
  339. "powderblue" => "#b0e0e6",
  340. "purple" => "#800080",
  341. "red" => "#f00",
  342. "rosybrown" => "#bc8f8f",
  343. "royalblue" => "#4169e1",
  344. "saddlebrown" => "#8b4513",
  345. "salmon" => "#fa8072",
  346. "sandybrown" => "#f4a460",
  347. "seagreen" => "#2e8b57",
  348. "seashell" => "#fff5ee",
  349. "sienna" => "#a0522d",
  350. "silver" => "#c0c0c0",
  351. "skyblue" => "#87ceeb",
  352. "slateblue" => "#6a5acd",
  353. "slategray" => "#708090",
  354. "snow" => "#fffafa",
  355. "springgreen" => "#00ff7f",
  356. "steelblue" => "#4682b4",
  357. "tan" => "#d2b48c",
  358. "teal" => "#008080",
  359. "thistle" => "#d8bfd8",
  360. "tomato" => "#ff6347",
  361. "turquoise" => "#40e0d0",
  362. "violet" => "#ee82ee",
  363. "wheat" => "#f5deb3",
  364. "white" => "#fff",
  365. "whitesmoke" => "#f5f5f5",
  366. "yellow" => "#ff0",
  367. "yellowgreen" => "#9acd32"
  368. );
  369. /**
  370. *
  371. * @var array
  372. */
  373. private static $fontWeightTransformations = array
  374. (
  375. "normal" => "400",
  376. "bold" => "700"
  377. );
  378. /**
  379. * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific counterparts.
  380. *
  381. * @var array
  382. */
  383. private static $propertyTransformations = array
  384. (
  385. // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored
  386. "animation" => array(null, "-webkit-animation", null, null),
  387. "animation-delay" => array(null, "-webkit-animation-delay", null, null),
  388. "animation-direction" => array(null, "-webkit-animation-direction", null, null),
  389. "animation-duration" => array(null, "-webkit-animation-duration", null, null),
  390. "animation-fill-mode" => array(null, "-webkit-animation-fill-mode", null, null),
  391. "animation-iteration-count" => array(null, "-webkit-animation-iteration-count", null, null),
  392. "animation-name" => array(null, "-webkit-animation-name", null, null),
  393. "animation-play-state" => array(null, "-webkit-animation-play-state", null, null),
  394. "animation-timing-function" => array(null, "-webkit-animation-timing-function", null, null),
  395. "appearance" => array("-moz-appearance", "-webkit-appearance", null, null),
  396. "backface-visibility" => array(null, "-webkit-backface-visibility", null, null),
  397. "background-clip" => array(null, "-webkit-background-clip", null, null),
  398. "background-composite" => array(null, "-webkit-background-composite", null, null),
  399. "background-inline-policy" => array("-moz-background-inline-policy", null, null, null),
  400. "background-origin" => array(null, "-webkit-background-origin", null, null),
  401. "background-position-x" => array(null, null, null, "-ms-background-position-x"),
  402. "background-position-y" => array(null, null, null, "-ms-background-position-y"),
  403. "background-size" => array(null, "-webkit-background-size", null, null),
  404. "behavior" => array(null, null, null, "-ms-behavior"),
  405. "binding" => array("-moz-binding", null, null, null),
  406. "border-after" => array(null, "-webkit-border-after", null, null),
  407. "border-after-color" => array(null, "-webkit-border-after-color", null, null),
  408. "border-after-style" => array(null, "-webkit-border-after-style", null, null),
  409. "border-after-width" => array(null, "-webkit-border-after-width", null, null),
  410. "border-before" => array(null, "-webkit-border-before", null, null),
  411. "border-before-color" => array(null, "-webkit-border-before-color", null, null),
  412. "border-before-style" => array(null, "-webkit-border-before-style", null, null),
  413. "border-before-width" => array(null, "-webkit-border-before-width", null, null),
  414. "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null),
  415. "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null),
  416. "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null),
  417. "border-end" => array("-moz-border-end", "-webkit-border-end", null, null),
  418. "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null),
  419. "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null),
  420. "border-end-width" => array("-moz-border-end-width", "-webkit-border-end-width", null, null),
  421. "border-fit" => array(null, "-webkit-border-fit", null, null),
  422. "border-horizontal-spacing" => array(null, "-webkit-border-horizontal-spacing", null, null),
  423. "border-image" => array("-moz-border-image", "-webkit-border-image", null, null),
  424. "border-left-colors" => array("-moz-border-left-colors", null, null, null),
  425. "border-radius" => array("-moz-border-radius", "-webkit-border-radius", null, null),
  426. "border-border-right-colors" => array("-moz-border-right-colors", null, null, null),
  427. "border-start" => array("-moz-border-start", "-webkit-border-start", null, null),
  428. "border-start-color" => array("-moz-border-start-color", "-webkit-border-start-color", null, null),
  429. "border-start-style" => array("-moz-border-start-style", "-webkit-border-start-style", null, null),
  430. "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null),
  431. "border-top-colors" => array("-moz-border-top-colors", null, null, null),
  432. "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null),
  433. "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null),
  434. "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null),
  435. "box-align" => array("-moz-box-align", "-webkit-box-align", null, null),
  436. "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null),
  437. "box-flex" => array("-moz-box-flex", "-webkit-box-flex", null, null),
  438. "box-flex-group" => array(null, "-webkit-box-flex-group", null, null),
  439. "box-flex-lines" => array(null, "-webkit-box-flex-lines", null, null),
  440. "box-ordinal-group" => array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null),
  441. "box-orient" => array("-moz-box-orient", "-webkit-box-orient", null, null),
  442. "box-pack" => array("-moz-box-pack", "-webkit-box-pack", null, null),
  443. "box-reflect" => array(null, "-webkit-box-reflect", null, null),
  444. "box-shadow" => array("-moz-box-shadow", "-webkit-box-shadow", null, null),
  445. "box-sizing" => array("-moz-box-sizing", null, null, null),
  446. "color-correction" => array(null, "-webkit-color-correction", null, null),
  447. "column-break-after" => array(null, "-webkit-column-break-after", null, null),
  448. "column-break-before" => array(null, "-webkit-column-break-before", null, null),
  449. "column-break-inside" => array(null, "-webkit-column-break-inside", null, null),
  450. "column-count" => array("-moz-column-count", "-webkit-column-count", null, null),
  451. "column-gap" => array("-moz-column-gap", "-webkit-column-gap", null, null),
  452. "column-rule" => array("-moz-column-rule", "-webkit-column-rule", null, null),
  453. "column-rule-color" => array("-moz-column-rule-color", "-webkit-column-rule-color", null, null),
  454. "column-rule-style" => array("-moz-column-rule-style", "-webkit-column-rule-style", null, null),
  455. "column-rule-width" => array("-moz-column-rule-width", "-webkit-column-rule-width", null, null),
  456. "column-span" => array(null, "-webkit-column-span", null, null),
  457. "column-width" => array("-moz-column-width", "-webkit-column-width", null, null),
  458. "columns" => array(null, "-webkit-columns", null, null),
  459. "filter" => array(null, null, null, "-ms-filter"),
  460. "float-edge" => array("-moz-float-edge", null, null, null),
  461. "font-feature-settings" => array("-moz-font-feature-settings", null, null, null),
  462. "font-language-override" => array("-moz-font-language-override", null, null, null),
  463. "font-size-delta" => array(null, "-webkit-font-size-delta", null, null),
  464. "font-smoothing" => array(null, "-webkit-font-smoothing", null, null),
  465. "force-broken-image-icon" => array("-moz-force-broken-image-icon", null, null, null),
  466. "highlight" => array(null, "-webkit-highlight", null, null),
  467. "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null),
  468. "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null),
  469. "hyphens" => array(null, "-webkit-hyphens", null, null),
  470. "force-broken-image-icon" => array("-moz-image-region", null, null, null),
  471. "ime-mode" => array(null, null, null, "-ms-ime-mode"),
  472. "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"),
  473. "layout-flow" => array(null, null, null, "-ms-layout-flow"),
  474. "layout-grid" => array(null, null, null, "-ms-layout-grid"),
  475. "layout-grid-char" => array(null, null, null, "-ms-layout-grid-char"),
  476. "layout-grid-line" => array(null, null, null, "-ms-layout-grid-line"),
  477. "layout-grid-mode" => array(null, null, null, "-ms-layout-grid-mode"),
  478. "layout-grid-type" => array(null, null, null, "-ms-layout-grid-type"),
  479. "line-break" => array(null, "-webkit-line-break", null, "-ms-line-break"),
  480. "line-clamp" => array(null, "-webkit-line-clamp", null, null),
  481. "line-grid-mode" => array(null, null, null, "-ms-line-grid-mode"),
  482. "logical-height" => array(null, "-webkit-logical-height", null, null),
  483. "logical-width" => array(null, "-webkit-logical-width", null, null),
  484. "margin-after" => array(null, "-webkit-margin-after", null, null),
  485. "margin-after-collapse" => array(null, "-webkit-margin-after-collapse", null, null),
  486. "margin-before" => array(null, "-webkit-margin-before", null, null),
  487. "margin-before-collapse" => array(null, "-webkit-margin-before-collapse", null, null),
  488. "margin-bottom-collapse" => array(null, "-webkit-margin-bottom-collapse", null, null),
  489. "margin-collapse" => array(null, "-webkit-margin-collapse", null, null),
  490. "margin-end" => array("-moz-margin-end", "-webkit-margin-end", null, null),
  491. "margin-start" => array("-moz-margin-start", "-webkit-margin-start", null, null),
  492. "margin-top-collapse" => array(null, "-webkit-margin-top-collapse", null, null),
  493. "marquee " => array(null, "-webkit-marquee", null, null),
  494. "marquee-direction" => array(null, "-webkit-marquee-direction", null, null),
  495. "marquee-increment" => array(null, "-webkit-marquee-increment", null, null),
  496. "marquee-repetition" => array(null, "-webkit-marquee-repetition", null, null),
  497. "marquee-speed" => array(null, "-webkit-marquee-speed", null, null),
  498. "marquee-style" => array(null, "-webkit-marquee-style", null, null),
  499. "mask" => array(null, "-webkit-mask", null, null),
  500. "mask-attachment" => array(null, "-webkit-mask-attachment", null, null),
  501. "mask-box-image" => array(null, "-webkit-mask-box-image", null, null),
  502. "mask-clip" => array(null, "-webkit-mask-clip", null, null),
  503. "mask-composite" => array(null, "-webkit-mask-composite", null, null),
  504. "mask-image" => array(null, "-webkit-mask-image", null, null),
  505. "mask-origin" => array(null, "-webkit-mask-origin", null, null),
  506. "mask-position" => array(null, "-webkit-mask-position", null, null),
  507. "mask-position-x" => array(null, "-webkit-mask-position-x", null, null),
  508. "mask-position-y" => array(null, "-webkit-mask-position-y", null, null),
  509. "mask-repeat" => array(null, "-webkit-mask-repeat", null, null),
  510. "mask-repeat-x" => array(null, "-webkit-mask-repeat-x", null, null),
  511. "mask-repeat-y" => array(null, "-webkit-mask-repeat-y", null, null),
  512. "mask-size" => array(null, "-webkit-mask-size", null, null),
  513. "match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null),
  514. "max-logical-height" => array(null, "-webkit-max-logical-height", null, null),
  515. "max-logical-width" => array(null, "-webkit-max-logical-width", null, null),
  516. "min-logical-height" => array(null, "-webkit-min-logical-height", null, null),
  517. "min-logical-width" => array(null, "-webkit-min-logical-width", null, null),
  518. "object-fit" => array(null, null, "-o-object-fit", null),
  519. "object-position" => array(null, null, "-o-object-position", null),
  520. "opacity" => array(array(__CLASS__, "_opacityTransformation")),
  521. "outline-radius" => array("-moz-outline-radius", null, null, null),
  522. "outline-bottom-left-radius" => array("-moz-outline-radius-bottomleft", null, null, null),
  523. "outline-bottom-right-radius" => array("-moz-outline-radius-bottomright", null, null, null),
  524. "outline-top-left-radius" => array("-moz-outline-radius-topleft", null, null, null),
  525. "outline-top-right-radius" => array("-moz-outline-radius-topright", null, null, null),
  526. "overflow-x" => array(null, null, null, "-ms-overflow-x"),
  527. "overflow-y" => array(null, null, null, "-ms-overflow-y"),
  528. "padding-after" => array(null, "-webkit-padding-after", null, null),
  529. "padding-before" => array(null, "-webkit-padding-before", null, null),
  530. "padding-end" => array("-moz-padding-end", "-webkit-padding-end", null, null),
  531. "padding-start" => array("-moz-padding-start", "-webkit-padding-start", null, null),
  532. "perspective" => array(null, "-webkit-perspective", null, null),
  533. "perspective-origin" => array(null, "-webkit-perspective-origin", null, null),
  534. "perspective-origin-x" => array(null, "-webkit-perspective-origin-x", null, null),
  535. "perspective-origin-y" => array(null, "-webkit-perspective-origin-y", null, null),
  536. "rtl-ordering" => array(null, "-webkit-rtl-ordering", null, null),
  537. "scrollbar-3dlight-color" => array(null, null, null, "-ms-scrollbar-3dlight-color"),
  538. "scrollbar-arrow-color" => array(null, null, null, "-ms-scrollbar-arrow-color"),
  539. "scrollbar-base-color" => array(null, null, null, "-ms-scrollbar-base-color"),
  540. "scrollbar-darkshadow-color" => array(null, null, null, "-ms-scrollbar-darkshadow-color"),
  541. "scrollbar-face-color" => array(null, null, null, "-ms-scrollbar-face-color"),
  542. "scrollbar-highlight-color" => array(null, null, null, "-ms-scrollbar-highlight-color"),
  543. "scrollbar-shadow-color" => array(null, null, null, "-ms-scrollbar-shadow-color"),
  544. "scrollbar-track-color" => array(null, null, null, "-ms-scrollbar-track-color"),
  545. "stack-sizing" => array("-moz-stack-sizing", null, null, null),
  546. "svg-shadow" => array(null, "-webkit-svg-shadow", null, null),
  547. "tab-size" => array("-moz-tab-size", null, "-o-tab-size", null),
  548. "table-baseline" => array(null, null, "-o-table-baseline", null),
  549. "text-align-last" => array(null, null, null, "-ms-text-align-last"),
  550. "text-autospace" => array(null, null, null, "-ms-text-autospace"),
  551. "text-combine" => array(null, "-webkit-text-combine", null, null),
  552. "text-decorations-in-effect" => array(null, "-webkit-text-decorations-in-effect", null, null),
  553. "text-emphasis" => array(null, "-webkit-text-emphasis", null, null),
  554. "text-emphasis-color" => array(null, "-webkit-text-emphasis-color", null, null),
  555. "text-emphasis-position" => array(null, "-webkit-text-emphasis-position", null, null),
  556. "text-emphasis-style" => array(null, "-webkit-text-emphasis-style", null, null),
  557. "text-fill-color" => array(null, "-webkit-text-fill-color", null, null),
  558. "text-justify" => array(null, null, null, "-ms-text-justify"),
  559. "text-kashida-space" => array(null, null, null, "-ms-text-kashida-space"),
  560. "text-overflow" => array(null, null, "-o-text-overflow", "-ms-text-overflow"),
  561. "text-security" => array(null, "-webkit-text-security", null, null),
  562. "text-size-adjust" => array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"),
  563. "text-stroke" => array(null, "-webkit-text-stroke", null, null),
  564. "text-stroke-color" => array(null, "-webkit-text-stroke-color", null, null),
  565. "text-stroke-width" => array(null, "-webkit-text-stroke-width", null, null),
  566. "text-underline-position" => array(null, null, null, "-ms-text-underline-position"),
  567. "transform" => array("-moz-transform", "-webkit-transform", "-o-transform", null),
  568. "transform-origin" => array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null),
  569. "transform-origin-x" => array(null, "-webkit-transform-origin-x", null, null),
  570. "transform-origin-y" => array(null, "-webkit-transform-origin-y", null, null),
  571. "transform-origin-z" => array(null, "-webkit-transform-origin-z", null, null),
  572. "transform-style" => array(null, "-webkit-transform-style", null, null),
  573. "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null),
  574. "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null),
  575. "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null),
  576. "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null),
  577. "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null),
  578. "user-drag" => array(null, "-webkit-user-drag", null, null),
  579. "user-focus" => array("-moz-user-focus", null, null, null),
  580. "user-input" => array("-moz-user-input", null, null, null),
  581. "user-modify" => array("-moz-user-modify", "-webkit-user-modify", null, null),
  582. "user-select" => array("-moz-user-select", "-webkit-user-select", null, null),
  583. "white-space" => array(array(__CLASS__, "_whiteSpacePreWrapTransformation")),
  584. "window-shadow" => array("-moz-window-shadow", null, null, null),
  585. "word-break" => array(null, null, null, "-ms-word-break"),
  586. "word-wrap" => array(null, null, null, "-ms-word-wrap"),
  587. "writing-mode" => array(null, "-webkit-writing-mode", null, "-ms-writing-mode"),
  588. "zoom" => array(null, null, null, "-ms-zoom")
  589. );
  590. /**
  591. * Minifies the Css.
  592. *
  593. * @param string $css Css as string
  594. * @param array $config {@link http://code.google.com/p/cssmin/wiki/Configuration Configuration} as array [optional]
  595. * @return string Minified css
  596. */
  597. public static function minify($css, $config = array())
  598. {
  599. $tokens = self::parse($css);
  600. // Normalize configuration parameters
  601. if (count($config) > 0)
  602. {
  603. $config = array_combine(array_map("trim", array_map("strtolower", array_keys($config))), array_values($config));
  604. }
  605. $config = array_merge(self::$defaultConfiguration, $config);
  606. // Minification options/variables
  607. $sRemoveEmptyBlocks = $config["remove-empty-blocks"];
  608. $sRemoveEmptyRulesets = $config["remove-empty-rulesets"];
  609. $sRemoveLastSemicolon = $config["remove-last-semicolons"];
  610. $sConvertCss3Properties = $config["convert-css3-properties"];
  611. $sCss3Variables = array();
  612. $sConvertFontWeightValues = $config["convert-font-weight-values"];
  613. $rConvertFontWeightValues = "/(^|\s)+(normal|bold)(\s|$)+/ie";
  614. $rConvertFontWeightValuesR = "'\\1'.self::\$fontWeightTransformations['\\2'].'\\3'";
  615. $sConvertNamedColorValues = $config["convert-named-color-values"];
  616. $rConvertNamedColorValues = "/(^|\s)+(" . implode("|", array_keys(self::$colorTransformations)) . ")(\s|$)+/ie";
  617. $rConvertNamedColorValuesR = "'\\1'.self::\$colorTransformations['\\2'].'\\3'";
  618. $sConvertRgbColorValues = $config["convert-rgb-color-values"];
  619. $rConvertRgbColorValues = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS";
  620. $sConvertHslColorValues = $config["convert-rgb-color-values"];
  621. $rConvertHslColorValues = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS";
  622. $sCompressColorValues = $config["compress-color-values"];
  623. $rCompressColorValues = "/\#([0-9a-f]{6})/iS";
  624. $sCompressUnitValues = $config["compress-unit-values"];
  625. $rCompressUnitValues1 = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS";
  626. $rCompressUnitValues1R = "\${1}.\${2}\${4}";
  627. $rCompressUnitValues2 = "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS";
  628. $rCompressUnitValues2R = "\${1}0";
  629. $sEmulateCcss3Variables = $config["emulate-css3-variables"];
  630. $sImportImports = $config["import-imports"];
  631. $sImportBasePath = $config["import-base-path"];
  632. $sImportRemoveInvalid = $config["import-remove-invalid"];
  633. $sImportStartBlockTokens = array(self::T_AT_MEDIA_START, self::T_AT_FONT_FACE_START, self::T_AT_PAGE_START);
  634. $sImportEndBlockTokens = array(self::T_AT_MEDIA_END, self::T_AT_FONT_FACE_END, self::T_AT_PAGE_END);
  635. $sImportStatementTokens = array(self::T_AT_RULE, self::T_AT_IMPORT);
  636. $sImportMediaEndToken = array(self::T_AT_MEDIA_END);
  637. $sImportImportedFiles = array();
  638. $sRemoveTokens = array(self::T_NULL, self::T_COMMENT);
  639. /*
  640. * Import @import at-rules.
  641. *
  642. * If the @import at-rule defines one or more media type the imported tokens wil get wrapped into T_AT_MEDIA_START
  643. * and T_AT_MEDIA_END token. @font-face, @media and @page at-rule blocks and at-rule statements will get excluded
  644. * of the wraping.
  645. *
  646. * Additional @media at-rule blocks with media types not defined in the @import at-rule have to get removed.
  647. * Browsers ignore @media at-rule block with media types incompatible to the media types defined in the @import
  648. * at-rule.
  649. *
  650. * Also @import rules require special treatment. If a included @import at-rule has no media type or only the
  651. * "all" media type defined the media type of the @import at-rule will get set to the ones defined in the parent
  652. * @import at-rule. Media types not defined in the parent @import at-rule will get filtered. @import at-rule
  653. * with not matching media types will get removed.
  654. *
  655. * For compression if a @media at-rule block is defined the same media type as the @import at-rule the
  656. * T_AT_MEDIA_START and T_AT_MEDIA_END tokens will get removed.
  657. */
  658. if ($sImportImports && is_dir($sImportBasePath))
  659. {
  660. $importFile = "";
  661. $importTokens = array();
  662. $importMediaStartToken = array(self::T_NULL);
  663. $importBlocks = array();
  664. for($i = 0, $l = count($tokens); $i < $l; $i++)
  665. {
  666. if ($tokens[$i][0] == self::T_AT_IMPORT && file_exists($sImportBasePath . $tokens[$i][1]))
  667. {
  668. $importFile = $sImportBasePath . $tokens[$i][1];
  669. // Import file already imported; remove this @import at-rule to prevent any recursion
  670. if (in_array($importFile, $sImportImportedFiles))
  671. {
  672. $tokens[$i] = array(self::T_NULL);
  673. }
  674. else
  675. {
  676. $sImportImportedFiles[] = $sImportBasePath . $tokens[$i][1];
  677. $importTokens = self::parse(file_get_contents($importFile));
  678. // The @import at-rule has media types defined requires special handling
  679. if (count($tokens[$i][2]) > 0 && !(count($tokens[$i][2]) == 1 && $tokens[$i][2][0] == "all"))
  680. {
  681. // Create T_AT_MEDIA_START token used for wrapping and array for blocks
  682. $importMediaStartToken = array(self::T_AT_MEDIA_START, $tokens[$i][2]);
  683. $importBlocks = array();
  684. // Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule
  685. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  686. {
  687. if ($importTokens[$ii][0] == self::T_AT_IMPORT)
  688. {
  689. // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule
  690. if (count($importTokens[$ii][2]) == 0 || (count($importTokens[$ii][2]) == 1 && $importTokens[$ii][2][0]) == "all")
  691. {
  692. $importTokens[$ii][2] = $tokens[$i][2];
  693. }
  694. // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule
  695. elseif (count($importTokens[$ii][2] > 0))
  696. {
  697. foreach ($importTokens[$ii][2] as $index => $mediaType)
  698. {
  699. if (!in_array($mediaType, $tokens[$i][2]))
  700. {
  701. unset($importTokens[$ii][2][$index]);
  702. }
  703. }
  704. $importTokens[$ii][2] = array_values($importTokens[$ii][2]);
  705. // If there are no media types left in the @import at-rule remove the @import at-rule
  706. if (count($importTokens[$ii][2]) == 0)
  707. {
  708. $importTokens[$ii] = array(self::T_NULL);
  709. }
  710. }
  711. }
  712. }
  713. // Remove media types of @media at-rule block not defined in the @import at-rule
  714. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  715. {
  716. if ($importTokens[$ii][0] == self::T_AT_MEDIA_START)
  717. {
  718. foreach ($importTokens[$ii][1] as $index => $mediaType)
  719. {
  720. if (!in_array($mediaType, $tokens[$i][2]))
  721. {
  722. unset($importTokens[$ii][1][$index]);
  723. }
  724. $importTokens[$ii][1] = array_values($importTokens[$ii][1]);
  725. }
  726. }
  727. }
  728. // If no media types left of the @media at-rule block remove the complete block
  729. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  730. {
  731. if ($importTokens[$ii][0] == self::T_AT_MEDIA_START)
  732. {
  733. if (count($importTokens[$ii][1]) == 0)
  734. {
  735. for ($iii = $ii; $iii < $ll; $iii++)
  736. {
  737. if ($importTokens[$iii][0] == self::T_AT_MEDIA_END)
  738. {
  739. break;
  740. }
  741. }
  742. if ($importTokens[$iii][0] == self::T_AT_MEDIA_END)
  743. {
  744. array_splice($importTokens, $ii, $iii - $ii + 1, array());
  745. $ll = count($importTokens);
  746. }
  747. }
  748. }
  749. }
  750. // If the media types of the @media at-rule equals the media types defined in the @import at-rule remove the T_AT_MEDIA_START and T_AT_MEDIA_END token
  751. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  752. {
  753. if ($importTokens[$ii][0] == self::T_AT_MEDIA_START && count(array_diff($tokens[$i][2], $importTokens[$ii][1])) == 0)
  754. {
  755. for ($iii = $ii; $iii < $ll; $iii++)
  756. {
  757. if ($importTokens[$iii][0] == self::T_AT_MEDIA_END)
  758. {
  759. break;
  760. }
  761. }
  762. if ($importTokens[$iii][0] == self::T_AT_MEDIA_END)
  763. {
  764. unset($importTokens[$ii]);
  765. unset($importTokens[$iii]);
  766. $importTokens = array_values($importTokens);
  767. $ll = count($importTokens);
  768. }
  769. }
  770. }
  771. // Extract @import at-rule tokens
  772. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  773. {
  774. if ($importTokens[$ii][0] == self::T_AT_IMPORT)
  775. {
  776. $importBlocks = array_merge($importBlocks, array_splice($importTokens, $ii, 1, array()));
  777. $ll = count($importTokens);
  778. }
  779. }
  780. // Extract T_AT_RULE tokens
  781. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  782. {
  783. if ($importTokens[$ii][0] == self::T_AT_RULE)
  784. {
  785. $importBlocks = array_merge($importBlocks, array_splice($importTokens, $ii, 1, array()));
  786. $ll = count($importTokens);
  787. }
  788. }
  789. // Extract the @font-face, @media and @page at-rule block
  790. for($ii = 0, $ll = count($importTokens); $ii < $ll; $ii++)
  791. {
  792. if (in_array($importTokens[$ii][0], $sImportStartBlockTokens))
  793. {
  794. for ($iii = $ii; $iii < $ll; $iii++)
  795. {
  796. if (in_array($importTokens[$iii][0], $sImportEndBlockTokens))
  797. {
  798. break;
  799. }
  800. }
  801. if (isset($importTokens[$iii][0]) && in_array($importTokens[$iii][0], $sImportEndBlockTokens))
  802. {
  803. $importBlocks = array_merge($importBlocks, array_splice($importTokens, $ii, $iii - $ii + 1, array()));
  804. $ll = count($importTokens);
  805. }
  806. }
  807. }
  808. // Create the array with imported tokens for @import at-rules with defined media types
  809. $importTokens = array_merge($importBlocks, array($importMediaStartToken), $importTokens, array($sImportMediaEndToken));
  810. }
  811. array_splice($tokens, $i, 1, $importTokens);
  812. // Modify parameters of the for-loop
  813. $i--;
  814. $l = count($tokens);
  815. }
  816. }
  817. }
  818. }
  819. /*
  820. * Remove tokens.
  821. *
  822. * Remove tokens not required for minification. Defaults to T_NULL and T_COMMENT tokens.
  823. *
  824. * If CSS Level 3 Variables (emulate-css3-variables) is disabled add T_AT_VARIABLES_START, T_VARIABLE_DECLARATION
  825. * and T_AT_VARIABLES_END tokens.
  826. *
  827. * If the configuration options "import-imports" and "import-remove-invalid" is enabled remove also remaining
  828. * T_AT_IMPORT tokens.
  829. */
  830. if (!$sEmulateCcss3Variables)
  831. {
  832. $sRemoveTokens = array_merge($sRemoveTokens, array(self::T_AT_VARIABLES_START, self::T_VARIABLE_DECLARATION, self::T_AT_VARIABLES_END));
  833. }
  834. if ($sImportImports && is_dir($sImportBasePath) && $sImportRemoveInvalid)
  835. {
  836. $sRemoveTokens[] = self::T_AT_IMPORT;
  837. }
  838. for($i = 0, $l = count($tokens); $i < $l; $i++)
  839. {
  840. if (in_array($tokens[$i][0], $sRemoveTokens))
  841. {
  842. unset($tokens[$i]);
  843. }
  844. }
  845. $tokens = array_values($tokens);
  846. /*
  847. * Remove empty rulesets
  848. *
  849. * The ruleset is empty if it only contains the tokens T_RULESET_START, T_SELECTORS, T_DECLARATIONS_START,
  850. * T_DECLARATIONS_END and T_RULESET_END
  851. */
  852. if ($sRemoveEmptyRulesets)
  853. {
  854. for($i = 0, $l = count($tokens); $i < $l; $i++)
  855. {
  856. if ($tokens[$i][0] == self::T_RULESET_START && $tokens[$i+4][0] == self::T_RULESET_END)
  857. {
  858. unset($tokens[$i]); // T_RULESET_START
  859. unset($tokens[++$i]); // T_SELECTORS
  860. unset($tokens[++$i]); // T_DECLARATIONS_START
  861. unset($tokens[++$i]); // T_DECLARATIONS_END
  862. unset($tokens[++$i]); // T_RULESET_END
  863. }
  864. }
  865. $tokens = array_values($tokens);
  866. }
  867. /*
  868. * Remove empty @media, @font-face or @page blocks
  869. */
  870. if ($sRemoveEmptyBlocks)
  871. {
  872. for($i = 0, $l = count($tokens); $i < $l; $i++)
  873. {
  874. if (($tokens[$i][0] == self::T_AT_MEDIA_START && $tokens[$i+1][0] == self::T_AT_MEDIA_END)
  875. || ($tokens[$i][0] == self::T_AT_FONT_FACE_START && $tokens[$i+1][0] == self::T_AT_FONT_FACE_END)
  876. || ($tokens[$i][0] == self::T_AT_PAGE_START && $tokens[$i+1][0] == self::T_AT_PAGE_END))
  877. {
  878. unset($tokens[$i]); // T_AT_MEDIA_START, T_AT_FONT_FACE_START, T_AT_PAGE_START
  879. unset($tokens[++$i]); // T_AT_MEDIA_END, T_AT_FONT_FACE_END, T_AT_PAGE_END
  880. }
  881. }
  882. $tokens = array_values($tokens);
  883. }
  884. /*
  885. * Parse CSS Level 3 variables if the configuration option "emulate-css3-variables" is enabled.
  886. */
  887. if ($sEmulateCcss3Variables)
  888. {
  889. for($i = 0, $l = count($tokens); $i < $l; $i++)
  890. {
  891. // Found a variable declaration
  892. if ($tokens[$i][0] == self::T_VARIABLE_DECLARATION)
  893. {
  894. for($i2 = 0, $l2 = count($tokens[$i][3]); $i2 < $l2; $i2++)
  895. {
  896. // Create the scope (all, screen, print, etc.) if not defined
  897. if (!isset($sCss3Variables[$tokens[$i][3][$i2]]))
  898. {
  899. $sCss3Variables[$tokens[$i][3][$i2]] = array();
  900. }
  901. // Store variable and value
  902. $sCss3Variables[$tokens[$i][3][$i2]][$tokens[$i][1]] = $tokens[$i][2];
  903. }
  904. }
  905. }
  906. }
  907. /*
  908. * Conversion and compression
  909. */
  910. for($i = 0, $l = count($tokens); $i < $l; $i++)
  911. {
  912. if ($tokens[$i][0] == self::T_DECLARATION)
  913. {
  914. /*
  915. * Search for CSS Level 3 variable statement if the configuration option "emulate-css3-variables" is
  916. * enabled.
  917. *
  918. * The variable value depends on the media type of the declaration. Primary the variable value
  919. * of the media type of the declaration will get used if available. If no variable value for the media
  920. * type of the declaration is defined use the variable value definition for the media type "all".
  921. */
  922. if ($sEmulateCcss3Variables)
  923. {
  924. // Found a 'var' statement
  925. if (strtolower(substr($tokens[$i][2], 0, 4)) == "var(" && substr($tokens[$i][2], -1, 1) == ")")
  926. {
  927. // Extract the variable name
  928. $variable = trim(substr($tokens[$i][2], 4, -1));
  929. // Append the media type "all" to the declaration
  930. $tokens[$i][3][] = "all";
  931. for($i2 = 0, $l2 = count($tokens[$i][3]); $i2 < $l2; $i2++)
  932. {
  933. // Found a variable value for the current media type scope
  934. if (isset($sCss3Variables[$tokens[$i][3][$i2]][$variable]))
  935. {
  936. $tokens[$i][2] = $sCss3Variables[$tokens[$i][3][$i2]][$variable];
  937. break;
  938. }
  939. }
  940. }
  941. }
  942. /*
  943. * Convert font-weight values if the configuration option "convert-font-weight-values" is enabled.
  944. *
  945. * Will convert font weight values "normal" to "400" and "bold" to "700". Restricted to "font-weight"
  946. * and "font" declarations.
  947. */
  948. if ($sConvertFontWeightValues && in_array(strtolower($tokens[$i][1]), array("font-weight", "font")) && preg_match($rConvertFontWeightValues, $tokens[$i][2]))
  949. {
  950. $tokens[$i][2] = preg_replace($rConvertFontWeightValues, $rConvertFontWeightValuesR, $tokens[$i][2]);
  951. }
  952. /**
  953. * Compress unit values if the configuration option "compress-unit-values" is enabled.
  954. *
  955. * This will compress:
  956. * 1. "0.5px" to ".5px"
  957. * 2. "0px" to "0"
  958. * 3. "0 0 0 0", "0 0 0" or "0 0" to "0"
  959. */
  960. if ($sCompressUnitValues)
  961. {
  962. $tokens[$i][2] = preg_replace($rCompressUnitValues1, $rCompressUnitValues1R, $tokens[$i][2]);
  963. $tokens[$i][2] = preg_replace($rCompressUnitValues2, $rCompressUnitValues2R, $tokens[$i][2]);
  964. if ($tokens[$i][2] == "0 0 0 0" || $tokens[$i][2] == "0 0 0" || $tokens[$i][2] == "0 0") {$tokens[$i][2] = "0";}
  965. }
  966. /*
  967. * Convert RGB color values if the configuration option "convert-rgb-color-values" is enabled.
  968. *
  969. * This will convert values like "rgb(200,60%,5)" to "#c89905".
  970. */
  971. if ($sConvertRgbColorValues && preg_match($rConvertRgbColorValues, $tokens[$i][2], $m))
  972. {
  973. for ($i2 = 1, $l2 = count($m); $i2 < $l2; $i2++)
  974. {
  975. if (strpos("%", $m[$i2]) !== false)
  976. {
  977. $m[$i2] = substr($m[$i2], 0, -1);
  978. $m[$i2] = (int) (256 * ($m[$i2] / 100));
  979. }
  980. $m[$i2] = str_pad(dechex($m[$i2]), 2, "0", STR_PAD_LEFT);
  981. }
  982. $tokens[$i][2] = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $tokens[$i][2]);
  983. }
  984. /**
  985. * Convert HSL color values if the configuration option "convert-hsl-color-values" is enabled.
  986. *
  987. * This will convert values like "hsl(232,36%,48%)" to "#4e5aa7".
  988. */
  989. if ($sConvertHslColorValues && preg_match($rConvertHslColorValues, $tokens[$i][2], $m))
  990. {
  991. $tokens[$i][2] = str_replace($m[0], self::_hsl2hex($m[1], $m[2], $m[3]), $tokens[$i][2]);
  992. }
  993. /**
  994. * Compress color values if the configuration option "compress-color-values" is enabled.
  995. *
  996. * This will convert color value like "#aabbcc" to their short notation "#abc".
  997. */
  998. if ($sCompressColorValues && preg_match($rCompressColorValues, $tokens[$i][2], $m))
  999. {
  1000. $m[1] = strtolower($m[1]);
  1001. if (substr($m[1], 0, 1) == substr($m[1], 1, 1) && substr($m[1], 2, 1) == substr($m[1], 3, 1) && substr($m[1], 4, 1) == substr($m[1], 5, 1))
  1002. {
  1003. $tokens[$i][2] = str_replace($m[0], "#" . substr($m[1], 0, 1) . substr($m[1], 2, 1) . substr($m[1], 4, 1), $tokens[$i][2]);
  1004. }
  1005. }
  1006. /**
  1007. * Convert named color values if the configuration option "convert-named-color-values" is enabled.
  1008. *
  1009. * This will convert named color value like "black" to their hexadecimal notation "#000".
  1010. */
  1011. if ($sConvertNamedColorValues && preg_match($rConvertNamedColorValues, $tokens[$i][2]))
  1012. {
  1013. $tokens[$i][2] = preg_replace($rConvertNamedColorValues, $rConvertNamedColorValuesR, $tokens[$i][2]);
  1014. }
  1015. }
  1016. }
  1017. /*
  1018. * Create minified css
  1019. */
  1020. $r = "";
  1021. for($i = 0, $l = count($tokens); $i < $l; $i++)
  1022. {
  1023. // T_AT_RULE
  1024. if ($tokens[$i][0] == self::T_AT_RULE)
  1025. {
  1026. $r .= "@" . $tokens[$i][1] . " " . $tokens[$i][2] . ";";
  1027. }
  1028. // T_AT_IMPORT
  1029. if ($tokens[$i][0] == self::T_AT_IMPORT)
  1030. {
  1031. $r .= "@import \"" . $tokens[$i][1] . "\" " . implode(",", $tokens[$i][2]) . ";";
  1032. }
  1033. // T_AT_MEDIA_START
  1034. elseif ($tokens[$i][0] == self::T_AT_MEDIA_START)
  1035. {
  1036. if (count($tokens[$i][1]) == 1 && $tokens[$i][1][0] == "all")
  1037. {
  1038. $r .= "@media{";
  1039. }
  1040. else
  1041. {
  1042. $r .= "@media " . implode(",", $tokens[$i][1]) . "{";
  1043. }
  1044. }
  1045. // T_AT_FONT_FACE_START
  1046. elseif ($tokens[$i][0] == self::T_AT_FONT_FACE_START)
  1047. {
  1048. $r .= "@font-face{";
  1049. }
  1050. // T_FONT_FACE_DECLARATION
  1051. elseif ($tokens[$i][0] == self::T_FONT_FACE_DECLARATION)
  1052. {
  1053. $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && $tokens[$i+1][0] == self::T_AT_FONT_FACE_END ? "" : ";");
  1054. }
  1055. // T_AT_PAGE_START
  1056. elseif ($tokens[$i][0] == self::T_AT_PAGE_START)
  1057. {
  1058. $r .= "@page{";
  1059. }
  1060. // T_PAGE_DECLARATION
  1061. elseif ($tokens[$i][0] == self::T_PAGE_DECLARATION)
  1062. {
  1063. $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && $tokens[$i+1][0] == self::T_AT_PAGE_END ? "" : ";");
  1064. }
  1065. // T_SELECTORS
  1066. elseif ($tokens[$i][0] == self::T_SELECTORS)
  1067. {
  1068. $r .= implode(",", $tokens[$i][1]);
  1069. }
  1070. // Start of declarations
  1071. elseif ($tokens[$i][0] == self::T_DECLARATIONS_START)
  1072. {
  1073. $r .= "{";
  1074. }
  1075. // T_DECLARATION
  1076. elseif ($tokens[$i][0] == self::T_DECLARATION)
  1077. {
  1078. // Convert CSS Level 3 and browser specific properties if "convert-css3-properties" is enabled
  1079. if ($sConvertCss3Properties && isset(self::$propertyTransformations[$tokens[$i][1]]))
  1080. {
  1081. foreach (self::$propertyTransformations[$tokens[$i][1]] as $value)
  1082. {
  1083. if (!is_null($value) && !is_array($value))
  1084. {
  1085. $r .= $value . ":" . $tokens[$i][2] . ";";
  1086. }
  1087. elseif (is_array($value) && is_callable($value))
  1088. {
  1089. $r .= call_user_func_array($value, array($tokens[$i][1], $tokens[$i][2]));
  1090. }
  1091. }
  1092. }
  1093. $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && (isset($tokens[$i+1]) &&$tokens[$i+1][0] == self::T_DECLARATIONS_END) ? "" : ";");
  1094. }
  1095. // T_DECLARATIONS_END, T_AT_MEDIA_END, T_AT_FONT_FACE_END, T_AT_PAGE_END
  1096. elseif (in_array($tokens[$i][0], array(self::T_DECLARATIONS_END, self::T_AT_MEDIA_END, self::T_AT_FONT_FACE_END, self::T_AT_PAGE_END)))
  1097. {
  1098. $r .= "}";
  1099. }
  1100. else
  1101. {
  1102. // Tokens with no output: T_NULL, T_COMMENT, T_RULESET_START, T_RULESET_END, T_AT_VARIABLES_START, T_VARIABLE_DECLARATION and T_AT_VARIABLES_END
  1103. }
  1104. }
  1105. return $r;
  1106. }
  1107. /**
  1108. * Parses the Css and returns an array of tokens.
  1109. *
  1110. * @param string $css
  1111. * @return array Array of tokens
  1112. */
  1113. public static function parse($css)
  1114. {
  1115. /*
  1116. * Settings
  1117. */
  1118. $sDefaultScope = array("all"); // Default scope
  1119. $sDefaultTrim = " \t\n\r\0\x0B"; // Default trim charlist
  1120. $sTokenChars = "@{}();:\n\"'/*,"; // Tokens triggering parser processing
  1121. $sWhitespaceChars = $sDefaultTrim; // Whitespace chars
  1122. /*
  1123. * Basic variables
  1124. */
  1125. $c = null; // Current char
  1126. $p = null; // Previous char
  1127. $buffer = ""; // Buffer
  1128. $errors = array();
  1129. $saveBuffer = ""; // Saved buffer
  1130. $state = array(self::T_DOCUMENT); // State stack
  1131. $currentState = self::T_DOCUMENT; // Current state
  1132. $scope = $sDefaultScope; // Current scope
  1133. $stringChar = null; // Current string delimiter char
  1134. $isFilterWs = true; // Filter double whitespaces? Will get disabled for comments, selectors, etc.
  1135. $selectors = array(); // Array with collected selectors
  1136. $importUrl = ""; // @import Url
  1137. $line = 1; // Line
  1138. $r = array(); // Return value
  1139. /*
  1140. * Prepare: normalize line endings
  1141. */
  1142. $css = str_replace("\r\n", "\n", $css); // Windows to Unix line endings
  1143. $css = str_replace("\r", "\n", $css); // Mac to Unix line endings
  1144. /**
  1145. * Parse:
  1146. */
  1147. for ($i = 0, $l = strlen($css); $i < $l; $i++)
  1148. {
  1149. // Set the current Char
  1150. $c = substr($css, $i, 1);
  1151. // Increments line number on line endings
  1152. if ($c == "\n")
  1153. {
  1154. $line++;
  1155. }
  1156. // Whitespace handling
  1157. if ($isFilterWs && strpos($sWhitespaceChars, $c) !== false)
  1158. {
  1159. // Filter double whitespaces if the previous char is also a whitespace
  1160. if (strpos($sWhitespaceChars, $p) !== false)
  1161. {
  1162. continue;
  1163. }
  1164. // Normalize whitespace chars to space
  1165. elseif ($c != " " && strpos($sWhitespaceChars, $c) !== false)
  1166. {
  1167. $c = " ";
  1168. }
  1169. }
  1170. $buffer .= $c;
  1171. // Extended processing only if the current char is a token char
  1172. if (strpos($sTokenChars, $c) !== false)
  1173. {
  1174. // Set the current state
  1175. $currentState = $state[count($state) - 1];
  1176. /*
  1177. * Start of comment
  1178. *
  1179. * The current buffer will get saved and restored at the end of the comment because comments are
  1180. * allowed within many parsable elements.
  1181. */
  1182. if ($p == "/" && $c == "*" && $currentState != self::T_STRING && $currentState != self::T_COMMENT)
  1183. {
  1184. $saveBuffer = substr($buffer, 0, -2); // Save the current buffer
  1185. $buffer = $p . $c;
  1186. $isFilterWs = false;
  1187. array_push($state, self::T_COMMENT);
  1188. }
  1189. /*
  1190. * End of comment
  1191. */
  1192. elseif ($p == "*" && $c == "/" && $currentState == self::T_COMMENT)
  1193. {
  1194. $r[] = array(self::T_COMMENT, trim($buffer));
  1195. $buffer = $saveBuffer; // Restore the buffer
  1196. $isFilterWs = true;
  1197. array_pop($state);
  1198. }
  1199. /*
  1200. * Start of string
  1201. */
  1202. elseif (($c == "\"" || $c == "'") && $currentState != self::T_STRING && $currentState != self::T_COMMENT && $currentState != self::T_STRING_URL)
  1203. {
  1204. $stringChar = $c;
  1205. $isFilterWs = false;
  1206. array_push($state, self::T_STRING);
  1207. }
  1208. /**
  1209. * Escaped LF in string => remove escape backslash a…

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