bool PageCache::canCachePageContainingThisFrame(Frame* frame) { for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { if (!canCachePageContainingThisFrame(child)) return false; } FrameLoader* frameLoader = frame->loader(); DocumentLoader* documentLoader = frameLoader->documentLoader(); Document* document = frame->document(); return documentLoader && documentLoader->mainDocumentError().isNull() // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs). && !(documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty()) && (!frameLoader->subframeLoader()->containsPlugins() || frame->page()->settings()->pageCacheSupportsPlugins()) && (!document->url().protocolIs("https") || (!documentLoader->response().cacheControlContainsNoCache() && !documentLoader->response().cacheControlContainsNoStore())) && (!document->domWindow() || !document->domWindow()->hasEventListeners(eventNames().unloadEvent)) #if ENABLE(SQL_DATABASE) && !DatabaseManager::manager().hasOpenDatabases(document) #endif #if ENABLE(SHARED_WORKERS) && !SharedWorkerRepository::hasSharedWorkers(document) #endif && frameLoader->history()->currentItem() && !frameLoader->quickRedirectComing() && !documentLoader->isLoadingInAPISense() && !documentLoader->isStopping() && document->canSuspendActiveDOMObjects() // FIXME: We should investigating caching frames that have an associated // application cache. <rdar://problem/5917899> tracks that work. && documentLoader->applicationCacheHost()->canCacheInPageCache() && frameLoader->client()->canCachePage(); }
PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bool clipAtTarget) { RefPtr<HistoryItem> bfItem = createItem(); saveScrollPositionAndViewStateToItem(m_previousItem.get()); if (!clipAtTarget || m_frame != targetFrame) { // save frame state for items that aren't loading (khtml doesn't save those) saveDocumentState(); // clipAtTarget is false for navigations within the same document, so // we should copy the documentSequenceNumber over to the newly create // item. Non-target items are just clones, and they should therefore // preserve the same itemSequenceNumber. if (m_previousItem) { if (m_frame != targetFrame) bfItem->setItemSequenceNumber(m_previousItem->itemSequenceNumber()); bfItem->setDocumentSequenceNumber(m_previousItem->documentSequenceNumber()); } for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { // If the child is a frame corresponding to an <object> element that never loaded, // we don't want to create a history item, because that causes fallback content // to be ignored on reload. FrameLoader* childLoader = child->loader(); if (childLoader->stateMachine()->startedFirstRealLoad() || !child->ownerElement()->isObjectElement()) bfItem->addChildItem(childLoader->history()->createItemTree(targetFrame, clipAtTarget)); } } // FIXME: Eliminate the isTargetItem flag in favor of itemSequenceNumber. if (m_frame == targetFrame) bfItem->setIsTargetItem(true); return bfItem; }
void HistoryController::updateBackForwardListClippedAtTarget(bool doClip) { // In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree. // The item that was the target of the user's navigation is designated as the "targetItem". // When this function is called with doClip=true we're able to create the whole tree except for the target's children, // which will be loaded in the future. That part of the tree will be filled out as the child loads are committed. Page* page = m_frame->page(); if (!page) return; if (m_frame->loader()->documentLoader()->urlForHistory().isEmpty()) return; Frame* mainFrame = page->mainFrame(); ASSERT(mainFrame); FrameLoader* frameLoader = mainFrame->loader(); frameLoader->checkDidPerformFirstNavigation(); RefPtr<HistoryItem> topItem = frameLoader->history()->createItemTree(m_frame, doClip); LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", topItem.get(), m_frame->loader()->documentLoader()->url().string().ascii().data()); page->backForward()->addItem(topItem.release()); }
PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bool clipAtTarget) { RefPtr<HistoryItem> bfItem = createItem(m_frame->tree()->parent() ? true : false); if (m_previousItem) saveScrollPositionAndViewStateToItem(m_previousItem.get()); if (!(clipAtTarget && m_frame == targetFrame)) { // save frame state for items that aren't loading (khtml doesn't save those) saveDocumentState(); for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { FrameLoader* childLoader = child->loader(); bool hasChildLoaded = childLoader->frameHasLoaded(); // If the child is a frame corresponding to an <object> element that never loaded, // we don't want to create a history item, because that causes fallback content // to be ignored on reload. if (!(!hasChildLoaded && childLoader->isHostedByObjectElement())) bfItem->addChildItem(childLoader->history()->createItemTree(targetFrame, clipAtTarget)); } } if (m_frame == targetFrame) bfItem->setIsTargetItem(true); return bfItem; }