Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1033
diff -u -p -r1.1033 common.inc
--- includes/common.inc	1 Nov 2009 14:08:17 -0000	1.1033
+++ includes/common.inc	1 Nov 2009 15:50:41 -0000
@@ -245,7 +245,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;
@@ -257,7 +257,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();
   }
 
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.357
diff -u -p -r1.357 menu.inc
--- includes/menu.inc	17 Oct 2009 11:39:15 -0000	1.357
+++ includes/menu.inc	1 Nov 2009 18:11:12 -0000
@@ -1089,8 +1089,24 @@ function menu_tree_page_data($menu_name,
           if (drupal_is_front_page()) {
             $args[] = '<front>';
           }
-          $parents = db_select('menu_links')
+          if (!empty($item['tab_root'])) {
+            // Replace wildcards in the root path using the current path.
+            $parts = arg(NULL, $item['tab_root']);
+            $map = $item['original_map'];
+            foreach ($parts as $index => $part) {
+              if ($part == '%') {
+                $parts[$index] = $map[$index];
+              }
+            }
+            $args[] = implode('/', $parts);
+
+            // And fallback to the untranslated tab root.
+            $args[] = $item['tab_root'];
+          }
+
+          $parents_candidates = db_select('menu_links')
             ->fields('menu_links', array(
+              'link_path',
               'p1',
               'p2',
               'p3',
@@ -1099,29 +1115,20 @@ function menu_tree_page_data($menu_name,
               'p6',
               'p7',
               'p8',
+              'p9',
             ))
             ->condition('menu_name', $menu_name)
             ->condition('link_path', $args, 'IN')
-            ->execute()->fetchAssoc();
+            ->execute()->fetchAllAssoc('link_path', PDO::FETCH_ASSOC);
 
-          if (empty($parents)) {
-            // 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.
-            $parents = 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();
+          $parents = array();
+          foreach ($args as $arg) {
+            if (isset($parents_candidates[$arg])) {
+              $parents = $parents_candidates[$arg];
+              break;
+            }
           }
+
           // We always want all the top-level links with plid == 0.
           $parents[] = '0';
 
@@ -2003,11 +2010,11 @@ function menu_set_active_trail($new_trai
       // 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();
+      $map = $item['original_map'];
       // Replace wildcards in the root path using the current path.
       foreach ($parts as $index => $part) {
         if ($part == '%') {
-          $parts[$index] = $args[$index];
+          $parts[$index] = $map[$index];
         }
       }
       // Retrieve the menu item using the root path after wildcard replacement.
@@ -2016,14 +2023,19 @@ function menu_set_active_trail($new_trai
         $item = $root_item;
       }
     }
+
     $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(db_or()
+        ->condition('ml.link_path', $item['path'])
+        ->condition('ml.link_path', $item['href'])
+      );
       $query->condition('ml.menu_name', $menu_names, 'IN');
+      $query->orderBy('ml.hidden', 'DESC');
       $result = $query->execute();
       $found = array();
       foreach ($result as $menu) {
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.214
diff -u -p -r1.214 menu.module
--- modules/menu/menu.module	1 Nov 2009 12:11:10 -0000	1.214
+++ modules/menu/menu.module	1 Nov 2009 16:05:46 -0000
@@ -222,8 +222,6 @@ function menu_load($menu_name) {
  *   - menu_name: The unique name of the custom menu.
  *   - title: The human readable menu title.
  *   - description: The custom menu description.
- *   - old_name: For existing menus, the current 'menu_name', otherwise empty.
- *     Decides whether hook_menu_insert() or hook_menu_update() will be invoked.
  *
  * Modules should always pass a fully populated $menu when saving a custom
  * menu, so other modules are able to output proper status or watchdog messages.
@@ -231,7 +229,7 @@ function menu_load($menu_name) {
  * @see menu_load()
  */
 function menu_save($menu) {
-  db_merge('menu_custom')
+  $status = db_merge('menu_custom')
     ->key(array('menu_name' => $menu['menu_name']))
     ->fields(array(
       'title' => $menu['title'],
@@ -239,17 +237,14 @@ function menu_save($menu) {
     ))
     ->execute();
 
-  // Since custom menus are keyed by name and their machine-name cannot be
-  // changed, there is no real differentiation between inserting and updating a
-  // menu. To overcome this, we define the existing menu_name as 'old_name' in
-  // menu_edit_menu().
-  // @todo Replace this condition when db_merge() returns the proper query
-  //   result (insert/update).
-  if (!empty($menu['old_name'])) {
-    module_invoke_all('menu_update', $menu);
-  }
-  else {
-    module_invoke_all('menu_insert', $menu);
+  switch ($status) {
+    case SAVED_NEW:
+      module_invoke_all('menu_insert', $menu);
+      break;
+
+    case SAVED_UPDATED:
+      module_invoke_all('menu_update', $menu);
+      break;
   }
 }
 
Index: modules/menu/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.test,v
retrieving revision 1.24
diff -u -p -r1.24 menu.test
--- modules/menu/menu.test	11 Oct 2009 03:07:18 -0000	1.24
+++ modules/menu/menu.test	1 Nov 2009 17:12:57 -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.'));
   }
 
   /**
