Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1229 diff -u -p -r1.1229 common.inc --- includes/common.inc 1 Oct 2010 18:37:22 -0000 1.1229 +++ includes/common.inc 2 Oct 2010 19:15:11 -0000 @@ -3116,12 +3116,24 @@ function drupal_pre_render_styles($eleme elseif ($group['preprocess']) { $import = array(); foreach ($group['items'] as $item) { - // The dummy query string needs to be added to the URL to control - // browser-caching. IE7 does not support a media type on the @import - // statement, so we instead specify the media for the group on the - // STYLE tag. - $query_string_separator = (strpos($item['data'], '?') !== FALSE) ? '&' : '?'; - $import[] = '@import url("' . check_plain(file_create_url($item['data']) . $query_string_separator . $query_string) . '");'; + // A theme's .info file may have an entry for a file that doesn't + // exist as a way of overriding a module or base theme CSS file from + // being added to the page. Normally, file_exists() calls that need + // to run for every page request should be minimized, but this one + // is okay, because it only runs when CSS aggregation is disabled. + // On a server under heavy enough load that file_exists() calls need + // to be minimized, CSS aggregation should be enabled, in which case + // this code is not run. When aggregation is enabled, + // drupal_load_stylesheet() checks file_exists(), but only when + // building the aggregate file, which is then reused for many page + // requests. + if (file_exists($item['data'])) { + // The dummy query string needs to be added to the URL to control + // browser-caching. IE7 does not support a media type on the + // @import statement, so we instead specify the media for the + // group on the STYLE tag. + $import[] = '@import url("' . check_plain(file_create_url($item['data']) . '?' . $query_string) . '");'; + } } // In addition to IE's limit of 31 total CSS inclusion tags, it also // has a limit of 31 @import statements per STYLE tag. @@ -3140,6 +3152,14 @@ function drupal_pre_render_styles($eleme else { foreach ($group['items'] as $item) { $element = $link_element_defaults; + // We do not check file_exists() here, because this code runs for + // files whose 'preprocess' is set to FALSE, and therefore, even + // when aggregation is enabled, and we want to avoid needlessly + // taxing a server that may be under heavy load. The file_exists() + // performed above for files whose 'preprocess' is TRUE is done for + // the benefit of theme .info files, but code that deals with files + // whose 'preprocess' is FALSE is responsible for ensuring the file + // exists. // The dummy query string needs to be added to the URL to control // browser-caching. $query_string_separator = (strpos($item['data'], '?') !== FALSE) ? '&' : '?'; Index: modules/simpletest/tests/theme.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/theme.test,v retrieving revision 1.20 diff -u -p -r1.20 theme.test --- modules/simpletest/tests/theme.test 22 Aug 2010 12:46:21 -0000 1.20 +++ modules/simpletest/tests/theme.test 2 Oct 2010 19:15:19 -0000 @@ -74,6 +74,29 @@ class ThemeUnitTest extends DrupalWebTes $this->drupalGet('theme-test/alter'); $this->assertText('The altered data is test_theme_theme_test_alter_alter was invoked.', t('The theme was able to implement an alter hook during page building before anything was rendered.')); } + + /** + * Ensures a theme's .info file is able to override a module CSS file from being added to the page. + * + * @see test_theme.info + */ + function testCSSOverride() { + // Reuse the same page as in testPreprocessForSuggestions(). We're testing + // what is output to the HTML HEAD based on what is in a theme's .info file, + // so it doesn't matter what page we get, as long as it is themed with the + // test theme. First we test with CSS aggregation disabled. + variable_set('preprocess_css', 0); + $this->drupalGet('theme-test/suggestion'); + $this->assertNoText('system.base.css', t('The theme\'s .info file is able to override a module CSS file from being added to the page.')); + + // Also test with aggregation enabled, simply ensuring no PHP errors are + // triggered during drupal_build_css_cache() when a source file doesn't + // exist. Then allow remaining tests to continue with aggregation disabled + // by default. + variable_set('preprocess_css', 1); + $this->drupalGet('theme-test/suggestion'); + variable_set('preprocess_css', 0); + } } /** Index: themes/tests/test_theme/test_theme.info =================================================================== RCS file: /cvs/drupal/drupal/themes/tests/test_theme/test_theme.info,v retrieving revision 1.1 diff -u -p -r1.1 test_theme.info --- themes/tests/test_theme/test_theme.info 21 Mar 2010 04:05:24 -0000 1.1 +++ themes/tests/test_theme/test_theme.info 2 Oct 2010 19:15:22 -0000 @@ -3,4 +3,16 @@ name = Test theme description = Theme for testing the theme system core = 7.x engine = phptemplate -hidden = TRUE \ No newline at end of file +hidden = TRUE + +; Normally, themes may list CSS files like this, and if they exist in the theme +; folder, then they get added to the page. If they have the same file name as a +; module CSS file, then the theme's version overrides the module's version, so +; that the module's version is not added to the page. Additionally, a theme may +; have an entry like this one, without having the corresponding CSS file in the +; theme's folder, and in this case, it just stops the module's version from +; being loaded, and does not replace it with an alternate version. We have this +; here in order for a test to ensure that this correctly prevents the module +; version from being loaded, and that errors aren't caused by the lack of this +; file within the theme folder. +stylesheets[all][] = system.base.css