Skip to main content

script/dom/window/
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 bytes::Bytes;
12use net_traits::blob_url_store::UrlWithBlobClaim;
13use net_traits::image_cache::{ImageCache, PendingImageId};
14use net_traits::request::{Destination, InternalRequest, RequestBuilder, RequestId};
15use net_traits::{FetchMetadata, FetchResponseMsg, NetworkError, ResourceFetchTiming};
16use servo_url::ServoUrl;
17
18use crate::dom::bindings::refcounted::Trusted;
19use crate::dom::bindings::reflector::DomGlobal;
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::csp::{GlobalCspReporting, Violation};
22use crate::dom::document::Document;
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::node::{Node, NodeTraits};
25use crate::dom::performance::performanceresourcetiming::InitiatorType;
26use crate::fetch::fetch::RequestWithGlobalScope;
27use crate::fetch::network_listener::{self, FetchResponseListener, ResourceTimingListener};
28
29struct LayoutImageContext {
30    id: PendingImageId,
31    cache: Arc<dyn ImageCache>,
32    doc: Trusted<Document>,
33    url: ServoUrl,
34}
35
36impl FetchResponseListener for LayoutImageContext {
37    fn process_request_body(&mut self, _: RequestId) {}
38    fn process_response(
39        &mut self,
40        _: &mut js::context::JSContext,
41        request_id: RequestId,
42        metadata: Result<FetchMetadata, NetworkError>,
43    ) {
44        self.cache.notify_pending_response(
45            self.id,
46            FetchResponseMsg::ProcessResponse(request_id, metadata),
47        );
48    }
49
50    fn process_response_chunk(
51        &mut self,
52        _: &mut js::context::JSContext,
53        request_id: RequestId,
54        payload: Bytes,
55    ) {
56        self.cache.notify_pending_response(
57            self.id,
58            FetchResponseMsg::ProcessResponseChunk(request_id, payload),
59        );
60    }
61
62    fn process_response_eof(
63        self,
64        cx: &mut js::context::JSContext,
65        request_id: RequestId,
66        response: Result<(), NetworkError>,
67        timing: ResourceFetchTiming,
68    ) {
69        self.cache.notify_pending_response(
70            self.id,
71            FetchResponseMsg::ProcessResponseEOF(request_id, response.clone(), timing.clone()),
72        );
73        network_listener::submit_timing(cx, &self, &response, &timing);
74    }
75
76    fn process_csp_violations(
77        &mut self,
78        cx: &mut js::context::JSContext,
79        _request_id: RequestId,
80        violations: Vec<Violation>,
81    ) {
82        let global = &self.resource_timing_global();
83        global.report_csp_violations(cx, violations, None, None);
84    }
85
86    fn process_content_length(&mut self, request_id: RequestId, size: usize) {
87        self.cache.notify_pending_response(
88            self.id,
89            FetchResponseMsg::ProcessContentLength(request_id, size),
90        );
91    }
92}
93
94impl ResourceTimingListener for LayoutImageContext {
95    fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
96        (InitiatorType::Other, self.url.clone())
97    }
98
99    fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
100        self.doc.root().global()
101    }
102}
103
104pub(crate) fn fetch_image_for_layout(
105    url: ServoUrl,
106    node: &Node,
107    id: PendingImageId,
108    is_internal_request: InternalRequest,
109    cache: Arc<dyn ImageCache>,
110) {
111    let document = node.owner_document();
112    let context = LayoutImageContext {
113        id,
114        cache,
115        doc: Trusted::new(&document),
116        url: url.clone(),
117    };
118
119    let global = node.owner_global();
120    let request = RequestBuilder::new(
121        Some(document.webview_id()),
122        UrlWithBlobClaim::from_url_without_having_claimed_blob(url),
123        global.get_referrer(),
124    )
125    .destination(Destination::Image)
126    .is_internal_request(is_internal_request)
127    .with_global_scope(&global);
128
129    // Layout image loads do not delay the document load event.
130    document.fetch_background(request, context);
131}