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 19:06:33 -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' => $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(), 'use_import' => NULL), + ), // 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 19:06:33 -0000 @@ -2033,6 +2033,154 @@ function theme_html_tag($variables) { } /** + * Preprocess variables for theme_stylesheets(). + * + * @see theme_stylesheets() + */ +function template_preprocess_stylesheets(&$variables) { + // To work around IE's limit of 31 total LINK (rel=stylesheet) plus STYLE + // tags per page, default the use_import variable to be TRUE when CSS + // aggregation is disabled and FALSE when it is enabled. + if (!isset($variables['use_import'])) { + $variables['use_import'] = !variable_get('preprocess_css', FALSE); + } + + // Order all the external CSS files to be after the non-external ones. + // @todo Why? + // Save the original order in case another preprocess function wants to undo + // this decision. + $variables['files_original'] = $variables['files']; + $internal = array(); + $external = array(); + foreach ($variables['files'] as $file) { + if ($file['external']) { + $external[] = $file; + } + else { + $internal[] = $file; + } + } + $variables['files'] = array_merge($internal, $external); +} + +/** + * Process variables for theme_stylesheets(). + * + * @see theme_stylesheets() + */ +function template_process_stylesheets(&$variables) { + // Without changing their order, split $files into groups, where each group + // contains files of the same media type and each group is limited to 31 + // files. This enables each group to be output within a single STYLE tag. + // Each group must contain files of the same media type, because IE7 does + // not support media type declaration on the @import statement, but only + // on the STYLE tag. Each group is limited to 31 files, because IE is + // limited to 31 @import statements per STYLE tag. + if ($variables['use_import']) { + $groups = array(); + $group = array(); + $media = NULL; + foreach ($variables['files'] as $file) { + if (count($groups) == 31 || (!empty($group) && $file['media'] != $media)) { + $groups[] = $group; + $group = array(); + } + $group[] = $file; + $media = $file['media']; + } + if (!empty($group)) { + $groups[] = $group; + } + $variables['groups'] = $groups; + } +} + +/** + * 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. + * - use_import: Boolean. TRUE if multiple CSS files should be included within + * a single STYLE tag using @import statements. Otherwise, each CSS file is + * included individually with a LINK tag. By default, this is TRUE when CSS + * aggregation is disabled and FALSE when CSS aggregation is enabled. This + * is to work around IE's limit of 31 total LINK (rel=stylesheet) plus STYLE + * tags per page. To minimize network traffic and optimize page loading + * speed, 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 CSS + * aggregation is enabled, it is very unlikely for there to be enough CSS + * files to encroach on this limit, and using LINK tags instead of STYLE + * tags is prefered. However, when CSS aggregation is disabled, with enough + * modules or a complex theme enabled, this limit could easily be reached, + * so combining multiple @import statements into a single STYLE tag is + * safer. + * - groups: If the use_import variable is TRUE, then the groups variable is + * an array of file groups. Each group is itself an array of files (a subset + * of the files array) that need to be included in the same STYLE tag. + * + * @ingroup themeable + */ +function theme_stylesheets($variables) { + $output = ''; + + // 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', + ), + ); + + if ($variables['use_import']) { + // Add 1 STYLE tag per group. + foreach ($variables['groups'] 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)); + } + } + else { + // Add 1 LINK tag per file. + foreach ($variables['files'] as $file) { + $element = $link_element_defaults; + $element['#attributes']['media'] = $file['media']; + $element['#attributes']['href'] = $file['href']; + $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 Index: modules/simpletest/tests/common.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v retrieving revision 1.97 diff -u -p -r1.97 common.test --- modules/simpletest/tests/common.test 15 Dec 2009 05:22:05 -0000 1.97 +++ modules/simpletest/tests/common.test 6 Jan 2010 19:06:35 -0000 @@ -558,7 +558,9 @@ class CascadingStylesheetsTestCase exten $css = 'http://example.com/style.css'; drupal_add_css($css, 'external'); $styles = drupal_get_css(); - $this->assertTrue(strpos($styles, 'href="' . $css) > 0, t('Rendering an external CSS file.')); + // Stylesheet URL may be the href of a LINK tag or in an @import statement + // of a STYLE tag. + $this->assertTrue(strpos($styles, 'href="' . $css) > 0 || strpos($styles, '@import url("' . $css . '")') > 0, t('Rendering an external CSS file.')); } /** @@ -631,8 +633,10 @@ class CascadingStylesheetsTestCase exten $styles = drupal_get_css(); - if (preg_match_all('/href="' . preg_quote($GLOBALS['base_url'] . '/', '/') . '([^?]+)\?/', $styles, $matches)) { - $result = $matches[1]; + // Stylesheet URL may be the href of a LINK tag or in an @import statement + // of a STYLE tag. + if (preg_match_all('/(href="|url\(")' . preg_quote($GLOBALS['base_url'] . '/', '/') . '([^?]+)\?/', $styles, $matches)) { + $result = $matches[2]; } else { $result = array();