Home | History | Annotate | Download | only in renderer
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /*
      6  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      7  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
      9  *     (http://www.torchmobile.com/)
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  *
     15  * 1.  Redistributions of source code must retain the above copyright
     16  *     notice, this list of conditions and the following disclaimer.
     17  * 2.  Redistributions in binary form must reproduce the above copyright
     18  *     notice, this list of conditions and the following disclaimer in the
     19  *     documentation and/or other materials provided with the distribution.
     20  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     21  *     its contributors may be used to endorse or promote products derived
     22  *     from this software without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     25  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     27  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     29  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 #include "content/renderer/history_controller.h"
     37 
     38 #include "content/renderer/render_frame_impl.h"
     39 #include "content/renderer/render_view_impl.h"
     40 #include "third_party/WebKit/public/web/WebFrame.h"
     41 
     42 using blink::WebFrame;
     43 using blink::WebHistoryCommitType;
     44 using blink::WebHistoryItem;
     45 using blink::WebURLRequest;
     46 
     47 namespace content {
     48 
     49 HistoryController::HistoryController(RenderViewImpl* render_view)
     50     : render_view_(render_view) {
     51 }
     52 
     53 HistoryController::~HistoryController() {
     54 }
     55 
     56 void HistoryController::GoToEntry(scoped_ptr<HistoryEntry> target_entry,
     57                                   WebURLRequest::CachePolicy cache_policy) {
     58   HistoryFrameLoadVector same_document_loads;
     59   HistoryFrameLoadVector different_document_loads;
     60 
     61   provisional_entry_ = target_entry.Pass();
     62 
     63   WebFrame* main_frame = render_view_->main_render_frame()->GetWebFrame();
     64   if (current_entry_) {
     65     RecursiveGoToEntry(
     66         main_frame, same_document_loads, different_document_loads);
     67   }
     68 
     69   if (same_document_loads.empty() && different_document_loads.empty()) {
     70     // If we don't have any frames to navigate at this point, either
     71     // (1) there is no previous history entry to compare against, or
     72     // (2) we were unable to match any frames by name. In the first case,
     73     // doing a different document navigation to the root item is the only valid
     74     // thing to do. In the second case, we should have been able to find a
     75     // frame to navigate based on names if this were a same document
     76     // navigation, so we can safely assume this is the different document case.
     77     different_document_loads.push_back(
     78         std::make_pair(main_frame, provisional_entry_->root()));
     79   }
     80 
     81   for (size_t i = 0; i < same_document_loads.size(); ++i) {
     82     WebFrame* frame = same_document_loads[i].first;
     83     if (!RenderFrameImpl::FromWebFrame(frame))
     84       continue;
     85     frame->loadHistoryItem(same_document_loads[i].second,
     86                            blink::WebHistorySameDocumentLoad,
     87                            cache_policy);
     88   }
     89   for (size_t i = 0; i < different_document_loads.size(); ++i) {
     90     WebFrame* frame = different_document_loads[i].first;
     91     if (!RenderFrameImpl::FromWebFrame(frame))
     92       continue;
     93     frame->loadHistoryItem(different_document_loads[i].second,
     94                            blink::WebHistoryDifferentDocumentLoad,
     95                            cache_policy);
     96   }
     97 }
     98 
     99 void HistoryController::RecursiveGoToEntry(
    100     WebFrame* frame,
    101     HistoryFrameLoadVector& same_document_loads,
    102     HistoryFrameLoadVector& different_document_loads) {
    103   DCHECK(provisional_entry_);
    104   DCHECK(current_entry_);
    105   RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
    106   const WebHistoryItem& new_item =
    107       provisional_entry_->GetItemForFrame(render_frame);
    108   const WebHistoryItem& old_item =
    109       current_entry_->GetItemForFrame(render_frame);
    110   if (new_item.isNull())
    111     return;
    112 
    113   if (old_item.isNull() ||
    114       new_item.itemSequenceNumber() != old_item.itemSequenceNumber()) {
    115     if (!old_item.isNull() &&
    116         new_item.documentSequenceNumber() == old_item.documentSequenceNumber())
    117       same_document_loads.push_back(std::make_pair(frame, new_item));
    118     else
    119       different_document_loads.push_back(std::make_pair(frame, new_item));
    120     return;
    121   }
    122 
    123   for (WebFrame* child = frame->firstChild(); child;
    124        child = child->nextSibling()) {
    125     RecursiveGoToEntry(child, same_document_loads, different_document_loads);
    126   }
    127 }
    128 
    129 void HistoryController::UpdateForInitialLoadInChildFrame(
    130     RenderFrameImpl* frame,
    131     const WebHistoryItem& item) {
    132   DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame());
    133   if (!current_entry_)
    134     return;
    135   if (HistoryEntry::HistoryNode* existing_node =
    136           current_entry_->GetHistoryNodeForFrame(frame)) {
    137     existing_node->set_item(item);
    138     return;
    139   }
    140   RenderFrameImpl* parent =
    141       RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent());
    142   if (HistoryEntry::HistoryNode* parent_history_node =
    143           current_entry_->GetHistoryNodeForFrame(parent)) {
    144     parent_history_node->AddChild(item, frame->GetRoutingID());
    145   }
    146 }
    147 
    148 void HistoryController::UpdateForCommit(RenderFrameImpl* frame,
    149                                         const WebHistoryItem& item,
    150                                         WebHistoryCommitType commit_type,
    151                                         bool navigation_within_page) {
    152   if (commit_type == blink::WebBackForwardCommit) {
    153     if (!provisional_entry_)
    154       return;
    155     current_entry_.reset(provisional_entry_.release());
    156   } else if (commit_type == blink::WebStandardCommit) {
    157     CreateNewBackForwardItem(frame, item, navigation_within_page);
    158   } else if (commit_type == blink::WebInitialCommitInChildFrame) {
    159     UpdateForInitialLoadInChildFrame(frame, item);
    160   }
    161 }
    162 
    163 HistoryEntry* HistoryController::GetCurrentEntry() {
    164   return current_entry_.get();
    165 }
    166 
    167 WebHistoryItem HistoryController::GetItemForNewChildFrame(
    168     RenderFrameImpl* frame) const {
    169   if (!current_entry_)
    170     return WebHistoryItem();
    171   return current_entry_->GetItemForFrame(frame);
    172 }
    173 
    174 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) {
    175   if (!provisional_entry_)
    176     return;
    177   if (HistoryEntry::HistoryNode* node =
    178           provisional_entry_->GetHistoryNodeForFrame(frame))
    179     node->RemoveChildren();
    180 }
    181 
    182 void HistoryController::CreateNewBackForwardItem(
    183     RenderFrameImpl* target_frame,
    184     const WebHistoryItem& new_item,
    185     bool clone_children_of_target) {
    186   if (!current_entry_) {
    187     current_entry_.reset(
    188         new HistoryEntry(new_item, target_frame->GetRoutingID()));
    189   } else {
    190     current_entry_.reset(current_entry_->CloneAndReplace(
    191         new_item, clone_children_of_target, target_frame, render_view_));
    192   }
    193 }
    194 
    195 }  // namespace content
    196