Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1077
diff -u -p -r1.1077 common.inc
--- includes/common.inc	4 Jan 2010 23:08:34 -0000	1.1077
+++ includes/common.inc	6 Jan 2010 04:28:24 -0000
@@ -3281,16 +3281,8 @@ function drupal_get_css($css = NULL) {
   // If CSS preprocessing is off, we still need to output the styles.
   // Additionally, go through any remaining styles if CSS preprocessing is on
   // and output the non-cached ones.
-  $css_element = array(
-    '#tag' => 'link',
-    '#attributes' => array(
-      'type' => 'text/css',
-      'rel' => 'stylesheet',
-    ),
-  );
-  $rendered_css = array();
-  $inline_css = '';
-  $external_css = '';
+  $files = array();
+  $inline = array();
   $preprocess_items = array();
   foreach ($css as $data => $item) {
     // Loop through each of the stylesheets, including them appropriately based
@@ -3299,28 +3291,22 @@ function drupal_get_css($css = NULL) {
       case 'file':
         // Depending on whether aggregation is desired, include the file.
         if (!$item['preprocess'] || !($is_writable && $preprocess_css)) {
-          $element = $css_element;
-          $element['#attributes']['media'] = $item['media'];
-          $element['#attributes']['href'] = file_create_url($item['data']) . $query_string;
-          $rendered_css[] = theme('html_tag', array('element' => $element));
+          $files[] = array('media' => $item['media'], 'href' => file_create_url($item['data']) . $query_string, 'external' => FALSE);
         }
         else {
           $preprocess_items[$item['media']][] = $item;
           // Mark the position of the preprocess element,
           // it should be at the position of the first preprocessed file.
-          $rendered_css['preprocess'] = '';
+          $files['preprocess_' . $item['media']] = NULL;
         }
         break;
       case 'inline':
         // Include inline stylesheets.
-        $inline_css .= drupal_load_stylesheet_content($item['data'], $item['preprocess']);
+        $inline[] = drupal_load_stylesheet_content($item['data'], $item['preprocess']);
         break;
       case 'external':
         // Preprocessing for external CSS files is ignored.
-        $element = $css_element;
-        $element['#attributes']['media'] = $item['media'];
-        $element['#attributes']['href'] = $item['data'];
-        $external_css .= theme('html_tag', array('element' => $element));
+        $files[] = array('media' => $item['media'], 'href' => $item['data'], 'external' => TRUE);
         break;
     }
   }
@@ -3329,24 +3315,13 @@ function drupal_get_css($css = NULL) {
     foreach ($preprocess_items as $media => $items) {
       // Prefix filename to prevent blocking by firewalls which reject files
       // starting with "ad*".
-      $element = $css_element;
-      $element['#attributes']['media'] = $media;
       $filename = 'css_' . md5(serialize($items) . $query_string) . '.css';
-      $element['#attributes']['href'] = file_create_url(drupal_build_css_cache($items, $filename));
-      $rendered_css['preprocess'] .= theme('html_tag', array('element' => $element));
+      $files['preprocess_' . $media] .= array('media' => $item['media'], 'href' => file_create_url(drupal_build_css_cache($items, $filename)), 'external' => FALSE);
     }
   }
-  // Enclose the inline CSS with the style tag if required.
-  if (!empty($inline_css)) {
-    $element = $css_element;
-    $element['#tag'] = 'style';
-    $element['#value'] = $inline_css;
-    unset($element['#attributes']['rel']);
-    $inline_css = "\n" . theme('html_tag', array('element' => $element));
-  }
 
-  // Output all the CSS files with the inline stylesheets showing up last.
-  return implode($rendered_css) . $external_css . $inline_css;
+  // Output all the CSS files.
+  return theme('stylesheets', array('files' => $files, 'inline' => $inline));
 }
 
 /**
@@ -5485,6 +5460,9 @@ function drupal_common_theme() {
     'html_tag' => array(
       'render element' => 'element',
     ),
+    'stylesheets' => array(
+      'variables' => array('files' => array(), 'inline' => array()),
+    ),
     // from theme.maintenance.inc
     'maintenance_page' => array(
       'variables' => array('content' => NULL, 'show_messages' => TRUE),
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.563
diff -u -p -r1.563 theme.inc
--- includes/theme.inc	5 Jan 2010 18:56:48 -0000	1.563
+++ includes/theme.inc	6 Jan 2010 04:28:24 -0000
@@ -2033,6 +2033,150 @@ function theme_html_tag($variables) {
 }
 
 /**
+ * Generate the LINK and STYLE tags for adding CSS stylesheets to the page.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - files: An array of CSS files to include. Each item in the array has the
+ *     following keys:
+ *     - media: The media for which the CSS file is appropriate.
+ *     - href: The URL of the CSS file.
+ *     - external: Boolean. TRUE if the CSS file is external to the website (if
+ *       it was added to drupal_add_css() using 'external' for the type option).
+ *   - inline: An array of inline CSS content. Each item in the array is a CSS
+ *     string.
+ *   - max_tags: (optional) The maximum number of combined LINK and STYLE tags
+ *     to output. If not specified, defaults to 31. This is to work around IE's
+ *     limitation of only being able to process this many total stylesheet
+ *     tags. A preprocess function can set this variable to something smaller to
+ *     accomodate a page that outputs additional LINK (rel="stylesheet") or
+ *     STYLE tags. LINK tags with a "rel" attribute of something other than
+ *     "stylesheet" doesn't count against IE's limit, so there is no need for a
+ *     preprocess function to decrease this number to accomodate non-stylesheet
+ *     LINK tags. This function includes as many stylesheets as it can using
+ *     LINK tags, and combines the rest into groups of upto 31 @import
+ *     statements per STYLE tag. Site administrators are encouraged to enable
+ *     the CSS aggregation setting on the /admin/config/development/performance
+ *     page once the website is no longer undergoing active theme development.
+ *     When aggregation is enabled, the total number of stylesheets should be
+ *     much smaller than this limit, so all of them can be included using a LINK
+ *     tag.
+ *
+ * @ingroup themeable
+ */
+function theme_stylesheets($variables) {
+  $output = '';
+
+  // Order all the external CSS files to be after the non-external ones.
+  // @todo Add a comment explaining why.
+  $internal = array();
+  $external = array();
+  foreach ($variables['files'] as $file) {
+    if ($file['external']) {
+      $external[] = $file;
+    }
+    else {
+      $internal[] = $file;
+    }
+  }
+  $files = array_merge($internal, $external);
+
+  // Default max_tags to 31, if it isn't specified. Then decrement if there is
+  // inline CSS since that will use up one.
+  $max_tags = !empty($variables['max_tags']) ? $variables['max_tags'] : 31;
+  if (!empty($variables['inline'])) {
+    $max_tags--;
+  }
+
+  // Without changing their order, split $files into groups, where each group
+  // contains files of the same media type and each group is restricted to 31
+  // items. This enables the use of STYLE tags on a per-group basis if needed
+  // to stay within the $max_tags limit. We must ensure that each file within a
+  // group is for the same media, because IE7 does not support media declaration
+  // in the @import statement, so the media declaration must be on the STYLE
+  // tag.
+  $file_groups = array();
+  $file_group = array();
+  $file_group_media = NULL;
+  $file_group_counts = array();
+  foreach ($files as $file) {
+    if (count($file_group) == 31 || ($file_group_media && $file['media'] != $file_group_media)) {
+      if (!empty($file_group)) {
+        $file_groups[] = $file_group;
+        $file_group_counts[] = count($file_group);
+        $file_group = array();
+      }
+      $file_group_media = $file['media'];
+    }
+    $file_group[] = $file;
+  }
+  if (!empty($file_group)) {
+    $file_groups[] = $file_group;
+    $file_group_counts[] = count($file_group);
+  }
+
+  // Split file groups into ones that can use a LINK tag vs. ones that must
+  // use a STYLE tag. After this code, $file_groups will contain files that can
+  // use a LINK tag and $file_groups_requiring_style_tag will contain the ones
+  // that must use a STYLE tag.
+  $file_groups_requiring_style_tag = array();
+  while (!empty($file_groups) && array_sum($file_group_counts) > $max_tags) {
+    $file_groups_requiring_style_tag[] = array_pop($file_groups);
+    array_pop($file_group_counts);
+    $max_tags--;
+  }
+  $file_groups_requiring_style_tag = array_reverse($file_groups_requiring_style_tag);
+
+  // Defaults for LINK and STYLE elements.
+  $link_element_defaults = array(
+    '#tag' => 'link',
+    '#attributes' => array(
+      'type' => 'text/css',
+      'rel' => 'stylesheet',
+    ),
+  );
+  $style_element_defaults = array(
+    '#tag' => 'style',
+    '#attributes' => array(
+      'type' => 'text/css',
+    ),
+  );
+
+  // Add the LINK tags.
+  foreach ($file_groups as $group) {
+    foreach ($group as $file) {
+      $element = $link_element_defaults;
+      $element['#attributes']['media'] = $file['media'];
+      $element['#attributes']['href'] = $file['href'];
+      $output .= theme('html_tag', array('element' => $element));
+    }
+  }
+
+  // Add the STYLE tags.
+  if (!empty($file_groups_requiring_style_tag)) {
+    foreach ($file_groups_requiring_style_tag as $group) {
+      $import = '';
+      foreach ($group as $file) {
+        $import .= '@import url("' . $file['href'] . '");' . "\n";
+      }
+      $element = $style_element_defaults;
+      $element['#value'] = $import;
+      $element['#attributes']['media'] = $group[0]['media'];
+      $output .= theme('html_tag', array('element' => $element));
+    }
+  }
+
+  // Add inline CSS content.
+  if (!empty($variables['inline'])) {
+    $element = $style_element_defaults;
+    $element['#value'] = implode($variables['inline']);
+    $output .= "\n" . theme('html_tag', array('element' => $element));
+  }
+
+  return $output;
+}
+
+/**
  * Returns code that emits the 'more' link used on blocks.
  *
  * @param $variables
