1use std::sync::Arc;
10
11use net_traits::image_cache::{ImageCache, PendingImageId};
12use net_traits::request::{Destination, RequestBuilder, RequestId};
13use net_traits::{FetchMetadata, FetchResponseMsg, NetworkError, ResourceFetchTiming};
14use servo_url::ServoUrl;
15
16use crate::dom::bindings::refcounted::Trusted;
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::csp::{GlobalCspReporting, Violation};
20use crate::dom::document::Document;
21use crate::dom::globalscope::GlobalScope;
22use crate::dom::node::{Node, NodeTraits};
23use crate::dom::performance::performanceresourcetiming::InitiatorType;
24use crate::fetch::RequestWithGlobalScope;
25use crate::network_listener::{self, FetchResponseListener, ResourceTimingListener};
26use crate::script_runtime::CanGc;
27
28struct LayoutImageContext {
29 id: PendingImageId,
30 cache: Arc<dyn ImageCache>,
31 doc: Trusted<Document>,
32 url: ServoUrl,
33}
34
35impl FetchResponseListener for LayoutImageContext {
36 fn process_request_body(&mut self, _: RequestId) {}
37 fn process_request_eof(&mut self, _: RequestId) {}
38 fn process_response(
39 &mut self,
40 request_id: RequestId,
41 metadata: Result<FetchMetadata, NetworkError>,
42 ) {
43 self.cache.notify_pending_response(
44 self.id,
45 FetchResponseMsg::ProcessResponse(request_id, metadata),
46 );
47 }
48
49 fn process_response_chunk(&mut self, request_id: RequestId, payload: Vec<u8>) {
50 self.cache.notify_pending_response(
51 self.id,
52 FetchResponseMsg::ProcessResponseChunk(request_id, payload.into()),
53 );
54 }
55
56 fn process_response_eof(
57 self,
58 cx: &mut js::context::JSContext,
59 request_id: RequestId,
60 response: Result<(), NetworkError>,
61 timing: ResourceFetchTiming,
62 ) {
63 self.cache.notify_pending_response(
64 self.id,
65 FetchResponseMsg::ProcessResponseEOF(request_id, response.clone(), timing.clone()),
66 );
67 network_listener::submit_timing(&self, &response, &timing, CanGc::from_cx(cx));
68 }
69
70 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
71 let global = &self.resource_timing_global();
72 global.report_csp_violations(violations, None, None);
73 }
74}
75
76impl ResourceTimingListener for LayoutImageContext {
77 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
78 (InitiatorType::Other, self.url.clone())
79 }
80
81 fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
82 self.doc.root().global()
83 }
84}
85
86pub(crate) fn fetch_image_for_layout(
87 url: ServoUrl,
88 node: &Node,
89 id: PendingImageId,
90 cache: Arc<dyn ImageCache>,
91) {
92 let document = node.owner_document();
93 let context = LayoutImageContext {
94 id,
95 cache,
96 doc: Trusted::new(&document),
97 url: url.clone(),
98 };
99
100 let global = node.owner_global();
101 let request = RequestBuilder::new(Some(document.webview_id()), url, global.get_referrer())
102 .destination(Destination::Image)
103 .with_global_scope(&global);
104
105 document.fetch_background(request, context);
107}