BackgroundPosition.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <?php
  2. /* W3C says:
  3. [ // adjective and number must be in correct order, even if
  4. // you could switch them without introducing ambiguity.
  5. // some browsers support that syntax
  6. [
  7. <percentage> | <length> | left | center | right
  8. ]
  9. [
  10. <percentage> | <length> | top | center | bottom
  11. ]?
  12. ] |
  13. [ // this signifies that the vertical and horizontal adjectives
  14. // can be arbitrarily ordered, however, there can only be two,
  15. // one of each, or none at all
  16. [
  17. left | center | right
  18. ] ||
  19. [
  20. top | center | bottom
  21. ]
  22. ]
  23. top, left = 0%
  24. center, (none) = 50%
  25. bottom, right = 100%
  26. */
  27. /* QuirksMode says:
  28. keyword + length/percentage must be ordered correctly, as per W3C
  29. Internet Explorer and Opera, however, support arbitrary ordering. We
  30. should fix it up.
  31. Minor issue though, not strictly necessary.
  32. */
  33. // control freaks may appreciate the ability to convert these to
  34. // percentages or something, but it's not necessary
  35. /**
  36. * Validates the value of background-position.
  37. */
  38. class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
  39. {
  40. /**
  41. * @type HTMLPurifier_AttrDef_CSS_Length
  42. */
  43. protected $length;
  44. /**
  45. * @type HTMLPurifier_AttrDef_CSS_Percentage
  46. */
  47. protected $percentage;
  48. public function __construct()
  49. {
  50. $this->length = new HTMLPurifier_AttrDef_CSS_Length();
  51. $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
  52. }
  53. /**
  54. * @param string $string
  55. * @param HTMLPurifier_Config $config
  56. * @param HTMLPurifier_Context $context
  57. * @return bool|string
  58. */
  59. public function validate($string, $config, $context)
  60. {
  61. $string = $this->parseCDATA($string);
  62. $bits = explode(' ', $string);
  63. $keywords = array();
  64. $keywords['h'] = false; // left, right
  65. $keywords['v'] = false; // top, bottom
  66. $keywords['ch'] = false; // center (first word)
  67. $keywords['cv'] = false; // center (second word)
  68. $measures = array();
  69. $i = 0;
  70. $lookup = array(
  71. 'top' => 'v',
  72. 'bottom' => 'v',
  73. 'left' => 'h',
  74. 'right' => 'h',
  75. 'center' => 'c'
  76. );
  77. foreach ($bits as $bit) {
  78. if ($bit === '') {
  79. continue;
  80. }
  81. // test for keyword
  82. $lbit = ctype_lower($bit) ? $bit : strtolower($bit);
  83. if (isset($lookup[$lbit])) {
  84. $status = $lookup[$lbit];
  85. if ($status == 'c') {
  86. if ($i == 0) {
  87. $status = 'ch';
  88. } else {
  89. $status = 'cv';
  90. }
  91. }
  92. $keywords[$status] = $lbit;
  93. $i++;
  94. }
  95. // test for length
  96. $r = $this->length->validate($bit, $config, $context);
  97. if ($r !== false) {
  98. $measures[] = $r;
  99. $i++;
  100. }
  101. // test for percentage
  102. $r = $this->percentage->validate($bit, $config, $context);
  103. if ($r !== false) {
  104. $measures[] = $r;
  105. $i++;
  106. }
  107. }
  108. if (!$i) {
  109. return false;
  110. } // no valid values were caught
  111. $ret = array();
  112. // first keyword
  113. if ($keywords['h']) {
  114. $ret[] = $keywords['h'];
  115. } elseif ($keywords['ch']) {
  116. $ret[] = $keywords['ch'];
  117. $keywords['cv'] = false; // prevent re-use: center = center center
  118. } elseif (count($measures)) {
  119. $ret[] = array_shift($measures);
  120. }
  121. if ($keywords['v']) {
  122. $ret[] = $keywords['v'];
  123. } elseif ($keywords['cv']) {
  124. $ret[] = $keywords['cv'];
  125. } elseif (count($measures)) {
  126. $ret[] = array_shift($measures);
  127. }
  128. if (empty($ret)) {
  129. return false;
  130. }
  131. return implode(' ', $ret);
  132. }
  133. }
  134. // vim: et sw=4 sts=4