Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.206
diff -u -p -r1.206 update.php
--- update.php	28 Nov 2006 20:52:51 -0000	1.206
+++ update.php	3 Dec 2006 17:52:07 -0000
@@ -785,6 +785,9 @@ if (($access_check == FALSE) || ($user->
   update_fix_watchdog();
   update_fix_sessions();
 
+  // Clear any cached CSS files, in case any module updates its CSS as well.
+  drupal_clear_css_cache();
+
   $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
   switch ($op) {
     case 'Update':
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.241
diff -u -p -r1.241 block.module
--- modules/block/block.module	1 Dec 2006 22:47:53 -0000	1.241
+++ modules/block/block.module	3 Dec 2006 17:52:08 -0000
@@ -205,7 +205,7 @@ function block_admin_display($theme = NU
   global $theme_key, $custom_theme;
 
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'block') .'/block.css');
+  drupal_add_css(drupal_get_path('module', 'block') .'/block.css', 'module', 'all', FALSE);
 
   // If non-default theme configuration has been selected, set the custom theme.
   if ($theme) {
Index: modules/color/color.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/color/color.module,v
retrieving revision 1.9
diff -u -p -r1.9 color.module
--- modules/color/color.module	30 Nov 2006 17:41:03 -0000	1.9
+++ modules/color/color.module	3 Dec 2006 17:52:08 -0000
@@ -41,7 +41,7 @@ function _color_page_alter(&$vars) {
   // Override stylesheet
   $path = variable_get('color_'. $theme_key .'_stylesheet', NULL);
   if ($path) {
-    $vars['css']['theme'] = array($path => array('path' => $path, 'media' => 'all'));
+    $vars['css']['all']['theme'][$path] = TRUE;
     $vars['styles'] = drupal_get_css($vars['css']);
   }
 
@@ -88,11 +88,11 @@ function color_scheme_form($theme) {
   $info = color_get_info($theme);
 
   // Add Farbtastic color picker
-  drupal_add_css('misc/farbtastic/farbtastic.css');
+  drupal_add_css('misc/farbtastic/farbtastic.css', 'module', 'all', FALSE);
   drupal_add_js('misc/farbtastic/farbtastic.js');
 
   // Add custom CSS/JS
-  drupal_add_css($base .'/color.css', 'module');
+  drupal_add_css($base .'/color.css', 'module', 'all', FALSE);
   drupal_add_js($base .'/color.js');
   drupal_add_js(array('color' => array(
     'reference' => color_get_palette($theme, true)
Index: modules/help/help.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.module,v
retrieving revision 1.66
diff -u -p -r1.66 help.module
--- modules/help/help.module	1 Dec 2006 22:47:53 -0000	1.66
+++ modules/help/help.module	3 Dec 2006 17:52:08 -0000
@@ -37,7 +37,7 @@ function help_menu($may_cache) {
  */
 function help_main() {
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'help') .'/help.css');
+  drupal_add_css(drupal_get_path('module', 'help') .'/help.css', 'module', 'all', FALSE);
 
   $output = t('
   <h2>Help topics</h2>
Index: modules/profile/profile.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/profile/profile.module,v
retrieving revision 1.182
diff -u -p -r1.182 profile.module
--- modules/profile/profile.module	1 Dec 2006 23:17:26 -0000	1.182
+++ modules/profile/profile.module	3 Dec 2006 17:52:08 -0000
@@ -410,7 +410,7 @@ function profile_admin_overview() {
  */
 function profile_browse() {
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'profile') .'/profile.css');
+  drupal_add_css(drupal_get_path('module', 'profile') .'/profile.css', 'module', 'all', FALSE);
 
   $name = arg(1);
   list(,,$value) = explode('/', $_GET['q'], 3);
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.204
diff -u -p -r1.204 search.module
--- modules/search/search.module	1 Dec 2006 22:47:53 -0000	1.204
+++ modules/search/search.module	3 Dec 2006 17:52:08 -0000
@@ -1076,7 +1076,7 @@ function theme_search_block_form($form) 
  */
 function search_data($keys = NULL, $type = 'node') {
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'search') .'/search.css');
+  drupal_add_css(drupal_get_path('module', 'search') .'/search.css', 'module', 'all', FALSE);
 
   if (isset($keys)) {
     if (module_hook($type, 'search')) {
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.416
diff -u -p -r1.416 system.module
--- modules/system/system.module	29 Nov 2006 23:12:41 -0000	1.416
+++ modules/system/system.module	3 Dec 2006 17:52:08 -0000
@@ -231,7 +231,7 @@ function system_menu($may_cache) {
     $items[] = array(
       'path' => 'admin/settings/page-caching',
       'title' => t('Page caching'),
-      'description' => t('Enable or disable page caching for anonymous users.'),
+      'description' => t('Enable or disable page caching for anonymous users, and enable or disable CSS caching.'),
       'callback' => 'drupal_get_form',
       'callback arguments' => array('system_page_caching_settings'));
     $items[] = array(
@@ -674,6 +674,19 @@ function system_page_caching_settings() 
     '#options' => $period,
     '#description' => t('On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.')
   );
+  $public_downloads = variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC;
+  $is_writable = is_writable(file_directory_path());
+  $form['cache_css'] = array(
+    '#type' => 'select',
+    '#title' => t('Cache and compress CSS files'),
+    '#default_value' => variable_get('cache_css', FALSE) && $public_downloads && $is_writable,
+    '#disabled' => !($public_downloads && $is_writable),
+    '#options' => array(t('Disabled'), t('Enabled')),
+    '#description' => t("A lot of Drupal modules include their own CSS files. When these modules are enabled, each module's CSS file adds an additional HTTP request to the page, which can slow down the loading time of each page. These HTTP requests can increase the server load. This option is disabled if you have not set up your files directory, or if your download method is set to private. It is recommended to only turn this option on when your site is in production, as leaving it on can interfere with theming development."),
+  );
+
+  $form['#submit']['system_settings_form_submit'] = array();
+  $form['#submit']['drupal_clear_css_cache'] = array();
 
   return system_settings_form($form);
 }
@@ -1102,6 +1115,7 @@ function system_settings_form_submit($fo
   else {
     drupal_set_message(t('The configuration options have been saved.'));
   }
+
   menu_rebuild();
 }
 
@@ -1109,6 +1123,8 @@ function system_settings_form_submit($fo
  * Menu callback; displays a listing of all themes.
  */
 function system_themes() {
+  // Clear cached CSS files.
+  drupal_clear_css_cache();
   $themes = system_theme_data();
   ksort($themes);
 
@@ -1485,6 +1501,10 @@ function system_modules_submit($form_id,
   if ($dependencies && !isset($form_values['confirm'])) {
     return FALSE;
   }
+
+  // Clear the CSS cache.
+  drupal_clear_css_cache();
+
   return 'admin/build/modules';
 }
 
Index: modules/tracker/tracker.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/tracker/tracker.module,v
retrieving revision 1.139
diff -u -p -r1.139 tracker.module
--- modules/tracker/tracker.module	1 Dec 2006 22:47:53 -0000	1.139
+++ modules/tracker/tracker.module	3 Dec 2006 17:52:08 -0000
@@ -74,7 +74,7 @@ function tracker_track_user() {
  */
 function tracker_page($uid = 0) {
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'tracker') .'/tracker.css');
+  drupal_add_css(drupal_get_path('module', 'tracker') .'/tracker.css', 'module', 'all', FALSE);
 
   if ($uid) {
     $sql = 'SELECT DISTINCT(n.nid), n.title, n.type, n.changed, n.uid, u.name, l.last_comment_timestamp AS last_post, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid LEFT JOIN {comments} c ON n.nid = c.nid AND (c.status = %d OR c.status IS NULL) WHERE n.status = 1 AND (n.uid = %d OR c.uid = %d) ORDER BY last_post DESC';
Index: modules/watchdog/watchdog.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/watchdog/watchdog.module,v
retrieving revision 1.163
diff -u -p -r1.163 watchdog.module
--- modules/watchdog/watchdog.module	1 Dec 2006 23:17:26 -0000	1.163
+++ modules/watchdog/watchdog.module	3 Dec 2006 17:52:09 -0000
@@ -53,7 +53,7 @@ function watchdog_menu($may_cache) {
   else {
     if (arg(0) == 'admin' && arg(1) == 'logs') {
       // Add the CSS for this module
-      drupal_add_css(drupal_get_path('module', 'watchdog') .'/watchdog.css');
+      drupal_add_css(drupal_get_path('module', 'watchdog') .'/watchdog.css', 'module', 'all', FALSE);
     }
   }
 
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.593
diff -u -p -r1.593 common.inc
--- includes/common.inc	30 Nov 2006 08:13:31 -0000	1.593
+++ includes/common.inc	3 Dec 2006 17:52:09 -0000
@@ -1362,19 +1362,27 @@ function drupal_add_link($attributes) {
  * Adds a CSS file to the stylesheet queue.
  *
  * @param $path
- *   The path to the CSS file relative to the base_path(), e.g., /modules/devel/devel.css.
+ *   (optional) The path to the CSS file relative to the base_path(), e.g., /modules/devel/devel.css.
  * @param $type
- *   The type of stylesheet that is being added. Types are: core, module, and theme.
+ *   (optional) The type of stylesheet that is being added. Types are: core, module, and theme.
  * @param $media
  *   (optional) The media type for the stylesheet, e.g., all, print, screen.
+ * @param $cache
+  *   (optional) Should this CSS file be cached if cache CSS setting is turned on?
  * @return
  *   An array of CSS files.
  */
-function drupal_add_css($path = NULL, $type = 'module', $media = 'all') {
-  static $css = array('core' => array(), 'module' => array(), 'theme' => array());
+function drupal_add_css($path = NULL, $type = 'module', $media = 'all', $cache = TRUE) {
+  static $css = array();
 
-  if (!is_null($path)) {
-    $css[$type][$path] = array('path' => $path, 'media' => $media);
+  // Create an array of CSS files for each media type first, since each type needs to be served
+  // to the browser differently.
+  if (isset($path)) {
+    // This check is necessary to ensure proper cascading of styles and is faster than an asort().
+    if (!isset($css[$media])) {
+      $css[$media] = array('core' => array(), 'module' => array(), 'theme' => array());
+    }
+    $css[$media][$type][$path] = $cache;
   }
 
   return $css;
@@ -1392,13 +1400,34 @@ function drupal_add_css($path = NULL, $t
  */
 function drupal_get_css($css = NULL) {
   $output = '';
-  if (is_null($css)) {
+  if (!isset($css)) {
     $css = drupal_add_css();
   }
 
-  foreach ($css as $type) {
-    foreach ($type as $file) {
-      $output .= '<style type="text/css" media="'. $file['media'] .'">@import "'. base_path() . $file['path'] ."\";</style>\n";
+  $cache_css = variable_get('cache_css', FALSE);
+  $directory_path = file_directory_path();
+  $is_writable = is_writable($directory_path) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
+
+  foreach ($css as $media => $types) {
+    if ($is_writable && $cache_css) {
+      $filename = md5(serialize($types)) .'.css';
+      $path = $directory_path .'/css/';
+
+      if (!file_exists($path . $filename)) {
+        drupal_build_css_cache($types, $filename);
+      }
+
+      $output .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $path . $filename .'";</style>'. "\n";
+    }
+
+    // If CSS caching is off, we still need to ouput the styles.
+    // Additionally, go through any remaining styles if CSS caching is on and output the non-cached ones.
+    foreach ($types as $type) {
+      foreach ($type as $file => $cache) {
+        if (!$cache || !($is_writable && $cache_css)) {
+          $output .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $file .'";</style>' ."\n";
+        }
+      }
     }
   }
 
@@ -1406,6 +1435,67 @@ function drupal_get_css($css = NULL) {
 }
 
 /**
+ * Aggregate and optimize CSS files, putting them in the files directory.
+ *
+ * @param $types
+ *   An array of types of CSS files (e.g., screen, print) to aggregate and compress into one file.
+ * @param $filename
+ *   The name of the aggregate CSS file.
+ * @return
+ *   The name of the CSS file.
+ */
+function drupal_build_css_cache($types, $filename) {
+  $data = '';
+
+  // Create the css/ within the files folder.
+  file_check_directory(file_create_path('css'), FILE_CREATE_DIRECTORY);
+
+  // Build aggregate CSS file.
+  foreach ($types as $type) {
+    foreach ($type as $file => $cache) {
+      if ($cache) {
+        $contents = file_get_contents($file);
+        // Return the path to where this CSS file originated from, stripping off the name of the file at the end of the path.
+        $path = base_path() . substr($file, 0, strrpos($file, '/')) .'/';
+        // Fix all paths within this CSS file, ignoring absolute paths.
+        $contents = preg_replace('/url\(([\'"]?)(?![a-z]+:)/i', 'url(\1'. $path . '\2', $contents);
+        // Fix any @import that don't use url() and is not absoslute.
+        $data .= preg_replace('/@import\s*([\'"]?)(?![a-z]+:)/i', '@import \1'. $path . '\2', $contents);
+      }
+    }
+  }
+
+  // @import rules must proceed any other style, so we move those to the top.
+  $regexp = '/@import[^;]+;/i';
+  preg_match_all($regexp, $data, $matches);
+  $data = preg_replace($regexp, '', $data);
+  $data = implode('', $matches[0]) . $data;
+
+  // Perform some safe CSS optimizations.
+  $data = preg_replace('<
+    \s*([@{}:;\)])\s* |          # Remove whitespace around separators.
+    /\*([^*\\\\]|\*(?!/))+\*/ |  # Remove comments that are not CSS hacks.
+    [\n\r]                       # Remove line breaks.
+    >x', '\1', $data);
+  
+  // Allow modules to add in additional compression logic.
+  foreach (module_implements('compress_css') as $module) {
+    $function = $module .'_compress_css';
+    $function($data);
+  }
+
+  // Create the CSS file.
+  file_save_data($data, file_create_path('css') .'/'. $filename, FILE_EXISTS_REPLACE);
+}
+
+/**
+ * Delete all cached CSS files.
+ */
+function drupal_clear_css_cache() {
+  file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+}
+
+/**
  * Add a JavaScript file, setting or inline code to the page.
  *
  * The behavior of this function depends on the parameters it is called with.
Index: includes/locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.98
diff -u -p -r1.98 locale.inc
--- includes/locale.inc	1 Dec 2006 22:47:52 -0000	1.98
+++ includes/locale.inc	3 Dec 2006 17:52:09 -0000
@@ -1284,7 +1284,7 @@ function _locale_export_remove_plural($e
  */
 function _locale_string_language_list($translation) {
   // Add CSS
-  drupal_add_css(drupal_get_path('module', 'locale') .'/locale.css');
+  drupal_add_css(drupal_get_path('module', 'locale') .'/locale.css', 'module', 'all', FALSE);
 
   $languages = locale_supported_languages(FALSE, TRUE);
   unset($languages['name']['en']);
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.328
diff -u -p -r1.328 theme.inc
--- includes/theme.inc	29 Nov 2006 20:39:37 -0000	1.328
+++ includes/theme.inc	3 Dec 2006 17:52:09 -0000
@@ -406,7 +406,7 @@ function theme_page($content) {
 
 function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) {
   drupal_set_header('Content-Type: text/html; charset=utf-8');
-  drupal_add_css('misc/maintenance.css', 'core');
+  drupal_add_css('misc/maintenance.css', 'core', 'all', FALSE);
   drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
 
   $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
