static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) { LOG_ASSERT(frame, "Close needs a valid Frame pointer!"); WebCore::Frame* pFrame = (WebCore::Frame*)frame; WebCore::BackForwardList* list = pFrame->page()->backForwardList(); RefPtr<WebCore::HistoryItem> current = list->currentItem(); // Remove each item instead of using close(). close() is intended to be used // right before the list is deleted. WebCore::HistoryItemVector& entries = list->entries(); int size = entries.size(); for (int i = size - 1; i >= 0; --i) list->removeItem(entries[i].get()); // Add the current item back to the list. if (current) { current->setBridge(0); // addItem will update the children to match the newly created bridge list->addItem(current); /* * The Grand Prix site uses anchor navigations to change the display. * WebKit tries to be smart and not load child frames that have the * same history urls during an anchor navigation. This means that the * current history item stored in the child frame's loader does not * match the item found in the history tree. If we remove all the * entries in the back/foward list, we have to restore the entire tree * or else a HistoryItem might have a deleted parent. * * In order to restore the history tree correctly, we have to look up * all the frames first and then look up the history item. We do this * because the history item in the tree may be null at this point. * Unfortunately, a HistoryItem can only search its immediately * children so we do a breadth-first rebuild of the tree. */ // Keep a small list of child frames to traverse. WTF::Vector<WebCore::Frame*> frameQueue; // Fix the top-level item. pFrame->loader()->history()->setCurrentItem(current.get()); WebCore::Frame* child = pFrame->tree()->firstChild(); // Remember the parent history item so we can search for a child item. RefPtr<WebCore::HistoryItem> parent = current; while (child) { // Use the old history item since the current one may have a // deleted parent. WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name()); child->loader()->history()->setCurrentItem(item); // Append the first child to the queue if it exists. If there is no // item, then we do not need to traverse the children since there // will be no parent history item. WebCore::Frame* firstChild; if (item && (firstChild = child->tree()->firstChild())) frameQueue.append(firstChild); child = child->tree()->nextSibling(); // If we don't have a sibling for this frame and the queue isn't // empty, use the next entry in the queue. if (!child && !frameQueue.isEmpty()) { child = frameQueue.at(0); frameQueue.remove(0); // Figure out the parent history item used when searching for // the history item to use. parent = child->tree()->parent()->loader()->history()->currentItem(); } } } }