script/
layout_image.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Infrastructure to initiate network requests for images needed by layout. The script thread needs
6//! to be responsible for them because there's no guarantee that the responsible nodes will still
7//! exist in the future if layout holds on to them during asynchronous operations.
8
9use std::sync::Arc;
10
11use net_traits::image_cache::{ImageCache, PendingImageId};
12use net_traits::request::{Destination, RequestBuilder as FetchRequestInit, RequestId};
13use net_traits::{
14    FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError, ResourceFetchTiming,
15    ResourceTimingType,
16};
17use servo_url::ServoUrl;
18
19use crate::dom::bindings::refcounted::Trusted;
20use crate::dom::bindings::reflector::DomGlobal;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::csp::{GlobalCspReporting, Violation};
23use crate::dom::document::Document;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::node::{Node, NodeTraits};
26use crate::dom::performanceresourcetiming::InitiatorType;
27use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
28use crate::script_runtime::CanGc;
29
30struct LayoutImageContext {
31    id: PendingImageId,
32    cache: Arc<dyn ImageCache>,
33    resource_timing: ResourceFetchTiming,
34    doc: Trusted<Document>,
35    url: ServoUrl,
36}
37
38impl FetchResponseListener for LayoutImageContext {
39    fn process_request_body(&mut self, _: RequestId) {}
40    fn process_request_eof(&mut self, _: RequestId) {}
41    fn process_response(
42        &mut self,
43        request_id: RequestId,
44        metadata: Result<FetchMetadata, NetworkError>,
45    ) {
46        self.cache.notify_pending_response(
47            self.id,
48            FetchResponseMsg::ProcessResponse(request_id, metadata),
49        );
50    }
51
52    fn process_response_chunk(&mut self, request_id: RequestId, payload: Vec<u8>) {
53        self.cache.notify_pending_response(
54            self.id,
55            FetchResponseMsg::ProcessResponseChunk(request_id, payload),
56        );
57    }
58
59    fn process_response_eof(
60        &mut self,
61        request_id: RequestId,
62        response: Result<ResourceFetchTiming, NetworkError>,
63    ) {
64        self.cache.notify_pending_response(
65            self.id,
66            FetchResponseMsg::ProcessResponseEOF(request_id, response),
67        );
68    }
69
70    fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
71        &mut self.resource_timing
72    }
73
74    fn resource_timing(&self) -> &ResourceFetchTiming {
75        &self.resource_timing
76    }
77
78    fn submit_resource_timing(&mut self) {
79        network_listener::submit_timing(self, CanGc::note())
80    }
81
82    fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
83        let global = &self.resource_timing_global();
84        global.report_csp_violations(violations, None, None);
85    }
86}
87
88impl ResourceTimingListener for LayoutImageContext {
89    fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
90        (InitiatorType::Other, self.url.clone())
91    }
92
93    fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
94        self.doc.root().global()
95    }
96}
97
98impl PreInvoke for LayoutImageContext {}
99
100pub(crate) fn fetch_image_for_layout(
101    url: ServoUrl,
102    node: &Node,
103    id: PendingImageId,
104    cache: Arc<dyn ImageCache>,
105) {
106    let document = node.owner_document();
107    let context = LayoutImageContext {
108        id,
109        cache,
110        resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
111        doc: Trusted::new(&document),
112        url: url.clone(),
113    };
114
115    let request = FetchRequestInit::new(
116        Some(document.webview_id()),
117        url,
118        document.global().get_referrer(),
119    )
120    .origin(document.origin().immutable().clone())
121    .destination(Destination::Image)
122    .pipeline_id(Some(document.global().pipeline_id()))
123    .insecure_requests_policy(document.insecure_requests_policy())
124    .has_trustworthy_ancestor_origin(document.has_trustworthy_ancestor_origin())
125    .policy_container(document.policy_container().to_owned());
126
127    // Layout image loads do not delay the document load event.
128    document.fetch_background(request, context);
129}