Index: modules/filter/filter.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v
retrieving revision 1.51
diff -u -p -r1.51 filter.admin.inc
--- modules/filter/filter.admin.inc	22 Nov 2009 08:14:27 -0000	1.51
+++ modules/filter/filter.admin.inc	2 Dec 2009 13:22:01 -0000
@@ -135,7 +135,8 @@ function filter_admin_format_form($form,
   }
   // Table with filters
   $filter_info = filter_get_filters();
-  $filters = filter_list_format($format->format);
+  // Load all configured filters for existing text formats.
+  $filters = !empty($format->format) ? filter_list_format($format->format) : array();
 
   $form['filters'] = array('#type' => 'fieldset',
     '#title' => t('Filters'),
Index: modules/filter/filter.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.install,v
retrieving revision 1.24
diff -u -p -r1.24 filter.install
--- modules/filter/filter.install	7 Nov 2009 22:14:58 -0000	1.24
+++ modules/filter/filter.install	2 Dec 2009 13:22:01 -0000
@@ -59,7 +59,7 @@ function filter_schema() {
       'fmn' => array('format', 'module', 'name'),
     ),
     'indexes' => array(
-      'list' => array('format', 'weight', 'module', 'name'),
+      'list' => array('weight', 'module', 'name'),
     ),
   );
   $schema['filter_format'] = array(
@@ -351,6 +351,14 @@ function filter_update_7005() {
 }
 
 /**
+ * Remove the 'format' column from 'list' index on {filter}.
+ */
+function filter_update_7006() {
+  db_drop_index('filter', 'list');
+  db_add_index('filter', 'list', array('weight', 'module', 'name'));
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.304
diff -u -p -r1.304 filter.module
--- modules/filter/filter.module	1 Dec 2009 13:14:42 -0000	1.304
+++ modules/filter/filter.module	2 Dec 2009 14:44:00 -0000
@@ -193,22 +193,43 @@ function filter_format_save(&$format) {
   }
 
   // Get the current filters in the format, to add new filters to the bottom.
-  $current = filter_list_format($format->format);
+  $current = ($return != SAVED_NEW ? filter_list_format($format->format) : array());
   $filter_info = filter_get_filters();
+  // Programmatic saves may not contain any filters.
   if (!isset($format->filters)) {
     $format->filters = array();
   }
-  foreach ($format->filters as $name => $filter) {
-    $fields = array();
+  foreach ($filter_info as $name => $filter) {
     // Add new filters to the bottom.
-    $fields['weight'] = isset($current[$name]->weight) ? $current[$name]->weight : 10;
-    $fields['status'] = $filter['status'];
-    $fields['module'] = $filter_info[$name]['module'];
-    $format->filters[$name]['module'] = $filter_info[$name]['module'];
-    // Only update settings if there are any.
-    if (!empty($filter['settings'])) {
-      $fields['settings'] = serialize($filter['settings']);
+    $format->filters[$name]['weight'] = isset($current[$name]->weight) ? $current[$name]->weight : 10;
+    $format->filters[$name]['status'] = isset($format->filters[$name]['status']) ? $format->filters[$name]['status'] : 0;
+    $format->filters[$name]['module'] = $filter['module'];
+
+    // Since filter configuration/order lives on separate pages, there may be no
+    // filter settings contained. In that case, we either fall back to currently
+    // stored settings, default settings (if existent), or an empty array.
+    // @see http://drupal.org/node/558666
+    // If settings were passed, only ensure default settings.
+    if (isset($format->filters[$name]['settings'])) {
+      if (isset($filter['default settings'])) {
+        $format->filters[$name]['settings'] = array_merge($filter['default settings'], $format->filters[$name]['settings']);
+      }
+    }
+    // If we have existing settings, take them over directly.
+    elseif (isset($current[$name]->settings)) {
+      $format->filters[$name]['settings'] = $current[$name]->settings;
     }
+    // Otherwise, use default settings or fall back to an empty array.
+    else {
+      $format->filters[$name]['settings'] = isset($filter['default settings']) ? $filter['default settings'] : array();
+    }
+
+    $fields = array();
+    $fields['weight'] = $format->filters[$name]['weight'];
+    $fields['status'] = $format->filters[$name]['status'];
+    $fields['module'] = $format->filters[$name]['module'];
+    $fields['settings'] = serialize($format->filters[$name]['settings']);
+
     db_merge('filter')
       ->key(array(
         'format' => $format->format,
@@ -530,7 +551,7 @@ function _filter_format_is_cacheable($fo
   $filter_info = filter_get_filters();
   foreach ($format->filters as $name => $filter) {
     // By default, 'cache' is TRUE for all filters unless specified otherwise.
-    if (isset($filter_info[$name]['cache']) && !$filter_info[$name]['cache']) {
+    if (!empty($filter['status']) && isset($filter_info[$name]['cache']) && !$filter_info[$name]['cache']) {
       return FALSE;
     }
   }
@@ -556,24 +577,21 @@ function filter_list_format($format_id) 
   $filters = &drupal_static(__FUNCTION__, array());
   $filter_info = filter_get_filters();
 
+  if (!isset($filters['all'])) {
+    $result = db_query('SELECT * FROM {filter} ORDER BY weight, module, name');
+    foreach ($result as $record) {
+      $filters['all'][$record->format][$record->name] = $record;
+    }
+  }
+
   if (!isset($filters[$format_id])) {
     $format_filters = array();
-    $query = db_select('filter', 'filter')
-      ->fields('filter')
-      ->condition('format', $format_id)
-      ->orderBy('weight')
-      ->orderBy('module')
-      ->orderBy('name');
-    $result = $query->execute()->fetchAllAssoc('name');
-    foreach ($result as $name => $filter) {
+    foreach ($filters['all'][$format_id] as $name => $filter) {
       if (isset($filter_info[$name])) {
         $filter->title = $filter_info[$name]['title'];
         // Unpack stored filter settings.
         $filter->settings = (isset($filter->settings) ? unserialize($filter->settings) : array());
-        // Apply default filter settings.
-        if (isset($filter_info[$name]['default settings'])) {
-          $filter->settings = array_merge($filter_info[$name]['default settings'], $filter->settings);
-        }
+
         $format_filters[$name] = $filter;
       }
     }
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.49
diff -u -p -r1.49 filter.test
--- modules/filter/filter.test	30 Nov 2009 00:42:01 -0000	1.49
+++ modules/filter/filter.test	2 Dec 2009 14:47:34 -0000
@@ -97,8 +97,9 @@ class FilterCRUDTestCase extends DrupalW
     foreach ($filters as $name => $filter) {
       // If this filter is not cacheable, update $cacheable accordingly, so we
       // can verify $format->cache after iterating over all filters.
-      if (isset($filter_info[$name]['cache']) && !$filter_info[$name]['cache']) {
+      if ($filter->status && isset($filter_info[$name]['cache']) && !$filter_info[$name]['cache']) {
         $cacheable = FALSE;
+        break;
       }
     }
     $this->assertEqual($filter_format->cache, $cacheable, t('Text format contains proper cache property.'));
@@ -114,18 +115,11 @@ class FilterCRUDTestCase extends DrupalW
     foreach ($filters as $name => $filter) {
       $t_args = array('%format' => $format->name, '%filter' => $name);
 
-      // Check whether the filter is contained in the saved $format.
-      if (isset($format_filters[$name])) {
-        // Verify that filter status is properly stored.
-        $this->assertEqual($filter->status, $format_filters[$name]['status'], t('Database: Proper status for %filter in text format %format.', $t_args));
+      // Verify that filter status is properly stored.
+      $this->assertEqual($filter->status, $format_filters[$name]['status'], t('Database: Proper status for %filter in text format %format.', $t_args));
 
-        // Verify that filter settings were properly stored.
-        $this->assertEqual(unserialize($filter->settings), isset($format_filters[$name]['settings']) ? $format_filters[$name]['settings'] : array(), t('Database: Proper filter settings for %filter in text format %format.', $t_args));
-      }
-      // Otherwise, the stored filter must be disabled.
-      else {
-        $this->assertTrue($filter->status == 0, t('Database: Proper status for disabled %filter in text format %format.', $t_args));
-      }
+      // Verify that filter settings were properly stored.
+      $this->assertEqual(unserialize($filter->settings), isset($format_filters[$name]['settings']) ? $format_filters[$name]['settings'] : array(), t('Database: Proper filter settings for %filter in text format %format.', $t_args));
 
       // Verify that each filter has a module name assigned.
       $this->assertTrue(!empty($filter->module), t('Database: Proper module name for %filter in text format %format.', $t_args));
@@ -143,18 +137,11 @@ class FilterCRUDTestCase extends DrupalW
     foreach ($filters as $name => $filter) {
       $t_args = array('%format' => $format->name, '%filter' => $name);
 
-      // Check whether the filter is contained in the saved $format.
-      if (isset($format_filters[$name])) {
-        // Verify that filter status is properly stored.
-        $this->assertEqual($filter->status, $format_filters[$name]['status'], t('filter_list_format: Proper status for %filter in text format %format.', $t_args));
+      // Verify that filter status is properly stored.
+      $this->assertEqual($filter->status, $format_filters[$name]['status'], t('filter_list_format: Proper status for %filter in text format %format.', $t_args));
 
-        // Verify that filter settings were properly stored.
-        $this->assertEqual($filter->settings, isset($format_filters[$name]['settings']) ? $format_filters[$name]['settings'] : array(), t('filter_list_format: Proper filter settings for %filter in text format %format.', $t_args));
-      }
-      // Otherwise, the stored filter must be disabled.
-      else {
-        $this->assertTrue($filter->status == 0, t('filter_list_format: Proper status for disabled %filter in text format %format.', $t_args));
-      }
+      // Verify that filter settings were properly stored.
+      $this->assertEqual($filter->settings, isset($format_filters[$name]['settings']) ? $format_filters[$name]['settings'] : array(), t('filter_list_format: Proper filter settings for %filter in text format %format.', $t_args));
 
       // Verify that each filter has a module name assigned.
       $this->assertTrue(!empty($filter->module), t('filter_list_format: Proper module name for %filter in text format %format.', $t_args));
Index: modules/php/php.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/php/php.install,v
retrieving revision 1.14
diff -u -p -r1.14 php.install
--- modules/php/php.install	20 Sep 2009 07:32:18 -0000	1.14
+++ modules/php/php.install	2 Dec 2009 15:44:16 -0000
@@ -16,25 +16,20 @@ function php_install() {
   // reliable method to identify the format in an uninstall hook or in
   // subsequent clean installs.
   if (!$format_exists) {
-    $format = db_insert('filter_format')
-      ->fields(array(
-        'name' => 'PHP code',
-        'cache' => 0,
-      ))
-      ->execute();
+    $php_format = array(
+      'name' => 'PHP code',
+      'filters' => array(
+        // Enable the PHP evaluator filter.
+        'php_code' => array(
+          'weight' => 0,
+          'status' => 1,
+        ),
+      ),
+    );
+    $php_format = (object) $php_format;
+    filter_format_save($php_format);
 
-    // Enable the PHP evaluator filter.
-    db_insert('filter')
-      ->fields(array(
-        'format' => $format,
-        'module' => 'php',
-        'name' => 'php_code',
-        'weight' => 0,
-        'status' => 1,
-      ))
-      ->execute();
-
-    drupal_set_message(t('A !php-code text format has been created.', array('!php-code' => l('PHP code', 'admin/config/content/formats/' . $format))));
+    drupal_set_message(t('A !php-code text format has been created.', array('!php-code' => l('PHP code', 'admin/config/content/formats/' . $php_format->format))));
   }
 }
 
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.426
diff -u -p -r1.426 system.install
--- modules/system/system.install	1 Dec 2009 19:19:49 -0000	1.426
+++ modules/system/system.install	2 Dec 2009 15:07:08 -0000
@@ -417,113 +417,6 @@ function system_install() {
     ))
     ->execute();
 
-  // Add text formats.
-  $filtered_html_format = db_insert('filter_format')
-    ->fields(array(
-      'name' => 'Filtered HTML',
-      'cache' => 1,
-      'weight' => 0,
-    ))
-    ->execute();
-  $full_html_format = db_insert('filter_format')
-    ->fields(array(
-      'name' => 'Full HTML',
-      'cache' => 1,
-      'weight' => 0,
-    ))
-    ->execute();
-  $plain_text_format = db_insert('filter_format')
-    ->fields(array(
-      'name' => 'Plain text',
-      'cache' => 1,
-      'weight' => 1,
-    ))
-    ->execute();
-
-  // Enable filters for each text format.
-
-  // Filtered HTML:
-  db_insert('filter')
-    ->fields(array('format', 'module', 'name', 'weight', 'status'))
-    // URL filter.
-    ->values(array(
-      'format' => $filtered_html_format,
-      'module' => 'filter',
-      'name' => 'filter_url',
-      'weight' => 0,
-      'status' => 1,
-    ))
-    // HTML filter.
-    ->values(array(
-      'format' => $filtered_html_format,
-      'module' => 'filter',
-      'name' => 'filter_html',
-      'weight' => 1,
-      'status' => 1,
-    ))
-    // Line break filter.
-    ->values(array(
-      'format' => $filtered_html_format,
-      'module' => 'filter',
-      'name' => 'filter_autop',
-      'weight' => 2,
-      'status' => 1,
-    ))
-    // HTML corrector filter.
-    ->values(array(
-      'format' => $filtered_html_format,
-      'module' => 'filter',
-      'name' => 'filter_htmlcorrector',
-      'weight' => 10,
-      'status' => 1,
-    ))
-  // Full HTML:
-    // URL filter.
-    ->values(array(
-      'format' => $full_html_format,
-      'module' => 'filter',
-      'name' => 'filter_url',
-      'weight' => 0,
-      'status' => 1,
-    ))
-    // Line break filter.
-    ->values(array(
-      'format' => $full_html_format,
-      'module' => 'filter',
-      'name' => 'filter_autop',
-      'weight' => 1,
-      'status' => 1,
-    ))
-    // HTML corrector filter.
-    ->values(array(
-      'format' => $full_html_format,
-      'module' => 'filter',
-      'name' => 'filter_htmlcorrector',
-      'weight' => 10,
-      'status' => 1,
-    ))
-  // Plain text:
-    // Escape all HTML.
-    ->values(array(
-      'format' => $plain_text_format,
-      'module' => 'filter',
-      'name' => 'filter_html_escape',
-      'weight' => 0,
-      'status' => 1,
-    ))
-    // Line break filter.
-    ->values(array(
-      'format' => $plain_text_format,
-      'module' => 'filter',
-      'name' => 'filter_autop',
-      'weight' => 1,
-      'status' => 1,
-    ))
-    ->execute();
-
-  // Set the fallback format to plain text.
-  variable_set('filter_fallback_format', $plain_text_format);
-
   $cron_key = md5(mt_rand());
 
   variable_set('cron_key', $cron_key);
Index: profiles/default/default.install
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.install,v
retrieving revision 1.18
diff -u -p -r1.18 default.install
--- profiles/default/default.install	10 Nov 2009 17:27:54 -0000	1.18
+++ profiles/default/default.install	2 Dec 2009 15:15:45 -0000
@@ -7,6 +7,81 @@
  * Perform actions to set up the site for this profile.
  */
 function default_install() {
+  // Add text formats.
+  $filtered_html_format = array(
+    'name' => 'Filtered HTML',
+    'weight' => 0,
+    'filters' => array(
+      // URL filter.
+      'filter_url' => array(
+        'weight' => 0,
+        'status' => 1,
+      ),
+      // HTML filter.
+      'filter_html' => array(
+        'weight' => 1,
+        'status' => 1,
+      ),
+      // Line break filter.
+      'filter_autop' => array(
+        'weight' => 2,
+        'status' => 1,
+      ),
+      // HTML corrector filter.
+      'filter_htmlcorrector' => array(
+        'weight' => 10,
+        'status' => 1,
+      ),
+    ),
+  );
+  $filtered_html_format = (object) $filtered_html_format;
+  filter_format_save($filtered_html_format);
+
+  $full_html_format = array(
+    'name' => 'Full HTML',
+    'weight' => 0,
+    'filters' => array(
+      // URL filter.
+      'filter_url' => array(
+        'weight' => 0,
+        'status' => 1,
+      ),
+      // Line break filter.
+      'filter_autop' => array(
+        'weight' => 1,
+        'status' => 1,
+      ),
+      // HTML corrector filter.
+      'filter_htmlcorrector' => array(
+        'weight' => 10,
+        'status' => 1,
+      ),
+    ),
+  );
+  $full_html_format = (object) $full_html_format;
+  filter_format_save($full_html_format);
+
+  $plain_text_format = array(
+    'name' => 'Plain text',
+    'weight' => 1,
+    'filters' => array(
+      // Escape all HTML.
+      'filter_html_escape' => array(
+        'weight' => 0,
+        'status' => 1,
+      ),
+      // Line break filter.
+      'filter_autop' => array(
+        'weight' => 1,
+        'status' => 1,
+      ),
+    ),
+  );
+  $plain_text_format = (object) $plain_text_format;
+  filter_format_save($plain_text_format);
+
+  // Set the fallback format to plain text.
+  variable_set('filter_fallback_format', $plain_text_format->format);
 
   // Enable some standard blocks.
   $values = array(
Index: profiles/expert/expert.install
===================================================================
RCS file: /cvs/drupal/drupal/profiles/expert/expert.install,v
retrieving revision 1.5
diff -u -p -r1.5 expert.install
--- profiles/expert/expert.install	10 Nov 2009 17:27:54 -0000	1.5
+++ profiles/expert/expert.install	2 Dec 2009 15:16:52 -0000
@@ -7,6 +7,27 @@
  * Perform actions to set up the site for this profile.
  */
 function expert_install() {
+  $plain_text_format = array(
+    'name' => 'Plain text',
+    'weight' => 1,
+    'filters' => array(
+      // Escape all HTML.
+      'filter_html_escape' => array(
+        'weight' => 0,
+        'status' => 1,
+      ),
+      // Line break filter.
+      'filter_autop' => array(
+        'weight' => 1,
+        'status' => 1,
+      ),
+    ),
+  );
+  $plain_text_format = (object) $plain_text_format;
+  filter_format_save($plain_text_format);
+
+  // Set the fallback format to plain text.
+  variable_set('filter_fallback_format', $plain_text_format->format);
 
   // Enable some standard blocks.
   $values = array(
