Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.505
diff -u -p -r1.505 theme.inc
--- includes/theme.inc	17 Aug 2009 19:14:39 -0000	1.505
+++ includes/theme.inc	19 Aug 2009 00:51:52 -0000
@@ -475,6 +475,23 @@ function _theme_build_registry($theme, $
   // Finally, hooks provided by the theme itself.
   _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename));
 
+  // Add 'alter functions' to each theme hook, so that we can run the equivalent
+  // of drupal_alter() on theme output at the end of the theme() function, but
+  // with better performance. Another benefit of storing these functions in the
+  // registry is that modules implementing hook_theme_registry_alter() can
+  // adjust them. This doesn't need to be built one at a time with
+  // _theme_process_registry(), because we're only interested in modules
+  // implementing the alter hooks, since that's the case with other uses of
+  // drupal_alter(). If someone comes up with a convincing reason to let themes
+  // implement alter functions the way they can implement preprocess functions,
+  // then this code would need to move to _theme_process_registry().
+  foreach ($cache as $hook => $info) {
+    $cache[$hook]['alter functions'] = array();
+    foreach (module_implements('theme_' . $hook . '_alter') as $module) {
+      $cache[$hook]['alter functions'][] = $module . '_theme_' . $hook . '_alter';
+    }
+  }
+
   // Let modules alter the registry
   drupal_alter('theme_registry', $cache);
   return $cache;
@@ -672,6 +689,10 @@ function list_themes($refresh = FALSE) {
  *   priority than items in template_files. theme() will then look for these
  *   files, one at a time, and use the first one
  *   that exists.
+ *
+ * Modules can alter the final output from the theme by implementing
+ * - MODULE_theme_HOOK_alter(&$output, $variables, $hook)
+ *
  * @param $hook
  *   The name of the theme function to call. May be an array, in which
  *   case the first hook that actually has an implementation registered
@@ -807,6 +828,18 @@ function theme() {
       }
     }
     $output = $render_function($template_file, $variables);
+
+    // Let 'alter functions' alter the output. Similar to drupal_alter(), but
+    // using the registry as a performance optimization and for greater
+    // flexibility.
+    if (!empty($info['alter functions'])) {
+      foreach ($info['alter functions'] as $alter_function) {
+        // Better performance than just drupal_function_exists().
+        if (function_exists($alter_function) || drupal_function_exists($alter_function)) {
+          $alter_function($output, $variables, $hook);
+        }
+      }
+    }
   }
   // restore path_to_theme()
   $theme_path = $temp;
@@ -1877,7 +1910,7 @@ function template_process(&$variables, $
  *
  * Any changes to variables in this preprocessor should also be changed inside
  * template_preprocess_maintenance_page() to keep all of them consistent.
- * 
+ *
  * @see drupal_render_page
  * @see template_process_page
  * @see page.tpl.php
@@ -1979,8 +2012,8 @@ function template_preprocess_page(&$vari
 /**
  * Process variables for page.tpl.php
  *
- * Perform final addition and modification of variables before passing into 
- * the template. To customize these variables, call drupal_render() on elements 
+ * Perform final addition and modification of variables before passing into
+ * the template. To customize these variables, call drupal_render() on elements
  * in $variables['page'] during THEME_preprocess_page().
  *
  * @see template_preprocess_page()
