Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.57
diff -u -r1.57 common.test
--- modules/simpletest/tests/common.test	30 Jul 2009 19:57:10 -0000	1.57
+++ modules/simpletest/tests/common.test	30 Jul 2009 23:59:38 -0000
@@ -225,6 +225,15 @@
   }
 
   /**
+   * Tests adding an external stylesheet.
+   */
+  function testAddExternal() {
+    $path = 'http://example.com/style.css';
+    $css = drupal_add_css($path, 'external');
+    $this->assertEqual($css[$path]['type'], 'external'], t('Adding an external CSS file caches it properly.'));
+  }
+
+  /**
    * Makes sure that reseting the CSS empties the cache.
    */
   function testReset() {
@@ -242,6 +251,15 @@
   }
 
   /**
+   * Tests rendering an external stylesheet.
+   */
+  function testRenderExternal() {
+    $css = 'http://example.com/style.css';
+    drupal_add_css($css, 'external');
+    $this->assertTrue(strpos(drupal_get_css(), 'href="' . $css) > 0, t('Rendering an external CSS file.'));
+  }
+
+  /**
    * Tests rendering inline stylesheets with preprocessing on.
    */
   function testRenderInlinePreprocess() {
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.949
diff -u -r1.949 common.inc
--- includes/common.inc	30 Jul 2009 19:57:09 -0000	1.949
+++ includes/common.inc	30 Jul 2009 23:59:38 -0000
@@ -2362,13 +2362,16 @@
  *   - 'inline': A string of CSS that should be placed in the given scope. Note
  *     that it is better practice to use 'file' stylesheets, rather than 'inline'
  *     as the CSS would then be aggregated and cached.
+ *   - 'external': Include an external CSS file that is not hosted on the local
+ *     server. These files will not be aggregated if CSS aggregation is
+ *     enabled.
  *
  * @param $options
  *   (optional) A string defining the 'type' of CSS that is being added in the
  *   $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'.
+ *   - 'type': The type of stylesheet being added. Available options are 'file',
+ *     'inline' or 'external'. Defaults to 'file'.
  *   - 'weight': The weight of the stylesheet specifies the order in which the
  *     CSS will appear when presented on the page.
  *
@@ -2393,7 +2396,8 @@
  *     files into one file that is then compressed by removing all extraneous
  *     white space. Note that preprocessed inline stylesheets will not be
  *     aggregated into this single file, instead it will just be compressed
- *     when being output on the page.
+ *     when being output on the page. External stylesheets will not be
+ *     aggregated at all.
  *
  *     The reason for merging the CSS files is outlined quite thoroughly here:
  *     http://www.die.net/musings/page_load_time/
@@ -2440,14 +2444,16 @@
 
     // 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;
+      default:
+        // Stylesheets of type "file" and "external" both use the location as the
+        // array item's key.
+        $css[$data] = $options;
+        break;
     }
   }
 
@@ -2515,6 +2521,7 @@
   // Additionally, go through any remaining styles if CSS preprocessing is on and output the non-cached ones.
   $rendered_css = array();
   $inline_css = '';
+  $external_css = '';
   $preprocess_items = array();
   foreach ($css as $data => $item) {
     // Loop through each of the stylesheets, including them appropriately based
@@ -2536,6 +2543,11 @@
         // Include inline stylesheets.
         $inline_css .= drupal_load_stylesheet_content($item['data'], $item['preprocess']);
         break;
+      case 'external':
+        // Validate the external CSS address by passing it through url().
+        $url = url($data, array('absolute' => TRUE, 'external' => TRUE));
+        $external_css .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . $url . '" />' . "\n";
+        break;
     }
   }
 
@@ -2554,7 +2566,7 @@
   }
 
   // Output all the CSS files with the inline stylesheets showing up last.
-  return implode("\n", $rendered_css) . $inline_css;
+  return implode("\n", $rendered_css) . $external_css . $inline_css;
 }
 
 /**
@@ -2997,8 +3009,10 @@
         break;
 
       case 'external':
+        // Validate the external JavaScript address by passing it through url().
+        $url = url($item['data'], array('absolute' => TRUE, 'external' => TRUE));
         // Preprocessing for external JavaScript files is ignored.
-        $output .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . ' src="' . $item['data'] . "\"></script>\n";
+        $output .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . ' src="' . $url . "\"></script>\n";
         break;
     }
   }
