--- htmlpurifier.module.orig	2010-06-04 09:44:15.000000000 -0700
+++ htmlpurifier.module	2010-06-08 07:29:56.000000000 -0700
@@ -92,6 +92,89 @@ function htmlpurifier_filter_tips($delta
   }
 }
 
+/**
+ * Implementation of hook_nodeapi().
+ */
+function htmlpurifier_nodeapi(&$node, $op, $a3, $a4) {
+  if ($op == 'view') {
+
+    // Should we load CSS cache data from teaser or body?
+    if ($a3 == TRUE) {
+      _htmlpurifier_add_css( $node->content['teaser']['#value'], $node->nid );
+    }
+    else {
+      _htmlpurifier_add_css( $node->content['body']['#value'], $node->nid );
+    }
+  }
+  // @todo: Deal with CCK fields - probably needs to go in op alter?
+}
+
+/**
+ * Helper function for hook_nodeapi
+ *  Finds extracted style blocks based on a cache link left by hook_filter
+ *  Aggregates the extracted style blocks and adds them to the document head
+ *  Also removes the cache link left in hook_filter to the CSS cache
+ *
+ * @param string &$field
+ *    Field to process, this should be the actual field value
+ *      ex. $node->content['body']['#value']
+ *
+ * @param int $nid
+ *    Node ID of the node to which these stylesheets belong
+ *    Since filters don't know their node context, we have to use a token
+ *      to generate the stylesheet scope, and replace it in hook_nodeapi
+ */
+function _htmlpurifier_add_css( &$field, $nid ) {
+
+  // Some basic validation to assure we really got a rendered field
+  if (!is_string($field)) {
+    return;
+  }
+
+  $cache_matches = array();
+  $cache_match = preg_match('#<!-- HTML Purifier Cache \#([-\w]*:[\w]*) -->#', $field, $cache_matches);
+
+  // If there's an HTML Purifier Cache #, we need to load CSSTidy blocks
+  if ($cache_match == 1) {
+    $cid = 'css:' . $cache_matches[1];
+    $old = cache_get($cid, 'cache_htmlpurifier');
+
+    // We should always have some cached style blocks to load, but if we don't, just bail
+    if ($old) {
+      $styles = array();
+      $style_rendered = '';
+      foreach($old->data as $i => $style) {
+
+        // Replace Node ID tokens if necessary, otherwise use cached CSSTidy blocks
+        if (strpos($style, '[%HTMLPURIFIER:NID%]') !== FALSE) {
+          $styles[$i] = str_replace('[%HTMLPURIFIER:NID%]', (int) $nid, $style);
+        }
+        else {
+          $styles[$i] = $style;
+        }
+
+        // Save any CSSTidy blocks we find to be rendered in the document head
+        if (!empty($style)) {
+          $style_rendered .= $styles[$i] . "\n";
+        }
+      }
+
+      // Add the rendered stylesheet to the document header
+      if ($style_rendered != '') {
+        drupal_set_html_head('<style type="text/css">' ."\n". '<!--' ."\n". $style_rendered . '--></style>');
+      }
+
+      // Remove the HTML Purifier cache key from the field argument
+      $field = str_replace($cache_matches[0], '', $field);
+
+      // If we had to update CSSTidy blocks, cache the results
+      if ($old->data != $styles) {
+        cache_set($cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT);
+      }
+    }
+  }
+}
+
 
 
 // -- INTERNAL FUNCTIONS ---------------------------------------------------- //
@@ -121,8 +204,44 @@ function _htmlpurifier_process($text, $f
   
   _htmlpurifier_load();
   $config = _htmlpurifier_get_config($format);
+
+  // If ExtractStyleBlocks is enabled, we'll need to do a bit more for CSSTidy
+  $config_extractstyleblocks = $config->get('Filter.ExtractStyleBlocks');
+
+  // Maybe this works if CSSTidy is at root? CSSTidy could be other places though
+  if ($config_extractstyleblocks == true) {
+    // If CSSTidy module is installed, it should have a copy we can use
+    $csstidy_path = drupal_get_path('module', 'csstidy') .'/csstidy';
+
+    // Some future-proofing for library path
+    if (function_exists('libraries_get_path')) {
+      $csstidy_library = libraries_get_path('csstidy');
+      if (file_exists("$csstidy_library/class.csstidy.php")) {
+        $csstidy_path = $csstidy_library;
+      }
+    }
+
+    // Load CSSTidy if we can find it
+    if (file_exists("$csstidy_path/class.csstidy.php")) {
+      require_once "$csstidy_path/class.csstidy.php";
+    }
+  }
+
   $purifier = new HTMLPurifier($config);
   $ret = $purifier->purify($text);
+
+  // If using Filter.ExtractStyleBlocks we need to handle the CSSTidy output
+  if ($config_extractstyleblocks == true) {
+
+    // We're only going to bother if we're caching! - no caching? no style blocks!
+    if ($cache) {
+
+      // Get style blocks, cache them, and help hook_nodeapi find the cache
+      $styles = $purifier->context->get('StyleBlocks');
+      cache_set('css:' . $cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT);
+      $ret = '<!-- HTML Purifier Cache #' . $cid . ' -->' . $ret;
+    }
+  }
   
   if ($cache) cache_set($cid, $ret, 'cache_htmlpurifier', CACHE_PERMANENT);
   
