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::event_loop::document_loader::LoadType;
27use crate::fetch::fetch::RequestWithGlobalScope;
28use crate::fetch::network_listener::{self, FetchResponseListener, ResourceTimingListener};
29
30struct LayoutImageContext {
31    id: PendingImageId,
32    cache: Arc<dyn ImageCache>,
33    doc: Trusted<Document>,
34    url: ServoUrl,
35}
36
37impl FetchResponseListener for LayoutImageContext {
38    fn process_request_body(&mut self, _: RequestId) {}
39    fn process_response(
40        &mut self,
41        _: &mut js::context::JSContext,
42        request_id: RequestId,
43        metadata: Result<FetchMetadata, NetworkError>,
44    ) {
45        self.cache.notify_pending_response(
46            self.id,
47            FetchResponseMsg::ProcessResponse(request_id, metadata),
48        );
49    }
50
51    fn process_response_chunk(
52        &mut self,
53        _: &mut js::context::JSContext,
54        request_id: RequestId,
55        payload: Bytes,
56    ) {
57        self.cache.notify_pending_response(
58            self.id,
59            FetchResponseMsg::ProcessResponseChunk(request_id, payload),
60        );
61    }
62
63    fn process_response_eof(
64        self,
65        cx: &mut js::context::JSContext,
66        request_id: RequestId,
67        response: Result<(), NetworkError>,
68        timing: ResourceFetchTiming,
69    ) {
70        self.cache.notify_pending_response(
71            self.id,
72            FetchResponseMsg::ProcessResponseEOF(request_id, response.clone(), timing.clone()),
73        );
74        network_listener::submit_timing(cx, &self, &response, &timing);
75        self.doc.root().finish_load(LoadType::Image(self.url), cx);
76    }
77
78    fn process_csp_violations(
79        &mut self,
80        cx: &mut js::context::JSContext,
81        _request_id: RequestId,
82        violations: Vec<Violation>,
83    ) {
84        let global = &self.resource_timing_global();
85        global.report_csp_violations(cx, violations, None, None);
86    }
87
88    fn process_content_length(&mut self, request_id: RequestId, size: usize) {
89        self.cache.notify_pending_response(
90            self.id,
91            FetchResponseMsg::ProcessContentLength(request_id, size),
92        );
93    }
94}
95
96impl ResourceTimingListener for LayoutImageContext {
97    fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
98        (InitiatorType::Css, self.url.clone())
99    }
100
101    fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
102        self.doc.root().global()
103    }
104}
105
106pub(crate) fn fetch_image_for_layout(
107    url: ServoUrl,
108    node: &Node,
109    id: PendingImageId,
110    is_internal_request: InternalRequest,
111    cache: Arc<dyn ImageCache>,
112) {
113    let document = node.owner_document();
114    let context = LayoutImageContext {
115        id,
116        cache,
117        doc: Trusted::new(&document),
118        url: url.clone(),
119    };
120
121    let global = node.owner_global();
122    let request = RequestBuilder::new(
123        Some(document.webview_id()),
124        UrlWithBlobClaim::from_url_without_having_claimed_blob(url.clone()),
125        global.get_referrer(),
126    )
127    .destination(Destination::Image)
128    .is_internal_request(is_internal_request)
129    .with_global_scope(&global);
130
131    // Even though https://github.com/w3c/csswg-drafts/issues/1088 has not been resolved,
132    // if we don't make this blocking we experience a lot of flakiness in WPT tests. These
133    // tests generally assume that `background-image` loads block the document load event.
134    // Hence we match other browsers behavior and make all of such fetches blocking.
135    document.fetch_blocking(LoadType::Image(url), request, context);
136}