? benchmark_318636.php
? benchmark_318636.txt
? test.php
? theme_head.php
? theme_head.txt
? theme_patched.php
? theme_patched.txt
? sites/all/modules/iframesrc.zip
? sites/all/modules/test569362.zip
? sites/default/private
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1021
diff -u -p -r1.1021 common.inc
--- includes/common.inc	15 Oct 2009 21:19:30 -0000	1.1021
+++ includes/common.inc	16 Oct 2009 06:02:04 -0000
@@ -4988,10 +4988,12 @@ function drupal_common_theme() {
     'html' => array(
       'arguments' => array('page' => NULL),
       'template' => 'html',
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
     ),
     'page' => array(
       'arguments' => array('page' => NULL),
       'template' => 'page',
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
     ),
     'region' => array(
       'arguments' => array('elements' => NULL),
@@ -5100,6 +5102,7 @@ function drupal_common_theme() {
     ),
     'menu_tree' => array(
       'arguments' => array('tree' => NULL),
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
     ),
     'menu_local_task' => array(
       'arguments' => array('element' => NULL),
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.536
diff -u -p -r1.536 theme.inc
--- includes/theme.inc	15 Oct 2009 12:27:34 -0000	1.536
+++ includes/theme.inc	16 Oct 2009 06:02:04 -0000
@@ -37,6 +37,29 @@ define('MARK_UPDATED', 2);
  * @} End of "Content markers".
  */
 
+/**
+ * @name Render integration modes
+ * @{
+ * How theme() should map a renderable element to theme hook arguments.
+ * @see theme(), hook_theme()
+ */
+
+/**
+ * When theme() is passed a renderable element instead of a variables array,
+ * set the first theme hook argument to the element.
+ */
+define('THEME_SET_FIRST_ARGUMENT_TO_ELEMENT', 1);
+
+/**
+ * When theme() is passed a renderable element instead of a variables array,
+ * set each argument to the value of the element's correspondingly named
+ * property.
+ */
+define('THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES', 2);
+
+/**
+ * @} End of "Render integration modes".
+ */
 
 /**
  * An exception to throw when a theme function is requested that does not exist.
@@ -308,6 +331,8 @@ function drupal_theme_rebuild() {
  *   - 'arguments': The arguments for this theme hook as defined in
  *     hook_theme(). If there is more than one implementation and 'arguments' is
  *     not specified in a later one, then the previous definition is kept.
+ *   - 'render integration': How theme() should map a renderable element to
+ *     the arguments delcared in 'arguments'.
  *   - 'theme paths': The paths where implementations of a theme hook can be
  *     found. Its definition is similarly inherited like 'arguments'. Each time
  *     _theme_process_registry() is called for this theme hook, either the
@@ -377,6 +402,10 @@ function _theme_process_registry(&$cache
       if (!isset($info['arguments']) && isset($cache[$hook])) {
         $result[$hook]['arguments'] = $cache[$hook]['arguments'];
       }
+      // Same for 'render integration'.
+      if (!isset($info['render integration']) && isset($cache[$hook]) && isset($cache[$hook]['render integration'])) {
+        $result[$hook]['render integration'] = $cache[$hook]['render integration'];
+      }
 
       // The following apply only to theming hooks implemented as templates.
       if (isset($info['template'])) {
@@ -516,13 +545,33 @@ function _theme_build_registry($theme, $
   // Let modules alter the registry.
   drupal_alter('theme_registry', $cache);
 
-  // Optimize the registry to not have empty arrays for functions.
+  // Final adjustments.
   foreach ($cache as $hook => $info) {
+    // Optimize the registry to not have empty arrays for functions.
     foreach (array('preprocess functions', 'process functions') as $phase) {
       if (empty($info[$phase])) {
         unset($cache[$hook][$phase]);
       }
     }
+    // Set a default render integration mode.
+    // @see hook_theme()
+    if (!isset($info['render integration']) && !empty($info['arguments'])) {
+      $arg_keys = array_keys($info['arguments']);
+      if (count($arg_keys) > 1) {
+        $cache[$hook]['render integration'] = THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES;
+      }
+      elseif (in_array($arg_keys[0], array('element', 'elements', 'form'))) {
+        $cache[$hook]['render integration'] = THEME_SET_FIRST_ARGUMENT_TO_ELEMENT;
+      }
+      else {
+        $cache[$hook]['render integration'] = THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES;
+      }
+    }
+    elseif (!isset($info['render integration'])) {
+      // For theme hooks with no arguments, still allow theme() to access this
+      // property without triggering a PHP Notice. 
+      $cache[$hook]['render integration'] = NULL;
+    }
   }
   return $cache;
 }
@@ -785,23 +834,24 @@ function theme($hook, $variables = array
   }
 
   // If a renderable array is passed as $variables, then set $variables to
-  // what's expected by the theme hook. If the theme hook expects a single
-  // argument, set the renderable array as that argument. If the theme hook
-  // expects multiple arguments, set the properties of the renderable array as
-  // those arguments.
+  // what's expected by the theme hook.
   if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
     $element = $variables;
     $variables = array();
-    $n = count($info['arguments']);
-    if ($n == 1) {
+    if (!empty($info['arguments'])) {
       $arg_keys = array_keys($info['arguments']);
-      $variables[$arg_keys[0]] = $element;
-    }
-    elseif ($n > 1) {
-      foreach ($info['arguments'] as $name => $default) {
-        if (isset($element["#$name"])) {
-          $variables[$name] = $element["#$name"];
-        }
+      switch ($info['render integration']) {
+        case THEME_SET_FIRST_ARGUMENT_TO_ELEMENT:
+          $variables[$arg_keys[0]] = $element;
+          break;
+
+        case THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES:
+          foreach ($arg_keys as $name) {
+            if (isset($element["#$name"])) {
+              $variables[$name] = $element["#$name"];
+            }
+          }
+          break;
       }
     }
   }
@@ -998,6 +1048,7 @@ function drupal_find_theme_functions($ca
             $templates[$new_hook] = array(
               'function' => $match,
               'arguments' => $info['arguments'],
+              'render integration' => isset($info['render integration']) ? $info['render integration'] : NULL,
             );
           }
         }
@@ -1102,6 +1153,7 @@ function drupal_find_theme_templates($ca
             'template' => $file,
             'path' => dirname($files[$match]->uri),
             'arguments' => $info['arguments'],
+            'render integration' => isset($info['render integration']) ? $info['render integration'] : NULL,
           );
         }
       }
Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.519
diff -u -p -r1.519 book.module
--- modules/book/book.module	15 Oct 2009 14:07:26 -0000	1.519
+++ modules/book/book.module	16 Oct 2009 06:02:04 -0000
@@ -27,6 +27,7 @@ function book_theme() {
     ),
     'book_all_books_block' => array(
       'arguments' => array('book_menus' => array()),
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
       'template' => 'book-all-books-block',
     ),
     'book_node_export_html' => array(
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.787
diff -u -p -r1.787 comment.module
--- modules/comment/comment.module	15 Oct 2009 16:18:45 -0000	1.787
+++ modules/comment/comment.module	16 Oct 2009 06:02:04 -0000
@@ -147,6 +147,7 @@ function comment_theme() {
     'comment_wrapper' => array(
       'template' => 'comment-wrapper',
       'arguments' => array('content' => NULL),
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
     ),
   );
 }
Index: modules/simpletest/simpletest.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v
retrieving revision 1.77
diff -u -p -r1.77 simpletest.module
--- modules/simpletest/simpletest.module	9 Oct 2009 01:00:03 -0000	1.77
+++ modules/simpletest/simpletest.module	16 Oct 2009 06:02:05 -0000
@@ -76,6 +76,7 @@ function simpletest_theme() {
   return array(
     'simpletest_test_table' => array(
       'arguments' => array('table' => NULL),
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
       'file' => 'simpletest.pages.inc',
     ),
     'simpletest_result_summary' => array(
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.90
diff -u -p -r1.90 system.api.php
--- modules/system/system.api.php	15 Oct 2009 17:55:55 -0000	1.90
+++ modules/system/system.api.php	16 Oct 2009 06:02:05 -0000
@@ -804,8 +804,32 @@ function hook_permission() {
  *   value allows the theme layer to properly utilize templates. The
  *   array keys represent the name of the variable, and the value will be
  *   used as the default value if not specified to the theme() function.
- *   These arguments must be in the same order that they will be given to
- *   the theme() function.
+ *   Template implementations receive these arguments as variables in the
+ *   template file. Function implementations receive these arguments within the
+ *   $variables parameter.
+ * - render integration: There's a close relationship between the drupal
+ *   element rendering system (invoked with render()) and the theme system.
+ *   Modules can assign any theme hook to be used for rendering any element.
+ *   However, for this to work properly, theme() needs to know how to convert
+ *   the element's data into arguments appropriate for the theme hook. This
+ *   property can be set to one of:
+ *   - THEME_SET_FIRST_ARGUMENT_TO_ELEMENT: specifies that the element should
+ *     be passed as the argument name that is declared first in the 'arguments'
+ *     property.
+ *   - THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES: specifies that for each
+ *     argument declared in 'arguments', the element's property of the same
+ *     name (except starting with '#' as all element properties must) should
+ *     be passed as that argument.
+ *   If this property is not specified, the theme system uses the following
+ *   logic to decide:
+ *   - If there is only 1 argument defined in 'arguments' and that argument is
+ *     named either 'element', 'elements', or 'form', then
+ *     THEME_SET_FIRST_ARGUMENT_TO_ELEMENT is assumed.
+ *   - Otherwise, THEME_SET_ARGUMENTS_TO_ELEMENT_PROPERTIES is assumed.
+ *   Because of this, it is encouraged that theme hooks intended to operate on
+ *   renderable elements be defined with 1 argument named one of the above.
+ *   However, if that recommendation isn't followed, this property can be used
+ *   to achieve the element-to-argument mapping needed by the theme hook.
  * - file: The file the implementation resides in. This file will be included
  *   prior to the theme being rendered, to make sure that the function or
  *   preprocess function (as needed) is actually loaded; this makes it possible
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.816
diff -u -p -r1.816 system.module
--- modules/system/system.module	15 Oct 2009 21:19:31 -0000	1.816
+++ modules/system/system.module	16 Oct 2009 06:02:05 -0000
@@ -180,6 +180,7 @@ function system_theme() {
     ),
     'status_report' => array(
       'arguments' => array('requirements' => NULL),
+      'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
       'file' => 'system.admin.inc',
     ),
     'admin_page' => array(
Index: modules/toolbar/toolbar.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.module,v
retrieving revision 1.13
diff -u -p -r1.13 toolbar.module
--- modules/toolbar/toolbar.module	15 Sep 2009 20:50:48 -0000	1.13
+++ modules/toolbar/toolbar.module	16 Oct 2009 06:02:05 -0000
@@ -24,6 +24,7 @@ function toolbar_permission() {
 function toolbar_theme($existing, $type, $theme, $path) {
   $items['toolbar'] = array(
     'arguments' => array('toolbar' => array()),
+    'render integration' => THEME_SET_FIRST_ARGUMENT_TO_ELEMENT,
     'template' => 'toolbar',
     'path' => drupal_get_path('module', 'toolbar'),
   );
Index: modules/update/update.report.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.report.inc,v
retrieving revision 1.26
diff -u -p -r1.26 update.report.inc
--- modules/update/update.report.inc	15 Oct 2009 21:19:31 -0000	1.26
+++ modules/update/update.report.inc	16 Oct 2009 06:02:05 -0000
@@ -199,7 +199,7 @@ function theme_update_report($variables)
             break;
             
           default:
-            $base_themes[] = theme('placeholder', $base_theme);
+            $base_themes[] = theme('placeholder', array('text' => $base_theme));
         }
       }
       $row .= t('Depends on: !basethemes', array('!basethemes' => implode(', ', $base_themes)));
