Example #1
0
void DumpRenderTreeSupportQt::clearFrameName(QWebFrame* frame)
{
    Frame* coreFrame = QWebFramePrivate::core(frame);
    coreFrame->tree()->clearName();
}
Example #2
0
FrameTree::~FrameTree()
{
    for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
        child->setView(nullptr);
}
void PaintLayerCompositor::updateIfNeededRecursive()
{
    FrameView* view = m_layoutView.frameView();
    if (view->shouldThrottleRendering())
        return;

    for (Frame* child = m_layoutView.frameView()->frame().tree().firstChild(); child; child = child->tree().nextSibling()) {
        if (!child->isLocalFrame())
            continue;
        LocalFrame* localFrame = toLocalFrame(child);
        // It's possible for trusted Pepper plugins to force hit testing in situations where
        // the frame tree is in an inconsistent state, such as in the middle of frame detach.
        // TODO(bbudge) Remove this check when trusted Pepper plugins are gone.
        if (localFrame->document()->isActive())
            localFrame->contentLayoutObject()->compositor()->updateIfNeededRecursive();
    }

    TRACE_EVENT0("blink", "PaintLayerCompositor::updateIfNeededRecursive");

    ASSERT(!m_layoutView.needsLayout());

    ScriptForbiddenScope forbidScript;

    // FIXME: enableCompositingModeIfNeeded can trigger a CompositingUpdateRebuildTree,
    // which asserts that it's not InCompositingUpdate.
    enableCompositingModeIfNeeded();

    if (m_needsUpdateDescendantDependentFlags) {
        updateDescendantDependentFlagsForEntireSubtree(*rootLayer());
        m_needsUpdateDescendantDependentFlags = false;
    }

    m_layoutView.commitPendingSelection();

    lifecycle().advanceTo(DocumentLifecycle::InCompositingUpdate);
    updateIfNeeded();
    lifecycle().advanceTo(DocumentLifecycle::CompositingClean);

    DocumentAnimations::updateCompositorAnimations(m_layoutView.document());

    m_layoutView.frameView()->scrollableArea()->updateCompositorScrollAnimations();
    if (const FrameView::ScrollableAreaSet* animatingScrollableAreas = m_layoutView.frameView()->animatingScrollableAreas()) {
        for (ScrollableArea* scrollableArea : *animatingScrollableAreas)
            scrollableArea->updateCompositorScrollAnimations();
    }

#if ENABLE(ASSERT)
    ASSERT(lifecycle().state() == DocumentLifecycle::CompositingClean);
    assertNoUnresolvedDirtyBits();
    for (Frame* child = m_layoutView.frameView()->frame().tree().firstChild(); child; child = child->tree().nextSibling()) {
        if (!child->isLocalFrame())
            continue;
        LocalFrame* localFrame = toLocalFrame(child);
        if (localFrame->shouldThrottleRendering())
            continue;
        localFrame->contentLayoutObject()->compositor()->assertNoUnresolvedDirtyBits();
    }
#endif
}
void InspectorResourceContentLoader::start()
{
    m_started = true;
    Vector<Document*> documents;
    for (Frame* frame = m_inspectedFrame; frame; frame = frame->tree().traverseNext(m_inspectedFrame)) {
        if (!frame->isLocalFrame())
            continue;
        LocalFrame* localFrame = toLocalFrame(frame);
        documents.append(localFrame->document());
        documents.appendVector(InspectorPageAgent::importsForFrame(localFrame));
    }
    for (Document* document : documents) {
        HashSet<String> urlsToFetch;

        ResourceRequest resourceRequest;
        HistoryItem* item = document->frame() ? document->frame()->loader().currentItem() : nullptr;
        if (item) {
            resourceRequest =
                FrameLoader::resourceRequestFromHistoryItem(item, ReturnCacheDataDontLoad);
        } else {
            resourceRequest = document->url();
            resourceRequest.setCachePolicy(ReturnCacheDataDontLoad);
        }
        resourceRequest.setRequestContext(WebURLRequest::RequestContextInternal);

        if (!resourceRequest.url().string().isEmpty()) {
            urlsToFetch.add(resourceRequest.url().string());
            FetchRequest request(resourceRequest, FetchInitiatorTypeNames::internal);
            ResourcePtr<Resource> resource = RawResource::fetch(request, document->fetcher());
            if (resource) {
                // Prevent garbage collection by holding a reference to this resource.
                m_resources.append(resource.get());
                ResourceClient* resourceClient = new ResourceClient(this);
                m_pendingResourceClients.add(resourceClient);
                resourceClient->waitForResource(resource.get());
            }
        }

        WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > styleSheets;
        InspectorCSSAgent::collectAllDocumentStyleSheets(document, styleSheets);
        for (CSSStyleSheet* styleSheet : styleSheets) {
            if (styleSheet->isInline() || !styleSheet->contents()->loadCompleted())
                continue;
            String url = styleSheet->baseURL().string();
            if (url.isEmpty() || urlsToFetch.contains(url))
                continue;
            urlsToFetch.add(url);
            FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::internal);
            request.mutableResourceRequest().setRequestContext(WebURLRequest::RequestContextInternal);
            ResourcePtr<Resource> resource = CSSStyleSheetResource::fetch(request, document->fetcher());
            if (!resource)
                continue;
            // Prevent garbage collection by holding a reference to this resource.
            m_resources.append(resource.get());
            ResourceClient* resourceClient = new ResourceClient(this);
            m_pendingResourceClients.add(resourceClient);
            resourceClient->waitForResource(resource.get());
        }
    }

    m_allRequestsStarted = true;
    checkDone();
}
Example #5
0
static unsigned logCanCacheFrameDecision(Frame* frame, int indentLevel)
{
#ifdef NDEBUG
    UNUSED_PARAM(indentLevel);
#endif
    PCLOG("+---");
    if (!frame->loader()->documentLoader()) {
        PCLOG("   -There is no DocumentLoader object");
        return 1 << NoDocumentLoader;
    }

    KURL currentURL = frame->loader()->documentLoader()->url();
    KURL newURL = frame->loader()->provisionalDocumentLoader() ? frame->loader()->provisionalDocumentLoader()->url() : KURL();
    if (!newURL.isEmpty())
        PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):");
    else
        PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:");
     
    unsigned rejectReasons = 0;
    if (!frame->loader()->documentLoader()->mainDocumentError().isNull()) {
        PCLOG("   -Main document has an error");
        rejectReasons |= 1 << MainDocumentError;
    }
    if (frame->loader()->documentLoader()->substituteData().isValid() && frame->loader()->documentLoader()->substituteData().failingURL().isEmpty()) {
        PCLOG("   -Frame is an error page");
        rejectReasons |= 1 << IsErrorPage;
    }
    if (frame->loader()->subframeLoader()->containsPlugins() && !frame->page()->settings()->pageCacheSupportsPlugins()) {
        PCLOG("   -Frame contains plugins");
        rejectReasons |= 1 << HasPlugins;
    }
    if (frame->document()->url().protocolIs("https")
        && (frame->loader()->documentLoader()->response().cacheControlContainsNoCache()
            || frame->loader()->documentLoader()->response().cacheControlContainsNoStore())) {
        PCLOG("   -Frame is HTTPS, and cache control prohibits caching or storing");
        rejectReasons |= 1 << IsHttpsAndCacheControlled;
    }
    if (frame->document()->domWindow() && frame->document()->domWindow()->hasEventListeners(eventNames().unloadEvent)) {
        PCLOG("   -Frame has an unload event listener");
        rejectReasons |= 1 << HasUnloadListener;
    }
#if ENABLE(SQL_DATABASE)
    if (DatabaseManager::manager().hasOpenDatabases(frame->document())) {
        PCLOG("   -Frame has open database handles");
        rejectReasons |= 1 << HasDatabaseHandles;
    }
#endif
#if ENABLE(SHARED_WORKERS)
    if (SharedWorkerRepository::hasSharedWorkers(frame->document())) {
        PCLOG("   -Frame has associated SharedWorkers");
        rejectReasons |= 1 << HasSharedWorkers;
    }
#endif
    if (!frame->loader()->history()->currentItem()) {
        PCLOG("   -No current history item");
        rejectReasons |= 1 << NoHistoryItem;
    }
    if (frame->loader()->quickRedirectComing()) {
        PCLOG("   -Quick redirect is coming");
        rejectReasons |= 1 << QuickRedirectComing;
    }
    if (frame->loader()->documentLoader()->isLoadingInAPISense()) {
        PCLOG("   -DocumentLoader is still loading in API sense");
        rejectReasons |= 1 << IsLoadingInAPISense;
    }
    if (frame->loader()->documentLoader()->isStopping()) {
        PCLOG("   -DocumentLoader is in the middle of stopping");
        rejectReasons |= 1 << IsStopping;
    }
    if (!frame->document()->canSuspendActiveDOMObjects()) {
        PCLOG("   -The document cannot suspect its active DOM Objects");
        rejectReasons |= 1 << CannotSuspendActiveDOMObjects;
    }
    if (!frame->loader()->documentLoader()->applicationCacheHost()->canCacheInPageCache()) {
        PCLOG("   -The DocumentLoader uses an application cache");
        rejectReasons |= 1 << DocumentLoaderUsesApplicationCache;
    }
    if (!frame->loader()->client()->canCachePage()) {
        PCLOG("   -The client says this frame cannot be cached");
        rejectReasons |= 1 << ClientDeniesCaching;
    }

    HistogramSupport::histogramEnumeration("PageCache.FrameCacheable", !rejectReasons, 2);
    int reasonCount = 0;
    for (int i = 0; i < NumberOfReasonsFramesCannotBeInPageCache; ++i) {
        if (rejectReasons & (1 << i)) {
            ++reasonCount;
            HistogramSupport::histogramEnumeration("PageCache.FrameRejectReason", i, NumberOfReasonsFramesCannotBeInPageCache);
        }
    }
    HistogramSupport::histogramEnumeration("PageCache.FrameRejectReasonCount", reasonCount, 1 + NumberOfReasonsFramesCannotBeInPageCache);

    for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
        rejectReasons |= logCanCacheFrameDecision(child, indentLevel + 1);
    
    PCLOG(rejectReasons ? " Frame CANNOT be cached" : " Frame CAN be cached");
    PCLOG("+---");
    
    return rejectReasons;
}
Example #6
0
static bool logCanCacheFrameDecision(Frame* frame, int indentLevel)
{
    // Only bother logging for frames that have actually loaded and have content.
    if (frame->loader()->stateMachine()->creatingInitialEmptyDocument())
        return false;
    KURL currentURL = frame->loader()->documentLoader() ? frame->loader()->documentLoader()->url() : KURL();
    if (currentURL.isEmpty())
        return false;

    PCLOG("+---");
    KURL newURL = frame->loader()->provisionalDocumentLoader() ? frame->loader()->provisionalDocumentLoader()->url() : KURL();
    if (!newURL.isEmpty())
        PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):");
    else
        PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:");

    bool cannotCache = false;

    do {
        if (!frame->loader()->documentLoader()) {
            PCLOG("   -There is no DocumentLoader object");
            cannotCache = true;
            break;
        }
        if (!frame->loader()->documentLoader()->mainDocumentError().isNull()) {
            PCLOG("   -Main document has an error");
            cannotCache = true;
        }
        if (frame->loader()->subframeLoader()->containsPlugins()) {
            PCLOG("   -Frame contains plugins");
            cannotCache = true;
        }
        if (frame->document()->url().protocolIs("https")) {
            PCLOG("   -Frame is HTTPS");
            cannotCache = true;
        }
        if (frame->domWindow() && frame->domWindow()->hasEventListeners(eventNames().unloadEvent)) {
            PCLOG("   -Frame has an unload event listener");
            cannotCache = true;
        }
#if ENABLE(DATABASE)
        if (frame->document()->hasOpenDatabases()) {
            PCLOG("   -Frame has open database handles");
            cannotCache = true;
        }
#endif
#if ENABLE(SHARED_WORKERS)
        if (SharedWorkerRepository::hasSharedWorkers(frame->document())) {
            PCLOG("   -Frame has associated SharedWorkers");
            cannotCache = true;
        }
#endif
        if (frame->document()->usingGeolocation()) {
            PCLOG("   -Frame uses Geolocation");
            cannotCache = true;
        }
        if (!frame->loader()->history()->currentItem()) {
            PCLOG("   -No current history item");
            cannotCache = true;
        }
        if (frame->loader()->quickRedirectComing()) {
            PCLOG("   -Quick redirect is coming");
            cannotCache = true;
        }
        if (frame->loader()->documentLoader()->isLoadingInAPISense()) {
            PCLOG("   -DocumentLoader is still loading in API sense");
            cannotCache = true;
        }
        if (frame->loader()->documentLoader()->isStopping()) {
            PCLOG("   -DocumentLoader is in the middle of stopping");
            cannotCache = true;
        }
        if (!frame->document()->canSuspendActiveDOMObjects()) {
            PCLOG("   -The document cannot suspect its active DOM Objects");
            cannotCache = true;
        }
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
        if (!frame->loader()->documentLoader()->applicationCacheHost()->canCacheInPageCache()) {
            PCLOG("   -The DocumentLoader uses an application cache");
            cannotCache = true;
        }
#endif
        if (!frame->loader()->client()->canCachePage()) {
            PCLOG("   -The client says this frame cannot be cached");
            cannotCache = true;
        }
    } while (false);

    for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
        if (!logCanCacheFrameDecision(child, indentLevel + 1))
            cannotCache = true;

    PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
    PCLOG("+---");

    return !cannotCache;
}
Example #7
0
void ProgressTracker::progressStarted(Frame& frame)
{
    LOG(Progress, "Progress started (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, &frame, frame.tree().uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());

    m_client.willChangeEstimatedProgress();
    
    if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame) {
        reset();
        m_progressValue = initialProgressValue;
        m_originatingProgressFrame = &frame;

        m_progressHeartbeatTimer.startRepeating(progressHeartbeatInterval);
        m_originatingProgressFrame->loader().loadProgressingStatusChanged();

        bool isMainFrame = !m_originatingProgressFrame->tree().parent();
        auto elapsedTimeSinceMainLoadComplete = std::chrono::steady_clock::now() - m_mainLoadCompletionTime;

        static const auto subframePartOfMainLoadThreshold = std::chrono::seconds(1);
        m_isMainLoad = isMainFrame || elapsedTimeSinceMainLoadComplete < subframePartOfMainLoadThreshold;

        m_client.progressStarted(*m_originatingProgressFrame);
    }
    m_numProgressTrackedFrames++;

    m_client.didChangeEstimatedProgress();
    InspectorInstrumentation::frameStartedLoading(frame);
}
Example #8
0
static unsigned logCanCacheFrameDecision(Frame& frame, DiagnosticLoggingClient& diagnosticLoggingClient, unsigned indentLevel)
{
    PCLOG("+---");
    if (!frame.loader().documentLoader()) {
        PCLOG("   -There is no DocumentLoader object");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noDocumentLoaderKey());
        return 1 << NoDocumentLoader;
    }

    URL currentURL = frame.loader().documentLoader()->url();
    URL newURL = frame.loader().provisionalDocumentLoader() ? frame.loader().provisionalDocumentLoader()->url() : URL();
    if (!newURL.isEmpty())
        PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):");
    else
        PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:");
     
    unsigned rejectReasons = 0;
    if (!frame.loader().documentLoader()->mainDocumentError().isNull()) {
        PCLOG("   -Main document has an error");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::mainDocumentErrorKey());

        if (frame.loader().documentLoader()->mainDocumentError().isCancellation() && frame.loader().documentLoader()->subresourceLoadersArePageCacheAcceptable())
            PCLOG("    -But, it was a cancellation and all loaders during the cancelation were loading images or XHR.");
        else
            rejectReasons |= 1 << MainDocumentError;
    }
    if (frame.loader().documentLoader()->substituteData().isValid() && frame.loader().documentLoader()->substituteData().failingURL().isEmpty()) {
        PCLOG("   -Frame is an error page");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isErrorPageKey());
        rejectReasons |= 1 << IsErrorPage;
    }
    if (frame.loader().subframeLoader().containsPlugins() && !frame.page()->settings().pageCacheSupportsPlugins()) {
        PCLOG("   -Frame contains plugins");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::hasPluginsKey());
        rejectReasons |= 1 << HasPlugins;
    }
    if (frame.isMainFrame() && frame.document()->url().protocolIs("https") && frame.loader().documentLoader()->response().cacheControlContainsNoStore()) {
        PCLOG("   -Frame is HTTPS, and cache control prohibits storing");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::httpsNoStoreKey());
        rejectReasons |= 1 << IsHttpsAndCacheControlled;
    }
    if (!frame.loader().history().currentItem()) {
        PCLOG("   -No current history item");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noCurrentHistoryItemKey());
        rejectReasons |= 1 << NoHistoryItem;
    }
    if (frame.loader().quickRedirectComing()) {
        PCLOG("   -Quick redirect is coming");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::quirkRedirectComingKey());
        rejectReasons |= 1 << QuickRedirectComing;
    }
    if (frame.loader().documentLoader()->isLoadingInAPISense()) {
        PCLOG("   -DocumentLoader is still loading in API sense");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::loadingAPISenseKey());
        rejectReasons |= 1 << IsLoadingInAPISense;
    }
    if (frame.loader().documentLoader()->isStopping()) {
        PCLOG("   -DocumentLoader is in the middle of stopping");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::documentLoaderStoppingKey());
        rejectReasons |= 1 << IsStopping;
    }

    Vector<ActiveDOMObject*> unsuspendableObjects;
    if (!frame.document()->canSuspendActiveDOMObjectsForPageCache(&unsuspendableObjects)) {
        PCLOG("   -The document cannot suspend its active DOM Objects");
        for (auto* activeDOMObject : unsuspendableObjects) {
            PCLOG("    - Unsuspendable: ", activeDOMObject->activeDOMObjectName());
            diagnosticLoggingClient.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::unsuspendableDOMObjectKey(), activeDOMObject->activeDOMObjectName(), ShouldSample::Yes);
            UNUSED_PARAM(activeDOMObject);
        }
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::cannotSuspendActiveDOMObjectsKey());
        rejectReasons |= 1 << CannotSuspendActiveDOMObjects;
    }
    if (!frame.loader().documentLoader()->applicationCacheHost()->canCacheInPageCache()) {
        PCLOG("   -The DocumentLoader uses an application cache");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::applicationCacheKey());
        rejectReasons |= 1 << DocumentLoaderUsesApplicationCache;
    }
    if (!frame.loader().client().canCachePage()) {
        PCLOG("   -The client says this frame cannot be cached");
        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::deniedByClientKey());
        rejectReasons |= 1 << ClientDeniesCaching;
    }

    for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
        rejectReasons |= logCanCacheFrameDecision(*child, diagnosticLoggingClient, indentLevel + 1);
    
    PCLOG(rejectReasons ? " Frame CANNOT be cached" : " Frame CAN be cached");
    PCLOG("+---");
    
    return rejectReasons;
}
Example #9
0
RefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame& frame, const Vector<Node*>& nodes, std::function<bool (Frame&)> frameFilter)
{
    const ResourceResponse& response = frame.loader().documentLoader()->response();
    URL responseURL = response.url();
    
    // it's possible to have a response without a URL here
    // <rdar://problem/5454935>
    if (responseURL.isNull())
        responseURL = URL(ParsedURLString, emptyString());

    RefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame.tree().uniqueName());
    if (!mainResource)
        return nullptr;

    Vector<RefPtr<LegacyWebArchive>> subframeArchives;
    Vector<RefPtr<ArchiveResource>> subresources;
    HashSet<URL> uniqueSubresources;

    size_t nodesSize = nodes.size();    
    for (size_t i = 0; i < nodesSize; ++i) {
        Node& node = *nodes[i];
        Frame* childFrame;
        if ((is<HTMLFrameElementBase>(node) || is<HTMLObjectElement>(node))
            && (childFrame = downcast<HTMLFrameOwnerElement>(node).contentFrame())) {
            if (frameFilter && !frameFilter(*childFrame))
                continue;
                
            if (RefPtr<LegacyWebArchive> subframeArchive = create(*childFrame->document(), frameFilter))
                subframeArchives.append(WTFMove(subframeArchive));
            else
                LOG_ERROR("Unabled to archive subframe %s", childFrame->tree().uniqueName().string().utf8().data());

        } else {
            ListHashSet<URL> subresourceURLs;
            node.getSubresourceURLs(subresourceURLs);
            
            DocumentLoader* documentLoader = frame.loader().documentLoader();

            for (const auto& subresourceURL : subresourceURLs) {
                if (uniqueSubresources.contains(subresourceURL))
                    continue;

                uniqueSubresources.add(subresourceURL);

                if (RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL)) {
                    subresources.append(WTFMove(resource));
                    continue;
                }

                ResourceRequest request(subresourceURL);
#if ENABLE(CACHE_PARTITIONING)
                request.setDomainForCachePartition(frame.document()->topOrigin()->domainForCachePartition());
#endif
                CachedResource* cachedResource = MemoryCache::singleton().resourceForRequest(request, frame.page()->sessionID());
                if (cachedResource) {
                    if (RefPtr<ArchiveResource> resource = ArchiveResource::create(cachedResource->resourceBuffer(), subresourceURL, cachedResource->response())) {
                        subresources.append(WTFMove(resource));
                        continue;
                    }
                }

                // FIXME: should do something better than spew to console here
                LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data());
            }
        }
    }

    // Add favicon if one exists for this page, if we are archiving the entire page.
    if (nodesSize && nodes[0]->isDocumentNode() && iconDatabase().isEnabled()) {
        const String& iconURL = iconDatabase().synchronousIconURLForPageURL(responseURL);
        if (!iconURL.isEmpty() && iconDatabase().synchronousIconDataKnownForIconURL(iconURL)) {
            if (Image* iconImage = iconDatabase().synchronousIconForPageURL(responseURL, IntSize(16, 16))) {
                if (RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), URL(ParsedURLString, iconURL), "image/x-icon", "", ""))
                    subresources.append(resource.release());
            }
        }
    }

    return create(WTFMove(mainResource), WTFMove(subresources), WTFMove(subframeArchives));
}
FrameTree::~FrameTree()
{
    for (Frame* child = firstChild(); child; child = child->tree()->nextSibling())
        child->setView(0);
}
Example #11
0
CachedFrame::CachedFrame(Frame& frame)
    : CachedFrameBase(frame)
{
#ifndef NDEBUG
    cachedFrameCounter.increment();
#endif
    ASSERT(m_document);
    ASSERT(m_documentLoader);
    ASSERT(m_view);

    if (frame.page()->focusController().focusedFrame() == &frame)
        frame.page()->focusController().setFocusedFrame(&frame.mainFrame());

    // Custom scrollbar renderers will get reattached when the document comes out of the page cache
    m_view->detachCustomScrollbars();

    m_document->setInPageCache(true);
    frame.loader().stopLoading(UnloadEventPolicyUnloadAndPageHide);

    // Create the CachedFrames for all Frames in the FrameTree.
    for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
        m_childFrames.append(std::make_unique<CachedFrame>(*child));

    // Active DOM objects must be suspended before we cache the frame script data,
    // but after we've fired the pagehide event, in case that creates more objects.
    // Suspending must also happen after we've recursed over child frames, in case
    // those create more objects.
    m_document->documentWillSuspendForPageCache();
    m_document->suspendScriptedAnimationControllerCallbacks();
    m_document->suspendActiveDOMObjects(ActiveDOMObject::PageCache);
    m_cachedFrameScriptData = std::make_unique<ScriptCachedFrameData>(frame);

    m_document->domWindow()->suspendForPageCache();

    frame.loader().client().savePlatformDataToCachedFrame(this);

    if (m_isComposited && PageCache::singleton().shouldClearBackingStores())
        frame.view()->clearBackingStores();

    // documentWillSuspendForPageCache() can set up a layout timer on the FrameView, so clear timers after that.
    frame.clearTimers();

    // Deconstruct the FrameTree, to restore it later.
    // We do this for two reasons:
    // 1 - We reuse the main frame, so when it navigates to a new page load it needs to start with a blank FrameTree.
    // 2 - It's much easier to destroy a CachedFrame while it resides in the PageCache if it is disconnected from its parent.
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        frame.tree().removeChild(&m_childFrames[i]->view()->frame());

    if (!m_isMainFrame)
        frame.page()->decrementSubframeCount();

    frame.loader().client().didSaveToPageCache();

#ifndef NDEBUG
    if (m_isMainFrame)
        LOG(PageCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
    else
        LOG(PageCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
#endif

#if PLATFORM(IOS)
    if (m_isMainFrame) {
        if (DOMWindow* domWindow = m_document->domWindow()) {
            if (domWindow->scrollEventListenerCount() && frame.page())
                frame.page()->chrome().client().setNeedsScrollNotifications(&frame, false);
        }
    }
#endif

    ASSERT_WITH_SECURITY_IMPLICATION(!m_documentLoader->isLoading());
}
Example #12
0
void ProgressTracker::progressStarted(Frame& frame)
{
    LOG(Progress, "Progress started (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, &frame, frame.tree().uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());

    m_client.willChangeEstimatedProgress();
    
    if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame) {
        reset();
        m_progressValue = initialProgressValue;
        m_originatingProgressFrame = &frame;

        m_progressHeartbeatTimer.startRepeating(progressHeartbeatInterval);
        m_originatingProgressFrame->loader().loadProgressingStatusChanged();

        m_client.progressStarted(*m_originatingProgressFrame);
    }
    m_numProgressTrackedFrames++;

    m_client.didChangeEstimatedProgress();
    InspectorInstrumentation::frameStartedLoading(frame);
}
Example #13
0
void PageSerializer::serializeFrame(Frame* frame)
{
    Document* document = frame->document();
    KURL url = document->url();
    if (!url.isValid() || url.isBlankURL()) {
        // For blank frames we generate a fake URL so they can be referenced by their containing frame.
        url = urlForBlankFrame(frame);
    }

    if (m_resourceURLs.contains(url)) {
        // FIXME: We could have 2 frame with the same URL but which were dynamically changed and have now
        // different content. So we should serialize both and somehow rename the frame src in the containing
        // frame. Arg!
        return;
    }

    Vector<Node*> nodes;
    SerializerMarkupAccumulator accumulator(this, document, &nodes);
    TextEncoding textEncoding(document->charset());
    CString data;
    if (!textEncoding.isValid()) {
        // FIXME: iframes used as images trigger this. We should deal with them correctly.
        return;
    }
    String text = accumulator.serializeNodes(document->documentElement(), 0, IncludeNode);
    CString frameHTML = textEncoding.encode(text.characters(), text.length(), EntitiesForUnencodables);
    m_resources->append(Resource(url, document->suggestedMIMEType(), SharedBuffer::create(frameHTML.data(), frameHTML.length())));
    m_resourceURLs.add(url);

    for (Vector<Node*>::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
        Node* node = *iter;
        if (!node->isElementNode())
            continue;

        Element* element = toElement(node);
        // We have to process in-line style as it might contain some resources (typically background images).
        if (element->isStyledElement())
            retrieveResourcesForProperties(static_cast<StyledElement*>(element)->inlineStyle(), document);

        if (element->hasTagName(HTMLNames::imgTag)) {
            HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(element);
            KURL url = document->completeURL(imageElement->getAttribute(HTMLNames::srcAttr));
            CachedImage* cachedImage = imageElement->cachedImage();
            addImageToResources(cachedImage, imageElement->renderer(), url);
        } else if (element->hasTagName(HTMLNames::linkTag)) {
            HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(element);
            if (CSSStyleSheet* sheet = linkElement->sheet()) {
                KURL url = document->completeURL(linkElement->getAttribute(HTMLNames::hrefAttr));
                serializeCSSStyleSheet(sheet, url);
                ASSERT(m_resourceURLs.contains(url));
            }
        } else if (element->hasTagName(HTMLNames::styleTag)) {
            HTMLStyleElement* styleElement = static_cast<HTMLStyleElement*>(element);
            if (CSSStyleSheet* sheet = styleElement->sheet())
                serializeCSSStyleSheet(sheet, KURL());
        }
    }

    for (Frame* childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
        serializeFrame(childFrame);
}
Example #14
0
static void setNeedsReapplyStylesInAllFrames(Page* page)
{
    for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
        frame->setNeedsReapplyStyles();
}
Example #15
0
void ProgressTracker::progressCompleted(Frame& frame)
{
    LOG(Progress, "Progress completed (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, &frame, frame.tree().uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
    
    if (m_numProgressTrackedFrames <= 0)
        return;
    
    m_client.willChangeEstimatedProgress();
        
    m_numProgressTrackedFrames--;
    if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame)
        finalProgressComplete();
    
    m_client.didChangeEstimatedProgress();
}
Example #16
0
static unsigned logCanCacheFrameDecision(Frame* frame, int indentLevel)
{
    PCLOG("+---");
    if (!frame->loader().documentLoader()) {
        PCLOG("   -There is no DocumentLoader object");
        return 1 << NoDocumentLoader;
    }

    URL currentURL = frame->loader().documentLoader()->url();
    URL newURL = frame->loader().provisionalDocumentLoader() ? frame->loader().provisionalDocumentLoader()->url() : URL();
    if (!newURL.isEmpty())
        PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):");
    else
        PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:");
     
    unsigned rejectReasons = 0;
    if (!frame->loader().documentLoader()->mainDocumentError().isNull()) {
        PCLOG("   -Main document has an error");
#if !PLATFORM(IOS)
        rejectReasons |= 1 << MainDocumentError;
#else
        if (frame->loader().documentLoader()->mainDocumentError().isCancellation() && frame->loader().documentLoader()->subresourceLoadersArePageCacheAcceptable())
            PCLOG("    -But, it was a cancellation and all loaders during the cancel were loading images.");
        else
            rejectReasons |= 1 << MainDocumentError;
#endif
    }
    if (frame->loader().documentLoader()->substituteData().isValid() && frame->loader().documentLoader()->substituteData().failingURL().isEmpty()) {
        PCLOG("   -Frame is an error page");
        rejectReasons |= 1 << IsErrorPage;
    }
    if (frame->loader().subframeLoader().containsPlugins() && !frame->page()->settings().pageCacheSupportsPlugins()) {
        PCLOG("   -Frame contains plugins");
        rejectReasons |= 1 << HasPlugins;
    }
    if (frame->document()->url().protocolIs("https")
        && (frame->loader().documentLoader()->response().cacheControlContainsNoCache()
            || frame->loader().documentLoader()->response().cacheControlContainsNoStore())) {
        PCLOG("   -Frame is HTTPS, and cache control prohibits caching or storing");
        rejectReasons |= 1 << IsHttpsAndCacheControlled;
    }
    if (frame->document()->domWindow() && frame->document()->domWindow()->hasEventListeners(eventNames().unloadEvent)) {
        PCLOG("   -Frame has an unload event listener");
#if !PLATFORM(IOS)
        rejectReasons |= 1 << HasUnloadListener;
#else
        // iOS allows pages with unload event listeners to enter the page cache.
        PCLOG("    -BUT iOS allows these pages to be cached.");
#endif
    }
#if ENABLE(SQL_DATABASE)
    if (DatabaseManager::manager().hasOpenDatabases(frame->document())) {
        PCLOG("   -Frame has open database handles");
        rejectReasons |= 1 << HasDatabaseHandles;
    }
#endif
#if ENABLE(SHARED_WORKERS)
    if (SharedWorkerRepository::hasSharedWorkers(frame->document())) {
        PCLOG("   -Frame has associated SharedWorkers");
        rejectReasons |= 1 << HasSharedWorkers;
    }
#endif
    if (!frame->loader().history().currentItem()) {
        PCLOG("   -No current history item");
        rejectReasons |= 1 << NoHistoryItem;
    }
    if (frame->loader().quickRedirectComing()) {
        PCLOG("   -Quick redirect is coming");
        rejectReasons |= 1 << QuickRedirectComing;
    }
    if (frame->loader().documentLoader()->isLoadingInAPISense()) {
        PCLOG("   -DocumentLoader is still loading in API sense");
        rejectReasons |= 1 << IsLoadingInAPISense;
    }
    if (frame->loader().documentLoader()->isStopping()) {
        PCLOG("   -DocumentLoader is in the middle of stopping");
        rejectReasons |= 1 << IsStopping;
    }
    if (!frame->document()->canSuspendActiveDOMObjects()) {
        PCLOG("   -The document cannot suspect its active DOM Objects");
        rejectReasons |= 1 << CannotSuspendActiveDOMObjects;
    }
    if (!frame->loader().documentLoader()->applicationCacheHost()->canCacheInPageCache()) {
        PCLOG("   -The DocumentLoader uses an application cache");
        rejectReasons |= 1 << DocumentLoaderUsesApplicationCache;
    }
    if (!frame->loader().client().canCachePage()) {
        PCLOG("   -The client says this frame cannot be cached");
        rejectReasons |= 1 << ClientDeniesCaching;
    }

    for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling())
        rejectReasons |= logCanCacheFrameDecision(child, indentLevel + 1);
    
    PCLOG(rejectReasons ? " Frame CANNOT be cached" : " Frame CAN be cached");
    PCLOG("+---");
    
    return rejectReasons;
}
Example #17
0
CachedFrame::CachedFrame(Frame* frame)
    : CachedFrameBase(frame)
{
#ifndef NDEBUG
    cachedFrameCounter().increment();
#endif
    ASSERT(m_document);
    ASSERT(m_documentLoader);
    ASSERT(m_view);

    if (frame->page()->focusController()->focusedFrame() == frame)
        frame->page()->focusController()->setFocusedFrame(frame->page()->mainFrame());

    // Custom scrollbar renderers will get reattached when the document comes out of the page cache
    m_view->detachCustomScrollbars();

    m_document->setInPageCache(true);
    frame->loader()->stopLoading(UnloadEventPolicyUnloadAndPageHide);

    // Create the CachedFrames for all Frames in the FrameTree.
    for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
        m_childFrames.append(CachedFrame::create(child));

    // Active DOM objects must be suspended before we cache the frame script data,
    // but after we've fired the pagehide event, in case that creates more objects.
    // Suspending must also happen after we've recursed over child frames, in case
    // those create more objects.
    m_document->documentWillSuspendForPageCache();
    m_document->suspendScriptedAnimationControllerCallbacks();
    m_document->suspendActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
    m_cachedFrameScriptData = adoptPtr(new ScriptCachedFrameData(frame));

    m_document->domWindow()->suspendForPageCache();

    frame->loader()->client()->savePlatformDataToCachedFrame(this);

#if USE(ACCELERATED_COMPOSITING)
    if (m_isComposited && pageCache()->shouldClearBackingStores())
        frame->view()->clearBackingStores();
#endif

    // documentWillSuspendForPageCache() can set up a layout timer on the FrameView, so clear timers after that.
    frame->clearTimers();

    // Deconstruct the FrameTree, to restore it later.
    // We do this for two reasons:
    // 1 - We reuse the main frame, so when it navigates to a new page load it needs to start with a blank FrameTree.
    // 2 - It's much easier to destroy a CachedFrame while it resides in the PageCache if it is disconnected from its parent.
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        frame->tree()->removeChild(m_childFrames[i]->view()->frame());

    if (!m_isMainFrame)
        frame->page()->decrementSubframeCount();

    frame->loader()->client()->didSaveToPageCache();

#ifndef NDEBUG
    if (m_isMainFrame)
        LOG(PageCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
    else
        LOG(PageCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
#endif

}
void FullscreenElementStack::requestFullScreenForElement(Element* element, unsigned short flags, FullScreenCheckType checkType)
{
    // The Mozilla Full Screen API <https://wiki.mozilla.org/Gecko:FullScreenAPI> has different requirements
    // for full screen mode, and do not have the concept of a full screen element stack.
    bool inLegacyMozillaMode = (flags & Element::LEGACY_MOZILLA_REQUEST);

    do {
        if (!element)
            element = document()->documentElement();

        // 1. If any of the following conditions are true, terminate these steps and queue a task to fire
        // an event named fullscreenerror with its bubbles attribute set to true on the context object's
        // node document:

        // The context object is not in a document.
        if (!element->inDocument())
            break;

        // The context object's node document, or an ancestor browsing context's document does not have
        // the fullscreen enabled flag set.
        if (checkType == EnforceIFrameAllowFullScreenRequirement && !fullScreenIsAllowedForElement(element))
            break;

        // The context object's node document fullscreen element stack is not empty and its top element
        // is not an ancestor of the context object. (NOTE: Ignore this requirement if the request was
        // made via the legacy Mozilla-style API.)
        if (!m_fullScreenElementStack.isEmpty() && !inLegacyMozillaMode) {
            Element* lastElementOnStack = m_fullScreenElementStack.last().get();
            if (lastElementOnStack == element || !lastElementOnStack->contains(element))
                break;
        }

        // A descendant browsing context's document has a non-empty fullscreen element stack.
        bool descendentHasNonEmptyStack = false;
        for (Frame* descendant = document()->frame() ? document()->frame()->tree().traverseNext() : 0; descendant; descendant = descendant->tree().traverseNext()) {
            if (fullscreenElementFrom(descendant->document())) {
                descendentHasNonEmptyStack = true;
                break;
            }
        }
        if (descendentHasNonEmptyStack && !inLegacyMozillaMode)
            break;

        // This algorithm is not allowed to show a pop-up:
        //   An algorithm is allowed to show a pop-up if, in the task in which the algorithm is running, either:
        //   - an activation behavior is currently being processed whose click event was trusted, or
        //   - the event listener for a trusted click event is being handled.
        // FIXME: Does this need to null-check settings()?
        if (!UserGestureIndicator::processingUserGesture() && (!element->isMediaElement() || document()->settings()->mediaFullscreenRequiresUserGesture()))
            break;

        // There is a previously-established user preference, security risk, or platform limitation.
        if (!document()->settings() || !document()->settings()->fullScreenEnabled())
            break;

        // 2. Let doc be element's node document. (i.e. "this")
        Document* currentDoc = document();

        // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc.
        Deque<Document*> docs;

        do {
            docs.prepend(currentDoc);
            currentDoc = currentDoc->ownerElement() ? &currentDoc->ownerElement()->document() : 0;
        } while (currentDoc);

        // 4. For each document in docs, run these substeps:
        Deque<Document*>::iterator current = docs.begin(), following = docs.begin();

        do {
            ++following;

            // 1. Let following document be the document after document in docs, or null if there is no
            // such document.
            Document* currentDoc = *current;
            Document* followingDoc = following != docs.end() ? *following : 0;

            // 2. If following document is null, push context object on document's fullscreen element
            // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
            // set to true on the document.
            if (!followingDoc) {
                from(currentDoc)->pushFullscreenElementStack(element);
                addDocumentToFullScreenChangeEventQueue(currentDoc);
                continue;
            }

            // 3. Otherwise, if document's fullscreen element stack is either empty or its top element
            // is not following document's browsing context container,
            Element* topElement = fullscreenElementFrom(currentDoc);
            if (!topElement || topElement != followingDoc->ownerElement()) {
                // ...push following document's browsing context container on document's fullscreen element
                // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
                // set to true on document.
                from(currentDoc)->pushFullscreenElementStack(followingDoc->ownerElement());
                addDocumentToFullScreenChangeEventQueue(currentDoc);
                continue;
            }

            // 4. Otherwise, do nothing for this document. It stays the same.
        } while (++current != docs.end());

        // 5. Return, and run the remaining steps asynchronously.
        // 6. Optionally, perform some animation.
        m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
        document()->frameHost()->chrome().client().enterFullScreenForElement(element);

        // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
        return;
    } while (0);

    m_fullScreenErrorEventTargetQueue.append(element ? element : document()->documentElement());
    m_fullScreenChangeDelayTimer.startOneShot(0);
}
Example #19
0
static void setLoadsImagesAutomaticallyInAllFrames(Page* page)
{
    for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
        frame->document()->cachedResourceLoader()->setAutoLoadImages(page->settings()->loadsImagesAutomatically());
}