Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1042
diff -u -p -r1.1042 common.inc
--- includes/common.inc	7 Nov 2009 14:02:31 -0000	1.1042
+++ includes/common.inc	7 Nov 2009 16:19:55 -0000
@@ -5516,9 +5516,6 @@ function drupal_common_theme() {
     'form_required_marker' => array(
       'arguments' => array('element' => NULL),
     ),
-    'text_format_wrapper' => array(
-      'render element' => 'element',
-    ),
     'vertical_tabs' => array(
       'render element' => 'element',
     ),
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.394
diff -u -p -r1.394 form.inc
--- includes/form.inc	7 Nov 2009 14:44:04 -0000	1.394
+++ includes/form.inc	7 Nov 2009 22:52:51 -0000
@@ -1083,10 +1083,11 @@ function form_builder($form_id, $element
       // Check to see if a tree of child elements is present. If so,
       // continue down the tree if required.
       $element[$key]['#parents'] = $element[$key]['#tree'] && $element['#tree'] ? array_merge($element['#parents'], array($key)) : array($key);
-      $array_parents = isset($element['#array_parents']) ? $element['#array_parents'] : array();
-      $array_parents[] = $key;
-      $element[$key]['#array_parents'] = $array_parents;
     }
+    // Ensure #array_parents matches the actual internal parents in the form.
+    $array_parents = isset($element['#array_parents']) ? $element['#array_parents'] : array();
+    $array_parents[] = $key;
+    $element[$key]['#array_parents'] = $array_parents;
 
     // Assign a decimal placeholder weight to preserve original array order.
     if (!isset($element[$key]['#weight'])) {
@@ -1992,110 +1993,6 @@ function form_process_radios($element) {
 }
 
 /**
- * Add text format selector to text elements with the #text_format property.
- *
- * The #text_format property should be the ID of an text format, found in
- * {filter_format}.format, which gets passed to filter_form().
- *
- * If the property #text_format is set, the form element will be expanded into
- * two separate form elements, one holding the content of the element, and the
- * other holding the text format selector. The original element is shifted into
- * a child element, but is otherwise unaltered, so that the format selector is
- * at the same level as the text field which it affects.
- *
- * For example:
- * @code
- *   // A simple textarea, such as a node body.
- *   $form['body'] = array(
- *     '#type' => 'textarea',
- *     '#title' => t('Body'),
- *     '#text_format' => isset($node->format) ? $node->format : filter_default_format(),
- *   );
- * @endcode
- *
- * Becomes:
- * @code
- *   $form['body'] = array(
- *     // Type switches to 'markup', as we're only interested in submitting the child elements.
- *     '#type' => 'markup',
- *     // 'value' holds the original element.
- *     'value' => array(
- *       '#type' => 'textarea',
- *       '#title' => t('Body'),
- *       '#parents' => array('body'),
- *     ),
- *     // 'format' holds the text format selector.
- *     'format' => array(
- *       '#parents' => array('body_format'),
- *       ...
- *     ),
- *   );
- * @endcode
- *
- * And would result in:
- * @code
- *   // Original, unaltered form element value.
- *   $form_state['values']['body'] = 'Example content';
- *   // Chosen text format.
- *   $form_state['values']['body_format'] = 1;
- * @endcode
- *
- * @see system_element_info(), filter_form()
- */
-function form_process_text_format($element) {
-  if (isset($element['#text_format'])) {
-    // Determine the form element parents and element name to use for the input
-    // format widget. This simulates the 'element' and 'element_format' pair of
-    // parents that filter_form() expects.
-    $element_parents = $element['#parents'];
-    $element_name = array_pop($element_parents);
-    $element_parents[] = $element_name . '_format';
-
-    // We need to break references, otherwise form_builder recurses infinitely.
-    $element['value'] = (array)$element;
-    $element['value']['#weight'] = 0;
-    unset($element['value']['#description']);
-    $element['#type'] = 'markup';
-    $element['#theme'] = NULL;
-    $element['#theme_wrappers'] = array('text_format_wrapper');
-    $element['format'] = filter_form($element['#text_format'], 1, $element_parents);
-
-    // We need to clear the #text_format from the new child otherwise we
-    // would get into an infinite loop.
-    unset($element['value']['#text_format']);
-  }
-  return $element;
-}
-
-/**
- * Theme a text format form element.
- *
- * @param $variables
- *   An associative array containing:
- *   - element: An associative array containing the properties of the element.
- *     Properties used: #children, #description
- *
- * @return
- *   A string representing the form element.
- *
- * @ingroup themeable
- */
-function theme_text_format_wrapper($variables) {
-  $element = $variables['element'];
-  $output = '<div class="text-format-wrapper">' . "\n";
-
-  $output .= $element['#children'] . "\n";
-
-  if (!empty($element['#description'])) {
-    $output .= '<div class="description">' . $element['#description'] . "</div>\n";
-  }
-
-  $output .= "</div>\n";
-
-  return $output;
-}
-
-/**
  * Theme a checkbox form element.
  *
  * @param $variables
@@ -2210,7 +2107,7 @@ function form_process_container($element
  * @param $element
  *   An associative array containing the properties and children of the
  *   group.
- *   Properties used: #children.
+ *   Properties used: #id, #attributes, #children.
  * @return
  *   A themed HTML string representing the form element.
  *
@@ -2218,7 +2115,12 @@ function form_process_container($element
  */
 function theme_container($variables) {
   $element = $variables['element'];
-  return '<div class="form-wrapper" id="' . $element['#id'] . '">' . $element['#children'] . '</div>';
+  if (!isset($element['#attributes']['id'])) {
+    $element['#attributes']['id'] = $element['#id'];
+  }
+  // Force the 'form-wrapper' class.
+  $element['#attributes']['class'][] = 'form-wrapper';
+  return '<div' . drupal_attributes($element['#attributes']) . '>' . $element['#children'] . '</div>';
 }
 
 /**
Index: misc/form.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/form.js,v
retrieving revision 1.12
diff -u -p -r1.12 form.js
--- misc/form.js	16 Oct 2009 16:37:00 -0000	1.12
+++ misc/form.js	7 Nov 2009 22:47:19 -0000
@@ -69,23 +69,6 @@ Drupal.behaviors.multiselectSelector = {
 };
 
 /**
- * Automatically display the guidelines of the selected text format.
- */
-Drupal.behaviors.filterGuidelines = {
-  attach: function (context) {
-    $('.filter-guidelines', context).once('filter-guidelines')
-      .find('label').hide()
-      .parents('.filter-wrapper').find('select.filter-list')
-      .bind('change', function () {
-        $(this).parents('.filter-wrapper')
-          .find('.filter-guidelines-item').hide()
-          .siblings('#filter-guidelines-' + this.value).show();
-      })
-      .change();
-  }
-};
-
-/**
  * Prepopulate form fields with information from the visitor cookie.
  */
 Drupal.behaviors.fillUserInfoFromCookie = {
Index: modules/block/block.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v
retrieving revision 1.61
diff -u -p -r1.61 block.admin.inc
--- modules/block/block.admin.inc	3 Nov 2009 05:27:18 -0000	1.61
+++ modules/block/block.admin.inc	6 Nov 2009 23:58:56 -0000
@@ -446,9 +446,9 @@ function block_add_block_form_validate($
 function block_add_block_form_submit($form, &$form_state) {
   $delta = db_insert('block_custom')
     ->fields(array(
-      'body' => $form_state['values']['body'],
+      'body' => $form_state['values']['body']['value'],
       'info' => $form_state['values']['info'],
-      'format' => $form_state['values']['body_format'],
+      'format' => $form_state['values']['body']['format'],
     ))
     ->execute();
 
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.395
diff -u -p -r1.395 block.module
--- modules/block/block.module	7 Nov 2009 13:35:20 -0000	1.395
+++ modules/block/block.module	7 Nov 2009 23:27:19 -0000
@@ -423,10 +423,10 @@ function block_custom_block_form($edit =
   );
   $form['body_field']['#weight'] = -17;
   $form['body_field']['body'] = array(
-    '#type' => 'textarea',
+    '#type' => 'textarea_format',
     '#title' => t('Block body'),
     '#default_value' => $edit['body'],
-    '#text_format' => isset($edit['format']) ? $edit['format'] : filter_default_format(),
+    '#format' => isset($edit['format']) ? $edit['format'] : NULL,
     '#rows' => 15,
     '#description' => t('The content of the block as shown to the user.'),
     '#required' => TRUE,
@@ -453,9 +453,9 @@ function block_custom_block_form($edit =
 function block_custom_block_save($edit, $delta) {
   db_update('block_custom')
     ->fields(array(
-      'body' => $edit['body'],
+      'body' => $edit['body']['value'],
       'info' => $edit['info'],
-      'format' => $edit['body_format'],
+      'format' => $edit['body']['format'],
     ))
     ->condition('bid', $delta)
     ->execute();
Index: modules/block/block.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.test,v
retrieving revision 1.30
diff -u -p -r1.30 block.test
--- modules/block/block.test	16 Oct 2009 23:48:37 -0000	1.30
+++ modules/block/block.test	21 Oct 2009 05:38:08 -0000
@@ -78,8 +78,8 @@ class BlockTestCase extends DrupalWebTes
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $this->randomName(8);
-    $custom_block['body'] = '<h1>Full HTML</h1>';
-    $custom_block['body_format'] = 2;
+    $custom_block['body[value]'] = '<h1>Full HTML</h1>';
+    $custom_block['body[format]'] = 2;
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
 
     // Set the created custom block to a specific region.
@@ -119,7 +119,7 @@ class BlockTestCase extends DrupalWebTes
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $title;
-    $custom_block['body'] = $this->randomName(32);
+    $custom_block['body[value]'] = $this->randomName(32);
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
     
     $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.802
diff -u -p -r1.802 comment.module
--- modules/comment/comment.module	7 Nov 2009 13:35:20 -0000	1.802
+++ modules/comment/comment.module	8 Nov 2009 01:19:36 -0000
@@ -1288,7 +1288,7 @@ function comment_save($comment) {
         'changed' => $comment->changed,
         'subject' => $comment->subject,
         'comment' => $comment->comment,
-        'format' => $comment->comment_format,
+        'format' => $comment->format,
         'uid' => $comment->uid,
         'name' => $comment->name,
         'mail' => $comment->mail,
@@ -1364,7 +1364,7 @@ function comment_save($comment) {
         'uid' => $comment->uid,
         'subject' => $comment->subject,
         'comment' => $comment->comment,
-        'format' => $comment->comment_format,
+        'format' => $comment->format,
         'hostname' => ip_address(),
         'created' => $comment->created,
         'changed' => $comment->changed,
@@ -1841,11 +1841,12 @@ function comment_form($form, &$form_stat
   }
 
   $form['comment'] = array(
-    '#type' => 'textarea',
+    '#type' => 'textarea_format',
     '#title' => t('Comment'),
     '#rows' => 15,
     '#default_value' => $default,
-    '#text_format' => isset($comment->format) ? $comment->format : filter_default_format(),
+    '#format' => isset($comment->format) ? $comment->format : NULL,
+    '#format_tree' => FALSE,
     '#required' => TRUE,
   );
 
@@ -1923,8 +1924,6 @@ function comment_preview($comment) {
   $node = node_load($comment->nid);
 
   if (!form_get_errors()) {
-    $comment->format = $comment->comment_format;
-
     // Attach the user and time information.
     if (!empty($comment->author)) {
       $account = user_load_by_name($comment->author);
@@ -2053,7 +2052,7 @@ function comment_submit($comment) {
     // 1) Filter it into HTML
     // 2) Strip out all HTML tags
     // 3) Convert entities back to plain-text.
-    $comment['subject'] = truncate_utf8(trim(decode_entities(strip_tags(check_markup($comment['comment'], $comment['comment_format'])))), 29, TRUE);
+    $comment['subject'] = truncate_utf8(trim(decode_entities(strip_tags(check_markup($comment['comment'], $comment['format'])))), 29, TRUE);
     // Edge cases where the comment body is populated only by HTML tags will
     // require a default subject.
     if ($comment['subject'] == '') {
Index: modules/comment/comment.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.pages.inc,v
retrieving revision 1.28
diff -u -p -r1.28 comment.pages.inc
--- modules/comment/comment.pages.inc	1 Nov 2009 12:11:10 -0000	1.28
+++ modules/comment/comment.pages.inc	8 Nov 2009 01:24:02 -0000
@@ -108,7 +108,6 @@ function comment_reply(stdClass $node, $
  */
 function comment_approve($comment) {
   $comment->status = COMMENT_PUBLISHED;
-  $comment->comment_format = $comment->format;
   comment_save($comment);
 
   drupal_set_message(t('Comment approved.'));
Index: modules/field/modules/text/text.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.js,v
retrieving revision 1.1
diff -u -p -r1.1 text.js
--- modules/field/modules/text/text.js	11 Sep 2009 13:30:49 -0000	1.1
+++ modules/field/modules/text/text.js	20 Oct 2009 22:58:37 -0000
@@ -5,9 +5,9 @@
 /**
  * Auto-hide summary textarea if empty and show hide and unhide links.
  */
-Drupal.behaviors.textTextareaSummary = {
+Drupal.behaviors.textSummary = {
   attach: function (context, settings) {
-    $('textarea.text-textarea-summary:not(.text-textarea-summary-processed)', context).addClass('text-textarea-summary-processed').each(function () {
+    $('textarea.text-summary', context).once('text-summary', function () {
       var $fieldset = $(this).closest('#body-wrapper');
       var $summary = $fieldset.find('div.text-summary-wrapper');
       var $summaryLabel = $summary.find('div.form-type-textarea label');
Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.35
diff -u -p -r1.35 text.module
--- modules/field/modules/text/text.module	1 Nov 2009 14:05:31 -0000	1.35
+++ modules/field/modules/text/text.module	7 Nov 2009 02:28:49 -0000
@@ -146,7 +146,7 @@ function text_field_instance_settings_fo
     '#default_value' => $settings['text_processing'],
     '#options' => array(
       t('Plain text'),
-      t('Filtered text (user selects input format)'),
+      t('Filtered text (user selects text format)'),
     ),
   );
   if ($field['type'] == 'text_with_summary') {
@@ -154,7 +154,7 @@ function text_field_instance_settings_fo
       '#type' => 'checkbox',
       '#title' => t('Summary input'),
       '#default_value' => $settings['display_summary'],
-      '#description' => t('This allows authors to input an explicit summary, to be displayed instead of the automatically trimmed text when using the "Summary or trimmed" display format.'),
+      '#description' => t('This allows authors to input an explicit summary, to be displayed instead of the automatically trimmed text when using the "Summary or trimmed" display type.'),
     );
   }
 
@@ -170,13 +170,16 @@ function text_field_instance_settings_fo
  */
 function text_field_validate($obj_type, $object, $field, $instance, $langcode, $items, &$errors) {
   foreach ($items as $delta => $item) {
-    foreach (array('value' => t('full text'), 'summary' => t('summary')) as $column => $desc) {
+    // @todo Length is counted separately for summary and value, so the maximum
+    //   length can be exceeded very easily.
+    foreach (array('value', 'summary') as $column) {
       if (!empty($item[$column])) {
         if (!empty($field['settings']['max_length']) && drupal_strlen($item[$column]) > $field['settings']['max_length']) {
           switch ($column) {
             case 'value':
               $message = t('%name: the text may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length']));
               break;
+
             case 'summary':
               $message = t('%name: the summary may not be longer than %max characters.', array('%name' => $instance['label'], '%max' => $field['settings']['max_length']));
               break;
@@ -205,11 +208,11 @@ function text_field_load($obj_type, $obj
       if (!empty($instances[$id]['settings']['text_processing'])) {
         // Only process items with a cacheable format, the rest will be
         // handled by text_field_sanitize().
-        $format = $item['format'];
-        if (filter_format_allowcache($format)) {
-          $items[$id][$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $langcode) : '';
+        $format_id = $item['format'];
+        if (filter_format_allowcache($format_id)) {
+          $items[$id][$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format_id, $langcode) : '';
           if ($field['type'] == 'text_with_summary') {
-            $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $langcode) : '';
+            $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format_id, $langcode) : '';
           }
         }
       }
@@ -235,10 +238,10 @@ function text_field_sanitize($obj_type, 
     // from a form preview.
     if (!isset($items[$delta]['safe'])) {
       if (!empty($instance['settings']['text_processing'])) {
-        $format = $item['format'];
-        $items[$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $langcode, TRUE) : '';
+        $format_id = $item['format'];
+        $items[$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format_id, $langcode, TRUE) : '';
         if ($field['type'] == 'text_with_summary') {
-          $items[$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $langcode, TRUE) : '';
+          $items[$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format_id, $langcode, TRUE) : '';
         }
       }
       else {
@@ -469,14 +472,6 @@ function text_summary($text, $format = N
 
 /**
  * Implement hook_field_widget_info().
- *
- * Here we indicate that the field module will handle
- * the default value and multiple values for these widgets.
- *
- * Callbacks can be omitted if default handing is used.
- * They're included here just so this module can be used
- * as an example for custom modules that might do things
- * differently.
  */
 function text_field_widget_info() {
   return array(
@@ -528,40 +523,6 @@ function text_field_widget_settings_form
 }
 
 /**
- * Implement hook_element_info().
- *
- * Autocomplete_path is not used by text_field_widget but other
- * widgets can use it (see nodereference and userreference).
- */
-function text_element_info() {
-  $types['text_textfield'] = array(
-    '#input' => TRUE,
-    '#columns' => array('value'),
-    '#delta' => 0,
-    '#process' => array('text_textfield_elements_process'),
-    '#theme_wrappers' => array('text_textfield'),
-    '#autocomplete_path' => FALSE,
-  );
-  $types['text_textarea'] = array(
-    '#input' => TRUE,
-    '#columns' => array('value', 'format'),
-    '#delta' => 0,
-    '#process' => array('text_textarea_elements_process'),
-    '#theme_wrappers' => array('text_textarea'),
-    '#filter_value' => filter_default_format(),
-  );
-  $types['text_textarea_with_summary'] = array(
-    '#input' => TRUE,
-    '#columns' => array('value', 'format', 'summary'),
-    '#delta' => 0,
-    '#process' => array('text_textarea_with_summary_process'),
-    '#theme_wrappers' => array('text_textarea'),
-    '#filter_value' => filter_default_format(),
-  );
-  return $types;
-}
-
-/**
  * Implement hook_field_widget().
  */
 function text_field_widget(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
@@ -569,8 +530,58 @@ function text_field_widget(&$form, &$for
     '#type' => $instance['widget']['type'],
     '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
   );
+
+  if (isset($element['#columns'][1]) && $element['#columns'][1] == 'summary') {
+    $field_key = $element['#columns'][1];
+    $display = !empty($items[$delta][$field_key]) || !empty($instance['settings']['display_summary']);
+    $element[$field_key] = array(
+      '#title' => t('Summary'),
+      '#type' => $display ? 'textarea' : 'value',
+      '#default_value' => isset($items[$delta][$field_key]) ? $items[$delta][$field_key] : NULL,
+      '#rows' => $instance['widget']['settings']['summary_rows'],
+      '#title' => t('Summary'),
+      '#description' => t('Leave blank to use trimmed value of full text as the summary.'),
+      '#attached' => array('js' => array(drupal_get_path('module', 'text') . '/text.js')),
+      '#attributes' => array('class' => array('text-summary')),
+      '#prefix' => '<div class="text-summary-wrapper">',
+      '#suffix' => '</div>',
+    );
+  }
+
+  $field_key = $element['#columns'][0];
+  switch ($instance['widget']['type']) {
+    case 'text_textfield':
+      $element[$field_key] = array(
+        '#type' => 'textfield',
+        '#default_value' => isset($items[$delta][$field_key]) ? $items[$delta][$field_key] : NULL,
+        '#size' => $instance['widget']['settings']['size'],
+        '#title' => $instance['label'],
+        '#description' => $instance['description'],
+        '#required' => $instance['required'],
+        '#attributes' => array('class' => array('text-textfield')),
+      );
+      break;
+
+    default:
+      $element[$field_key] = array(
+        '#type' => 'textarea',
+        '#default_value' => isset($items[$delta][$field_key]) ? $items[$delta][$field_key] : NULL,
+        '#rows' => $instance['widget']['settings']['rows'],
+        '#title' => $instance['label'],
+        '#description' => $instance['description'],
+        '#required' => $instance['required'],
+        '#attributes' => array('class' => array('text-textarea')),
+        '#prefix' => '<div class="text-full-wrapper">',
+        '#suffix' => '</div>',
+      );
+      break;
+  }
+
+  // Conditionally alter the form element's type if text processing is enabled.
   if (!empty($instance['settings']['text_processing'])) {
-    $element['#value_callback'] = 'text_field_widget_formatted_text_value';
+    $element[$field_key]['#type'] .= '_format';
+    $element[$field_key]['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
+    $element[$field_key]['#format_tree'] = FALSE;
   }
 
   return $element;
@@ -593,170 +604,3 @@ function text_field_widget_error($elemen
   form_error($error_element, $error['message']);
 }
 
-/**
- * Process an individual element.
- *
- * Build the form element. When creating a form using FAPI #process,
- * note that $element['#value'] is already set.
- *
- * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
- *
- * TODO: For widgets to be actual FAPI 'elements', reusable outside of a
- * 'field' context, they shoudn't rely on $field and $instance. The bits of
- * information needed to adjust the behavior of the 'element' should be
- * extracted in hook_field_widget() above.
- */
-function text_textfield_elements_process($element, $form_state, $form) {
-  $field = $form['#fields'][$element['#field_name']]['field'];
-  $instance = $form['#fields'][$element['#field_name']]['instance'];
-  $field_key = $element['#columns'][0];
-  $delta = $element['#delta'];
-
-  $element[$field_key] = array(
-    '#type' => 'textfield',
-    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
-    '#autocomplete_path' => $element['#autocomplete_path'],
-    '#size' => $instance['widget']['settings']['size'],
-    '#attributes' => array('class' => array('text')),
-    '#title' => $element['#title'],
-    '#description' => $element['#description'],
-    '#required' => $element['#required'],
-  );
-
-  $element[$field_key]['#maxlength'] = !empty($field['settings']['max_length']) ? $field['settings']['max_length'] : NULL;
-
-  if (!empty($instance['settings']['text_processing'])) {
-    $filter_key  = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
-    $format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : filter_default_format();
-    $element[$field_key]['#text_format'] = $format;
-  }
-
-  return $element;
-}
-
-/**
- * Process an individual element.
- *
- * Build the form element. When creating a form using FAPI #process,
- * note that $element['#value'] is already set.
- *
- * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
- */
-function text_textarea_elements_process($element, $form_state, $form) {
-  $field = $form['#fields'][$element['#field_name']]['field'];
-  $instance = $form['#fields'][$element['#field_name']]['instance'];
-  $field_key = $element['#columns'][0];
-  $delta = $element['#delta'];
-
-  $element[$field_key] = array(
-    '#type' => 'textarea',
-    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
-    '#rows' => $instance['widget']['settings']['rows'],
-    '#weight' => 0,
-    '#title' => $element['#title'],
-    '#description' => $element['#description'],
-    '#required' => $element['#required'],
-  );
-
-  if (!empty($instance['settings']['text_processing'])) {
-    $filter_key = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
-    $format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : filter_default_format();
-    $element[$field_key]['#text_format'] = $format;
-  }
-
-  return $element;
-}
-
-/**
- * Process an individual element.
- *
- * Build the form element. When creating a form using FAPI #process,
- * note that $element['#value'] is already set.
- *
- * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
- */
-function text_textarea_with_summary_process($element, $form_state, $form) {
-  $field = $form['#fields'][$element['#field_name']]['field'];
-  $instance = $form['#fields'][$element['#field_name']]['instance'];
-  $delta = $element['#delta'];
-
-  $field_key = $element['#columns'][1];
-  $display = !empty($element['#value'][$field_key]) || !empty($instance['settings']['display_summary']);
-  $element[$field_key] = array(
-    '#title' => t('Summary'),
-    '#type' => $display ? 'textarea' : 'value',
-    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
-    '#rows' => $instance['widget']['settings']['summary_rows'],
-    '#weight' => 0,
-    '#title' => t('Summary'),
-    '#description' => t('Leave blank to use trimmed value of full text as the summary.'),
-    '#display' => $display,
-    '#attached' => array('js' => array(drupal_get_path('module', 'text') . '/text.js')),
-    '#attributes' => array('class' => array('text-textarea-summary')),
-    '#prefix' => '<div class="text-summary-wrapper">',
-    '#suffix' => '</div>',
-  );
-
-  $field_key = $element['#columns'][0];
-  $element[$field_key] = array(
-    '#type' => 'textarea',
-    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
-    '#rows' => $instance['widget']['settings']['rows'],
-    '#weight' => 1,
-    '#title' => $display ? t('Full text') : $element['#title'],
-    '#description' => $element['#description'],
-    '#required' => $element['#required'],
-    '#attributes' => array('class' => array('text-full-textarea')),
-    '#prefix' => '<div class="text-full-wrapper">',
-    '#suffix' => '</div>',
-  );
-
-  if (!empty($instance['settings']['text_processing'])) {
-    $filter_key  = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
-    $format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : filter_default_format();
-    $element[$field_key]['#text_format'] = $format;
-  }
-
-  return $element;
-}
-
-/**
- * Helper function to determine the value for a formatted text widget.
- *
- * '#text_format' puts the format in '[column 0]_format' in incoming values,
- * while we need it in '[column 1]'.
- */
-function text_field_widget_formatted_text_value($form, $edit = FALSE) {
-  if ($edit !== FALSE) {
-    $field_key = $form['#columns'][0];
-    $filter_key = (count($form['#columns']) == 2) ? $form['#columns'][1] : 'format';
-    $default_key = $field_key . '_format';
-    // The format selector uses #access = FALSE if only one format is
-    // available. In this case, we don't receive its value, and need to
-    // manually set it.
-    $edit['format'] = !empty($edit[$default_key]) ? $edit[$default_key] : filter_default_format();
-    unset($edit[$default_key]);
-    return $edit;
-  }
-}
-
-/**
- * FAPI theme for an individual text elements.
- *
- * The textfield or textarea is already rendered by the
- * textfield or textarea themes and the html output
- * lives in $variables['element']['#children']. Override this theme to
- * make custom changes to the output.
- *
- * $variables['element']['#field_name'] contains the field name
- * $variables['element']['#delta] is the position of this element in the group
- */
-function theme_text_textfield($variables) {
-  $element = $variables['element'];
-  return $element['#children'];
-}
-
-function theme_text_textarea($variables) {
-  $element = $variables['element'];
-  return $element['#children'];
-}
Index: modules/field/modules/text/text.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.test,v
retrieving revision 1.14
diff -u -p -r1.14 text.test
--- modules/field/modules/text/text.test	16 Oct 2009 03:47:14 -0000	1.14
+++ modules/field/modules/text/text.test	7 Nov 2009 23:57:22 -0000
@@ -166,7 +166,7 @@ class TextFieldTestCase extends DrupalWe
     // no format selector will be displayed.
     $this->drupalGet('test-entity/add/test-bundle');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
-    $this->assertNoFieldByName("{$this->field_name}[$langcode][0][value_format]", '', t('Format selector is not displayed'));
+    $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is not displayed'));
 
     // Submit with data that should be filtered.
     $value = '<em>' . $this->randomName() . '</em>';
@@ -202,11 +202,11 @@ class TextFieldTestCase extends DrupalWe
     // We should now have a 'text format' selector.
     $this->drupalGet('test-entity/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
-    $this->assertFieldByName("{$this->field_name}[$langcode][0][value_format]", '', t('Format selector is displayed'));
+    $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));
 
     // Edit and change the text format to the new one that was created.
     $edit = array(
-      "{$this->field_name}[$langcode][0][value_format]" => $format_id,
+      "{$this->field_name}[$langcode][0][format]" => $format_id,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
     $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), t('Entity was updated'));
Index: modules/filter/filter.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.css,v
retrieving revision 1.1
diff -u -p -r1.1 filter.css
--- modules/filter/filter.css	30 Mar 2009 03:15:40 -0000	1.1
+++ modules/filter/filter.css	7 Nov 2009 22:55:41 -0000
@@ -11,7 +11,6 @@
 }
 .filter-wrapper .form-item {
   float: left;
-  margin: 0;
   padding: 0 0 0.5em 1.5em;
 }
 .filter-wrapper .form-item label {
Index: modules/filter/filter.js
===================================================================
RCS file: modules/filter/filter.js
diff -N modules/filter/filter.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/filter/filter.js	7 Nov 2009 22:46:56 -0000
@@ -0,0 +1,21 @@
+// $Id: form.js,v 1.12 2009/10/16 16:37:00 dries Exp $
+(function ($) {
+
+/**
+ * Automatically display the guidelines of the selected text format.
+ */
+Drupal.behaviors.filterGuidelines = {
+  attach: function (context) {
+    $('.filter-guidelines', context).once('filter-guidelines')
+      .find('label').hide()
+      .parents('.filter-wrapper').find('select.filter-list')
+      .bind('change', function () {
+        $(this).parents('.filter-wrapper')
+          .find('.filter-guidelines-item').hide()
+          .siblings('#filter-guidelines-' + this.value).show();
+      })
+      .change();
+  }
+};
+
+})(jQuery);
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.300
diff -u -p -r1.300 filter.module
--- modules/filter/filter.module	23 Oct 2009 22:24:14 -0000	1.300
+++ modules/filter/filter.module	7 Nov 2009 23:27:29 -0000
@@ -49,6 +49,9 @@ function filter_theme() {
       'variables' => array('tips' => NULL, 'long' => FALSE),
       'file' => 'filter.pages.inc',
     ),
+    'filter_format_wrapper' => array(
+      'render element' => 'element',
+    ),
     'filter_tips_more_info' => array(
       'variables' => array(),
     ),
@@ -59,6 +62,24 @@ function filter_theme() {
 }
 
 /**
+ * Implement of hook_elements().
+ *
+ * Elements defined by Filter module are wrappers around the respective,
+ * non-prefixed elements and are expanded by filter_process_format().
+ *
+ * @see filter_process_format()
+ */
+function filter_element_info() {
+  $type['textfield_format'] = array(
+    '#process' => array('filter_process_format'),
+  );
+  $type['textarea_format'] = array(
+    '#process' => array('filter_process_format'),
+  );
+  return $type;
+}
+
+/**
  * Implement hook_menu().
  */
 function filter_menu() {
@@ -617,69 +638,187 @@ function check_markup($text, $format_id 
 /**
  * Generates a selector for choosing a format in a form.
  *
- * @param $selected_format
- *   The ID of the format that is currently selected; uses the default format
- *   for the current user if not provided.
- * @param $weight
- *   The weight of the form element within the form.
- * @param $parents
- *   The parents array of the element. Required when defining multiple text
- *   formats on a single form or having a different parent than 'format'.
+ * The form element will be expanded into two separate form elements, one
+ * holding the content of the element, and the other holding the text format
+ * selector. The original element is shifted into a child element, but is
+ * otherwise unaltered, so that the format selector is at the same level as the
+ * text field which it affects.
+ *
+ * The optional #format property should be the ID of an text format, found in
+ * {filter_format}.format, or NULL to use the default format for the current
+ * user. For example:
+ * @code
+ *   $form['body'] = array(
+ *     '#type' => 'textarea_format',
+ *     '#title' => t('Body'),
+ *     '#format' => isset($node->format) ? $node->format : NULL,
+ *   );
+ * @endcode
+ *
+ * Becomes:
+ * @code
+ *   $form['body'] = array(
+ *     '#type' => 'markup',
+ *     // 'value' holds the original element.
+ *     'value' => array(
+ *       '#type' => 'textarea',
+ *       '#title' => t('Body'),
+ *       '#parents' => array('body', 'value'),
+ *     ),
+ *     // 'format' holds the text format widget.
+ *     'format' => array(
+ *       '#parents' => array('body', 'format'),
+ *     ),
+ *   );
+ * @endcode
+ *
+ * Which results in the submitted form values:
+ * @code
+ *   // Original, unaltered form element value.
+ *   $form_state['values']['body']['value'] = 'Example content';
+ *   // Chosen text format.
+ *   $form_state['values']['body']['format'] = 1;
+ * @endcode
+ *
+ * @param $element
+ *   The form element to process. Properties used:
+ *   - #type: A form element #type suffixed with '_format'. The form element for
+ *     'value' will use this #type without the '_format' suffix. For example,
+ *     if the to be processed form element specifies 'textarea_format', then the
+ *     new child element in 'value' will use the #type 'textarea'. By default,
+ *     Filter module registers 'textarea_format' and 'textfield_format' in
+ *     filter_element_info(). Custom implementations needs to register the
+ *     suffixed '_format' types in hook_element_info().
+ *   - #format: (optional) The text format id to preselect. If 0, NULL, or not
+ *     defined, the default format for the current user will be used.
+ *   - #format_tree: (optional) If set to FALSE, then the new born child element
+ *     'format' will appear on the same array level as the original $element.
  *
  * @return
- *   Form API array for the form element.
- *
- * @ingroup forms
+ *   The expanded element.
  */
-function filter_form($selected_format = NULL, $weight = NULL, $parents = array('format')) {
+function filter_process_format($element) {
   global $user;
 
-  // Use the default format for this user if none was selected.
-  if (empty($selected_format)) {
-    $selected_format = filter_default_format($user);
+  // By default, the element will be expanded into two new child elements
+  // 'value' and 'format', which should end up as sub-keys of the original
+  // element in the submitted form values (equaling Form API's #tree behavior).
+  // However, in certain situations, form validation and submit handlers may
+  // expect the original element's value at its original location, and the
+  // 'format' value next to it on the same level (e.g. Text field module). If
+  // #format_tree was explicitly set to FALSE, then we mimic #tree = FALSE to
+  // some extent, but having the difference that the resulting values will not
+  // end up on the top-level of the form; the #parents property of the new child
+  // elements take over the #parents of the original element, and the 'format'
+  // element is placed next to the original element.
+  $tree = !isset($element['#format_tree']) || $element['#format_tree'];
+
+  $value_parents = $element['#parents'];
+  $format_parents = $element['#parents'];
+  // If #format_tree is FALSE, make the 'format' element appear on the same
+  // level as the passed in element.
+  if (!$tree) {
+    array_pop($format_parents);
   }
+  else {
+    $value_parents[] = 'value';
+  }
+  $format_parents[] = 'format';
 
+  // Move this element into sub-element 'value'. Break references and remove
+  // this #process function to prevent form_builder() to recurse infinitely.
+  $element['value'] = (array) $element;
+  $element['value']['#process'] = array_diff($element['value']['#process'], array('filter_process_format'));
+
+  // Turn this element into a text format wrapper.
+  $element['#type'] = 'markup';
+  unset($element['#theme']);
+  $element['#theme_wrappers'] = array('filter_format_wrapper');
+  $path = drupal_get_path('module', 'filter');
+  $element['#attached']['js'][] = $path . '/filter.js';
+  $element['#attached']['css'][] = $path . '/filter.css';
+
+  // Setup child element for value.
+  // The #type without '_format' suffix is expected to be a valid #type. This
+  // allows to enhance further (and custom) form elements with text formats.
+  $element['value']['#type'] = strtr($element['value']['#type'], array('_format' => ''));
+  $element['value'] += element_info($element['value']['#type']);
+  $element['value']['#parents'] = $value_parents;
+  // Description is handled by theme_filter_format_wrapper() and weight needs
+  // to be reset to ensure proper ordering.
+  unset($element['value']['#description'], $element['value']['#weight']);
+  // Unset properties that will be processed for the original element already.
+  unset($element['value']['#prefix'], $element['value']['#suffix'], $element['value']['#attached']);
+
+  // Setup child element for text format widget.
+  $element['format'] = element_info('fieldset');
+  $element['format']['#defaults_loaded'] = TRUE;
+  $element['format']['#attributes']['class'][] = 'filter-wrapper';
+
+  // Prepare text format guidelines.
+  $element['format']['guidelines'] = array(
+    '#type' => 'container',
+    '#attributes' => array('class' => array('filter-guidelines')),
+    '#weight' => 20,
+  );
   // Get a list of formats that the current user has access to.
   $formats = filter_formats($user);
-
-  drupal_add_js('misc/form.js');
-  drupal_add_css(drupal_get_path('module', 'filter') . '/filter.css');
-  $element_id = drupal_html_id('edit-' . implode('-', $parents));
-
-  $form = array(
-    '#type' => 'fieldset',
-    '#weight' => $weight,
-    '#attributes' => array('class' => array('filter-wrapper')),
-  );
-  $form['format_guidelines'] = array(
-    '#prefix' => '<div id="' . $element_id . '-guidelines" class="filter-guidelines">',
-    '#suffix' => '</div>',
-    '#weight' => 2,
-  );
   foreach ($formats as $format) {
     $options[$format->format] = $format->name;
-    $form['format_guidelines'][$format->format] = array(
-      '#markup' => theme('filter_guidelines', array('format' => $format)),
+    $element['format']['guidelines'][$format->format] = array(
+      '#theme' => 'filter_guidelines',
+      '#format' => $format,
     );
   }
-  $form['format'] = array(
+
+  // Use the default format for this user if none was selected.
+  if (empty($element['#format'])) {
+    $element['#format'] = filter_default_format($user);
+  }
+  $element['format']['format'] = array(
     '#type' => 'select',
     '#title' => t('Text format'),
     '#options' => $options,
-    '#default_value' => $selected_format,
-    '#parents' => $parents,
+    '#default_value' => $element['#format'],
     '#access' => count($formats) > 1,
-    '#id' => $element_id,
+    '#weight' => 10,
     '#attributes' => array('class' => array('filter-list')),
+    '#parents' => $format_parents,
   );
-  $form['format_help'] = array(
-    '#prefix' => '<div id="' . $element_id . '-help" class="filter-help">',
-    '#markup' => theme('filter_tips_more_info'),
-    '#suffix' => '</div>',
-    '#weight' => 1,
+
+  $element['format']['help'] = array(
+    '#type' => 'container',
+    '#theme' => 'filter_tips_more_info',
+    '#attributes' => array('class' => array('filter-help')),
+    '#weight' => 0,
   );
 
-  return $form;
+  return $element;
+}
+
+/**
+ * Theme a text format form element.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties of the element.
+ *     Properties used: #children, #description
+ *
+ * @return
+ *   A string representing the form element.
+ *
+ * @ingroup themeable
+ */
+function theme_filter_format_wrapper($variables) {
+  $element = $variables['element'];
+  $output = '<div class="text-format-wrapper">';
+  $output .= $element['#children'];
+  if (!empty($element['#description'])) {
+    $output .= '<div class="description">' . $element['#description'] . '</div>';
+  }
+  $output .= "</div>\n";
+
+  return $output;
 }
 
 /**
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.46
diff -u -p -r1.46 filter.test
--- modules/filter/filter.test	13 Oct 2009 15:39:41 -0000	1.46
+++ modules/filter/filter.test	8 Nov 2009 00:00:05 -0000
@@ -277,7 +277,7 @@ class FilterAdminTestCase extends Drupal
     $langcode = FIELD_LANGUAGE_NONE;
     $edit["title[$langcode][0][value]"] = $this->randomName();
     $edit["body[$langcode][0][value]"] = $text;
-    $edit["body[$langcode][0][value_format]"] = $filtered;
+    $edit["body[$langcode][0][format]"] = $filtered;
     $this->drupalPost('node/add/page', $edit, t('Save'));
     $this->assertRaw(t('Page %title has been created.', array('%title' => $edit["title[$langcode][0][value]"])), t('Filtered node created.'));
 
@@ -289,7 +289,7 @@ class FilterAdminTestCase extends Drupal
 
     // Use plain text and see if it escapes all tags, whether allowed or not.
     $edit = array();
-    $edit["body[$langcode][0][value_format]"] = $plain;
+    $edit["body[$langcode][0][format]"] = $plain;
     $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
     $this->drupalGet('node/' . $node->nid);
     $this->assertText(check_plain($text), t('The "Plain text" text format escapes all HTML tags.'));
@@ -1161,9 +1161,9 @@ class FilterHooksTestCase extends Drupal
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $this->randomName(8);
-    $custom_block['body'] = $this->randomName(32);
+    $custom_block['body[value]'] = $this->randomName(32);
     // Use the format created.
-    $custom_block['body_format'] = $format_id;
+    $custom_block['body[format]'] = $format_id;
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
     $this->assertText(t('The block has been created.'), t('New block successfully created.'));
 
Index: modules/php/php.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/php/php.test,v
retrieving revision 1.18
diff -u -p -r1.18 php.test
--- modules/php/php.test	11 Oct 2009 03:07:19 -0000	1.18
+++ modules/php/php.test	8 Nov 2009 00:02:17 -0000
@@ -65,7 +65,7 @@ class PHPFilterTestCase extends PHPTestC
     // Change filter to PHP filter and see that PHP code is evaluated.
     $edit = array();
     $langcode = FIELD_LANGUAGE_NONE;
-    $edit["body[$langcode][0][value_format]"] = $this->php_code_format;
+    $edit["body[$langcode][0][format]"] = $this->php_code_format;
     $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
     $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value'])), t('PHP code filter turned on.'));
 
Index: modules/search/search.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.test,v
retrieving revision 1.42
diff -u -p -r1.42 search.test
--- modules/search/search.test	19 Oct 2009 23:28:40 -0000	1.42
+++ modules/search/search.test	8 Nov 2009 01:23:01 -0000
@@ -488,7 +488,7 @@ class SearchCommentTestCase extends Drup
     $edit_comment = array(
       'subject' => $this->randomName(2),
       'comment' => '<h1>' . $comment_body . '</h1>',
-      'comment_format' => 2,
+      'format' => 2,
     );
     $this->drupalPost('comment/reply/' . $node->nid, $edit_comment, t('Save'));
 
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.837
diff -u -p -r1.837 system.module
--- modules/system/system.module	7 Nov 2009 13:35:21 -0000	1.837
+++ modules/system/system.module	7 Nov 2009 16:19:57 -0000
@@ -354,7 +354,7 @@ function system_element_info() {
     '#size' => 60,
     '#maxlength' => 128,
     '#autocomplete_path' => FALSE,
-    '#process' => array('form_process_text_format', 'ajax_process_form'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'textfield',
     '#theme_wrappers' => array('form_element'),
   );
@@ -376,7 +376,7 @@ function system_element_info() {
     '#cols' => 60,
     '#rows' => 5,
     '#resizable' => TRUE,
-    '#process' => array('form_process_text_format', 'ajax_process_form'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'textarea',
     '#theme_wrappers' => array('form_element'),
   );
