Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.557
diff -u -p -r1.557 theme.inc
--- includes/theme.inc	2 Dec 2009 14:56:32 -0000	1.557
+++ includes/theme.inc	16 Dec 2009 00:51:02 -0000
@@ -2234,34 +2234,57 @@ function template_preprocess(&$variables
   $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
   $variables['id'] = $count[$hook]++;
 
-  // Tell all templates where they are located.
-  $variables['directory'] = path_to_theme();
+  // Tell all templates where they are located. Using the global variable is
+  // faster than calling path_to_theme().
+  global $theme_path;
+  $variables['directory'] = $theme_path;
 
   // Initialize html class attribute for the current hook.
   $variables['classes_array'] = array($hook);
 
-  // Initialize attributes for the top-level template entity and its title and
-  // content.
-  $variables['attributes_array'] = array();
-  $variables['title_attributes_array'] = array();
-  $variables['content_attributes_array'] = array();
-
-  // Set default variables that depend on the database.
-  $variables['is_admin']            = FALSE;
-  $variables['is_front']            = FALSE;
-  $variables['logged_in']           = FALSE;
-  if ($variables['db_is_active'] = db_is_active()  && !defined('MAINTENANCE_MODE')) {
-    // Check for administrators.
-    if (user_access('access administration pages')) {
-      $variables['is_admin'] = TRUE;
-    }
-    // Flag front page status.
+  // Merge in variables that don't depend on hook and don't change during a
+  // single page request.
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static = array();
+  isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
+  $default_variables = &$drupal_static[__FUNCTION__];
+  // Global $user object shouldn't change during a page request once rendering
+  // has started, but if there's an edge case where it does, re-fetch the
+  // variables appropriate for the new user.
+  if (!isset($default_variables) || ($user != $default_variables['user'])) {
+    $default_variables = _template_preprocess_default_variables();
+  }
+  $variables += $default_variables;
+}
+
+/**
+ * Returns hook-independant variables to template_preprocess().
+ */
+function _template_preprocess_default_variables() {
+  global $user;
+
+  // Variables that don't depend on a database connection.
+  $variables = array(
+    'attributes_array' => array(),
+    'title_attributes_array' => array(),
+    'content_attributes_array' => array(),
+    'user' => $user,
+    'db_is_active' => db_is_active(),
+  );
+
+  // Variables that depend on a database connection.
+  if ($variables['db_is_active'] && !defined('MAINTENANCE_MODE')) {
+    $variables['is_admin'] = user_access('access administration pages');
     $variables['is_front'] = drupal_is_front_page();
-    // Tell all templates by which kind of user they're viewed.
     $variables['logged_in'] = ($user->uid > 0);
-    // Provide user object to all templates
-    $variables['user'] = $user;
   }
+  else {
+    $variables['is_admin'] = FALSE;
+    $variables['is_front'] = FALSE;
+    $variables['logged_in'] = FALSE;
+  }
+
+  return $variables;
 }
 
 /**
