=== modified file 'includes/common.inc'
--- includes/common.inc	2009-07-27 19:53:17 +0000
+++ includes/common.inc	2009-07-28 00:55:44 +0000
@@ -40,6 +40,21 @@
 define('SAVED_DELETED', 3);
 
 /**
+ * The default weight of system CSS files added to the page.
+ */
+define('CSS_SYSTEM', -100);
+
+/**
+ * The default weight of CSS files added to the page.
+ */
+define('CSS_DEFAULT', 0);
+
+/**
+ * The default weight of theme CSS files added to the page.
+ */
+define('CSS_THEME', 100);
+
+/**
  * The weight of JavaScript libraries, settings or jQuery plugins being
  * added to the page.
  */
@@ -2328,7 +2343,7 @@
  * @param $data
  *   (optional) The stylesheet data to be added, depending on what is passed
  *   through to the $options['type'] parameter:
- *   - 'module' or 'theme': The path to the CSS file relative to the base_path(),
+ *   - 'file': The path to the CSS file relative to the base_path(),
  *     e.g., "modules/devel/devel.css".
  *
  *     Modules should always prefix the names of their CSS files with the
@@ -2345,15 +2360,28 @@
  *     directory. This CSS file should contain overrides for properties which
  *     should be reversed or otherwise different in a right-to-left display.
  *   - 'inline': A string of CSS that should be placed in the given scope. Note
- *     that it is better practice to use 'module' or 'theme' stylesheets, rather
- *     than 'inline' as the CSS would then be aggregated and cached.
+ *     that it is better practice to use 'file' stylesheets, rather than 'inline'
+ *     as the CSS would then be aggregated and cached.
  *
  * @param $options
  *   (optional) A string defining the 'type' of CSS that is being added in the
- *   $data parameter ('module', 'theme' or 'inline'), or an associative array of
- *   additional options, with the following keys:
- *   - 'type': The type of stylesheet that is being added. Types are: 'module',
- *     'theme' or 'inline'. Defaults to 'module'.
+ *   $data parameter ('file'/'inline'), or an array which can have any or all of
+ *   the following keys:
+ *   - 'type': The type of stylesheet being added. Available options are 'file'
+ *     or 'inline'. Defaults to 'file'.
+ *   - 'weight': The weight of the stylesheet specifies the order in which the
+ *     CSS will appear when presented on the page.
+ *
+ *       Available constants are:
+ *       - CSS_SYSTEM: Any system-layer CSS.
+ *       - CSS_DEFAULT: Any module-layer CSS.
+ *       - CSS_THEME: Any theme-layer CSS.
+ *
+ *       If you need to embed a CSS file before any other module's stylesheets,
+ *       for example, you would use CSS_DEFAULT - 1. Note that inline CSS is
+ *       simply appended to the end of the specified scope (region), so they
+ *       always come last.
+ *
  *   - 'media': The media type for the stylesheet, e.g., all, print, screen.
  *     Defaults to 'all'.
  *   - 'preprocess': Allows the CSS to be aggregated and compressed if the
@@ -2385,7 +2413,6 @@
  */
 function drupal_add_css($data = NULL, $options = NULL) {
   $css = &drupal_static(__FUNCTION__, array());
-  global $language;
 
   // Construct the options, taking the defaults into consideration.
   if (isset($options)) {
@@ -2401,25 +2428,26 @@
   // to the browser differently.
   if (isset($data)) {
     $options += array(
-      'type' => 'module',
+      'type' => 'file',
+      'weight' => CSS_DEFAULT,
       'media' => 'all',
-      'preprocess' => TRUE
+      'preprocess' => TRUE,
+      'data' => $data,
     );
-    $media = $options['media'];
-    $type = $options['type'];
-
-    // This check is necessary to ensure proper cascading of styles and is faster than an asort().
-    if (!isset($css[$media])) {
-      $css[$media] = array('module' => array(), 'theme' => array(), 'inline' => array());
-    }
-    $css[$media][$type][$data] = $options['preprocess'];
-
-    // If the current language is RTL, add the CSS file with RTL overrides.
-    if ($type != 'inline' && $language->direction == LANGUAGE_RTL) {
-      $rtl_path = str_replace('.css', '-rtl.css', $data);
-      if (file_exists($rtl_path)) {
-        $css[$media][$type][$rtl_path] = $options['preprocess'];
-      }
+
+    // Always add a tiny value to the weight, to conserve the insertion order.
+    $options['weight'] += count($css) / 1000;
+
+    // Add the data to the CSS array depending on the type.
+    switch ($options['type']) {
+      case 'file':
+        $css[$data] = $options;
+        break;
+      case 'inline':
+        // For inline stylesheets, we don't want to use the $data as the array
+        // key as $data could be a very long string of CSS.
+        $css[] = $options;
+        break;
     }
   }
 
@@ -2453,9 +2481,6 @@
   if (!isset($css)) {
     $css = drupal_add_css();
   }
-  $no_module_preprocess = '';
-  $no_theme_preprocess = '';
-  $no_inline_preprocess = '';
 
   $preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
   $directory = file_directory_path();
@@ -2467,76 +2492,82 @@
   // URL changed.
   $query_string = '?' . substr(variable_get('css_js_query_string', '0'), 0, 1);
 
-  foreach ($css as $media => $types) {
-    // 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.
-    foreach ($types as $type => $information) {
-      if ($type == 'module') {
-        // Setup theme overrides for module styles.
-        $theme_styles = array();
-        foreach (array_keys($css[$media]['theme']) as $theme_style) {
-          $theme_styles[] = basename($theme_style);
-        }
+  // Allow modules to alter the css items.
+  drupal_alter('css', $css);
+
+  // Sort css items according to their weights.
+  uasort($css, 'drupal_sort_weight');
+
+  // Remove the overriden CSS files. Later CSS files override former ones.
+  $previous_item = array();
+  foreach ($css as $key => $item) {
+    if ($item['type'] == 'file') {
+      $basename = basename($item['data']);
+      if (isset($previous_item[$basename])) {
+        // Remove the previous item that shared the same base name.
+        unset($css[$previous_item[$basename]]);
       }
-      foreach ($types[$type] as $data => $preprocess) {
-        // If the theme supplies its own style using the name of the module style, skip its inclusion.
-        // This includes any RTL styles associated with its main LTR counterpart.
-        if ($type == 'module' && in_array(str_replace('-rtl.css', '.css', basename($data)), $theme_styles)) {
-          // Unset the file to prevent its inclusion when CSS aggregation is enabled.
-          unset($types[$type][$data]);
-          continue;
-        }
+      $previous_item[$basename] = $key;
+    }
+  }
+
+  // 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.
+  $rendered_css = array();
+  $inline_css = '';
+  $preprocess_items = array();
+  foreach ($css as $data => $item) {
+    // Loop through each of the stylesheets, including them appropriately based
+    // on their type.
+    switch ($item['type']) {
+      case 'file':
+        // Depending on whether aggregation is desired, include the file.
+        if (!$item['preprocess'] || !($is_writable && $preprocess_css)) {
+          $rendered_css[] = '<link type="text/css" rel="stylesheet" media="' . $item['media'] . '" href="' . base_path() . $item['data'] . $query_string . '" />';
+        }
+        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'] = '';
+        }
+        break;
+      case 'inline':
         // Include inline stylesheets.
-        if ($type == 'inline') {
-          $no_inline_preprocess .= drupal_load_stylesheet_content($data, $preprocess);
-        }
-        // Only include the stylesheet if it exists.
-        elseif (file_exists($data)) {
-          if (!$preprocess || !($is_writable && $preprocess_css)) {
-            // If a CSS file is not to be preprocessed and it's a module CSS file, it needs to *always* appear at the *top*,
-            // regardless of whether preprocessing is on or off.
-            if (!$preprocess && $type == 'module') {
-              $no_module_preprocess .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n";
-            }
-            // If a CSS file is not to be preprocessed and it's a theme CSS file, it needs to *always* appear at the *bottom*,
-            // regardless of whether preprocessing is on or off.
-            elseif (!$preprocess && $type == 'theme') {
-              $no_theme_preprocess .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n";
-            }
-            else {
-              $output .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n";
-            }
-          }
-        }
-      }
+        $inline_css .= drupal_load_stylesheet_content($item['data'], $item['preprocess']);
+        break;
     }
+  }
 
-    if ($is_writable && $preprocess_css) {
+  if (!empty($preprocess_items)) {
+    foreach ($preprocess_items as $media => $items) {
       // Prefix filename to prevent blocking by firewalls which reject files
       // starting with "ad*".
-      $filename = 'css_' . md5(serialize($types) . $query_string) . '.css';
-      $preprocess_file = drupal_build_css_cache($types, $filename);
-      $output .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $preprocess_file . '" />' . "\n";
+      $filename = 'css_' . md5(serialize($items) . $query_string) . '.css';
+      $preprocess_file = drupal_build_css_cache($items, $filename);
+      $rendered_css['preprocess'] .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $preprocess_file . '" />' . "\n";
     }
   }
-  if (!empty($no_inline_preprocess)) {
-    $no_inline_preprocess = '<style type="text/css">' . $no_inline_preprocess . '</style>';
+  // Enclose the inline CSS with the style tag if required.
+  if (!empty($inline_css)) {
+    $inline_css = "\n" . '<style type="text/css">' . $inline_css .'</style>';
   }
-  return $no_module_preprocess . $output . $no_theme_preprocess . $no_inline_preprocess;
+
+  // Output all the CSS files with the inline stylesheets showing up last.
+  return implode("\n", $rendered_css) . $inline_css;
 }
 
 /**
  * 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 $css
+ *   An array of CSS files 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) {
+function drupal_build_css_cache($css, $filename) {
   $data = '';
 
   // Create the css/ within the files folder.
@@ -2545,19 +2576,15 @@
 
   if (!file_exists($csspath . '/' . $filename)) {
     // Build aggregate CSS file.
-    foreach ($types as $type => $css) {
-      // Only 'module' or 'theme' stylesheets can be aggregated.
-      if ($type == 'module' || $type == 'theme') {
-        foreach ($css as $stylesheet => $cache) {
-          if ($cache) {
-            $contents = drupal_load_stylesheet($stylesheet, TRUE);
-            // Return the path to where this CSS file originated from.
-            $base = base_path() . dirname($stylesheet) . '/';
-            _drupal_build_css_path(NULL, $base);
-            // Prefix all paths within this CSS file, ignoring external and absolute paths.
-            $data .= preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_drupal_build_css_path', $contents);
-          }
-        }
+    foreach ($css as $stylesheet) {
+      // Only 'file' stylesheets can be aggregated.
+      if ($stylesheet['type'] == 'file') {
+        $contents = drupal_load_stylesheet($stylesheet['data'], TRUE);
+        // Return the path to where this CSS file originated from.
+        $base = base_path() . dirname($stylesheet['data']) . '/';
+        _drupal_build_css_path(NULL, $base);
+        // Prefix all paths within this CSS file, ignoring external and absolute paths.
+        $data .= preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_drupal_build_css_path', $contents);
       }
     }
 

=== modified file 'includes/theme.inc'
--- includes/theme.inc	2009-07-27 18:38:35 +0000
+++ includes/theme.inc	2009-07-28 00:55:44 +0000
@@ -132,7 +132,7 @@
   // And now add the stylesheets properly
   foreach ($final_stylesheets as $media => $stylesheets) {
     foreach ($stylesheets as $stylesheet) {
-      drupal_add_css($stylesheet, array('type' => 'theme', 'media' => $media));
+      drupal_add_css($stylesheet, array('weight' => CSS_THEME, 'media' => $media));
     }
   }
 

=== modified file 'modules/locale/locale.module'
--- modules/locale/locale.module	2009-07-20 18:51:31 +0000
+++ modules/locale/locale.module	2009-07-28 00:55:44 +0000
@@ -583,6 +583,33 @@
   }
 }
 
+/*
+ * Implement hook_css_alter().
+ *
+ * This function checks all CSS files currently added via drupal_add_css() and
+ * and checks to see if a related right to left CSS file should be included.
+ */
+function locale_css_alter(&$css) {
+  global $language;
+
+  // If the current language is RTL, add the CSS file with the RTL overrides.
+  if ($language->direction == LANGUAGE_RTL) {
+    foreach ($css as $data => $item) {
+      // Only provide RTL overrides for files.
+      if ($item['type'] == 'file') {
+        $rtl_path = str_replace('.css', '-rtl.css', $item['data']);
+        if (file_exists($rtl_path) && !isset($css[$rtl_path])) {
+          // Replicate the same item, but with the RTL path and a little larger
+          // weight so that it appears directly after the original CSS file.
+          $item['data'] = $rtl_path;
+          $item['weight'] += 0.01;
+          $css[$rtl_path] = $item;
+        }
+      }
+    }
+  }
+}
+
 // ---------------------------------------------------------------------------------
 // Language switcher block
 

=== modified file 'modules/simpletest/tests/common.test'
--- modules/simpletest/tests/common.test	2009-07-15 17:40:17 +0000
+++ modules/simpletest/tests/common.test	2009-07-28 00:55:44 +0000
@@ -203,7 +203,7 @@
   }
 
   function setUp() {
-    parent::setUp('php');
+    parent::setUp('php', 'locale');
     // Reset drupal_add_css() before each test.
     drupal_static_reset('drupal_add_css');
   }
@@ -221,7 +221,7 @@
   function testAddFile() {
     $path = drupal_get_path('module', 'simpletest') . '/simpletest.css';
     $css = drupal_add_css($path);
-    $this->assertEqual($css['all']['module'][$path], TRUE, t('Adding a CSS file caches it properly.'));
+    $this->assertEqual($css[$path]['data'], $path, t('Adding a CSS file caches it properly.'));
   }
 
   /**
@@ -249,7 +249,7 @@
     $css_preprocessed = '<style type="text/css">' . drupal_load_stylesheet_content($css, TRUE) . '</style>';
     drupal_add_css($css, 'inline');
     $css = drupal_get_css();
-    $this->assertEqual($css, $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.'));
+    $this->assertEqual($css, "\n" . $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.'));
   }
 
   /**
@@ -280,6 +280,74 @@
     $this->drupalGet('node/' . $node->nid);
     $this->assertRaw($expected, t('Inline stylesheets appear in the full page rendering.'));
   }
+
+  /**
+   * Test CSS ordering.
+   */
+  function testRenderOrder() {
+    // A module CSS file.
+    drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
+    // A few system CSS files, ordered in a strange way.
+    $system_path = drupal_get_path('module', 'system');
+    drupal_add_css($system_path . '/defaults.css', array('weight' => CSS_SYSTEM));
+    drupal_add_css($system_path . '/system.css', array('weight' => CSS_SYSTEM - 10));
+    drupal_add_css($system_path . '/system-menus.css', array('weight' => CSS_SYSTEM));
+
+    $expected = array(
+      $system_path . '/system.css',
+      $system_path . '/defaults.css',
+      $system_path . '/system-menus.css',
+      drupal_get_path('module', 'simpletest') . '/simpletest.css',
+    );
+
+    $css = drupal_get_css();
+    if (preg_match_all('/href="' . preg_quote(base_path(), '/') . '([^?]+)\?/', $css, $matches)) {
+      $result = $matches[1];
+    }
+    else {
+      $result = array();
+    }
+
+    $this->assertIdentical($result, $expected, t('The CSS files are in the expected order.'));
+  }
+
+  /**
+   * Test CSS override.
+   */
+  function testRenderOverride() {
+    drupal_add_css(drupal_get_path('module', 'system') . '/system.css');
+    drupal_add_css(drupal_get_path('module', 'simpletest') . '/tests/system.css');
+
+    // The dummy stylesheet should be the only one included.
+    $css = drupal_get_css();
+    $this->assert(strpos($css, drupal_get_path('module', 'simpletest') . '/tests/system.css') !== FALSE, t('The overriding CSS file is output.'));
+    $this->assert(strpos($css, drupal_get_path('module', 'system') . '/system.css') === FALSE, t('The overriden CSS file is not output.'));
+
+    drupal_add_css(drupal_get_path('module', 'simpletest') . '/tests/system.css');
+    drupal_add_css(drupal_get_path('module', 'system') . '/system.css');
+
+    // The standard stylesheet should be the only one included.
+    $css = drupal_get_css();
+    $this->assert(strpos($css, drupal_get_path('module', 'system') . '/system.css') !== FALSE, t('The overriding CSS file is output.'));
+    $this->assert(strpos($css, drupal_get_path('module', 'simpletest') . '/tests/system.css') === FALSE, t('The overriden CSS file is not output.'));
+  }
+
+  /**
+   * Tests Locale module's CSS Alter to include RTL overrides.
+   */
+  function testAlter() {
+    // Switch the language to a right to left language and add system.css.
+    global $language;
+    $language->direction = LANGUAGE_RTL;
+    drupal_add_css(drupal_get_path('module', 'system') . '/system.css');
+
+    // Check to see if system-rtl.css was also added.
+    $css = drupal_get_css();
+    $this->assert(strpos($css, drupal_get_path('module', 'system') . '/system-rtl.css') !== FALSE, t('CSS is alterable as right to left overrides are added.'));
+
+    // Change the language back to left to right.
+    $language->direction = LANGUAGE_LTR;
+  }
 }
 
 /**

=== modified file 'modules/system/system.api.php'
--- modules/system/system.api.php	2009-07-27 19:53:17 +0000
+++ modules/system/system.api.php	2009-07-28 00:55:44 +0000
@@ -281,6 +281,19 @@
 }
 
 /**
+ * Alter CSS files before they are output on the page.
+ *
+ * @param $css
+ *   An array of all CSS items (files and inline CSS) being requested on the page.
+ * @see drupal_add_css()
+ * @see drupal_get_css()
+ */
+function hook_css_alter(&$css) {
+  // Remove defaults.css file.
+  unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
+}
+
+/**
  * Perform alterations before a page is rendered.
  *
  * Use this hook when you want to add, remove, or alter elements at the page

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2009-07-27 19:53:17 +0000
+++ modules/system/system.module	2009-07-28 00:55:44 +0000
@@ -1336,13 +1336,13 @@
   if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
     global $custom_theme;
     $custom_theme = variable_get('admin_theme', 0);
-    drupal_add_css(drupal_get_path('module', 'system') . '/admin.css');
+    drupal_add_css(drupal_get_path('module', 'system') . '/admin.css', array('weight' => CSS_SYSTEM));
   }
 
   // Add the CSS for this module.
-  drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css');
-  drupal_add_css(drupal_get_path('module', 'system') . '/system.css');
-  drupal_add_css(drupal_get_path('module', 'system') . '/system-menus.css');
+  drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css', array('weight' => CSS_SYSTEM));
+  drupal_add_css(drupal_get_path('module', 'system') . '/system.css', array('weight' => CSS_SYSTEM));
+  drupal_add_css(drupal_get_path('module', 'system') . '/system-menus.css', array('weight' => CSS_SYSTEM));
 
 
   // Ignore slave database servers for this request.

