Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1214
diff -u -p -r1.1214 common.inc
--- includes/common.inc	5 Sep 2010 15:38:16 -0000	1.1214
+++ includes/common.inc	7 Sep 2010 13:48:58 -0000
@@ -230,7 +230,7 @@ function drupal_get_profile() {
 function drupal_set_breadcrumb($breadcrumb = NULL) {
   $stored_breadcrumb = &drupal_static(__FUNCTION__);
 
-  if (!is_null($breadcrumb)) {
+  if (isset($breadcrumb)) {
     $stored_breadcrumb = $breadcrumb;
   }
   return $stored_breadcrumb;
@@ -242,7 +242,7 @@ function drupal_set_breadcrumb($breadcru
 function drupal_get_breadcrumb() {
   $breadcrumb = drupal_set_breadcrumb();
 
-  if (is_null($breadcrumb)) {
+  if (!isset($breadcrumb)) {
     $breadcrumb = menu_get_active_breadcrumb();
   }
 
@@ -2264,15 +2264,27 @@ function drupal_attributes(array $attrib
 function l($text, $path, array $options = array()) {
   global $language_url;
   static $use_theme = NULL;
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['active'] = &drupal_static(__FUNCTION__);
+  }
+  $active_href = &$drupal_static_fast['active'];
 
   // Merge in defaults.
   $options += array(
-      'attributes' => array(),
-      'html' => FALSE,
-    );
+    'attributes' => array(),
+    'html' => FALSE,
+  );
 
+  // The active item needs to be cached by $_GET['q'] to account for an altered
+  // path via menu_set_active_item().
+  if (!isset($active_href[$_GET['q']])) {
+    $active_item = menu_get_active_item();
+    $active_href[$_GET['q']] = $active_item['href'];
+  }
   // Append active class.
-  if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
+  if (($path == $active_href[$_GET['q']] || ($path == '<front>' && drupal_is_front_page())) &&
       (empty($options['language']) || $options['language']->language == $language_url->language)) {
     $options['attributes']['class'][] = 'active';
   }
@@ -6154,7 +6166,7 @@ function drupal_write_record($table, &$r
     }
 
     if (!property_exists($object, $field)) {
-      // Skip fields that are not provided, default values are already known 
+      // Skip fields that are not provided, default values are already known
       // by the database.
       continue;
     }
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.408
diff -u -p -r1.408 menu.inc
--- includes/menu.inc	1 Sep 2010 02:59:04 -0000	1.408
+++ includes/menu.inc	7 Sep 2010 13:48:28 -0000
@@ -141,9 +141,9 @@ define('MENU_NORMAL_ITEM', MENU_VISIBLE_
  * Menu type -- A hidden, internal callback, typically used for API calls.
  *
  * Callbacks simply register a path so that the correct function is fired
- * when the URL is accessed. They are not shown in the menu.
+ * when the URL is accessed. They do not appear in menus or breadcrumbs.
  */
-define('MENU_CALLBACK', MENU_VISIBLE_IN_BREADCRUMB);
+define('MENU_CALLBACK', 0x0000);
 
 /**
  * Menu type -- A normal menu item, hidden until enabled by an administrator.
@@ -728,12 +728,26 @@ function _menu_translate(&$router_item, 
 
   // Generate the link path for the page request or local tasks.
   $link_map = explode('/', $router_item['path']);
+  if (isset($router_item['tab_root'])) {
+    $tab_root_map = explode('/', $router_item['tab_root']);
+  }
+  if (isset($router_item['tab_parent'])) {
+    $tab_parent_map = explode('/', $router_item['tab_parent']);
+  }
   for ($i = 0; $i < $router_item['number_parts']; $i++) {
     if ($link_map[$i] == '%') {
       $link_map[$i] = $path_map[$i];
     }
+    if (isset($tab_root_map[$i]) && $tab_root_map[$i] == '%') {
+      $tab_root_map[$i] = $path_map[$i];
+    }
+    if (isset($tab_parent_map[$i]) && $tab_parent_map[$i] == '%') {
+      $tab_parent_map[$i] = $path_map[$i];
+    }
   }
   $router_item['href'] = implode('/', $link_map);
+  $router_item['tab_root_href'] = implode('/', $tab_root_map);
+  $router_item['tab_parent_href'] = implode('/', $tab_parent_map);
   $router_item['options'] = array();
   _menu_check_access($router_item, $map);
 
@@ -778,7 +792,11 @@ function menu_tail_to_arg($arg, $map, $i
  * preparation such as always calling to_arg functions
  *
  * @param $item
- *   A menu link
+ *   A menu link.
+ * @param $translate
+ *   (optional) Whether to try to translate a link containing dynamic path
+ *   argument placeholders (%) based on the menu router item of the current
+ *   path. Defaults to FALSE. Internally used for breadcrumbs only.
  *
  * @return
  *   Returns the map of path arguments with objects loaded as defined in the
@@ -789,7 +807,7 @@ function menu_tail_to_arg($arg, $map, $i
  *   $item['options'] is unserialized; it is also changed within the call here
  *   to $item['localized_options'] by _menu_item_localize().
  */
-function _menu_link_translate(&$item) {
+function _menu_link_translate(&$item, $translate = FALSE) {
   $item['options'] = unserialize($item['options']);
   if ($item['external']) {
     $item['access'] = 1;
@@ -799,13 +817,34 @@ function _menu_link_translate(&$item) {
     $item['localized_options'] = $item['options'];
   }
   else {
+    // Complete the path of the menu link with elements from the current path,
+    // if it contains dynamic placeholders (%).
     $map = explode('/', $item['link_path']);
-    if (!empty($item['to_arg_functions'])) {
-      _menu_link_map_translate($map, $item['to_arg_functions']);
+    if (strpos($item['link_path'], '%') !== FALSE) {
+      // Invoke registered to_arg callbacks.
+      if (!empty($item['to_arg_functions'])) {
+        _menu_link_map_translate($map, $item['to_arg_functions']);
+      }
+      // Or try to derive the path argument map from the current router item,
+      // if this $item's path is within the router item's path. This means that
+      // if we are on the current path 'foo/%/bar/%/baz', then menu_get_item()
+      // will have translated the menu router item for the current path, and we
+      // can take over the argument map for a link like 'foo/%/bar'. This
+      // inheritance is primarily used for breadcrumb links.
+      elseif ($translate && ($current_router_item = menu_get_item())) {
+        if (strpos($current_router_item['path'], $item['link_path']) === 0) {
+          $count = count($map);
+          $map = array_slice($current_router_item['original_map'], 0, $count);
+          $item['original_map'] = $map;
+          if (isset($current_router_item['map'])) {
+            $item['map'] = array_slice($current_router_item['map'], 0, $count);
+          }
+        }
+      }
     }
     $item['href'] = implode('/', $map);
 
-    // Note - skip callbacks without real values for their arguments.
+    // Skip links containing untranslated arguments.
     if (strpos($item['href'], '%') !== FALSE) {
       $item['access'] = FALSE;
       return FALSE;
@@ -993,7 +1032,7 @@ function menu_tree_all_data($menu_name, 
   // Use $mlid as a flag for whether the data being loaded is for the whole tree.
   $mlid = isset($link['mlid']) ? $link['mlid'] : 0;
   // Generate a cache ID (cid) specific for this $menu_name, $link, $language, and depth.
-  $cid = 'links:' . $menu_name . ':all-cid:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int) $max_depth;
+  $cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int) $max_depth;
 
   if (!isset($tree[$cid])) {
     // If the static variable doesn't have the data, check {cache_menu}.
@@ -1042,9 +1081,16 @@ function menu_tree_all_data($menu_name, 
  * field, see http://drupal.org/node/141866 for more.
  *
  * @param $menu_name
- *   The named menu links to return
+ *   The named menu links to return.
  * @param $max_depth
- *   Optional maximum depth of links to retrieve.
+ *   (optional) The maximum depth of links to retrieve.
+ * @param $only_active_trail
+ *   (optional) Whether to only return the links in the active trail (TRUE)
+ *   instead of all links on every level of the menu link tree (FALSE). If set
+ *   to TRUE, links containing dynamic path argument placeholders (%) in the
+ *   active trail are additionally tried to be translated based on the menu
+ *   router item of the current path. Defaults to FALSE. Internally used for
+ *   breadcrumbs only.
  *
  * @return
  *   An array of menu links, in the order they should be rendered. The array
@@ -1053,7 +1099,7 @@ function menu_tree_all_data($menu_name, 
  *   submenu below the link if there is one, and it is a subtree that has the
  *   same structure described for the top-level array.
  */
-function menu_tree_page_data($menu_name, $max_depth = NULL) {
+function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
   $tree = &drupal_static(__FUNCTION__, array());
 
   // Load the menu item corresponding to the current page.
@@ -1062,7 +1108,7 @@ function menu_tree_page_data($menu_name,
       $max_depth = min($max_depth, MENU_MAX_DEPTH);
     }
     // Generate a cache ID (cid) specific for this page.
-    $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth;
+    $cid = 'links:' . $menu_name . ':page:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth . ':' . (int) $only_active_trail;
 
     if (!isset($tree[$cid])) {
       // If the static variable doesn't have the data, check {cache_menu}.
@@ -1078,57 +1124,34 @@ function menu_tree_page_data($menu_name,
           'min_depth' => 1,
           'max_depth' => $max_depth,
         );
+        // Parent mlids; used both as key and value to ensure uniqueness.
+        // We always want all the top-level links with plid == 0.
+        $active_trail = array('0' => '0');
+
         // If the item for the current page is accessible, build the tree
         // parameters accordingly.
         if ($item['access']) {
-          // Check whether a menu link exists that corresponds to the current path.
-          $args[] = $item['href'];
-          if (drupal_is_front_page()) {
-            $args[] = '<front>';
-          }
-          $active_link = db_select('menu_links')
-            ->fields('menu_links', array(
-              'p1',
-              'p2',
-              'p3',
-              'p4',
-              'p5',
-              'p6',
-              'p7',
-              'p8',
-            ))
-            ->condition('menu_name', $menu_name)
-            ->condition('link_path', $args, 'IN')
-            ->execute()->fetchAssoc();
-
-          if (empty($active_link)) {
-            // If no link exists, we may be on a local task that's not in the links.
-            // TODO: Handle the case like a local task on a specific node in the menu.
-            $active_link = db_select('menu_links')
-              ->fields('menu_links', array(
-                'p1',
-                'p2',
-                'p3',
-                'p4',
-                'p5',
-                'p6',
-                'p7',
-                'p8',
-              ))
-              ->condition('menu_name', $menu_name)
-              ->condition('link_path', $item['tab_root'])
-              ->execute()->fetchAssoc();
+          // Find a menu link corresponding to the current path.
+          if ($top_link = menu_link_get_preferred()) {
+            // Use all the coordinates, except the last one because there
+            // can be no child beyond the last column.
+            for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
+              if ($top_link['p' . $i]) {
+                $active_trail[$top_link['p' . $i]] = $top_link['p' . $i];
+              }
+            }
           }
-
-          // We always want all the top-level links with plid == 0.
-          $active_link[] = '0';
-
-          // Use array_values() so that the indices are numeric.
-          $parents = $active_link = array_unique(array_values($active_link));
+          $parents = $active_trail;
 
           $expanded = variable_get('menu_expanded', array());
+          // If we are asked to build links for the active trail only, then skip
+          // the entire 'expanded' handling. Since there is no breadcrumb on
+          // access denied pages, it is safe to set this only here.
+          if ($only_active_trail) {
+            $tree_parameters['only_active_trail'] = TRUE;
+          }
           // Check whether the current menu has any links set to be expanded.
-          if (in_array($menu_name, $expanded)) {
+          elseif (in_array($menu_name, $expanded)) {
             // Collect all the links set to be expanded, and then add all of
             // their children to the list as well.
             do {
@@ -1142,19 +1165,19 @@ function menu_tree_page_data($menu_name,
                 ->execute();
               $num_rows = FALSE;
               foreach ($result as $item) {
-                $parents[] = $item['mlid'];
+                $parents[$item['mlid']] = $item['mlid'];
                 $num_rows = TRUE;
               }
             } while ($num_rows);
           }
           $tree_parameters['expanded'] = $parents;
-          $tree_parameters['active_trail'] = $active_link;
+          $tree_parameters['active_trail'] = $active_trail;
         }
-        // Otherwise, only show the top-level menu items when access is denied.
+        // If access is denied, we only show top-level links in menus.
         else {
-          $tree_parameters['expanded'] = array(0);
+          $tree_parameters['expanded'] = $active_trail;
+          $tree_parameters['active_trail'] = $active_trail;
         }
-
         // Cache the tree building parameters using the page-specific cid.
         cache_set($cid, $tree_parameters, 'cache_menu');
       }
@@ -1178,9 +1201,14 @@ function menu_tree_page_data($menu_name,
  *   (optional) An associative array of build parameters. Possible keys:
  *   - expanded: An array of parent link ids to return only menu links that are
  *     children of one of the plids in this list. If empty, the whole menu tree
- *     is built.
+ *     is built, unless 'only_active_trail' is TRUE.
  *   - active_trail: An array of mlids, representing the coordinates of the
  *     currently active menu link.
+ *   - only_active_trail: Whether to only return links that are in the active
+ *     trail. This option is ignored, if 'expanded' is non-empty. If enabled,
+ *     links containing dynamic path argument placeholders (%) are additionally
+ *     translated based on the menu router item of the current path. Internally
+ *     used for breadcrumbs only.
  *   - min_depth: The minimum depth of menu links in the resulting tree.
  *     Defaults to 1, which is the default to build a whole tree for a menu, i.e.
  *     excluding menu container itself.
@@ -1193,7 +1221,7 @@ function menu_build_tree($menu_name, arr
   // Build the menu tree.
   $data = _menu_build_tree($menu_name, $parameters);
   // Check access for the current user to each item in the tree.
-  menu_tree_check_access($data['tree'], $data['node_links']);
+  menu_tree_check_access($data['tree'], $data['node_links'], $parameters);
   return $data['tree'];
 }
 
@@ -1241,6 +1269,8 @@ function _menu_build_tree($menu_name, ar
       'page_callback',
       'page_arguments',
       'delivery_callback',
+      'tab_parent',
+      'tab_root',
       'title',
       'title_callback',
       'title_arguments',
@@ -1256,6 +1286,9 @@ function _menu_build_tree($menu_name, ar
     if (!empty($parameters['expanded'])) {
       $query->condition('ml.plid', $parameters['expanded'], 'IN');
     }
+    elseif (!empty($parameters['only_active_trail'])) {
+      $query->condition('ml.mlid', $parameters['active_trail'], 'IN');
+    }
     $min_depth = (isset($parameters['min_depth']) ? $parameters['min_depth'] : 1);
     if ($min_depth != 1) {
       $query->condition('ml.depth', $min_depth, '>=');
@@ -1269,8 +1302,8 @@ function _menu_build_tree($menu_name, ar
     foreach ($query->execute() as $item) {
       $links[] = $item;
     }
-    $active_link = (isset($parameters['active_trail']) ? $parameters['active_trail'] : array());
-    $data['tree'] = menu_tree_data($links, $active_link, $min_depth);
+    $active_trail = (isset($parameters['active_trail']) ? $parameters['active_trail'] : array());
+    $data['tree'] = menu_tree_data($links, $active_trail, $min_depth);
     $data['node_links'] = array();
     menu_tree_collect_node_links($data['tree'], $data['node_links']);
 
@@ -1313,9 +1346,11 @@ function menu_tree_collect_node_links(&$
  * @param $node_links
  *   A collection of node link references generated from $tree by
  *   menu_tree_collect_node_links().
+ * @param $parameters
+ *   (optional) An associative array of tree building parameters. See
+ *   menu_build_tree() for details.
  */
-function menu_tree_check_access(&$tree, $node_links = array()) {
-
+function menu_tree_check_access(&$tree, $node_links = array(), array $parameters = array()) {
   if ($node_links) {
     $nids = array_keys($node_links);
     $select = db_select('node', 'n');
@@ -1330,21 +1365,20 @@ function menu_tree_check_access(&$tree, 
       }
     }
   }
-  _menu_tree_check_access($tree);
-  return;
+  _menu_tree_check_access($tree, $parameters);
 }
 
 /**
  * Recursive helper function for menu_tree_check_access()
  */
-function _menu_tree_check_access(&$tree) {
+function _menu_tree_check_access(&$tree, $parameters) {
   $new_tree = array();
   foreach ($tree as $key => $v) {
     $item = &$tree[$key]['link'];
-    _menu_link_translate($item);
+    _menu_link_translate($item, !empty($parameters['only_active_trail']));
     if ($item['access']) {
       if ($tree[$key]['below']) {
-        _menu_tree_check_access($tree[$key]['below']);
+        _menu_tree_check_access($tree[$key]['below'], $parameters);
       }
       // The weights are made a uniform 5 digits by adding 50000 as an offset.
       // After _menu_link_translate(), $item['title'] has the localized link title.
@@ -1729,7 +1763,7 @@ function menu_local_tasks($level = 0) {
     // If this router item points to its parent, start from the parents to
     // compute tabs and actions.
     if ($router_item && ($router_item['type'] & MENU_LINKS_TO_PARENT)) {
-      $router_item = menu_get_item($router_item['tab_parent']);
+      $router_item = menu_get_item($router_item['tab_parent_href']);
     }
 
     // If we failed to fetch a router item or the current user doesn't have
@@ -2089,6 +2123,29 @@ function menu_get_active_menu_names() {
 }
 
 /**
+ * Get the active item for the current page, ignoring default local tasks.
+ *
+ * @return
+ *   The menu item that should be active for the current page. If the current
+ *   path is a default local task, the tab's parent should be marked active
+ *   instead.
+ *
+ * Note that the return value of this function should be statically cached by
+ * the current path (i.e., $_GET['q']) if it is called multiple times within a
+ * single request.
+ *
+ * @see l()
+ * @see menu_get_item()
+ */
+function menu_get_active_item() {
+  $item = menu_get_item();
+  while (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) {
+    $item = menu_get_item($item['tab_parent_href']);
+  }
+  return $item;
+}
+
+/**
  * Set the active path, which determines which page is loaded.
  *
  * @param $path
@@ -2103,7 +2160,7 @@ function menu_set_active_item($path) {
 }
 
 /**
- * Sets or gets the active trail (path to root menu root) of the current page.
+ * Sets or gets the active trail (path to menu tree root) of the current page.
  *
  * @param $new_trail
  *   Menu trail to set, or NULL to use previously-set or calculated trail. If
@@ -2133,76 +2190,134 @@ function menu_set_active_trail($new_trai
   elseif (!isset($trail)) {
     $trail = array();
     $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array(), 'type' => 0);
-    $item = menu_get_item();
 
-    // Check whether the current item is a local task (displayed as a tab).
-    if ($item['tab_parent']) {
-      // The title of a local task is used for the tab, never the page title.
-      // Thus, replace it with the item corresponding to the root path to get
-      // the relevant href and title. For example, the menu item corresponding
-      // to 'admin' is used when on the 'By module' tab at 'admin/by-module'.
-      $parts = explode('/', $item['tab_root']);
-      $args = arg();
-      // Replace wildcards in the root path using the current path.
-      foreach ($parts as $index => $part) {
-        if ($part == '%') {
-          $parts[$index] = $args[$index];
-        }
-      }
-      // Retrieve the menu item using the root path after wildcard replacement.
-      $root_item = menu_get_item(implode('/', $parts));
-      if ($root_item && $root_item['access']) {
-        $item = $root_item;
-      }
+    // Try to retrieve a menu link corresponding to the current path. If more
+    // than one exists, the link from the most preferred menu is returned.
+    $preferred_link = menu_link_get_preferred();
+    $current_item = menu_get_item();
+
+    if ($preferred_link) {
+      $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE);
+      list($key, $curr) = each($tree);
     }
-    $menu_names = menu_get_active_menu_names();
-    $curr = FALSE;
-    // Determine if the current page is a link in any of the active menus.
-    if ($menu_names) {
-      $query = db_select('menu_links', 'ml');
-      $query->fields('ml', array('menu_name'));
-      $query->condition('ml.link_path', $item['href']);
-      $query->condition('ml.menu_name', $menu_names, 'IN');
-      $result = $query->execute();
-      $found = array();
-      foreach ($result as $menu) {
-        $found[] = $menu->menu_name;
-      }
-      // The $menu_names array is ordered, so take the first one that matches.
-      $found_menu_names = array_intersect($menu_names, $found);
-      $name = current($found_menu_names);
-      if ($name !== FALSE) {
-        $tree = menu_tree_page_data($name);
-        list($key, $curr) = each($tree);
-      }
+    else {
+      $preferred_link = $current_item;
+      $curr = FALSE;
     }
 
     while ($curr) {
-      // Terminate the loop when we find the current path in the active trail.
-      if ($curr['link']['href'] == $item['href']) {
-        $trail[] = $curr['link'];
-        $curr = FALSE;
-      }
-      else {
-        // Add the link if it's in the active trail, then move to the link below.
-        if ($curr['link']['in_active_trail']) {
-          $trail[] = $curr['link'];
-          $tree = $curr['below'] ? $curr['below'] : array();
+      $link = $curr['link'];
+      if ($link['in_active_trail']) {
+        // Add the link to the trail, unless it links to its parent.
+        if (!($link['type'] & MENU_LINKS_TO_PARENT)) {
+          $trail[] = $link;
         }
-        list($key, $curr) = each($tree);
+        $tree = $curr['below'] ? $curr['below'] : array();
       }
+      list($key, $curr) = each($tree);
     }
     // Make sure the current page is in the trail (needed for the page title),
-    // but exclude tabs and the front page.
-    $last = count($trail) - 1;
-    if ($trail[$last]['href'] != $item['href'] && !(bool) ($item['type'] & MENU_IS_LOCAL_TASK) && !drupal_is_front_page()) {
-      $trail[] = $item;
+    // if the link's type allows it to be shown in the breadcrumb. Also exclude
+    // it if we are on the front page.
+    $last = end($trail);
+    if ($last['href'] != $preferred_link['href'] && ($preferred_link['type'] & MENU_VISIBLE_IN_BREADCRUMB) == MENU_VISIBLE_IN_BREADCRUMB && !drupal_is_front_page()) {
+      $trail[] = $preferred_link;
     }
   }
   return $trail;
 }
 
 /**
+ * Lookup the preferred menu link for a given system path.
+ *
+ * @param $path
+ *   The path, for example 'node/5'. The function will find the corresponding
+ *   menu link ('node/5' if it exists, or fallback to 'node/%').
+ *
+ * @return
+ *   A fully translated menu link, or NULL if not matching menu link was
+ *   found. The most specific menu link ('node/5' preferred over 'node/%') in
+ *   the most preferred menu (as defined by menu_get_active_menu_names()) is
+ *   returned.
+ */
+function menu_link_get_preferred($path = NULL) {
+  $preferred_links = &drupal_static(__FUNCTION__);
+
+  if (!isset($path)) {
+    $path = $_GET['q'];
+  }
+
+  if (!isset($preferred_links[$path])) {
+    $preferred_links[$path] = FALSE;
+
+    // Look for the correct menu link by building a list of candidate paths,
+    // which are ordered by priority (translated hrefs are preferred over
+    // untranslated paths). Afterwards, the most relevant path is picked from
+    // the menus, ordered by menu preference.
+    $item = menu_get_item($path);
+    $path_candidates = array();
+    // 1. The current item href.
+    $path_candidates[] = $item['href'];
+    // 2. The tab root href of the current item (if any).
+    if ($item['tab_parent'] && ($tab_root = menu_get_item($item['tab_root_href']))) {
+      $path_candidates[] = $tab_root['href'];
+    }
+    // 3. The current item path (with wildcards).
+    $path_candidates[] = $item['path'];
+    // 4. The tab root path of the current item (if any).
+    if (!empty($tab_root)) {
+      $path_candidates[] = $tab_root['path'];
+    }
+
+    // Retrieve a list of menu names, ordered by preference.
+    $menu_names = menu_get_active_menu_names();
+
+    $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
+    $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
+    $query->fields('ml');
+    // Weight must be taken from {menu_links}, not {menu_router}.
+    $query->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight')));
+    $query->condition('ml.menu_name', $menu_names, 'IN');
+    $query->condition('ml.link_path', $path_candidates, 'IN');
+    // Include links
+    // - appearing in trees (MENU_VISIBLE_IN_TREE).
+    // - appearing in breadcrumbs (MENU_VISIBLE_IN_BREADCRUMB). This is
+    //   required, since breadcrumbs are based on regular menu link trees.
+    // - not mapping to a router path (NULL).
+    $query->condition(db_or()
+      ->condition('m.type', MENU_VISIBLE_IN_TREE, '&')
+      ->condition('m.type', MENU_VISIBLE_IN_BREADCRUMB, '&')
+      ->isNull('m.type')
+    );
+
+    // Sort candidates by link path and menu name.
+    $candidates = array();
+    foreach ($query->execute() as $candidate) {
+      $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
+    }
+
+    // Pick the most specific link, in the most preferred menu.
+    foreach ($path_candidates as $link_path) {
+      if (!isset($candidates[$link_path])) {
+        continue;
+      }
+      foreach ($menu_names as $menu_name) {
+        if (!isset($candidates[$link_path][$menu_name])) {
+          continue;
+        }
+        $candidate_item = $candidates[$link_path][$menu_name];
+        $map = explode('/', $path);
+        _menu_translate($candidate_item, $map);
+        $preferred_links[$path] = $candidate_item;
+        break 2;
+      }
+    }
+  }
+
+  return $preferred_links[$path];
+}
+
+/**
  * Gets the active trail (path to root menu root) of the current page.
  *
  * See menu_set_active_trail() for details of return value.
@@ -2223,17 +2338,34 @@ function menu_get_active_breadcrumb() {
   }
 
   $item = menu_get_item();
-  if ($item && $item['access']) {
+  if (!empty($item['access'])) {
     $active_trail = menu_get_active_trail();
 
-    foreach ($active_trail as $parent) {
-      $breadcrumb[] = l($parent['title'], $parent['href'], $parent['localized_options']);
-    }
+    // Don't show a link to the current page in the breadcrumb trail.
     $end = end($active_trail);
+    if ($item['href'] == $end['href']) {
+      array_pop($active_trail);
+    }
 
-    // Don't show a link to the current page in the breadcrumb trail.
-    if ($item['href'] == $end['href'] || (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT && $end['href'] != '<front>')) {
-      array_pop($breadcrumb);
+    // Remove the tab root (parent) if the current path links to its parent.
+    // Normally, the tab root link is included in the breadcrumb, as soon as we
+    // are on a local task or any other child link. However, if we are on a
+    // default local task (e.g., node/%/view), then we do not want the tab root
+    // link (e.g., node/%) to appear, as it would be identical to the current
+    // page. Since this behavior also needs to work recursively (i.e., on
+    // default local tasks of default local tasks), and since the last non-task
+    // link in the trail is used as page title (see menu_get_active_title()),
+    // this condition cannot be cleanly integrated into menu_get_active_trail().
+    // menu_get_active_trail() already skips all links that link to their parent
+    // (commonly MENU_DEFAULT_LOCAL_TASK). In order to also hide the parent link
+    // itself, we always remove the last link in the trail, if the current
+    // router item links to its parent.
+    if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) {
+      array_pop($active_trail);
+    }
+
+    foreach ($active_trail as $parent) {
+      $breadcrumb[] = l($parent['title'], $parent['href'], $parent['localized_options']);
     }
   }
   return $breadcrumb;
@@ -2319,6 +2451,8 @@ function menu_reset_static_cache() {
   drupal_static_reset('menu_tree_all_data');
   drupal_static_reset('menu_tree_page_data');
   drupal_static_reset('menu_load_all');
+  drupal_static_reset('menu_link_get_preferred');
+  drupal_static_reset('l');
 }
 
 /**
Index: modules/aggregator/aggregator.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.module,v
retrieving revision 1.443
diff -u -p -r1.443 aggregator.module
--- modules/aggregator/aggregator.module	5 Sep 2010 02:21:38 -0000	1.443
+++ modules/aggregator/aggregator.module	7 Sep 2010 12:39:08 -0000
@@ -134,7 +134,6 @@ function aggregator_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('aggregator_admin_remove_feed', 5),
     'access arguments' => array('administer news feeds'),
-    'type' => MENU_CALLBACK,
     'file' => 'aggregator.admin.inc',
   );
   $items['admin/config/services/aggregator/update/%aggregator_feed'] = array(
@@ -142,7 +141,6 @@ function aggregator_menu() {
     'page callback' => 'aggregator_admin_refresh_feed',
     'page arguments' => array(5),
     'access arguments' => array('administer news feeds'),
-    'type' => MENU_CALLBACK,
     'file' => 'aggregator.admin.inc',
   );
   $items['admin/config/services/aggregator/list'] = array(
@@ -227,7 +225,6 @@ function aggregator_menu() {
     'page callback' => 'aggregator_page_source',
     'page arguments' => array(2),
     'access arguments' => array('access news feeds'),
-    'type' => MENU_CALLBACK,
     'file' => 'aggregator.pages.inc',
   );
   $items['aggregator/sources/%aggregator_feed/view'] = array(
@@ -257,7 +254,6 @@ function aggregator_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('aggregator_form_feed', 6),
     'access arguments' => array('administer news feeds'),
-    'type' => MENU_CALLBACK,
     'file' => 'aggregator.admin.inc',
   );
   $items['admin/config/services/aggregator/edit/category/%aggregator_category'] = array(
@@ -265,7 +261,6 @@ function aggregator_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('aggregator_form_category', 6),
     'access arguments' => array('administer news feeds'),
-    'type' => MENU_CALLBACK,
     'file' => 'aggregator.admin.inc',
   );
 
Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.551
diff -u -p -r1.551 book.module
--- modules/book/book.module	5 Sep 2010 02:21:38 -0000	1.551
+++ modules/book/book.module	7 Sep 2010 12:39:08 -0000
@@ -182,7 +182,6 @@ function book_menu() {
     'access callback' => '_book_outline_remove_access',
     'access arguments' => array(1),
     'theme callback' => '_node_custom_theme',
-    'type' => MENU_CALLBACK,
     'file' => 'book.pages.inc',
   );
 
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.894
diff -u -p -r1.894 comment.module
--- modules/comment/comment.module	5 Sep 2010 02:21:38 -0000	1.894
+++ modules/comment/comment.module	7 Sep 2010 12:39:08 -0000
@@ -240,7 +240,6 @@ function comment_menu() {
     'page callback' => 'comment_permalink',
     'page arguments' => array(1),
     'access arguments' => array('access comments'),
-    'type' => MENU_CALLBACK,
   );
   $items['comment/%/view'] = array(
     'title' => 'View comment',
@@ -263,7 +262,6 @@ function comment_menu() {
     'page callback' => 'comment_approve',
     'page arguments' => array(1),
     'access arguments' => array('administer comments'),
-    'type' => MENU_CALLBACK,
     'file' => 'comment.pages.inc',
     'weight' => 1,
   );
@@ -282,7 +280,6 @@ function comment_menu() {
     'page arguments' => array(2),
     'access callback' => 'node_access',
     'access arguments' => array('view', 2),
-    'type' => MENU_CALLBACK,
     'file' => 'comment.pages.inc',
   );
 
Index: modules/contact/contact.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/contact/contact.module,v
retrieving revision 1.147
diff -u -p -r1.147 contact.module
--- modules/contact/contact.module	13 Apr 2010 15:13:41 -0000	1.147
+++ modules/contact/contact.module	7 Sep 2010 12:39:08 -0000
@@ -77,7 +77,6 @@ function contact_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('contact_category_edit_form', 4),
     'access arguments' => array('administer contact forms'),
-    'type' => MENU_CALLBACK,
     'file' => 'contact.admin.inc',
   );
   $items['admin/structure/contact/delete/%contact'] = array(
@@ -85,7 +84,6 @@ function contact_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('contact_category_delete_form', 4),
     'access arguments' => array('administer contact forms'),
-    'type' => MENU_CALLBACK,
     'file' => 'contact.admin.inc',
   );
   $items['contact'] = array(
Index: modules/dashboard/dashboard.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/dashboard/dashboard.module,v
retrieving revision 1.34
diff -u -p -r1.34 dashboard.module
--- modules/dashboard/dashboard.module	30 Aug 2010 00:22:03 -0000	1.34
+++ modules/dashboard/dashboard.module	7 Sep 2010 12:39:08 -0000
@@ -53,7 +53,6 @@ function dashboard_menu() {
     'page callback' => 'dashboard_admin',
     'page arguments' => array(TRUE),
     'access arguments' => array('access dashboard'),
-    'type' => MENU_CALLBACK,
   );
   $items['admin/dashboard/drawer'] = array(
     'page callback' => 'dashboard_show_disabled',
Index: modules/dblog/dblog.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/dblog/dblog.module,v
retrieving revision 1.55
diff -u -p -r1.55 dblog.module
--- modules/dblog/dblog.module	1 Sep 2010 03:03:05 -0000	1.55
+++ modules/dblog/dblog.module	7 Sep 2010 12:39:08 -0000
@@ -67,7 +67,6 @@ function dblog_menu() {
     'page callback' => 'dblog_event',
     'page arguments' => array(3),
     'access arguments' => array('access site reports'),
-    'type' => MENU_CALLBACK,
     'file' => 'dblog.admin.inc',
   );
 
Index: modules/field/modules/options/options.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.test,v
retrieving revision 1.16
diff -u -p -r1.16 options.test
--- modules/field/modules/options/options.test	17 Aug 2010 21:48:39 -0000	1.16
+++ modules/field/modules/options/options.test	7 Sep 2010 12:39:08 -0000
@@ -77,7 +77,7 @@ class OptionsWidgetsTestCase extends Fie
     field_test_entity_save($entity);
 
     // With no field data, no buttons are checked.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoFieldChecked("edit-card-1-$langcode-0");
     $this->assertNoFieldChecked("edit-card-1-$langcode-1");
     $this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -89,7 +89,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Check that the selected button is checked.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-card-1-$langcode-0");
     $this->assertNoFieldChecked("edit-card-1-$langcode-1");
     $this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -104,7 +104,7 @@ class OptionsWidgetsTestCase extends Fie
     field_update_field($this->card_1);
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-card-1-$langcode-99");
   }
 
@@ -134,7 +134,7 @@ class OptionsWidgetsTestCase extends Fie
     field_test_entity_save($entity);
 
     // Display form: with no field data, nothing is checked.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -150,7 +150,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertFieldChecked("edit-card-2-$langcode-2");
@@ -165,7 +165,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -194,7 +194,7 @@ class OptionsWidgetsTestCase extends Fie
     field_update_field($this->card_2);
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-99");
   }
 
@@ -222,7 +222,7 @@ class OptionsWidgetsTestCase extends Fie
     field_test_entity_save($entity);
 
     // Display form.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     // A required field without any value has a "none" option.
     $this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- Select a value -'))), t('A required select list has a "Select a value" choice.'));
 
@@ -244,7 +244,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     // A required field with a value has no 'none' option.
     $this->assertFalse($this->xpath('//select[@id=:id]//option[@value="_none"]', array(':id' => 'edit-card-1-' . $langcode)), t('A required select list with an actual value has no "none" choice.'));
     $this->assertOptionSelected("edit-card-1-$langcode", 0);
@@ -256,12 +256,12 @@ class OptionsWidgetsTestCase extends Fie
     field_update_instance($instance);
 
     // Display form.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     // A non-required field has a 'none' option.
     $this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- None -'))), t('A non-required select list has a "None" choice.'));
     // Submit form: Unselect the option.
     $edit = array("card_1[$langcode]" => '_none');
-    $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array());
 
     // Test optgroups.
@@ -271,7 +271,7 @@ class OptionsWidgetsTestCase extends Fie
     field_update_field($this->card_1);
 
     // Display form: with no field data, nothing is selected
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoOptionSelected("edit-card-1-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 2);
@@ -284,14 +284,14 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertOptionSelected("edit-card-1-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 2);
 
     // Submit form: Unselect the option.
     $edit = array("card_1[$langcode]" => '_none');
-    $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array());
   }
 
@@ -318,7 +318,7 @@ class OptionsWidgetsTestCase extends Fie
     field_test_entity_save($entity);
 
     // Display form: with no field data, nothing is selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -330,7 +330,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertOptionSelected("edit-card-2-$langcode", 2);
@@ -341,7 +341,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -361,18 +361,18 @@ class OptionsWidgetsTestCase extends Fie
     // Check that the 'none' option has no efect if actual options are selected
     // as well.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none', 0 => 0));
-    $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Check that selecting the 'none' option empties the field.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none'));
-    $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array());
 
     // A required select list does not have an empty key.
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-2-' . $langcode)), t('A required select list does not have an empty key.'));
 
     // We do not have to test that a required select list with one option is
@@ -388,7 +388,7 @@ class OptionsWidgetsTestCase extends Fie
     field_update_instance($instance);
 
     // Display form: with no field data, nothing is selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -401,14 +401,14 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
 
     // Submit form: Unselect the option.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none'));
-    $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array());
   }
 
@@ -435,7 +435,7 @@ class OptionsWidgetsTestCase extends Fie
     field_test_entity_save($entity);
 
     // Display form: with no field data, option is unchecked.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoFieldChecked("edit-bool-$langcode");
     $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>', t('Option text was properly filtered.'));
 
@@ -445,7 +445,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'bool', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertFieldChecked("edit-bool-$langcode");
 
     // Submit form: uncheck the option.
@@ -454,7 +454,7 @@ class OptionsWidgetsTestCase extends Fie
     $this->assertFieldValues($entity_init, 'bool', $langcode, array(1));
 
     // Display form: with 'off' value, option is unchecked.
-    $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
     $this->assertNoFieldChecked("edit-bool-$langcode");
   }
 }
Index: modules/field/modules/text/text.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.test,v
retrieving revision 1.27
diff -u -p -r1.27 text.test
--- modules/field/modules/text/text.test	17 Aug 2010 18:25:31 -0000	1.27
+++ modules/field/modules/text/text.test	7 Sep 2010 12:39:08 -0000
@@ -115,7 +115,7 @@ class TextFieldTestCase extends DrupalWe
       "{$this->field_name}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
 
@@ -184,7 +184,7 @@ class TextFieldTestCase extends DrupalWe
       "{$this->field_name}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
 
@@ -210,7 +210,7 @@ class TextFieldTestCase extends DrupalWe
 
     // Display edition form.
     // We should now have a 'text format' selector.
-    $this->drupalGet('test-entity/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
     $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));
 
Index: modules/field/tests/field.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field.test,v
retrieving revision 1.39
diff -u -p -r1.39 field.test
--- modules/field/tests/field.test	18 Aug 2010 00:44:52 -0000	1.39
+++ modules/field/tests/field.test	7 Sep 2010 12:39:08 -0000
@@ -1259,14 +1259,14 @@ class FieldFormTestCase extends FieldTes
     $value = mt_rand(1, 127);
     $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
     $entity = field_test_entity_test_load($id);
     $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
 
     // Display edit form.
-    $this->drupalGet('test-entity/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", $value, 'Widget is displayed with the correct default value');
     $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
 
@@ -1281,7 +1281,7 @@ class FieldFormTestCase extends FieldTes
     // Empty the field.
     $value = '';
     $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
-    $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
     $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
     $entity = field_test_entity_test_load($id);
     $this->assertIdentical($entity->{$this->field_name}, array(), 'Field was emptied');
@@ -1306,7 +1306,7 @@ class FieldFormTestCase extends FieldTes
     $value = mt_rand(1, 127);
     $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
     $entity = field_test_entity_test_load($id);
@@ -1315,7 +1315,7 @@ class FieldFormTestCase extends FieldTes
     // Edit with missing required value.
     $value = '';
     $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
-    $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
     $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
   }
 
@@ -1384,7 +1384,7 @@ class FieldFormTestCase extends FieldTes
 
     // Submit the form and create the entity.
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
     $entity = field_test_entity_test_load($id);
@@ -1474,7 +1474,7 @@ class FieldFormTestCase extends FieldTes
     // Create entity with three values.
     $edit = array("{$this->field_name}[$langcode]" => '1, 2, 3');
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
 
     // Check that the values were saved.
@@ -1482,7 +1482,7 @@ class FieldFormTestCase extends FieldTes
     $this->assertFieldValues($entity_init, $this->field_name, $langcode, array(1, 2, 3));
 
     // Display the form, check that the values are correctly filled in.
-    $this->drupalGet('test-entity/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode]", '1, 2, 3', t('Widget is displayed.'));
 
     // Submit the form with more values than the field accepts.
@@ -1529,7 +1529,7 @@ class FieldFormTestCase extends FieldTes
     // Create entity.
     $edit = array("{$field_name}[$langcode][0][value]" => 1);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
 
     // Check that the default value was saved.
@@ -1539,7 +1539,7 @@ class FieldFormTestCase extends FieldTes
 
     // Create a new revision.
     $edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
-    $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
 
     // Check that the new revision has the expected values.
     $entity = field_test_entity_test_load($id);
@@ -2721,7 +2721,7 @@ class FieldTranslationsTestCase extends 
     // Create a new revision.
     $langcode = field_valid_language(NULL);
     $edit = array("{$field_name}[$langcode][0][value]" => $entity->{$field_name}[$langcode][0]['value'], 'revision' => TRUE);
-    $this->drupalPost('test-entity/' . $eid . '/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $eid . '/edit', $edit, t('Save'));
 
     // Check translation revisions.
     $this->checkTranslationRevisions($eid, $eid, $available_languages);
Index: modules/field/tests/field_test.entity.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.entity.inc,v
retrieving revision 1.12
diff -u -p -r1.12 field_test.entity.inc
--- modules/field/tests/field_test.entity.inc	17 Jun 2010 13:44:45 -0000	1.12
+++ modules/field/tests/field_test.entity.inc	7 Sep 2010 12:39:08 -0000
@@ -347,7 +347,7 @@ function field_test_entity_form_submit($
   drupal_set_message($message);
 
   if ($entity->ftid) {
-    $form_state['redirect'] = 'test-entity/' . $entity->ftid . '/edit';
+    $form_state['redirect'] = 'test-entity/manage/' . $entity->ftid . '/edit';
   }
   else {
     // Error on save.
Index: modules/field/tests/field_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.module,v
retrieving revision 1.9
diff -u -p -r1.9 field_test.module
--- modules/field/tests/field_test.module	8 Aug 2010 02:18:53 -0000	1.9
+++ modules/field/tests/field_test.module	7 Sep 2010 12:39:08 -0000
@@ -52,10 +52,10 @@ function field_test_menu() {
       'type' => MENU_NORMAL_ITEM,
     );
   }
-  $items['test-entity/%field_test_entity_test/edit'] = array(
+  $items['test-entity/manage/%field_test_entity_test/edit'] = array(
     'title' => 'Edit test entity',
     'page callback' => 'field_test_entity_edit',
-    'page arguments' => array(1),
+    'page arguments' => array(2),
     'access arguments' => array('administer field_test content'),
     'type' => MENU_NORMAL_ITEM,
   );
Index: modules/field_ui/field_ui.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field_ui/field_ui.module,v
retrieving revision 1.31
diff -u -p -r1.31 field_ui.module
--- modules/field_ui/field_ui.module	26 Jun 2010 02:06:53 -0000	1.31
+++ modules/field_ui/field_ui.module	7 Sep 2010 12:39:08 -0000
@@ -114,7 +114,6 @@ function field_ui_menu() {
             'title arguments' => array($field_position),
             'page callback' => 'drupal_get_form',
             'page arguments' => array('field_ui_field_edit_form', $field_position),
-            'type' => MENU_LOCAL_TASK,
             'file' => 'field_ui.admin.inc',
           ) + $access;
           $items["$path/fields/%field_ui_menu/edit"] = array(
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.342
diff -u -p -r1.342 filter.module
--- modules/filter/filter.module	4 Sep 2010 17:55:43 -0000	1.342
+++ modules/filter/filter.module	7 Sep 2010 12:39:08 -0000
@@ -114,7 +114,6 @@ function filter_menu() {
     'file' => 'filter.admin.inc',
   );
   $items['admin/config/content/formats/%filter_format'] = array(
-    'type' => MENU_CALLBACK,
     'title callback' => 'filter_admin_format_title',
     'title arguments' => array(4),
     'page callback' => 'filter_admin_format_page',
@@ -128,7 +127,6 @@ function filter_menu() {
     'page arguments' => array('filter_admin_delete', 4),
     'access callback' => '_filter_delete_format_access',
     'access arguments' => array(4),
-    'type' => MENU_CALLBACK,
     'file' => 'filter.admin.inc',
   );
   return $items;
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.574
diff -u -p -r1.574 forum.module
--- modules/forum/forum.module	5 Sep 2010 02:21:38 -0000	1.574
+++ modules/forum/forum.module	7 Sep 2010 12:39:08 -0000
@@ -147,7 +147,6 @@ function forum_menu() {
     'page callback' => 'forum_form_main',
     'page arguments' => array('container', 5),
     'access arguments' => array('administer forums'),
-    'type' => MENU_CALLBACK,
     'file' => 'forum.admin.inc',
   );
   $items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
@@ -155,7 +154,6 @@ function forum_menu() {
     'page callback' => 'forum_form_main',
     'page arguments' => array('forum', 5),
     'access arguments' => array('administer forums'),
-    'type' => MENU_CALLBACK,
     'file' => 'forum.admin.inc',
   );
   return $items;
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.62
diff -u -p -r1.62 forum.test
--- modules/forum/forum.test	30 Aug 2010 00:22:03 -0000	1.62
+++ modules/forum/forum.test	7 Sep 2010 12:39:08 -0000
@@ -25,9 +25,25 @@ class ForumTestCase extends DrupalWebTes
   function setUp() {
     parent::setUp('taxonomy', 'comment', 'forum');
     // Create users.
-    $this->admin_user = $this->drupalCreateUser(array('administer blocks', 'administer forums', 'administer menu', 'administer taxonomy', 'create forum content')); // 'access administration pages'));
-    $this->edit_any_topics_user = $this->drupalCreateUser(array('create forum content', 'edit any forum content', 'delete any forum content', 'access administration pages'));
-    $this->edit_own_topics_user = $this->drupalCreateUser(array('create forum content', 'edit own forum content', 'delete own forum content'));
+    $this->admin_user = $this->drupalCreateUser(array(
+      'access administration pages',
+      'administer blocks',
+      'administer forums',
+      'administer menu',
+      'administer taxonomy',
+      'create forum content',
+    ));
+    $this->edit_any_topics_user = $this->drupalCreateUser(array(
+      'access administration pages',
+      'create forum content',
+      'edit any forum content',
+      'delete any forum content',
+    ));
+    $this->edit_own_topics_user = $this->drupalCreateUser(array(
+      'create forum content',
+      'edit own forum content',
+      'delete own forum content',
+    ));
     $this->web_user = $this->drupalCreateUser(array());
   }
 
Index: modules/help/help.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/help/help.module,v
retrieving revision 1.96
diff -u -p -r1.96 help.module
--- modules/help/help.module	12 Jan 2010 23:04:47 -0000	1.96
+++ modules/help/help.module	7 Sep 2010 12:39:08 -0000
@@ -25,7 +25,6 @@ function help_menu() {
       'page callback' => 'help_page',
       'page arguments' => array(2),
       'access arguments' => array('access administration pages'),
-      'type' => MENU_CALLBACK,
       'file' => 'help.admin.inc',
     );
   }
Index: modules/image/image.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/image/image.module,v
retrieving revision 1.48
diff -u -p -r1.48 image.module
--- modules/image/image.module	1 Sep 2010 20:08:17 -0000	1.48
+++ modules/image/image.module	7 Sep 2010 12:39:08 -0000
@@ -125,7 +125,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_style_form', 5),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
   $items['admin/config/media/image-styles/delete/%image_style'] = array(
@@ -135,7 +134,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_style_delete_form', 5),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
   $items['admin/config/media/image-styles/revert/%image_style'] = array(
@@ -145,7 +143,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_style_revert_form', 5),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
   $items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect'] = array(
@@ -155,7 +152,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_effect_form', 5, 7),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
   $items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect/delete'] = array(
@@ -165,7 +161,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_effect_delete_form', 5, 7),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
   $items['admin/config/media/image-styles/edit/%image_style/add/%image_effect_definition'] = array(
@@ -175,7 +170,6 @@ function image_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('image_effect_form', 5, 7),
     'access arguments' => array('administer image styles'),
-    'type' => MENU_CALLBACK,
     'file' => 'image.admin.inc',
   );
 
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.297
diff -u -p -r1.297 locale.module
--- modules/locale/locale.module	5 Aug 2010 08:08:43 -0000	1.297
+++ modules/locale/locale.module	7 Sep 2010 12:39:08 -0000
@@ -150,7 +150,6 @@ function locale_menu() {
     'page arguments' => array('locale_languages_edit_form', 5),
     'access arguments' => array('administer languages'),
     'file' => 'locale.admin.inc',
-    'type' => MENU_CALLBACK,
   );
   $items['admin/config/regional/language/delete/%'] = array(
     'title' => 'Confirm',
@@ -158,7 +157,6 @@ function locale_menu() {
     'page arguments' => array('locale_languages_delete_form', 5),
     'access arguments' => array('administer languages'),
     'file' => 'locale.admin.inc',
-    'type' => MENU_CALLBACK,
   );
 
   // Translation functionality
@@ -205,7 +203,6 @@ function locale_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('locale_translate_edit_form', 5),
     'access arguments' => array('translate interface'),
-    'type' => MENU_CALLBACK,
     'file' => 'locale.admin.inc',
   );
   $items['admin/config/regional/translate/delete/%'] = array(
@@ -213,7 +210,6 @@ function locale_menu() {
     'page callback' => 'locale_translate_delete_page',
     'page arguments' => array(5),
     'access arguments' => array('translate interface'),
-    'type' => MENU_CALLBACK,
     'file' => 'locale.admin.inc',
   );
 
@@ -233,7 +229,6 @@ function locale_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('locale_date_format_form', 5),
     'access arguments' => array('administer site configuration'),
-    'type' => MENU_CALLBACK,
     'file' => 'locale.admin.inc',
   );
   $items['admin/config/regional/date-time/locale/%/reset'] = array(
@@ -242,7 +237,6 @@ function locale_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('locale_date_format_reset_form', 5),
     'access arguments' => array('administer site configuration'),
-    'type' => MENU_CALLBACK,
     'file' => 'locale.admin.inc',
   );
 
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.231
diff -u -p -r1.231 menu.module
--- modules/menu/menu.module	1 Aug 2010 23:33:18 -0000	1.231
+++ modules/menu/menu.module	7 Sep 2010 12:39:08 -0000
@@ -95,7 +95,6 @@ function menu_menu() {
     'title callback' => 'menu_overview_title',
     'title arguments' => array(4),
     'access arguments' => array('administer menu'),
-    'type' => MENU_CALLBACK,
     'file' => 'menu.admin.inc',
   );
   $items['admin/structure/menu/manage/%menu/list'] = array(
@@ -126,7 +125,6 @@ function menu_menu() {
     'page callback' => 'menu_delete_menu_page',
     'page arguments' => array(4),
     'access arguments' => array('administer menu'),
-    'type' => MENU_CALLBACK,
     'file' => 'menu.admin.inc',
   );
   $items['admin/structure/menu/item/%menu_link/edit'] = array(
@@ -134,7 +132,6 @@ function menu_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('menu_edit_item', 'edit', 4, NULL),
     'access arguments' => array('administer menu'),
-    'type' => MENU_CALLBACK,
     'file' => 'menu.admin.inc',
   );
   $items['admin/structure/menu/item/%menu_link/reset'] = array(
@@ -142,7 +139,6 @@ function menu_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('menu_reset_item_confirm', 4),
     'access arguments' => array('administer menu'),
-    'type' => MENU_CALLBACK,
     'file' => 'menu.admin.inc',
   );
   $items['admin/structure/menu/item/%menu_link/delete'] = array(
@@ -150,7 +146,6 @@ function menu_menu() {
     'page callback' => 'menu_item_delete_page',
     'page arguments' => array(4),
     'access arguments' => array('administer menu'),
-    'type' => MENU_CALLBACK,
     'file' => 'menu.admin.inc',
   );
   return $items;
@@ -702,7 +697,7 @@ function menu_form_node_type_form_alter(
   $form['menu']['menu_options'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Available menus'),
-    '#default_value' => variable_get('menu_options_' . $type->type, array('main-menu' => 'main-menu')),
+    '#default_value' => variable_get('menu_options_' . $type->type, array('main-menu')),
     '#options' => $menu_options,
     '#description' => t('The menus available to place links in for this content type.'),
   );
Index: modules/menu/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.test,v
retrieving revision 1.40
diff -u -p -r1.40 menu.test
--- modules/menu/menu.test	30 Aug 2010 00:22:03 -0000	1.40
+++ modules/menu/menu.test	7 Sep 2010 12:39:08 -0000
@@ -112,14 +112,14 @@ class MenuTestCase extends DrupalWebTest
 
     // Assert the new menu.
     $this->drupalGet('admin/structure/menu/manage/' . $menu_name . '/edit');
-    $this->assertText($title, t('Custom menu was added.'));
+    $this->assertRaw($title, t('Custom menu was added.'));
 
     // Edit the menu.
     $new_title = $this->randomName(16);
     $menu['title'] = $new_title;
     menu_save($menu);
     $this->drupalGet('admin/structure/menu/manage/' . $menu_name . '/edit');
-    $this->assertText($new_title, t('Custom menu was edited.'));
+    $this->assertRaw($new_title, t('Custom menu was edited.'));
   }
 
   /**
Index: modules/node/content_types.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/content_types.inc,v
retrieving revision 1.117
diff -u -p -r1.117 content_types.inc
--- modules/node/content_types.inc	3 Sep 2010 17:47:20 -0000	1.117
+++ modules/node/content_types.inc	7 Sep 2010 12:39:08 -0000
@@ -326,6 +326,7 @@ function node_type_form_submit($form, &$
     return;
   }
 
+  form_state_values_clean($form_state);
   $variables = $form_state['values'];
 
   // Remove everything that's been saved already - whatever's left is assumed
@@ -336,8 +337,6 @@ function node_type_form_submit($form, &$
     }
   }
 
-  unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id'], $variables['form_build_id']);
-
   // Save or reset persistent variable values.
   foreach ($variables as $key => $value) {
     $variable_new = $key . '_' . $type->type;
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1296
diff -u -p -r1.1296 node.module
--- modules/node/node.module	5 Sep 2010 02:21:38 -0000	1.1296
+++ modules/node/node.module	7 Sep 2010 12:39:08 -0000
@@ -1847,12 +1847,10 @@ function node_menu() {
     'title' => 'Delete',
     'page arguments' => array('node_type_delete_confirm', 4),
     'access arguments' => array('administer content types'),
-    'type' => MENU_CALLBACK,
     'file' => 'content_types.inc',
   );
 
   $items['node'] = array(
-    'title' => 'Content',
     'page callback' => 'node_page_default',
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
@@ -1898,7 +1896,6 @@ function node_menu() {
     'page arguments' => array(1),
     'access callback' => 'node_access',
     'access arguments' => array('view', 1),
-    'type' => MENU_CALLBACK,
   );
   $items['node/%node/view'] = array(
     'title' => 'View',
@@ -1946,7 +1943,6 @@ function node_menu() {
     'page arguments' => array(1, TRUE),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1),
-    'type' => MENU_CALLBACK,
   );
   $items['node/%node/revisions/%/revert'] = array(
     'title' => 'Revert to earlier revision',
@@ -1955,7 +1951,6 @@ function node_menu() {
     'page arguments' => array('node_revision_revert_confirm', 1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1, 'update'),
-    'type' => MENU_CALLBACK,
     'file' => 'node.pages.inc',
   );
   $items['node/%node/revisions/%/delete'] = array(
@@ -1965,7 +1960,6 @@ function node_menu() {
     'page arguments' => array('node_revision_delete_confirm', 1),
     'access callback' => '_node_revision_access',
     'access arguments' => array(1, 'delete'),
-    'type' => MENU_CALLBACK,
     'file' => 'node.pages.inc',
   );
   return $items;
Index: modules/openid/openid.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.module,v
retrieving revision 1.95
diff -u -p -r1.95 openid.module
--- modules/openid/openid.module	22 Aug 2010 22:00:16 -0000	1.95
+++ modules/openid/openid.module	7 Sep 2010 12:39:08 -0000
@@ -32,7 +32,6 @@ function openid_menu() {
     'page arguments' => array('openid_user_delete_form', 1),
     'access callback' => 'user_edit_access',
     'access arguments' => array(1),
-    'type' => MENU_CALLBACK,
     'file' => 'openid.pages.inc',
   );
   return $items;
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.183
diff -u -p -r1.183 path.module
--- modules/path/path.module	13 Feb 2010 21:41:58 -0000	1.183
+++ modules/path/path.module	7 Sep 2010 12:39:08 -0000
@@ -66,7 +66,6 @@ function path_menu() {
     'page callback' => 'path_admin_edit',
     'page arguments' => array(5),
     'access arguments' => array('administer url aliases'),
-    'type' => MENU_CALLBACK,
     'file' => 'path.admin.inc',
   );
   $items['admin/config/search/path/delete/%path'] = array(
@@ -74,7 +73,6 @@ function path_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('path_admin_delete_confirm', 5),
     'access arguments' => array('administer url aliases'),
-    'type' => MENU_CALLBACK,
     'file' => 'path.admin.inc',
   );
   $items['admin/config/search/path/list'] = array(
Index: modules/profile/profile.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/profile/profile.module,v
retrieving revision 1.292
diff -u -p -r1.292 profile.module
--- modules/profile/profile.module	10 Jul 2010 01:44:28 -0000	1.292
+++ modules/profile/profile.module	7 Sep 2010 12:39:08 -0000
@@ -99,7 +99,6 @@ function profile_menu() {
     'page arguments' => array('profile_field_form'),
     'access arguments' => array('administer users'),
     'file' => 'profile.admin.inc',
-    'type' => MENU_CALLBACK,
   );
   $items['admin/config/people/profile/autocomplete'] = array(
     'title' => 'Profile category autocomplete',
@@ -114,7 +113,6 @@ function profile_menu() {
     'page arguments' => array('profile_field_form'),
     'access arguments' => array('administer users'),
     'file' => 'profile.admin.inc',
-    'type' => MENU_CALLBACK,
   );
   $items['admin/config/people/profile/delete'] = array(
     'title' => 'Delete field',
@@ -122,7 +120,6 @@ function profile_menu() {
     'page arguments' => array('profile_field_delete'),
     'access arguments' => array('administer users'),
     'file' => 'profile.admin.inc',
-    'type' => MENU_CALLBACK,
   );
   $items['profile/autocomplete'] = array(
     'title' => 'Profile autocomplete',
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.359
diff -u -p -r1.359 search.module
--- modules/search/search.module	5 Sep 2010 02:21:38 -0000	1.359
+++ modules/search/search.module	7 Sep 2010 12:39:08 -0000
@@ -182,7 +182,6 @@ function search_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('search_reindex_confirm'),
     'access arguments' => array('administer search'),
-    'type' => MENU_CALLBACK,
     'file' => 'search.admin.inc',
   );
 
Index: modules/search/search.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.test,v
retrieving revision 1.74
diff -u -p -r1.74 search.test
--- modules/search/search.test	4 Sep 2010 13:33:53 -0000	1.74
+++ modules/search/search.test	7 Sep 2010 12:39:08 -0000
@@ -236,13 +236,16 @@ class SearchMatchTestCase extends Drupal
   }
 }
 
-class SearchBikeShed extends DrupalWebTestCase {
+/**
+ * Tests the bike shed text on no results page, and text on the search page.
+ */
+class SearchPageText extends DrupalWebTestCase {
   protected $searching_user;
 
   public static function getInfo() {
     return array(
-      'name' => 'Bike shed',
-      'description' => 'Tests the bike shed text on the no results page.',
+      'name' => 'Search page text',
+      'description' => 'Tests the bike shed text on the no results page, and various other text on search pages.',
       'group' => 'Search'
     );
   }
@@ -251,18 +254,31 @@ class SearchBikeShed extends DrupalWebTe
     parent::setUp('search');
 
     // Create user.
-    $this->searching_user = $this->drupalCreateUser(array('search content'));
+    $this->searching_user = $this->drupalCreateUser(array('search content', 'access user profiles'));
   }
 
-  function testFailedSearch() {
+  /**
+   * Tests the failed search text, and various other text on the search page.
+   */
+  function testSearchText() {
     $this->drupalLogin($this->searching_user);
     $this->drupalGet('search/node');
     $this->assertText(t('Enter your keywords'));
+    $this->assertText(t('Search'));
+    $title = t('Search') . ' | Drupal';
+    $this->assertTitle($title, 'Search page title is correct');
 
     $edit = array();
     $edit['keys'] = 'bike shed ' . $this->randomName();
     $this->drupalPost('search/node', $edit, t('Search'));
     $this->assertText(t('Consider loosening your query with OR. bike OR shed will often show more results than bike shed.'), t('Help text is displayed when search returns no results.'));
+    $this->assertText(t('Search'));
+    $this->assertTitle($title, 'Search page title is correct');
+
+    $edit['keys'] = $this->searching_user->name;
+    $this->drupalPost('search/user', $edit, t('Search'));
+    $this->assertText(t('Search'));
+    $this->assertTitle($title, 'Search page title is correct');
   }
 }
 
Index: modules/shortcut/shortcut.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/shortcut/shortcut.module,v
retrieving revision 1.26
diff -u -p -r1.26 shortcut.module
--- modules/shortcut/shortcut.module	3 Aug 2010 23:07:01 -0000	1.26
+++ modules/shortcut/shortcut.module	7 Sep 2010 12:39:08 -0000
@@ -91,7 +91,6 @@ function shortcut_menu() {
     'title arguments' => array(4),
     'access callback' => 'shortcut_set_edit_access',
     'access arguments' => array(4),
-    'type' => MENU_CALLBACK,
     'file' => 'shortcut.admin.inc',
   );
   $items['admin/config/user-interface/shortcut/%shortcut_set/links'] = array(
@@ -114,7 +113,6 @@ function shortcut_menu() {
     'page arguments' => array('shortcut_set_delete_form', 4),
     'access callback' => 'shortcut_set_delete_access',
     'access arguments' => array(4),
-    'type' => MENU_CALLBACK,
     'file' => 'shortcut.admin.inc',
   );
   $items['admin/config/user-interface/shortcut/%shortcut_set/add-link'] = array(
@@ -141,7 +139,6 @@ function shortcut_menu() {
     'page arguments' => array('shortcut_link_edit', 5),
     'access callback' => 'shortcut_link_access',
     'access arguments' => array(5),
-    'type' => MENU_CALLBACK,
     'file' => 'shortcut.admin.inc',
   );
   $items['admin/config/user-interface/shortcut/link/%menu_link/delete'] = array(
@@ -150,7 +147,6 @@ function shortcut_menu() {
     'page arguments' => array('shortcut_link_delete', 5),
     'access callback' => 'shortcut_link_access',
     'access arguments' => array(5),
-    'type' => MENU_CALLBACK,
     'file' => 'shortcut.admin.inc',
   );
   $items['user/%user/shortcuts'] = array(
Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.231
diff -u -p -r1.231 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	4 Sep 2010 13:33:53 -0000	1.231
+++ modules/simpletest/drupal_web_test_case.php	7 Sep 2010 13:55:19 -0000
@@ -2662,7 +2662,14 @@ class DrupalWebTestCase extends DrupalTe
    *   TRUE on pass, FALSE on fail.
    */
   protected function assertTitle($title, $message = '', $group = 'Other') {
-    return $this->assertEqual(current($this->xpath('//title')), $title, $message, $group);
+    $actual = (string) current($this->xpath('//title'));
+    if (!$message) {
+      $message = t('Page title @actual is equal to @expected.', array(
+        '@actual' => var_export($actual, TRUE),
+        '@expected' => var_export($title, TRUE),
+      ));
+    }
+    return $this->assertEqual($actual, $title, $message, $group);
   }
 
   /**
@@ -2678,7 +2685,14 @@ class DrupalWebTestCase extends DrupalTe
    *   TRUE on pass, FALSE on fail.
    */
   protected function assertNoTitle($title, $message = '', $group = 'Other') {
-    return $this->assertNotEqual(current($this->xpath('//title')), $title, $message, $group);
+    $actual = (string) current($this->xpath('//title'));
+    if (!$message) {
+      $message = t('Page title @actual is not equal to @unexpected.', array(
+        '@actual' => var_export($actual, TRUE),
+        '@unexpected' => var_export($title, TRUE),
+      ));
+    }
+    return $this->assertNotEqual($actual, $title, $message, $group);
   }
 
   /**
@@ -3016,6 +3030,24 @@ class DrupalWebTestCase extends DrupalTe
   }
 
   /**
+   * Assert the page do not respond with the specified response code.
+   *
+   * @param $code
+   *   Response code. For example 200 is a successful page request. For a list
+   *   of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
+   * @param $message
+   *   Message to display.
+   *
+   * @return
+   *   Assertion result.
+   */
+  protected function assertNoResponse($code, $message = '') {
+    $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+    $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
+    return $this->assertFalse($match, $message ? $message : t('HTTP response not expected !code, actual !curl_code', array('!code' => $code, '!curl_code' => $curl_code)), t('Browser'));
+  }
+
+  /**
    * Asserts that the most recently sent e-mail message has the given value.
    *
    * The field in $name must have the content described in $value.
Index: modules/simpletest/simpletest.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v
retrieving revision 1.93
diff -u -p -r1.93 simpletest.module
--- modules/simpletest/simpletest.module	1 Sep 2010 20:08:17 -0000	1.93
+++ modules/simpletest/simpletest.module	7 Sep 2010 12:39:08 -0000
@@ -56,7 +56,6 @@ function simpletest_menu() {
     'page arguments' => array('simpletest_result_form', 5),
     'description' => 'View result of tests.',
     'access arguments' => array('administer unit tests'),
-    'type' => MENU_CALLBACK,
     'file' => 'simpletest.pages.inc',
   );
   return $items;
Index: modules/simpletest/tests/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu.test,v
retrieving revision 1.34
diff -u -p -r1.34 menu.test
--- modules/simpletest/tests/menu.test	8 Aug 2010 19:35:49 -0000	1.34
+++ modules/simpletest/tests/menu.test	7 Sep 2010 14:10:50 -0000
@@ -525,3 +525,555 @@ class MenuTreeDataTestCase extends Drupa
     return $this->assert($link1['mlid'] == $link2['mlid'], $message ? $message : t('First link is identical to second link'));
   }
 }
+
+/**
+ * Menu breadcrumbs related tests.
+ */
+class MenuBreadcrumbTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Breadcrumbs',
+      'description' => 'Tests breadcrumbs functionality.',
+      'group' => 'Menu',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('menu_test'));
+    $perms = array_keys(module_invoke_all('permission'));
+    $this->admin_user = $this->drupalCreateUser($perms);
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Tests breadcrumbs on node and administrative paths.
+   */
+  function testBreadCrumbs() {
+    // Prepare common base breadcrumb elements.
+    $home = array('<front>' => 'Home');
+    $admin = $home + array('admin' => t('Administer'));
+    $config = $admin + array('admin/config' => t('Configuration'));
+    $type = 'article';
+    $langcode = LANGUAGE_NONE;
+
+    // Verify breadcrumbs for default local tasks.
+    $expected = array(
+      'menu-test' => t('Menu test root'),
+    );
+    $title = t('Breadcrumbs test: Local tasks');
+    $trail = $home + $expected;
+    $tree = $expected + array(
+      'menu-test/breadcrumb/tasks' => $title,
+    );
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks', $trail, $title, $tree);
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first', $trail, $title, $tree, FALSE);
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/first', $trail, $title, $tree, FALSE);
+    $trail += array(
+      'menu-test/breadcrumb/tasks' => t('Breadcrumbs test: Local tasks'),
+    );
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/second', $trail, $title, $tree, FALSE);
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second', $trail, $title, $tree, FALSE);
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/first', $trail, $title, $tree, FALSE);
+    $trail += array(
+      'menu-test/breadcrumb/tasks/second' => t('Second'),
+    );
+    $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/second', $trail, $title, $tree, FALSE);
+
+    // Verify Taxonomy administration breadcrumbs.
+    $trail = $admin + array(
+      'admin/structure' => t('Structure'),
+    );
+    $this->assertBreadcrumb('admin/structure/taxonomy', $trail);
+
+    $trail += array(
+      'admin/structure/taxonomy' => t('Taxonomy'),
+    );
+    $this->assertBreadcrumb('admin/structure/taxonomy/tags', $trail);
+    $trail += array(
+      'admin/structure/taxonomy/tags' => t('Tags'),
+    );
+    $this->assertBreadcrumb('admin/structure/taxonomy/tags/edit', $trail);
+    $this->assertBreadcrumb('admin/structure/taxonomy/tags/fields', $trail);
+    $this->assertBreadcrumb('admin/structure/taxonomy/tags/add', $trail);
+
+    // Verify Menu administration breadcrumbs.
+    $trail = $admin + array(
+      'admin/structure' => t('Structure'),
+    );
+    $this->assertBreadcrumb('admin/structure/menu', $trail);
+
+    $trail += array(
+      'admin/structure/menu' => t('Menus'),
+    );
+    $this->assertBreadcrumb('admin/structure/menu/manage/navigation', $trail);
+    $trail += array(
+      'admin/structure/menu/manage/navigation' => t('Navigation'),
+    );
+    $this->assertBreadcrumb('admin/structure/menu/manage/navigation/edit', $trail);
+    $this->assertBreadcrumb('admin/structure/menu/manage/navigation/add', $trail);
+
+    // Verify Node administration breadcrumbs.
+    $trail = $admin + array(
+      'admin/structure' => t('Structure'),
+      'admin/structure/types' => t('Content types'),
+    );
+    $this->assertBreadcrumb('admin/structure/types/add', $trail);
+    $this->assertBreadcrumb("admin/structure/types/manage/$type", $trail);
+    $trail += array(
+      "admin/structure/types/manage/$type" => t('Article'),
+    );
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/fields", $trail);
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/display", $trail);
+    $trail_teaser = $trail + array(
+      "admin/structure/types/manage/$type/display" => t('Manage display'),
+    );
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/display/teaser", $trail_teaser);
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/fields", $trail);
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/display", $trail);
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/delete", $trail);
+    $trail += array(
+      "admin/structure/types/manage/$type/fields" => t('Manage fields'),
+    );
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body", $trail);
+    $trail += array(
+      "admin/structure/types/manage/$type/fields/body" => t('Body'),
+    );
+    $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body/widget-type", $trail);
+
+    // Verify Filter text format administration breadcrumbs.
+    $format = db_query_range("SELECT format, name FROM {filter_format}", 1, 1)->fetch();
+    $format_id = $format->format;
+    $trail = $config + array(
+      'admin/config/content' => t('Content authoring'),
+    );
+    $this->assertBreadcrumb('admin/config/content/formats', $trail);
+
+    $trail += array(
+      'admin/config/content/formats' => t('Text formats'),
+    );
+    $this->assertBreadcrumb('admin/config/content/formats/add', $trail);
+    $this->assertBreadcrumb("admin/config/content/formats/$format_id", $trail);
+    $trail += array(
+      "admin/config/content/formats/$format_id" => $format->name,
+    );
+    $this->assertBreadcrumb("admin/config/content/formats/$format_id/delete", $trail);
+
+    // Verify node breadcrumbs (without menu link).
+    $node1 = $this->drupalCreateNode();
+    $nid1 = $node1->nid;
+    $trail = $home;
+    $this->assertBreadcrumb("node/$nid1", $trail);
+    // Also verify that the node does not appear elsewhere (e.g., menu trees).
+    $this->assertNoLink($node1->title);
+    // The node itself should not be contained in the breadcrumb on the default
+    // local task, since there is no difference between both pages.
+    $this->assertBreadcrumb("node/$nid1/view", $trail);
+    // Also verify that the node does not appear elsewhere (e.g., menu trees).
+    $this->assertNoLink($node1->title);
+
+    $trail += array(
+      "node/$nid1" => $node1->title,
+    );
+    $this->assertBreadcrumb("node/$nid1/edit", $trail);
+
+    // Verify that breadcrumb on node listing page contains "Home" only.
+    $trail = array();
+    $this->assertBreadcrumb('node', $trail);
+
+    // Verify node breadcrumbs (in menu).
+    // Do this separately for Main menu and Navigation menu, since only the
+    // latter is a preferred menu by default.
+    // @todo Also test all themes? Manually testing led to the suspicion that
+    //   breadcrumbs may differ, possibly due to template.php overrides.
+    $menus = array('main-menu', 'navigation');
+    // Alter node type menu settings.
+    variable_set("menu_options_$type", $menus);
+    variable_set("menu_parent_$type", 'navigation:0');
+
+    foreach ($menus as $menu) {
+      // Create a parent node in the current menu.
+      $title = $this->randomName();
+      $node2 = $this->drupalCreateNode(array(
+        'type' => $type,
+        'title' => $title,
+        'menu' => array(
+          'enabled' => 1,
+          'link_title' => 'Parent ' . $title,
+          'description' => '',
+          'menu_name' => $menu,
+          'plid' => 0,
+        ),
+      ));
+      $nid2 = $node2->nid;
+
+      $trail = $home;
+      $tree = array(
+        "node/$nid2" => $node2->menu['link_title'],
+      );
+      $this->assertBreadcrumb("node/$nid2", $trail, $node2->title, $tree);
+      // The node itself should not be contained in the breadcrumb on the
+      // default local task, since there is no difference between both pages.
+      $this->assertBreadcrumb("node/$nid2/view", $trail, $node2->title, $tree);
+      $trail += array(
+        "node/$nid2" => $node2->menu['link_title'],
+      );
+      $this->assertBreadcrumb("node/$nid2/edit", $trail);
+
+      // Create a child node in the current menu.
+      $title = $this->randomName();
+      $node3 = $this->drupalCreateNode(array(
+        'type' => $type,
+        'title' => $title,
+        'menu' => array(
+          'enabled' => 1,
+          'link_title' => 'Child ' . $title,
+          'description' => '',
+          'menu_name' => $menu,
+          'plid' => $node2->menu['mlid'],
+        ),
+      ));
+      $nid3 = $node3->nid;
+
+      $this->assertBreadcrumb("node/$nid3", $trail, $node3->title, $tree, FALSE);
+      // The node itself should not be contained in the breadcrumb on the
+      // default local task, since there is no difference between both pages.
+      $this->assertBreadcrumb("node/$nid3/view", $trail, $node3->title, $tree, FALSE);
+      $trail += array(
+        "node/$nid3" => $node3->menu['link_title'],
+      );
+      $tree += array(
+        "node/$nid3" => $node3->menu['link_title'],
+      );
+      $this->assertBreadcrumb("node/$nid3/edit", $trail);
+
+      // Verify that node listing page still contains "Home" only.
+      $trail = array();
+      $this->assertBreadcrumb('node', $trail);
+
+      if ($menu == 'navigation') {
+        $parent = $node2;
+        $child = $node3;
+      }
+    }
+
+    // Create a Navigation menu link for 'node', move the last parent node menu
+    // link below it, and verify a full breadcrumb for the last child node.
+    $menu = 'navigation';
+    $edit = array(
+      'link_title' => 'Root',
+      'link_path' => 'node',
+    );
+    $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+    $link = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(':title' => 'Root'))->fetchAssoc();
+
+    $edit = array(
+      'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'],
+    );
+    $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
+    $expected = array(
+      "node" => $link['link_title'],
+    );
+    $trail = $home + $expected;
+    $tree = $expected + array(
+      "node/{$parent->nid}" => $parent->menu['link_title'],
+    );
+    $this->assertBreadcrumb(NULL, $trail, $parent->title, $tree);
+    $trail += array(
+      "node/{$parent->nid}" => $parent->menu['link_title'],
+    );
+    $tree += array(
+      "node/{$child->nid}" => $child->menu['link_title'],
+    );
+    $this->assertBreadcrumb("node/{$child->nid}", $trail, $child->title, $tree);
+
+    // Add a taxonomy term/tag to last node, and add a link for that term to the
+    // Navigation menu.
+    $tags = array(
+      'Drupal' => array(),
+      'Breadcrumbs' => array(),
+    );
+    $edit = array(
+      "field_tags[$langcode]" => implode(',', array_keys($tags)),
+    );
+    $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
+
+    // Put both terms into a hierarchy Drupal » Breadcrumbs. Required for both
+    // the menu links and the terms itself, since taxonomy_term_page() resets
+    // the breadcrumb based on taxonomy term hierarchy.
+    $parent_tid = 0;
+    foreach ($tags as $name => $null) {
+      $terms = taxonomy_term_load_multiple(NULL, array('name' => $name));
+      $term = reset($terms);
+      $tags[$name]['term'] = $term;
+      if ($parent_tid) {
+        $edit = array(
+          'parent[]' => array($parent_tid),
+        );
+        $this->drupalPost("taxonomy/term/{$term->tid}/edit", $edit, t('Save'));
+      }
+      $parent_tid = $term->tid;
+    }
+    $parent_mlid = 0;
+    foreach ($tags as $name => $data) {
+      $term = $data['term'];
+      $edit = array(
+        'link_title' => "$name link",
+        'link_path' => "taxonomy/term/{$term->tid}",
+        'parent' => "$menu:{$parent_mlid}",
+      );
+      $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+      $tags[$name]['link'] = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+        ':title' => $edit['link_title'],
+        ':href' => $edit['link_path'],
+      ))->fetchAssoc();
+      $tags[$name]['link']['link_path'] = $edit['link_path'];
+      $parent_mlid = $tags[$name]['link']['mlid'];
+    }
+
+    // Verify expected breadcrumbs for menu links.
+    $trail = $home;
+    $tree = array();
+    foreach ($tags as $name => $data) {
+      $term = $data['term'];
+      $link = $data['link'];
+
+      $tree += array(
+        $link['link_path'] => $link['link_title'],
+      );
+      // @todo Normally, you'd expect $term->name as page title here.
+      $this->assertBreadcrumb($link['link_path'], $trail, $link['link_title'], $tree);
+      $this->assertRaw(check_plain($parent->title), 'Tagged node found.');
+
+      // Additionally make sure that this link appears only once; i.e., the
+      // untranslated menu links automatically generated from menu router items
+      // ('taxonomy/term/%') should never be translated and appear in any menu
+      // other than the breadcrumb trail.
+      $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
+        ':menu' => 'block-system-navigation',
+        ':href' => url($link['link_path']),
+      ));
+      $this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once.");
+
+      // Next iteration should expect this tag as parent link.
+      // Note: Term name, not link name, due to taxonomy_term_page().
+      $trail += array(
+        $link['link_path'] => $term->name,
+      );
+    }
+
+    // Verify breadcrumbs on user and user/%.
+    // We need to log back in and out below, and cannot simply grant the
+    // 'administer users' permission, since user_page() makes your head explode.
+    user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
+      'access user profiles',
+    ));
+    $this->drupalLogout();
+
+    // Verify breadcrumb on front page.
+    $this->assertBreadcrumb('<front>', array());
+
+    $trail = $home;
+    $this->assertBreadcrumb('user', $trail, t('User account'));
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name);
+
+    $this->drupalLogin($this->admin_user);
+    $trail += array(
+      'user/' . $this->admin_user->uid => $this->admin_user->name,
+    );
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name);
+
+    // Add a Navigation menu links for 'user' and $this->admin_user.
+    // Although it may be faster to manage these links via low-level API
+    // functions, there's a lot that can go wrong in doing so.
+    $edit = array(
+      'link_title' => 'User',
+      'link_path' => 'user',
+    );
+    $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+    $link_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+      ':title' => $edit['link_title'],
+      ':href' => $edit['link_path'],
+    ))->fetchAssoc();
+
+    $edit = array(
+      'link_title' => $this->admin_user->name . ' link',
+      'link_path' => 'user/' . $this->admin_user->uid,
+    );
+    $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+    $link_admin_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+      ':title' => $edit['link_title'],
+      ':href' => $edit['link_path'],
+    ))->fetchAssoc();
+
+    // Verify expected breadcrumbs for the two separate links.
+    $this->drupalLogout();
+    $trail = $home;
+    $tree = array(
+      $link_user['link_path'] => $link_user['link_title'],
+    );
+    $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
+    $tree = array(
+      $link_admin_user['link_path'] => $link_admin_user['link_title'],
+    );
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
+
+    $this->drupalLogin($this->admin_user);
+    $trail += array(
+      $link_admin_user['link_path'] => $link_admin_user['link_title'],
+    );
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
+
+    // Move 'user/%' below 'user' and verify again.
+    $edit = array(
+      'parent' => "$menu:{$link_user['mlid']}",
+    );
+    $this->drupalPost("admin/structure/menu/item/{$link_admin_user['mlid']}/edit", $edit, t('Save'));
+
+    $this->drupalLogout();
+    $trail = $home;
+    $tree = array(
+      $link_user['link_path'] => $link_user['link_title'],
+    );
+    $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
+    $trail += array(
+      $link_user['link_path'] => $link_user['link_title'],
+    );
+    $tree += array(
+      $link_admin_user['link_path'] => $link_admin_user['link_title'],
+    );
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
+
+    $this->drupalLogin($this->admin_user);
+    $trail += array(
+      $link_admin_user['link_path'] => $link_admin_user['link_title'],
+    );
+    $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
+
+    // Create an only slightly privileged user being able to access site reports
+    // but not administration pages.
+    $this->web_user = $this->drupalCreateUser(array(
+      'access site reports',
+    ));
+    $this->drupalLogin($this->web_user);
+
+    // Verify that we can access recent log entries, there is a corresponding
+    // page title, and that the breadcrumb is empty (because the user is not
+    // able to access "Administer", so the trail cannot recurse into it).
+    $trail = array();
+    $this->assertBreadcrumb('admin', $trail, t('Access denied'));
+    $this->assertResponse(403);
+
+    $trail = $home;
+    $this->assertBreadcrumb('admin/reports', $trail, t('Reports'));
+    $this->assertNoResponse(403);
+
+    $this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
+    $this->assertNoResponse(403);
+  }
+
+  /**
+   * Assert that a given path shows certain breadcrumb links.
+   *
+   * @param string $goto
+   *   (optional) A system path to pass to DrupalWebTestCase::drupalGet().
+   * @param array $trail
+   *   An associative array whose keys are expected breadcrumb link paths and
+   *   whose values are expected breadcrumb link texts (not sanitized).
+   * @param string $page_title
+   *   (optional) A page title to additionally assert via
+   *   DrupalWebTestCase::assertTitle(). Without site name suffix.
+   * @param array $tree
+   *   (optional) An associative array whose keys are link paths and whose
+   *   values are link titles (not sanitized) of an expected active trail in a
+   *   menu tree output on the page.
+   * @param $last_active
+   *   (optional) Whether the last link in $tree is expected to be active (TRUE)
+   *   or just to be in the active trail (FALSE).
+   */
+  protected function assertBreadcrumb($goto, array $trail, $page_title = NULL, array $tree = array(), $last_active = TRUE) {
+    if (isset($goto)) {
+      $this->drupalGet($goto);
+    }
+    // Compare paths with actual breadcrumb.
+    $parts = $this->getParts();
+    $pass = TRUE;
+    foreach ($trail as $path => $title) {
+      $url = url($path);
+      $part = array_shift($parts);
+      $pass = ($pass && $part['href'] === $url && $part['text'] === check_plain($title));
+    }
+    // No parts must be left, or an expected "Home" will always pass.
+    $pass = ($pass && empty($parts));
+
+    $this->assertTrue($pass, t('Breadcrumb %parts found on @path.', array(
+      '%parts' => implode(' » ', $trail),
+      '@path' => $goto,
+    )));
+
+    // Additionally assert page title, if given.
+    if (isset($page_title)) {
+      $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)));
+    }
+
+    // Additionally assert active trail in a menu tree output, if given.
+    if ($tree) {
+      end($tree);
+      $active_link_path = key($tree);
+      $active_link_title = array_pop($tree);
+      $xpath = '';
+      if ($tree) {
+        $i = 0;
+        foreach ($tree as $link_path => $link_title) {
+          $part_xpath = (!$i ? '//' : '/following-sibling::ul/descendant::');
+          $part_xpath .= 'li[contains(@class, :class)]/a[contains(@href, :href) and contains(text(), :title)]';
+          $part_args = array(
+            ':class' => 'active-trail',
+            ':href' => url($link_path),
+            ':title' => $link_title,
+          );
+          $xpath .= $this->buildXPathQuery($part_xpath, $part_args);
+          $i++;
+        }
+        $elements = $this->xpath($xpath);
+        $this->assertTrue(!empty($elements), t('Active trail to current page was found in menu tree.'));
+
+        // Append prefix for active link asserted below.
+        $xpath .= '/following-sibling::ul/descendant::';
+      }
+      else {
+        $xpath .= '//';
+      }
+      $last_active = ($last_active ? 'and contains(@class, :class-active)' : '');
+      $xpath .= 'li[contains(@class, :class-trail)]/a[contains(@href, :href) ' . $last_active . 'and contains(text(), :title)]';
+      $args = array(
+        ':class-trail' => 'active-trail',
+        ':class-active' => 'active',
+        ':href' => url($active_link_path),
+        ':title' => $active_link_title,
+      );
+      $elements = $this->xpath($xpath, $args);
+      $this->assertTrue(!empty($elements), t('Active link %title was found in menu tree, including active trail links %tree.', array(
+        '%title' => $active_link_title,
+        '%tree' => implode(' » ', $tree),
+      )));
+    }
+  }
+
+  /**
+   * Returns the breadcrumb contents of the current page in the internal browser.
+   */
+  protected function getParts() {
+    $parts = array();
+    $elements = $this->xpath('//div[@class="breadcrumb"]/a');
+    if (!empty($elements)) {
+      foreach ($elements as $element) {
+        $parts[] = array(
+          'text' => (string) $element,
+          'href' => (string) $element['href'],
+          'title' => (string) $element['title'],
+        );
+      }
+    }
+    return $parts;
+  }
+}
Index: modules/simpletest/tests/menu_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu_test.module,v
retrieving revision 1.15
diff -u -p -r1.15 menu_test.module
--- modules/simpletest/tests/menu_test.module	7 Jul 2010 08:05:01 -0000	1.15
+++ modules/simpletest/tests/menu_test.module	7 Sep 2010 12:39:09 -0000
@@ -77,7 +77,7 @@ function menu_test_menu() {
     'access arguments' => array('access content'),
   );
   $items['menu-test/hidden'] = array(
-    'title' => 'Menu test parent',
+    'title' => 'Hidden test root',
     'page callback' => 'node_page_default',
     'access arguments' => array('access content'),
   );
@@ -110,7 +110,6 @@ function menu_test_menu() {
     'title' => 'Customize menu',
     'page callback' => 'node_page_default',
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
   $items['menu-test/hidden/menu/manage/%menu/list'] = array(
     'title' => 'List links',
@@ -135,7 +134,6 @@ function menu_test_menu() {
     'title' => 'Delete menu',
     'page callback' => 'node_page_default',
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   // Hidden tests; two dynamic arguments.
@@ -173,6 +171,41 @@ function menu_test_menu() {
     'context' => MENU_CONTEXT_NONE,
   );
 
+  // Breadcrumbs tests.
+  // @see MenuBreadcrumbTestCase
+  $base = array(
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  // Local tasks: Second level below default local task.
+  $items['menu-test/breadcrumb/tasks'] = array(
+    'title' => 'Breadcrumbs test: Local tasks',
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/first'] = array(
+    'title' => 'First',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/second'] = array(
+    'title' => 'Second',
+    'type' => MENU_LOCAL_TASK,
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/first/first'] = array(
+    'title' => 'First first',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/first/second'] = array(
+    'title' => 'First second',
+    'type' => MENU_LOCAL_TASK,
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/second/first'] = array(
+    'title' => 'Second first',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  ) + $base;
+  $items['menu-test/breadcrumb/tasks/second/second'] = array(
+    'title' => 'Second second',
+    'type' => MENU_LOCAL_TASK,
+  ) + $base;
+
   // File inheritance tests. This menu item should inherit the page callback
   // system_admin_menu_block_page() and therefore render its children as links
   // on the page.
Index: modules/statistics/statistics.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics/statistics.module,v
retrieving revision 1.338
diff -u -p -r1.338 statistics.module
--- modules/statistics/statistics.module	30 Aug 2010 05:58:46 -0000	1.338
+++ modules/statistics/statistics.module	7 Sep 2010 12:39:09 -0000
@@ -163,7 +163,6 @@ function statistics_menu() {
     'page callback' => 'statistics_access_log',
     'page arguments' => array(3),
     'access arguments' => array('access statistics'),
-    'type' => MENU_CALLBACK,
     'file' => 'statistics.admin.inc',
   );
   $items['admin/config/system/statistics'] = array(
Index: modules/statistics/statistics.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics/statistics.test,v
retrieving revision 1.22
diff -u -p -r1.22 statistics.test
--- modules/statistics/statistics.test	5 Aug 2010 23:53:39 -0000	1.22
+++ modules/statistics/statistics.test	7 Sep 2010 12:39:09 -0000
@@ -10,7 +10,15 @@ class StatisticsTestCase extends DrupalW
     parent::setUp('statistics');
 
     // Create user.
-    $this->blocking_user = $this->drupalCreateUser(array('block IP addresses', 'access statistics', 'administer blocks', 'administer statistics', 'administer users'));
+    $this->blocking_user = $this->drupalCreateUser(array(
+      'access administration pages',
+      'access site reports',
+      'access statistics',
+      'block IP addresses',
+      'administer blocks',
+      'administer statistics',
+      'administer users',
+    ));
     $this->drupalLogin($this->blocking_user);
 
     // Enable access logging.
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.959
diff -u -p -r1.959 system.module
--- modules/system/system.module	5 Sep 2010 02:21:38 -0000	1.959
+++ modules/system/system.module	7 Sep 2010 12:39:09 -0000
@@ -647,7 +647,6 @@ function system_menu() {
   $items['admin/modules/list/confirm'] = array(
     'title' => 'List',
     'access arguments' => array('administer modules'),
-    'type' => MENU_CALLBACK,
   );
   $items['admin/modules/uninstall'] = array(
     'title' => 'Uninstall',
@@ -660,7 +659,6 @@ function system_menu() {
   $items['admin/modules/uninstall/confirm'] = array(
     'title' => 'Uninstall',
     'access arguments' => array('administer modules'),
-    'type' => MENU_CALLBACK,
     'file' => 'system.admin.inc',
   );
 
@@ -687,7 +685,6 @@ function system_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_ip_blocking_delete', 5),
     'access arguments' => array('block IP addresses'),
-    'type' => MENU_CALLBACK,
     'file' => 'system.admin.inc',
   );
 
@@ -828,7 +825,6 @@ function system_menu() {
   $items['admin/config/regional/date-time/types/%/delete'] = array(
     'title' => 'Delete date type',
     'description' => 'Allow users to delete a configured date type.',
-    'type' => MENU_CALLBACK,
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_delete_date_format_type_form', 5),
     'access arguments' => array('administer site configuration'),
@@ -856,7 +852,6 @@ function system_menu() {
   $items['admin/config/regional/date-time/formats/%/edit'] = array(
     'title' => 'Edit date format',
     'description' => 'Allow users to edit a configured date format.',
-    'type' => MENU_CALLBACK,
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_configure_date_formats_form', 5),
     'access arguments' => array('administer site configuration'),
@@ -865,7 +860,6 @@ function system_menu() {
   $items['admin/config/regional/date-time/formats/%/delete'] = array(
     'title' => 'Delete date format',
     'description' => 'Allow users to delete a configured date format.',
-    'type' => MENU_CALLBACK,
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_date_delete_format_form', 5),
     'access arguments' => array('administer site configuration'),
@@ -873,7 +867,6 @@ function system_menu() {
   );
   $items['admin/config/regional/date-time/formats/lookup'] = array(
     'title' => 'Date and time lookup',
-    'type' => MENU_CALLBACK,
     'page callback' => 'system_date_time_lookup',
     'access arguments' => array('administer site configuration'),
     'file' => 'system.admin.inc',
@@ -937,7 +930,6 @@ function system_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_actions_configure'),
     'access arguments' => array('administer actions'),
-    'type' => MENU_CALLBACK,
     'file' => 'system.admin.inc',
   );
   $items['admin/config/system/actions/delete/%actions'] = array(
@@ -946,7 +938,6 @@ function system_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('system_actions_delete_form', 5),
     'access arguments' => array('administer actions'),
-    'type' => MENU_CALLBACK,
     'file' => 'system.admin.inc',
   );
   $items['admin/config/system/actions/orphan'] = array(
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.141
diff -u -p -r1.141 system.test
--- modules/system/system.test	30 Aug 2010 00:22:03 -0000	1.141
+++ modules/system/system.test	7 Sep 2010 12:39:09 -0000
@@ -653,8 +653,7 @@ class AccessDeniedTestCase extends Drupa
     parent::setUp();
 
     // Create an administrative user.
-    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer blocks'));
-    $this->drupalLogin($this->admin_user);
+    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks'));
   }
 
   function testAccessDenied() {
@@ -662,6 +661,7 @@ class AccessDeniedTestCase extends Drupa
     $this->assertText(t('Access denied'), t('Found the default 403 page'));
     $this->assertResponse(403);
 
+    $this->drupalLogin($this->admin_user);
     $edit = array(
       'title' => $this->randomName(10),
       'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
@@ -671,6 +671,7 @@ class AccessDeniedTestCase extends Drupa
     // Use a custom 403 page.
     $this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration'));
 
+    $this->drupalLogout();
     $this->drupalGet('admin');
     $this->assertText($node->title, t('Found the custom 403 page'));
 
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.604
diff -u -p -r1.604 taxonomy.module
--- modules/taxonomy/taxonomy.module	4 Sep 2010 15:40:52 -0000	1.604
+++ modules/taxonomy/taxonomy.module	7 Sep 2010 12:39:09 -0000
@@ -285,7 +285,6 @@ function taxonomy_menu() {
     'page callback' => 'taxonomy_term_page',
     'page arguments' => array(2),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
     'file' => 'taxonomy.pages.inc',
   );
   $items['taxonomy/term/%taxonomy_term/view'] = array(
Index: modules/taxonomy/taxonomy.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v
retrieving revision 1.53
diff -u -p -r1.53 taxonomy.pages.inc
--- modules/taxonomy/taxonomy.pages.inc	22 Aug 2010 13:53:37 -0000	1.53
+++ modules/taxonomy/taxonomy.pages.inc	7 Sep 2010 12:39:09 -0000
@@ -19,6 +19,8 @@ function taxonomy_term_page($term) {
   $current = (object) array(
     'tid' => $term->tid,
   );
+  // @todo This overrides any other possible breadcrumb and is a pure hard-coded
+  //   presumption. Make this behavior configurable per vocabulary or term.
   $breadcrumb = array();
   while ($parents = taxonomy_get_parents($current->tid)) {
     $current = array_shift($parents);
Index: modules/taxonomy/taxonomy.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.test,v
retrieving revision 1.90
diff -u -p -r1.90 taxonomy.test
--- modules/taxonomy/taxonomy.test	22 Aug 2010 15:45:03 -0000	1.90
+++ modules/taxonomy/taxonomy.test	7 Sep 2010 12:39:09 -0000
@@ -557,7 +557,7 @@ class TaxonomyTermTestCase extends Taxon
     // the first edit link found on the listing page is to our term.
     $this->clickLink(t('edit'));
 
-    $this->assertText($edit['name'], t('The randomly generated term name is present.'));
+    $this->assertRaw($edit['name'], t('The randomly generated term name is present.'));
     $this->assertText($edit['description[value]'], t('The randomly generated term description is present.'));
 
     $edit = array(
@@ -939,7 +939,7 @@ class TaxonomyTermFieldTestCase extends 
       "{$this->field_name}[$langcode]" => array($term->tid),
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
     $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
 
Index: modules/trigger/trigger.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/trigger/trigger.module,v
retrieving revision 1.64
diff -u -p -r1.64 trigger.module
--- modules/trigger/trigger.module	10 Jul 2010 01:44:28 -0000	1.64
+++ modules/trigger/trigger.module	7 Sep 2010 12:39:09 -0000
@@ -80,7 +80,6 @@ function trigger_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('trigger_unassign'),
     'access arguments' => array('administer actions'),
-    'type' => MENU_CALLBACK,
     'file' => 'trigger.admin.inc',
   );
 
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1198
diff -u -p -r1.1198 user.module
--- modules/user/user.module	5 Sep 2010 02:21:38 -0000	1.1198
+++ modules/user/user.module	7 Sep 2010 14:18:33 -0000
@@ -1525,7 +1525,12 @@ function user_menu() {
     'title' => 'User account',
     'page callback' => 'user_page',
     'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
+    // Edge-case: No menu links should be auto-generated for this and below
+    // items, which makes it a MENU_CALLBACK. However, this item's title is
+    // expected to appear on user login, register, and password pages, so we
+    // need to use MENU_VISIBLE_IN_BREADCRUMB to make
+    // menu_get_active_breadcrumb() account for it.
+    'type' => MENU_VISIBLE_IN_BREADCRUMB,
     'file' => 'user.pages.inc',
   );
 
@@ -1620,7 +1625,6 @@ function user_menu() {
     'page arguments' => array('user_admin_role', 5),
     'access callback' => 'user_role_edit_access',
     'access arguments' => array(5),
-    'type' => MENU_CALLBACK,
   );
   $items['admin/people/permissions/roles/delete/%user_role'] = array(
     'title' => 'Delete role',
@@ -1628,7 +1632,6 @@ function user_menu() {
     'page arguments' => array('user_admin_role_delete_confirm', 5),
     'access callback' => 'user_role_edit_access',
     'access arguments' => array(5),
-    'type' => MENU_CALLBACK,
     'file' => 'user.admin.inc',
   );
 
@@ -1691,7 +1694,6 @@ function user_menu() {
     'page arguments' => array('user_cancel_confirm_form', 1),
     'access callback' => 'user_cancel_access',
     'access arguments' => array(1),
-    'type' => MENU_CALLBACK,
     'file' => 'user.pages.inc',
   );
 
@@ -1701,7 +1703,6 @@ function user_menu() {
     'page arguments' => array(1, 4, 5),
     'access callback' => 'user_cancel_access',
     'access arguments' => array(1),
-    'type' => MENU_CALLBACK,
     'file' => 'user.pages.inc',
   );
 
