diff --git a/NEWS b/NEWS
index 9a80c1ca..db0ba917 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
- Fixed broken numeric entity conversion
- Malformed UTF-8 and non-SGML character detection and cleaning implemented
- API documentation completed
+- Shorthand CSS properties implemented: font
1.0.0beta, released 2006-08-16
- First public release, most functionality implemented. Notable omissions are:
diff --git a/TODO b/TODO
index 3643491a..9d3cc436 100644
--- a/TODO
+++ b/TODO
@@ -5,7 +5,6 @@ Core:
- border-collapse, caption-side, empty-cells, table-layout, vertical-align
- background (and friends)
- border, border-*
- - font
- list-style
- Implement all non-essential attribute transforms
- Microsoft Word HTML cleaning
diff --git a/docs/progress.html b/docs/progress.html
index 80c6a9b1..a2ffb688 100644
--- a/docs/progress.html
+++ b/docs/progress.html
@@ -148,7 +148,7 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
font-size | COMPOSITE(<absolute-size>,
diff --git a/library/HTMLPurifier/AttrDef/Font.php b/library/HTMLPurifier/AttrDef/Font.php
new file mode 100644
index 00000000..7ce21b12
--- /dev/null
+++ b/library/HTMLPurifier/AttrDef/Font.php
@@ -0,0 +1,154 @@
+ true,
+ 'icon' => true,
+ 'menu' => true,
+ 'message-box' => true,
+ 'small-caption' => true,
+ 'status-bar' => true
+ );
+
+ function HTMLPurifier_AttrDef_Font() {
+ $def = HTMLPurifier_CSSDefinition::instance();
+ $this->info['font-style'] = $def->info['font-style'];
+ $this->info['font-variant'] = $def->info['font-variant'];
+ $this->info['font-weight'] = $def->info['font-weight'];
+ $this->info['font-size'] = $def->info['font-size'];
+ $this->info['line-height'] = $def->info['line-height'];
+ $this->info['font-family'] = $def->info['font-family'];
+ }
+
+ function validate($string, $config, &$context) {
+
+ // regular pre-processing
+ $string = $this->parseCDATA($string);
+ if ($string === '') return false;
+
+ // check if it's one of the keywords
+ $lowercase_string = strtolower($string);
+ if (isset($this->system_fonts[$lowercase_string])) {
+ return $lowercase_string;
+ }
+
+ $bits = explode(' ', $string); // bits to process
+ $stage = 0; // this indicates what we're looking for
+ $caught = array(); // which stage 0 properties have we caught?
+ $stage_1 = array('font-style', 'font-variant', 'font-weight');
+ $final = ''; // output
+
+ for ($i = 0, $size = count($bits); $i < $size; $i++) {
+ if ($bits[$i] === '') continue;
+ switch ($stage) {
+
+ // attempting to catch font-style, font-variant or font-weight
+ case 0:
+ foreach ($stage_1 as $validator_name) {
+ if (isset($caught[$validator_name])) continue;
+ $r = $this->info[$validator_name]->validate(
+ $bits[$i], $config, &$context);
+ if ($r !== false) {
+ $final .= $r . ' ';
+ $caught[$validator_name] = true;
+ break;
+ }
+ }
+ // all three caught, continue on
+ if (count($caught) >= 3) $stage = 1;
+ if ($r !== false) break;
+
+ // attempting to catch font-size and perhaps line-height
+ case 1:
+ $found_slash = false;
+ if (strpos($bits[$i], '/') !== false) {
+ list($font_size, $line_height) =
+ explode('/', $bits[$i]);
+ if ($line_height === '') {
+ // ooh, there's a space after the slash!
+ $line_height = false;
+ $found_slash = true;
+ }
+ } else {
+ $font_size = $bits[$i];
+ $line_height = false;
+ }
+ $r = $this->info['font-size']->validate(
+ $font_size, $config, &$context);
+ if ($r !== false) {
+ $final .= $r;
+ // attempt to catch line-height
+ if ($line_height === false) {
+ // we need to scroll forward
+ for ($j = $i + 1; $j < $size; $j++) {
+ if ($bits[$j] === '') continue;
+ if ($bits[$j] === '/') {
+ if ($found_slash) {
+ return false;
+ } else {
+ $found_slash = true;
+ continue;
+ }
+ }
+ $line_height = $bits[$j];
+ break;
+ }
+ } else {
+ // slash already found
+ $found_slash = true;
+ $j = $i;
+ }
+ if ($found_slash) {
+ $i = $j;
+ $r = $this->info['line-height']->validate(
+ $line_height, $config, &$context);
+ if ($r !== false) {
+ $final .= '/' . $r;
+ }
+ }
+ $final .= ' ';
+ $stage = 2;
+ break;
+ }
+ return false;
+
+ // attempting to catch font-family
+ case 2:
+ $font_family =
+ implode(' ', array_slice($bits, $i, $size - $i));
+ $r = $this->info['font-family']->validate(
+ $font_family, $config, &$context);
+ if ($r !== false) {
+ $final .= $r . ' ';
+ // processing completed successfully
+ return rtrim($final);
+ }
+ return false;
+ }
+ }
+ return false;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php
index f1dfad63..9517fdfa 100644
--- a/library/HTMLPurifier/CSSDefinition.php
+++ b/library/HTMLPurifier/CSSDefinition.php
@@ -8,6 +8,7 @@ require_once 'HTMLPurifier/AttrDef/Percentage.php';
require_once 'HTMLPurifier/AttrDef/Multiple.php';
require_once 'HTMLPurifier/AttrDef/TextDecoration.php';
require_once 'HTMLPurifier/AttrDef/FontFamily.php';
+require_once 'HTMLPurifier/AttrDef/Font.php';
/**
* Defines allowed CSS attributes and what their values are.
@@ -165,6 +166,10 @@ class HTMLPurifier_CSSDefinition
array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300',
'400', '500', '600', '700', '800', '900'), false);
+ // MUST be called after other font properties, as it references
+ // a CSSDefinition object
+ $this->info['font'] = new HTMLPurifier_AttrDef_Font();
+
}
}
diff --git a/tests/HTMLPurifier/AttrDef/CSSTest.php b/tests/HTMLPurifier/AttrDef/CSSTest.php
index 897c09e4..efe69873 100644
--- a/tests/HTMLPurifier/AttrDef/CSSTest.php
+++ b/tests/HTMLPurifier/AttrDef/CSSTest.php
@@ -60,6 +60,7 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('text-decoration:underline;');
$this->assertDef('font-family:sans-serif;');
$this->assertDef('font-family:Gill, \'Times New Roman\', sans-serif;');
+ //$this->assertDef('font:12px serif;');
// duplicates
$this->assertDef('text-align:right;text-align:left;',
diff --git a/tests/HTMLPurifier/AttrDef/FontTest.php b/tests/HTMLPurifier/AttrDef/FontTest.php
new file mode 100644
index 00000000..18ce3bae
--- /dev/null
+++ b/tests/HTMLPurifier/AttrDef/FontTest.php
@@ -0,0 +1,36 @@
+def = new HTMLPurifier_AttrDef_Font();
+
+ // hodgepodge of usage cases from W3C spec, but " -> '
+ $this->assertDef('12px/14px sans-serif');
+ $this->assertDef('80% sans-serif');
+ $this->assertDef('x-large/110% \'New Century Schoolbook\', serif');
+ $this->assertDef('bold italic large Palatino, serif');
+ $this->assertDef('normal small-caps 120%/120% fantasy');
+ $this->assertDef('300 italic 1.3em/1.7em \'FB Armada\', sans-serif');
+ $this->assertDef('600 9px Charcoal');
+ $this->assertDef('600 9px/ 12px Charcoal', '600 9px/12px Charcoal');
+
+ // spacing
+ $this->assertDef('12px / 14px sans-serif', '12px/14px sans-serif');
+
+ // system fonts
+ $this->assertDef('menu');
+
+ $this->assertDef('800', false);
+ $this->assertDef('600 9px//12px Charcoal', false);
+
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/tests/index.php b/tests/index.php
index 2c605fb8..7ea6cf94 100644
--- a/tests/index.php
+++ b/tests/index.php
@@ -75,6 +75,7 @@ $test_files[] = 'AttrDef/FontFamilyTest.php';
$test_files[] = 'AttrDef/HostTest.php';
$test_files[] = 'AttrDef/IPv4Test.php';
$test_files[] = 'AttrDef/IPv6Test.php';
+$test_files[] = 'AttrDef/FontTest.php';
$test_files[] = 'IDAccumulatorTest.php';
$test_files[] = 'TagTransformTest.php';
$test_files[] = 'AttrTransform/LangTest.php';
|