1use std::cell::Cell;
6use std::collections::HashSet;
7use std::default::Default;
8use std::rc::Rc;
9use std::sync::Arc;
10use std::{char, mem};
11
12use app_units::{AU_PER_PX, Au};
13use cssparser::{Parser, ParserInput};
14use dom_struct::dom_struct;
15use euclid::default::{Point2D, Size2D};
16use html5ever::{LocalName, Prefix, QualName, local_name, ns};
17use js::jsapi::JSAutoRealm;
18use js::rust::HandleObject;
19use mime::{self, Mime};
20use net_traits::http_status::HttpStatus;
21use net_traits::image_cache::{
22 Image, ImageCache, ImageCacheResult, ImageLoadListener, ImageOrMetadataAvailable,
23 ImageResponse, PendingImageId, UsePlaceholder,
24};
25use net_traits::request::{Destination, Initiator, RequestId};
26use net_traits::{
27 FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError, ReferrerPolicy,
28 ResourceFetchTiming, ResourceTimingType,
29};
30use num_traits::ToPrimitive;
31use pixels::{
32 CorsStatus, ImageMetadata, PixelFormat, Snapshot, SnapshotAlphaMode, SnapshotPixelFormat,
33};
34use servo_url::ServoUrl;
35use servo_url::origin::MutableOrigin;
36use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_integer, parse_length};
37use style::context::QuirksMode;
38use style::parser::ParserContext;
39use style::stylesheets::{CssRuleType, Origin};
40use style::values::specified::AbsoluteLength;
41use style::values::specified::length::{Length, NoCalcLength};
42use style::values::specified::source_size_list::SourceSizeList;
43use style_traits::ParsingMode;
44use url::Url;
45
46use crate::document_loader::{LoadBlocker, LoadType};
47use crate::dom::activation::Activatable;
48use crate::dom::attr::Attr;
49use crate::dom::bindings::cell::{DomRefCell, RefMut};
50use crate::dom::bindings::codegen::Bindings::DOMRectBinding::DOMRect_Binding::DOMRectMethods;
51use crate::dom::bindings::codegen::Bindings::ElementBinding::Element_Binding::ElementMethods;
52use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
53use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
54use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
55use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
56use crate::dom::bindings::error::{Error, Fallible};
57use crate::dom::bindings::inheritance::Castable;
58use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
59use crate::dom::bindings::reflector::DomGlobal;
60use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
61use crate::dom::bindings::str::{DOMString, USVString};
62use crate::dom::csp::{GlobalCspReporting, Violation};
63use crate::dom::document::{Document, determine_policy_for_token};
64use crate::dom::element::{
65 AttributeMutation, CustomElementCreationMode, Element, ElementCreator, LayoutElementHelpers,
66 cors_setting_for_element, referrer_policy_for_element, reflect_cross_origin_attribute,
67 reflect_referrer_policy_attribute, set_cross_origin_attribute,
68};
69use crate::dom::event::Event;
70use crate::dom::eventtarget::EventTarget;
71use crate::dom::globalscope::GlobalScope;
72use crate::dom::html::htmlareaelement::HTMLAreaElement;
73use crate::dom::html::htmlelement::HTMLElement;
74use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
75use crate::dom::html::htmlmapelement::HTMLMapElement;
76use crate::dom::html::htmlpictureelement::HTMLPictureElement;
77use crate::dom::html::htmlsourceelement::HTMLSourceElement;
78use crate::dom::mouseevent::MouseEvent;
79use crate::dom::node::{BindContext, Node, NodeDamage, NodeTraits, ShadowIncluding, UnbindContext};
80use crate::dom::performanceresourcetiming::InitiatorType;
81use crate::dom::promise::Promise;
82use crate::dom::values::UNSIGNED_LONG_MAX;
83use crate::dom::virtualmethods::VirtualMethods;
84use crate::dom::window::Window;
85use crate::fetch::create_a_potential_cors_request;
86use crate::microtask::{Microtask, MicrotaskRunnable};
87use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
88use crate::realms::enter_realm;
89use crate::script_runtime::CanGc;
90use crate::script_thread::ScriptThread;
91
92#[derive(Clone, Copy, Debug)]
93enum ParseState {
94 InDescriptor,
95 InParens,
96 AfterDescriptor,
97}
98
99#[derive(MallocSizeOf)]
100pub(crate) struct SourceSet {
101 image_sources: Vec<ImageSource>,
102 source_size: SourceSizeList,
103}
104
105impl SourceSet {
106 fn new() -> SourceSet {
107 SourceSet {
108 image_sources: Vec::new(),
109 source_size: SourceSizeList::empty(),
110 }
111 }
112}
113
114#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
115pub struct ImageSource {
116 pub url: String,
117 pub descriptor: Descriptor,
118}
119
120#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
121pub struct Descriptor {
122 pub width: Option<u32>,
123 pub density: Option<f64>,
124}
125
126#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
127#[allow(dead_code)]
128enum State {
129 Unavailable,
130 PartiallyAvailable,
131 CompletelyAvailable,
132 Broken,
133}
134
135#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
136enum ImageRequestPhase {
137 Pending,
138 Current,
139}
140#[derive(JSTraceable, MallocSizeOf)]
141#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
142struct ImageRequest {
143 state: State,
144 #[no_trace]
145 parsed_url: Option<ServoUrl>,
146 source_url: Option<USVString>,
147 blocker: DomRefCell<Option<LoadBlocker>>,
148 #[no_trace]
149 image: Option<Image>,
150 #[no_trace]
151 metadata: Option<ImageMetadata>,
152 #[no_trace]
153 final_url: Option<ServoUrl>,
154 current_pixel_density: Option<f64>,
155}
156#[dom_struct]
157pub(crate) struct HTMLImageElement {
158 htmlelement: HTMLElement,
159 image_request: Cell<ImageRequestPhase>,
160 current_request: DomRefCell<ImageRequest>,
161 pending_request: DomRefCell<ImageRequest>,
162 form_owner: MutNullableDom<HTMLFormElement>,
163 generation: Cell<u32>,
164 source_set: DomRefCell<SourceSet>,
165 dimension_attribute_source: MutNullableDom<Element>,
168 last_selected_source: DomRefCell<Option<USVString>>,
169 #[ignore_malloc_size_of = "promises are hard"]
170 image_decode_promises: DomRefCell<Vec<Rc<Promise>>>,
171 line_number: u64,
173}
174
175impl HTMLImageElement {
176 pub(crate) fn is_usable(&self) -> Fallible<bool> {
178 if let Some(image) = &self.current_request.borrow().image {
180 let intrinsic_size = image.metadata();
181 if intrinsic_size.width == 0 || intrinsic_size.height == 0 {
182 return Ok(false);
183 }
184 }
185
186 match self.current_request.borrow().state {
187 State::Broken => Err(Error::InvalidState),
189 State::CompletelyAvailable => Ok(true),
190 State::PartiallyAvailable | State::Unavailable => Ok(false),
192 }
193 }
194
195 pub(crate) fn image_data(&self) -> Option<Image> {
196 self.current_request.borrow().image.clone()
197 }
198
199 pub(crate) fn get_raster_image_data(&self) -> Option<Snapshot> {
201 let Some(img) = self.image_data()?.as_raster_image() else {
202 warn!("Vector image is not supported as raster image source");
203 return None;
204 };
205
206 let size = Size2D::new(img.metadata.width, img.metadata.height);
207 let format = match img.format {
208 PixelFormat::BGRA8 => SnapshotPixelFormat::BGRA,
209 PixelFormat::RGBA8 => SnapshotPixelFormat::RGBA,
210 pixel_format => {
211 unimplemented!("unsupported pixel format ({:?})", pixel_format)
212 },
213 };
214
215 let alpha_mode = SnapshotAlphaMode::Transparent {
216 premultiplied: false,
217 };
218
219 let snapshot = Snapshot::from_vec(
220 size.cast(),
221 format,
222 alpha_mode,
223 img.first_frame().bytes.to_vec(),
224 );
225
226 Some(snapshot)
227 }
228}
229
230struct ImageContext {
232 image_cache: Arc<dyn ImageCache>,
234 status: Result<(), NetworkError>,
236 id: PendingImageId,
238 aborted: bool,
240 doc: Trusted<Document>,
242 resource_timing: ResourceFetchTiming,
244 url: ServoUrl,
245 element: Trusted<HTMLImageElement>,
246}
247
248impl FetchResponseListener for ImageContext {
249 fn process_request_body(&mut self, _: RequestId) {}
250 fn process_request_eof(&mut self, _: RequestId) {}
251
252 fn process_response(
253 &mut self,
254 request_id: RequestId,
255 metadata: Result<FetchMetadata, NetworkError>,
256 ) {
257 debug!("got {:?} for {:?}", metadata.as_ref().map(|_| ()), self.url);
258 self.image_cache.notify_pending_response(
259 self.id,
260 FetchResponseMsg::ProcessResponse(request_id, metadata.clone()),
261 );
262
263 let metadata = metadata.ok().map(|meta| match meta {
264 FetchMetadata::Unfiltered(m) => m,
265 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
266 });
267
268 if let Some(metadata) = metadata.as_ref() {
270 if let Some(ref content_type) = metadata.content_type {
271 let mime: Mime = content_type.clone().into_inner().into();
272 if mime.type_() == mime::MULTIPART && mime.subtype().as_str() == "x-mixed-replace" {
273 self.aborted = true;
274 }
275 }
276 }
277
278 let status = metadata
279 .as_ref()
280 .map(|m| m.status.clone())
281 .unwrap_or_else(HttpStatus::new_error);
282
283 self.status = {
284 if status.is_error() {
285 Err(NetworkError::Internal(
286 "No http status code received".to_owned(),
287 ))
288 } else if status.is_success() {
289 Ok(())
290 } else {
291 Err(NetworkError::Internal(format!(
292 "HTTP error code {}",
293 status.code()
294 )))
295 }
296 };
297 }
298
299 fn process_response_chunk(&mut self, request_id: RequestId, payload: Vec<u8>) {
300 if self.status.is_ok() {
301 self.image_cache.notify_pending_response(
302 self.id,
303 FetchResponseMsg::ProcessResponseChunk(request_id, payload),
304 );
305 }
306 }
307
308 fn process_response_eof(
309 &mut self,
310 request_id: RequestId,
311 response: Result<ResourceFetchTiming, NetworkError>,
312 ) {
313 self.image_cache.notify_pending_response(
314 self.id,
315 FetchResponseMsg::ProcessResponseEOF(request_id, response),
316 );
317 }
318
319 fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
320 &mut self.resource_timing
321 }
322
323 fn resource_timing(&self) -> &ResourceFetchTiming {
324 &self.resource_timing
325 }
326
327 fn submit_resource_timing(&mut self) {
328 network_listener::submit_timing(self, CanGc::note())
329 }
330
331 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
332 let global = &self.resource_timing_global();
333 let elem = self.element.root();
334 let source_position = elem
335 .upcast::<Element>()
336 .compute_source_position(elem.line_number as u32);
337 global.report_csp_violations(violations, None, Some(source_position));
338 }
339}
340
341impl ResourceTimingListener for ImageContext {
342 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
343 (
344 InitiatorType::LocalName("img".to_string()),
345 self.url.clone(),
346 )
347 }
348
349 fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
350 self.doc.root().global()
351 }
352}
353
354impl PreInvoke for ImageContext {
355 fn should_invoke(&self) -> bool {
356 !self.aborted
357 }
358}
359
360#[allow(non_snake_case)]
361impl HTMLImageElement {
362 fn fetch_image(&self, img_url: &ServoUrl, can_gc: CanGc) {
364 let window = self.owner_window();
365
366 let cache_result = window.image_cache().get_cached_image_status(
367 img_url.clone(),
368 window.origin().immutable().clone(),
369 cors_setting_for_element(self.upcast()),
370 UsePlaceholder::Yes,
371 );
372
373 match cache_result {
374 ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
375 image,
376 url,
377 is_placeholder,
378 }) => {
379 if is_placeholder {
380 if let Some(raster_image) = image.as_raster_image() {
381 self.process_image_response(
382 ImageResponse::PlaceholderLoaded(raster_image, url),
383 can_gc,
384 )
385 }
386 } else {
387 self.process_image_response(ImageResponse::Loaded(image, url), can_gc)
388 }
389 },
390 ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(
391 metadata,
392 id,
393 )) => {
394 self.process_image_response(ImageResponse::MetadataLoaded(metadata), can_gc);
395 self.register_image_cache_callback(id, ChangeType::Element);
396 },
397 ImageCacheResult::Pending(id) => {
398 self.register_image_cache_callback(id, ChangeType::Element);
399 },
400 ImageCacheResult::ReadyForRequest(id) => {
401 self.fetch_request(img_url, id);
402 self.register_image_cache_callback(id, ChangeType::Element);
403 },
404 ImageCacheResult::LoadError => self.process_image_response(ImageResponse::None, can_gc),
405 };
406 }
407
408 fn register_image_cache_callback(&self, id: PendingImageId, change_type: ChangeType) {
409 let trusted_node = Trusted::new(self);
410 let generation = self.generation_id();
411 let window = self.owner_window();
412 let sender = window.register_image_cache_listener(id, move |response| {
413 let trusted_node = trusted_node.clone();
414 let window = trusted_node.root().owner_window();
415 let callback_type = change_type.clone();
416
417 window
418 .as_global_scope()
419 .task_manager()
420 .networking_task_source()
421 .queue(task!(process_image_response: move || {
422 let element = trusted_node.root();
423
424 if generation != element.generation_id() {
426 return;
427 }
428
429 match callback_type {
430 ChangeType::Element => {
431 element.process_image_response(response.response, CanGc::note());
432 }
433 ChangeType::Environment { selected_source, selected_pixel_density } => {
434 element.process_image_response_for_environment_change(
435 response.response, selected_source, generation, selected_pixel_density, CanGc::note()
436 );
437 }
438 }
439 }));
440 });
441
442 window
443 .image_cache()
444 .add_listener(ImageLoadListener::new(sender, window.pipeline_id(), id));
445 }
446
447 fn fetch_request(&self, img_url: &ServoUrl, id: PendingImageId) {
448 let document = self.owner_document();
449 let window = self.owner_window();
450
451 let context = ImageContext {
452 image_cache: window.image_cache(),
453 status: Ok(()),
454 id,
455 aborted: false,
456 doc: Trusted::new(&document),
457 element: Trusted::new(self),
458 resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
459 url: img_url.clone(),
460 };
461
462 let global = document.global();
465 let mut request = create_a_potential_cors_request(
466 Some(window.webview_id()),
467 img_url.clone(),
468 Destination::Image,
469 cors_setting_for_element(self.upcast()),
470 None,
471 global.get_referrer(),
472 document.insecure_requests_policy(),
473 document.has_trustworthy_ancestor_or_current_origin(),
474 global.policy_container(),
475 )
476 .origin(document.origin().immutable().clone())
477 .pipeline_id(Some(document.global().pipeline_id()))
478 .referrer_policy(referrer_policy_for_element(self.upcast()));
479
480 if Self::uses_srcset_or_picture(self.upcast()) {
481 request = request.initiator(Initiator::ImageSet);
482 }
483
484 document.fetch_background(request, context);
487 }
488
489 fn handle_loaded_image(&self, image: Image, url: ServoUrl, can_gc: CanGc) {
491 self.current_request.borrow_mut().metadata = Some(image.metadata());
492 self.current_request.borrow_mut().final_url = Some(url);
493 self.current_request.borrow_mut().image = Some(image);
494 self.current_request.borrow_mut().state = State::CompletelyAvailable;
495 LoadBlocker::terminate(&self.current_request.borrow().blocker, can_gc);
496 self.upcast::<Node>().dirty(NodeDamage::Other);
498 self.resolve_image_decode_promises();
499 }
500
501 fn process_image_response(&self, image: ImageResponse, can_gc: CanGc) {
503 let (trigger_image_load, trigger_image_error) = match (image, self.image_request.get()) {
505 (ImageResponse::Loaded(image, url), ImageRequestPhase::Current) => {
506 self.handle_loaded_image(image, url, can_gc);
507 (true, false)
508 },
509 (ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Current) => {
510 self.handle_loaded_image(Image::Raster(image), url, can_gc);
511 (false, true)
512 },
513 (ImageResponse::Loaded(image, url), ImageRequestPhase::Pending) => {
514 self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc);
515 self.image_request.set(ImageRequestPhase::Current);
516 self.handle_loaded_image(image, url, can_gc);
517 (true, false)
518 },
519 (ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Pending) => {
520 self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc);
521 self.image_request.set(ImageRequestPhase::Current);
522 self.handle_loaded_image(Image::Raster(image), url, can_gc);
523 (false, true)
524 },
525 (ImageResponse::MetadataLoaded(meta), ImageRequestPhase::Current) => {
526 self.current_request.borrow_mut().state = State::PartiallyAvailable;
527 self.current_request.borrow_mut().metadata = Some(meta);
528 (false, false)
529 },
530 (ImageResponse::MetadataLoaded(_), ImageRequestPhase::Pending) => {
531 self.pending_request.borrow_mut().state = State::PartiallyAvailable;
532 (false, false)
533 },
534 (ImageResponse::None, ImageRequestPhase::Current) => {
535 self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
536 (false, true)
537 },
538 (ImageResponse::None, ImageRequestPhase::Pending) => {
539 self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
540 self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc);
541 self.image_request.set(ImageRequestPhase::Current);
542 (false, true)
543 },
544 };
545
546 if trigger_image_load {
548 self.upcast::<EventTarget>()
550 .fire_event(atom!("load"), can_gc);
551 self.upcast::<EventTarget>()
552 .fire_event(atom!("loadend"), can_gc);
553 }
554
555 if trigger_image_error {
557 self.upcast::<EventTarget>()
558 .fire_event(atom!("error"), can_gc);
559 self.upcast::<EventTarget>()
560 .fire_event(atom!("loadend"), can_gc);
561 }
562 }
563
564 fn process_image_response_for_environment_change(
565 &self,
566 image: ImageResponse,
567 src: USVString,
568 generation: u32,
569 selected_pixel_density: f64,
570 can_gc: CanGc,
571 ) {
572 match image {
573 ImageResponse::Loaded(image, url) => {
574 self.pending_request.borrow_mut().metadata = Some(image.metadata());
575 self.pending_request.borrow_mut().final_url = Some(url);
576 self.pending_request.borrow_mut().image = Some(image);
577 self.finish_reacting_to_environment_change(src, generation, selected_pixel_density);
578 },
579 ImageResponse::PlaceholderLoaded(image, url) => {
580 let image = Image::Raster(image);
581 self.pending_request.borrow_mut().metadata = Some(image.metadata());
582 self.pending_request.borrow_mut().final_url = Some(url);
583 self.pending_request.borrow_mut().image = Some(image);
584 self.finish_reacting_to_environment_change(src, generation, selected_pixel_density);
585 },
586 ImageResponse::MetadataLoaded(meta) => {
587 self.pending_request.borrow_mut().metadata = Some(meta);
588 },
589 ImageResponse::None => {
590 self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc);
591 },
592 };
593 }
594
595 fn abort_request(&self, state: State, request: ImageRequestPhase, can_gc: CanGc) {
597 let mut request = match request {
598 ImageRequestPhase::Current => self.current_request.borrow_mut(),
599 ImageRequestPhase::Pending => self.pending_request.borrow_mut(),
600 };
601 LoadBlocker::terminate(&request.blocker, can_gc);
602 request.state = state;
603 request.image = None;
604 request.metadata = None;
605
606 if matches!(state, State::Broken) {
607 self.reject_image_decode_promises();
608 } else if matches!(state, State::CompletelyAvailable) {
609 self.resolve_image_decode_promises();
610 }
611 }
612
613 fn update_source_set(&self) {
615 *self.source_set.borrow_mut() = SourceSet::new();
617
618 let elem = self.upcast::<Element>();
620 let parent = elem.upcast::<Node>().GetParentElement();
621 let nodes;
622 let elements = match parent.as_ref() {
623 Some(p) => {
624 if p.is::<HTMLPictureElement>() {
625 nodes = p.upcast::<Node>().children();
626 nodes
627 .filter_map(DomRoot::downcast::<Element>)
628 .map(|n| DomRoot::from_ref(&*n))
629 .collect()
630 } else {
631 vec![DomRoot::from_ref(elem)]
632 }
633 },
634 None => vec![DomRoot::from_ref(elem)],
635 };
636
637 let width = match elem.get_attribute(&ns!(), &local_name!("width")) {
639 Some(x) => match parse_length(&x.value()) {
640 LengthOrPercentageOrAuto::Length(x) => {
641 let abs_length = AbsoluteLength::Px(x.to_f32_px());
642 Some(Length::NoCalc(NoCalcLength::Absolute(abs_length)))
643 },
644 _ => None,
645 },
646 None => None,
647 };
648
649 for element in &elements {
651 if *element == DomRoot::from_ref(elem) {
653 let mut source_set = SourceSet::new();
654 if let Some(x) = element.get_attribute(&ns!(), &local_name!("srcset")) {
656 source_set.image_sources = parse_a_srcset_attribute(&x.value());
657 }
658
659 if let Some(x) = element.get_attribute(&ns!(), &local_name!("sizes")) {
661 source_set.source_size =
662 parse_a_sizes_attribute(DOMString::from_string(x.value().to_string()));
663 }
664
665 let src_attribute = element.get_string_attribute(&local_name!("src"));
667 let is_src_empty = src_attribute.is_empty();
668 let no_density_source_of_1 = source_set
669 .image_sources
670 .iter()
671 .all(|source| source.descriptor.density != Some(1.));
672 let no_width_descriptor = source_set
673 .image_sources
674 .iter()
675 .all(|source| source.descriptor.width.is_none());
676 if !is_src_empty && no_density_source_of_1 && no_width_descriptor {
677 source_set.image_sources.push(ImageSource {
678 url: src_attribute.to_string(),
679 descriptor: Descriptor {
680 width: None,
681 density: None,
682 },
683 })
684 }
685
686 self.normalise_source_densities(&mut source_set, width);
688
689 *self.source_set.borrow_mut() = source_set;
691
692 return;
694 }
695 if !element.is::<HTMLSourceElement>() {
697 continue;
698 }
699
700 let mut source_set = SourceSet::new();
702 match element.get_attribute(&ns!(), &local_name!("srcset")) {
703 Some(x) => {
704 source_set.image_sources = parse_a_srcset_attribute(&x.value());
705 },
706 _ => continue,
707 }
708
709 if source_set.image_sources.is_empty() {
711 continue;
712 }
713
714 if let Some(x) = element.get_attribute(&ns!(), &local_name!("media")) {
716 if !elem.matches_environment(&x.value()) {
717 continue;
718 }
719 }
720
721 if let Some(x) = element.get_attribute(&ns!(), &local_name!("sizes")) {
723 source_set.source_size =
724 parse_a_sizes_attribute(DOMString::from_string(x.value().to_string()));
725 }
726
727 if let Some(x) = element.get_attribute(&ns!(), &local_name!("type")) {
729 let mime = x.value().parse::<Mime>();
731 match mime {
732 Ok(m) => match m.type_() {
733 mime::IMAGE => (),
734 _ => continue,
735 },
736 _ => continue,
737 }
738 }
739
740 if element
742 .get_attribute(&ns!(), &local_name!("width"))
743 .is_some() ||
744 element
745 .get_attribute(&ns!(), &local_name!("height"))
746 .is_some()
747 {
748 self.dimension_attribute_source.set(Some(element));
749 }
750
751 self.normalise_source_densities(&mut source_set, width);
753
754 *self.source_set.borrow_mut() = source_set;
756 return;
757 }
758 }
759
760 fn evaluate_source_size_list(
761 &self,
762 source_size_list: &mut SourceSizeList,
763 _width: Option<Length>,
764 ) -> Au {
765 let document = self.owner_document();
766 let quirks_mode = document.quirks_mode();
767 source_size_list.evaluate(document.window().layout().device(), quirks_mode)
768 }
769
770 fn normalise_source_densities(&self, source_set: &mut SourceSet, width: Option<Length>) {
772 let source_size = &mut source_set.source_size;
774
775 let source_size_length = self.evaluate_source_size_list(source_size, width);
777
778 for imgsource in &mut source_set.image_sources {
780 if imgsource.descriptor.density.is_some() {
782 continue;
783 }
784 if imgsource.descriptor.width.is_some() {
786 let wid = imgsource.descriptor.width.unwrap();
787 imgsource.descriptor.density = Some(wid as f64 / source_size_length.to_f64_px());
788 } else {
789 imgsource.descriptor.density = Some(1_f64);
791 }
792 }
793 }
794
795 fn select_image_source(&self) -> Option<(USVString, f64)> {
797 self.update_source_set();
799 let source_set = &*self.source_set.borrow_mut();
800 let len = source_set.image_sources.len();
801
802 if len == 0 {
804 return None;
805 }
806
807 let mut repeat_indices = HashSet::new();
809 for outer_index in 0..len {
810 if repeat_indices.contains(&outer_index) {
811 continue;
812 }
813 let imgsource = &source_set.image_sources[outer_index];
814 let pixel_density = imgsource.descriptor.density.unwrap();
815 for inner_index in (outer_index + 1)..len {
816 let imgsource2 = &source_set.image_sources[inner_index];
817 if pixel_density == imgsource2.descriptor.density.unwrap() {
818 repeat_indices.insert(inner_index);
819 }
820 }
821 }
822
823 let mut max = (0f64, 0);
824 let img_sources = &mut vec![];
825 for (index, image_source) in source_set.image_sources.iter().enumerate() {
826 if repeat_indices.contains(&index) {
827 continue;
828 }
829 let den = image_source.descriptor.density.unwrap();
830 if max.0 < den {
831 max = (den, img_sources.len());
832 }
833 img_sources.push(image_source);
834 }
835
836 let mut best_candidate = max;
838 let device_pixel_ratio = self
839 .owner_document()
840 .window()
841 .viewport_details()
842 .hidpi_scale_factor
843 .get() as f64;
844 for (index, image_source) in img_sources.iter().enumerate() {
845 let current_den = image_source.descriptor.density.unwrap();
846 if current_den < best_candidate.0 && current_den >= device_pixel_ratio {
847 best_candidate = (current_den, index);
848 }
849 }
850 let selected_source = img_sources.remove(best_candidate.1).clone();
851 Some((
852 USVString(selected_source.url),
853 selected_source.descriptor.density.unwrap(),
854 ))
855 }
856
857 fn init_image_request(
858 &self,
859 request: &mut RefMut<'_, ImageRequest>,
860 url: &ServoUrl,
861 src: &USVString,
862 can_gc: CanGc,
863 ) {
864 request.parsed_url = Some(url.clone());
865 request.source_url = Some(src.clone());
866 request.image = None;
867 request.metadata = None;
868 let document = self.owner_document();
869 LoadBlocker::terminate(&request.blocker, can_gc);
870 *request.blocker.borrow_mut() =
871 Some(LoadBlocker::new(&document, LoadType::Image(url.clone())));
872 }
873
874 fn prepare_image_request(
876 &self,
877 url: &ServoUrl,
878 src: &USVString,
879 selected_pixel_density: f64,
880 can_gc: CanGc,
881 ) {
882 match self.image_request.get() {
883 ImageRequestPhase::Pending => {
884 if let Some(pending_url) = self.pending_request.borrow().parsed_url.clone() {
885 if pending_url == *url {
887 return;
888 }
889 }
890 },
891 ImageRequestPhase::Current => {
892 let mut current_request = self.current_request.borrow_mut();
893 let mut pending_request = self.pending_request.borrow_mut();
894 match (current_request.parsed_url.clone(), current_request.state) {
896 (Some(parsed_url), State::PartiallyAvailable) => {
897 if parsed_url == *url {
899 pending_request.image = None;
901 pending_request.parsed_url = None;
902 LoadBlocker::terminate(&pending_request.blocker, can_gc);
903 return;
905 }
906 pending_request.current_pixel_density = Some(selected_pixel_density);
907 self.image_request.set(ImageRequestPhase::Pending);
908 self.init_image_request(&mut pending_request, url, src, can_gc);
909 },
910 (_, State::Broken) | (_, State::Unavailable) => {
911 current_request.current_pixel_density = Some(selected_pixel_density);
913 self.init_image_request(&mut current_request, url, src, can_gc);
914 self.reject_image_decode_promises();
915 },
916 (_, _) => {
917 pending_request.current_pixel_density = Some(selected_pixel_density);
919 self.image_request.set(ImageRequestPhase::Pending);
920 self.init_image_request(&mut pending_request, url, src, can_gc);
921 },
922 }
923 },
924 }
925 self.fetch_image(url, can_gc);
926 }
927
928 fn update_the_image_data_sync_steps(&self, can_gc: CanGc) {
930 let document = self.owner_document();
931 let global = self.owner_global();
932 let task_manager = global.task_manager();
933 let task_source = task_manager.dom_manipulation_task_source();
934 let this = Trusted::new(self);
935 let (src, pixel_density) = match self.select_image_source() {
936 Some(data) => data,
938 None => {
939 self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
940 self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc);
941 task_source.queue(task!(image_null_source_error: move || {
943 let this = this.root();
944 {
945 let mut current_request =
946 this.current_request.borrow_mut();
947 current_request.source_url = None;
948 current_request.parsed_url = None;
949 }
950 let elem = this.upcast::<Element>();
951 let src_present = elem.has_attribute(&local_name!("src"));
952
953 if src_present || Self::uses_srcset_or_picture(elem) {
954 this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
955 }
956 }));
957 return;
958 },
959 };
960
961 let base_url = document.base_url();
963 let parsed_url = base_url.join(&src.0);
964 match parsed_url {
965 Ok(url) => {
966 self.prepare_image_request(&url, &src, pixel_density, can_gc);
968 },
969 Err(_) => {
970 self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
971 self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc);
972 let src = src.0;
974 task_source.queue(task!(image_selected_source_error: move || {
975 let this = this.root();
976 {
977 let mut current_request =
978 this.current_request.borrow_mut();
979 current_request.source_url = Some(USVString(src))
980 }
981 this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
982
983 }));
984 },
985 }
986 }
987
988 pub(crate) fn update_the_image_data(&self, can_gc: CanGc) {
990 let document = self.owner_document();
991 let window = document.window();
992 let elem = self.upcast::<Element>();
993 let src = elem.get_url_attribute(&local_name!("src"));
994 let base_url = document.base_url();
995
996 {
1000 let mut current_request = self.current_request.borrow_mut();
1001 current_request.state = State::Unavailable;
1002 }
1003
1004 if !document.is_active() {
1005 }
1009 let mut selected_source = None;
1014 let mut pixel_density = None;
1015 let src_set = elem.get_url_attribute(&local_name!("srcset"));
1016 let is_parent_picture = elem
1017 .upcast::<Node>()
1018 .GetParentElement()
1019 .is_some_and(|p| p.is::<HTMLPictureElement>());
1020 if src_set.is_empty() && !is_parent_picture && !src.is_empty() {
1021 selected_source = Some(src.clone());
1022 pixel_density = Some(1_f64);
1023 };
1024
1025 self.last_selected_source
1027 .borrow_mut()
1028 .clone_from(&selected_source);
1029
1030 if let Some(src) = selected_source {
1032 if let Ok(img_url) = base_url.join(&src) {
1033 let image_cache = window.image_cache();
1034 let response = image_cache.get_image(
1035 img_url.clone(),
1036 window.origin().immutable().clone(),
1037 cors_setting_for_element(self.upcast()),
1038 );
1039
1040 if let Some(image) = response {
1041 self.generation.set(self.generation.get() + 1);
1044 let metadata = image.metadata();
1046 self.abort_request(
1048 State::CompletelyAvailable,
1049 ImageRequestPhase::Current,
1050 can_gc,
1051 );
1052 self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc);
1053 let mut current_request = self.current_request.borrow_mut();
1054 current_request.final_url = Some(img_url.clone());
1055 current_request.image = Some(image);
1056 current_request.metadata = Some(metadata);
1057 current_request.current_pixel_density = pixel_density;
1059 let this = Trusted::new(self);
1060 let src = src.0;
1061
1062 self.owner_global()
1063 .task_manager()
1064 .dom_manipulation_task_source()
1065 .queue(task!(image_load_event: move || {
1066 let this = this.root();
1067 {
1068 let mut current_request =
1069 this.current_request.borrow_mut();
1070 current_request.parsed_url = Some(img_url);
1071 current_request.source_url = Some(USVString(src));
1072 }
1073 this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note());
1075 }));
1076 return;
1077 }
1078 }
1079 }
1080 self.generation.set(self.generation.get() + 1);
1082 let task = ImageElementMicrotask::StableStateUpdateImageData {
1083 elem: DomRoot::from_ref(self),
1084 generation: self.generation.get(),
1085 };
1086 ScriptThread::await_stable_state(Microtask::ImageElement(task));
1087 }
1088
1089 pub(crate) fn react_to_environment_changes(&self) {
1091 let task = ImageElementMicrotask::EnvironmentChanges {
1093 elem: DomRoot::from_ref(self),
1094 generation: self.generation.get(),
1095 };
1096 ScriptThread::await_stable_state(Microtask::ImageElement(task));
1097 }
1098
1099 fn react_to_environment_changes_sync_steps(&self, generation: u32, can_gc: CanGc) {
1101 let elem = self.upcast::<Element>();
1102 let document = elem.owner_document();
1103 let has_pending_request = matches!(self.image_request.get(), ImageRequestPhase::Pending);
1104
1105 if !document.is_active() || !Self::uses_srcset_or_picture(elem) || has_pending_request {
1107 return;
1108 }
1109
1110 let (selected_source, selected_pixel_density) = match self.select_image_source() {
1112 Some(selected) => selected,
1113 None => return,
1114 };
1115
1116 let same_source = match *self.last_selected_source.borrow() {
1118 Some(ref last_src) => *last_src == selected_source,
1119 _ => false,
1120 };
1121
1122 let same_selected_pixel_density = match self.current_request.borrow().current_pixel_density
1123 {
1124 Some(den) => selected_pixel_density == den,
1125 _ => false,
1126 };
1127
1128 if same_source && same_selected_pixel_density {
1129 return;
1130 }
1131
1132 let base_url = document.base_url();
1133 let img_url = match base_url.join(&selected_source.0) {
1135 Ok(url) => url,
1136 Err(_) => return,
1137 };
1138
1139 self.image_request.set(ImageRequestPhase::Pending);
1141 self.init_image_request(
1142 &mut self.pending_request.borrow_mut(),
1143 &img_url,
1144 &selected_source,
1145 can_gc,
1146 );
1147
1148 let window = self.owner_window();
1150 let cache_result = window.image_cache().get_cached_image_status(
1151 img_url.clone(),
1152 window.origin().immutable().clone(),
1153 cors_setting_for_element(self.upcast()),
1154 UsePlaceholder::No,
1155 );
1156
1157 let change_type = ChangeType::Environment {
1158 selected_source: selected_source.clone(),
1159 selected_pixel_density,
1160 };
1161
1162 match cache_result {
1163 ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable { .. }) => {
1164 self.finish_reacting_to_environment_change(
1166 selected_source,
1167 generation,
1168 selected_pixel_density,
1169 )
1170 },
1171 ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m, id)) => {
1172 self.process_image_response_for_environment_change(
1173 ImageResponse::MetadataLoaded(m),
1174 selected_source,
1175 generation,
1176 selected_pixel_density,
1177 can_gc,
1178 );
1179 self.register_image_cache_callback(id, change_type);
1180 },
1181 ImageCacheResult::LoadError => {
1182 self.process_image_response_for_environment_change(
1183 ImageResponse::None,
1184 selected_source,
1185 generation,
1186 selected_pixel_density,
1187 can_gc,
1188 );
1189 },
1190 ImageCacheResult::ReadyForRequest(id) => {
1191 self.fetch_request(&img_url, id);
1192 self.register_image_cache_callback(id, change_type);
1193 },
1194 ImageCacheResult::Pending(id) => {
1195 self.register_image_cache_callback(id, change_type);
1196 },
1197 }
1198 }
1199
1200 fn react_to_decode_image_sync_steps(&self, promise: Rc<Promise>, can_gc: CanGc) {
1202 let document = self.owner_document();
1203 if !document.is_fully_active() ||
1205 matches!(self.current_request.borrow().state, State::Broken)
1206 {
1207 promise.reject_error(Error::Encoding, can_gc);
1208 } else if matches!(
1209 self.current_request.borrow().state,
1210 State::CompletelyAvailable
1211 ) {
1212 promise.resolve_native(&(), can_gc);
1214 } else {
1215 self.image_decode_promises
1216 .borrow_mut()
1217 .push(promise.clone());
1218 }
1219 }
1220
1221 fn resolve_image_decode_promises(&self) {
1223 if self.image_decode_promises.borrow().is_empty() {
1224 return;
1225 }
1226
1227 let trusted_image_decode_promises: Vec<TrustedPromise> = self
1231 .image_decode_promises
1232 .borrow()
1233 .iter()
1234 .map(|promise| TrustedPromise::new(promise.clone()))
1235 .collect();
1236
1237 self.image_decode_promises.borrow_mut().clear();
1238
1239 self.owner_global()
1240 .task_manager()
1241 .dom_manipulation_task_source()
1242 .queue(task!(fulfill_image_decode_promises: move || {
1243 for trusted_promise in trusted_image_decode_promises {
1244 trusted_promise.root().resolve_native(&(), CanGc::note());
1245 }
1246 }));
1247 }
1248
1249 fn reject_image_decode_promises(&self) {
1251 if self.image_decode_promises.borrow().is_empty() {
1252 return;
1253 }
1254
1255 let trusted_image_decode_promises: Vec<TrustedPromise> = self
1258 .image_decode_promises
1259 .borrow()
1260 .iter()
1261 .map(|promise| TrustedPromise::new(promise.clone()))
1262 .collect();
1263
1264 self.image_decode_promises.borrow_mut().clear();
1265
1266 self.owner_global()
1267 .task_manager()
1268 .dom_manipulation_task_source()
1269 .queue(task!(reject_image_decode_promises: move || {
1270 for trusted_promise in trusted_image_decode_promises {
1271 trusted_promise.root().reject_error(Error::Encoding, CanGc::note());
1272 }
1273 }));
1274 }
1275
1276 fn finish_reacting_to_environment_change(
1278 &self,
1279 src: USVString,
1280 generation: u32,
1281 selected_pixel_density: f64,
1282 ) {
1283 let this = Trusted::new(self);
1284 let src = src.0;
1285 self.owner_global().task_manager().dom_manipulation_task_source().queue(
1286 task!(image_load_event: move || {
1287 let this = this.root();
1288 let relevant_mutation = this.generation.get() != generation;
1289 if relevant_mutation {
1291 this.abort_request(State::Unavailable, ImageRequestPhase::Pending, CanGc::note());
1292 return;
1293 }
1294 *this.last_selected_source.borrow_mut() = Some(USVString(src));
1296
1297 {
1298 let mut pending_request = this.pending_request.borrow_mut();
1299 pending_request.current_pixel_density = Some(selected_pixel_density);
1300
1301 pending_request.state = State::CompletelyAvailable;
1303
1304 #[allow(clippy::swap_with_temporary)]
1309 mem::swap(&mut this.current_request.borrow_mut(), &mut pending_request);
1310 }
1311 this.abort_request(State::Unavailable, ImageRequestPhase::Pending, CanGc::note());
1312
1313 this.upcast::<Node>().dirty(NodeDamage::Other);
1315
1316 this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note());
1318 })
1319 );
1320 }
1321
1322 fn uses_srcset_or_picture(elem: &Element) -> bool {
1323 let has_src = elem.has_attribute(&local_name!("srcset"));
1324 let is_parent_picture = elem
1325 .upcast::<Node>()
1326 .GetParentElement()
1327 .is_some_and(|p| p.is::<HTMLPictureElement>());
1328 has_src || is_parent_picture
1329 }
1330
1331 fn new_inherited(
1332 local_name: LocalName,
1333 prefix: Option<Prefix>,
1334 document: &Document,
1335 creator: ElementCreator,
1336 ) -> HTMLImageElement {
1337 HTMLImageElement {
1338 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
1339 image_request: Cell::new(ImageRequestPhase::Current),
1340 current_request: DomRefCell::new(ImageRequest {
1341 state: State::Unavailable,
1342 parsed_url: None,
1343 source_url: None,
1344 image: None,
1345 metadata: None,
1346 blocker: DomRefCell::new(None),
1347 final_url: None,
1348 current_pixel_density: None,
1349 }),
1350 pending_request: DomRefCell::new(ImageRequest {
1351 state: State::Unavailable,
1352 parsed_url: None,
1353 source_url: None,
1354 image: None,
1355 metadata: None,
1356 blocker: DomRefCell::new(None),
1357 final_url: None,
1358 current_pixel_density: None,
1359 }),
1360 form_owner: Default::default(),
1361 generation: Default::default(),
1362 source_set: DomRefCell::new(SourceSet::new()),
1363 dimension_attribute_source: Default::default(),
1364 last_selected_source: DomRefCell::new(None),
1365 image_decode_promises: DomRefCell::new(vec![]),
1366 line_number: creator.return_line_number(),
1367 }
1368 }
1369
1370 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1371 pub(crate) fn new(
1372 local_name: LocalName,
1373 prefix: Option<Prefix>,
1374 document: &Document,
1375 proto: Option<HandleObject>,
1376 creator: ElementCreator,
1377 can_gc: CanGc,
1378 ) -> DomRoot<HTMLImageElement> {
1379 let image_element = Node::reflect_node_with_proto(
1380 Box::new(HTMLImageElement::new_inherited(
1381 local_name, prefix, document, creator,
1382 )),
1383 document,
1384 proto,
1385 can_gc,
1386 );
1387 image_element
1388 .dimension_attribute_source
1389 .set(Some(image_element.upcast()));
1390 image_element
1391 }
1392
1393 pub(crate) fn areas(&self) -> Option<Vec<DomRoot<HTMLAreaElement>>> {
1394 let elem = self.upcast::<Element>();
1395 let usemap_attr = elem.get_attribute(&ns!(), &local_name!("usemap"))?;
1396
1397 let value = usemap_attr.value();
1398
1399 if value.is_empty() || !value.is_char_boundary(1) {
1400 return None;
1401 }
1402
1403 let (first, last) = value.split_at(1);
1404
1405 if first != "#" || last.is_empty() {
1406 return None;
1407 }
1408
1409 let useMapElements = self
1410 .owner_document()
1411 .upcast::<Node>()
1412 .traverse_preorder(ShadowIncluding::No)
1413 .filter_map(DomRoot::downcast::<HTMLMapElement>)
1414 .find(|n| {
1415 n.upcast::<Element>()
1416 .get_name()
1417 .is_some_and(|n| *n == *last)
1418 });
1419
1420 useMapElements.map(|mapElem| mapElem.get_area_elements())
1421 }
1422
1423 pub(crate) fn same_origin(&self, origin: &MutableOrigin) -> bool {
1424 if let Some(ref image) = self.current_request.borrow().image {
1425 return image.cors_status() == CorsStatus::Safe;
1426 }
1427
1428 self.current_request
1429 .borrow()
1430 .final_url
1431 .as_ref()
1432 .is_some_and(|url| url.scheme() == "data" || url.origin().same_origin(origin))
1433 }
1434
1435 fn generation_id(&self) -> u32 {
1436 self.generation.get()
1437 }
1438}
1439
1440#[derive(JSTraceable, MallocSizeOf)]
1441pub(crate) enum ImageElementMicrotask {
1442 StableStateUpdateImageData {
1443 elem: DomRoot<HTMLImageElement>,
1444 generation: u32,
1445 },
1446 EnvironmentChanges {
1447 elem: DomRoot<HTMLImageElement>,
1448 generation: u32,
1449 },
1450 Decode {
1451 elem: DomRoot<HTMLImageElement>,
1452 #[ignore_malloc_size_of = "promises are hard"]
1453 promise: Rc<Promise>,
1454 },
1455}
1456
1457impl MicrotaskRunnable for ImageElementMicrotask {
1458 fn handler(&self, can_gc: CanGc) {
1459 match *self {
1460 ImageElementMicrotask::StableStateUpdateImageData {
1461 ref elem,
1462 ref generation,
1463 } => {
1464 if elem.generation.get() == *generation {
1467 elem.update_the_image_data_sync_steps(can_gc);
1468 }
1469 },
1470 ImageElementMicrotask::EnvironmentChanges {
1471 ref elem,
1472 ref generation,
1473 } => {
1474 elem.react_to_environment_changes_sync_steps(*generation, can_gc);
1475 },
1476 ImageElementMicrotask::Decode {
1477 ref elem,
1478 ref promise,
1479 } => {
1480 elem.react_to_decode_image_sync_steps(promise.clone(), can_gc);
1481 },
1482 }
1483 }
1484
1485 fn enter_realm(&self) -> JSAutoRealm {
1486 match self {
1487 &ImageElementMicrotask::StableStateUpdateImageData { ref elem, .. } |
1488 &ImageElementMicrotask::EnvironmentChanges { ref elem, .. } |
1489 &ImageElementMicrotask::Decode { ref elem, .. } => enter_realm(&**elem),
1490 }
1491 }
1492}
1493
1494pub(crate) trait LayoutHTMLImageElementHelpers {
1495 fn image_url(self) -> Option<ServoUrl>;
1496 fn image_density(self) -> Option<f64>;
1497 fn image_data(self) -> (Option<Image>, Option<ImageMetadata>);
1498 fn get_width(self) -> LengthOrPercentageOrAuto;
1499 fn get_height(self) -> LengthOrPercentageOrAuto;
1500}
1501
1502impl<'dom> LayoutDom<'dom, HTMLImageElement> {
1503 #[allow(unsafe_code)]
1504 fn current_request(self) -> &'dom ImageRequest {
1505 unsafe { self.unsafe_get().current_request.borrow_for_layout() }
1506 }
1507
1508 #[allow(unsafe_code)]
1509 fn dimension_attribute_source(self) -> LayoutDom<'dom, Element> {
1510 unsafe {
1511 self.unsafe_get()
1512 .dimension_attribute_source
1513 .get_inner_as_layout()
1514 .expect("dimension attribute source should be always non-null")
1515 }
1516 }
1517}
1518
1519impl LayoutHTMLImageElementHelpers for LayoutDom<'_, HTMLImageElement> {
1520 fn image_url(self) -> Option<ServoUrl> {
1521 self.current_request().parsed_url.clone()
1522 }
1523
1524 fn image_data(self) -> (Option<Image>, Option<ImageMetadata>) {
1525 let current_request = self.current_request();
1526 (current_request.image.clone(), current_request.metadata)
1527 }
1528
1529 fn image_density(self) -> Option<f64> {
1530 self.current_request().current_pixel_density
1531 }
1532
1533 fn get_width(self) -> LengthOrPercentageOrAuto {
1534 self.dimension_attribute_source()
1535 .get_attr_for_layout(&ns!(), &local_name!("width"))
1536 .map(|x| *AttrValue::from_dimension(x.to_string()).as_dimension())
1537 .unwrap_or(LengthOrPercentageOrAuto::Auto)
1538 }
1539
1540 fn get_height(self) -> LengthOrPercentageOrAuto {
1541 self.dimension_attribute_source()
1542 .get_attr_for_layout(&ns!(), &local_name!("height"))
1543 .map(|x| *AttrValue::from_dimension(x.to_string()).as_dimension())
1544 .unwrap_or(LengthOrPercentageOrAuto::Auto)
1545 }
1546}
1547
1548pub(crate) fn parse_a_sizes_attribute(value: DOMString) -> SourceSizeList {
1550 let mut input = ParserInput::new(&value);
1551 let mut parser = Parser::new(&mut input);
1552 let url_data = Url::parse("about:blank").unwrap().into();
1553 let context = ParserContext::new(
1554 Origin::Author,
1555 &url_data,
1556 Some(CssRuleType::Style),
1557 ParsingMode::empty(),
1560 QuirksMode::NoQuirks,
1561 Default::default(),
1562 None,
1563 None,
1564 );
1565 SourceSizeList::parse(&context, &mut parser)
1566}
1567
1568fn get_correct_referrerpolicy_from_raw_token(token: &DOMString) -> DOMString {
1569 if token.is_empty() {
1570 DOMString::new()
1573 } else {
1574 let policy = determine_policy_for_token(token);
1575
1576 if policy == ReferrerPolicy::EmptyString {
1577 return DOMString::new();
1578 }
1579
1580 DOMString::from_string(policy.to_string())
1581 }
1582}
1583
1584#[allow(non_snake_case)]
1585impl HTMLImageElementMethods<crate::DomTypeHolder> for HTMLImageElement {
1586 fn Image(
1588 window: &Window,
1589 proto: Option<HandleObject>,
1590 can_gc: CanGc,
1591 width: Option<u32>,
1592 height: Option<u32>,
1593 ) -> Fallible<DomRoot<HTMLImageElement>> {
1594 let element = Element::create(
1595 QualName::new(None, ns!(html), local_name!("img")),
1596 None,
1597 &window.Document(),
1598 ElementCreator::ScriptCreated,
1599 CustomElementCreationMode::Synchronous,
1600 proto,
1601 can_gc,
1602 );
1603
1604 let image = DomRoot::downcast::<HTMLImageElement>(element).unwrap();
1605 if let Some(w) = width {
1606 image.SetWidth(w, can_gc);
1607 }
1608 if let Some(h) = height {
1609 image.SetHeight(h, can_gc);
1610 }
1611
1612 image.update_the_image_data(can_gc);
1615
1616 Ok(image)
1617 }
1618
1619 make_getter!(Alt, "alt");
1621 make_setter!(SetAlt, "alt");
1623
1624 make_url_getter!(Src, "src");
1626
1627 make_url_setter!(SetSrc, "src");
1629
1630 make_url_getter!(Srcset, "srcset");
1632 make_url_setter!(SetSrcset, "srcset");
1634
1635 fn GetCrossOrigin(&self) -> Option<DOMString> {
1637 reflect_cross_origin_attribute(self.upcast::<Element>())
1638 }
1639
1640 fn SetCrossOrigin(&self, value: Option<DOMString>, can_gc: CanGc) {
1642 set_cross_origin_attribute(self.upcast::<Element>(), value, can_gc);
1643 }
1644
1645 make_getter!(UseMap, "usemap");
1647 make_setter!(SetUseMap, "usemap");
1649
1650 make_bool_getter!(IsMap, "ismap");
1652 make_bool_setter!(SetIsMap, "ismap");
1654
1655 fn Width(&self) -> u32 {
1657 let node = self.upcast::<Node>();
1658 node.content_box()
1659 .map(|rect| rect.size.width.to_px() as u32)
1660 .unwrap_or_else(|| self.NaturalWidth())
1661 }
1662
1663 fn SetWidth(&self, value: u32, can_gc: CanGc) {
1665 image_dimension_setter(self.upcast(), local_name!("width"), value, can_gc);
1666 }
1667
1668 fn Height(&self) -> u32 {
1670 let node = self.upcast::<Node>();
1671 node.content_box()
1672 .map(|rect| rect.size.height.to_px() as u32)
1673 .unwrap_or_else(|| self.NaturalHeight())
1674 }
1675
1676 fn SetHeight(&self, value: u32, can_gc: CanGc) {
1678 image_dimension_setter(self.upcast(), local_name!("height"), value, can_gc);
1679 }
1680
1681 fn NaturalWidth(&self) -> u32 {
1683 let request = self.current_request.borrow();
1684 let pixel_density = request.current_pixel_density.unwrap_or(1f64);
1685
1686 match request.metadata {
1687 Some(ref metadata) => (metadata.width as f64 / pixel_density) as u32,
1688 None => 0,
1689 }
1690 }
1691
1692 fn NaturalHeight(&self) -> u32 {
1694 let request = self.current_request.borrow();
1695 let pixel_density = request.current_pixel_density.unwrap_or(1f64);
1696
1697 match request.metadata {
1698 Some(ref metadata) => (metadata.height as f64 / pixel_density) as u32,
1699 None => 0,
1700 }
1701 }
1702
1703 fn Complete(&self) -> bool {
1705 let elem = self.upcast::<Element>();
1706 let srcset_absent = !elem.has_attribute(&local_name!("srcset"));
1707 if !elem.has_attribute(&local_name!("src")) && srcset_absent {
1708 return true;
1709 }
1710 let src = elem.get_string_attribute(&local_name!("src"));
1711 if srcset_absent && src.is_empty() {
1712 return true;
1713 }
1714 let request = self.current_request.borrow();
1715 let request_state = request.state;
1716 match request_state {
1717 State::CompletelyAvailable | State::Broken => true,
1718 State::PartiallyAvailable | State::Unavailable => false,
1719 }
1720 }
1721
1722 fn CurrentSrc(&self) -> USVString {
1724 let current_request = self.current_request.borrow();
1725 let url = ¤t_request.parsed_url;
1726 match *url {
1727 Some(ref url) => USVString(url.clone().into_string()),
1728 None => {
1729 let unparsed_url = ¤t_request.source_url;
1730 match *unparsed_url {
1731 Some(ref url) => url.clone(),
1732 None => USVString("".to_owned()),
1733 }
1734 },
1735 }
1736 }
1737
1738 fn ReferrerPolicy(&self) -> DOMString {
1740 reflect_referrer_policy_attribute(self.upcast::<Element>())
1741 }
1742
1743 fn SetReferrerPolicy(&self, value: DOMString, can_gc: CanGc) {
1745 let referrerpolicy_attr_name = local_name!("referrerpolicy");
1746 let element = self.upcast::<Element>();
1747 let previous_correct_attribute_value = get_correct_referrerpolicy_from_raw_token(
1748 &element.get_string_attribute(&referrerpolicy_attr_name),
1749 );
1750 let correct_value_or_empty_string = get_correct_referrerpolicy_from_raw_token(&value);
1751 if previous_correct_attribute_value != correct_value_or_empty_string {
1752 element.set_string_attribute(
1755 &referrerpolicy_attr_name,
1756 correct_value_or_empty_string,
1757 can_gc,
1758 );
1759 }
1760 }
1761
1762 fn Decode(&self, can_gc: CanGc) -> Rc<Promise> {
1764 let promise = Promise::new(&self.global(), can_gc);
1766
1767 let task = ImageElementMicrotask::Decode {
1769 elem: DomRoot::from_ref(self),
1770 promise: promise.clone(),
1771 };
1772 ScriptThread::await_stable_state(Microtask::ImageElement(task));
1773
1774 promise
1776 }
1777
1778 make_getter!(Name, "name");
1780
1781 make_atomic_setter!(SetName, "name");
1783
1784 make_getter!(Align, "align");
1786
1787 make_setter!(SetAlign, "align");
1789
1790 make_uint_getter!(Hspace, "hspace");
1792
1793 make_uint_setter!(SetHspace, "hspace");
1795
1796 make_uint_getter!(Vspace, "vspace");
1798
1799 make_uint_setter!(SetVspace, "vspace");
1801
1802 make_getter!(LongDesc, "longdesc");
1804
1805 make_setter!(SetLongDesc, "longdesc");
1807
1808 make_getter!(Border, "border");
1810
1811 make_setter!(SetBorder, "border");
1813}
1814
1815impl VirtualMethods for HTMLImageElement {
1816 fn super_type(&self) -> Option<&dyn VirtualMethods> {
1817 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
1818 }
1819
1820 fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
1821 self.super_type().unwrap().adopting_steps(old_doc, can_gc);
1822 self.update_the_image_data(can_gc);
1823 }
1824
1825 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
1826 self.super_type()
1827 .unwrap()
1828 .attribute_mutated(attr, mutation, can_gc);
1829 match attr.local_name() {
1830 &local_name!("src") |
1831 &local_name!("srcset") |
1832 &local_name!("width") |
1833 &local_name!("crossorigin") |
1834 &local_name!("sizes") |
1835 &local_name!("referrerpolicy") => self.update_the_image_data(can_gc),
1836 _ => {},
1837 }
1838 }
1839
1840 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
1841 match name {
1842 &local_name!("width") | &local_name!("height") => {
1843 AttrValue::from_dimension(value.into())
1844 },
1845 &local_name!("hspace") | &local_name!("vspace") => AttrValue::from_u32(value.into(), 0),
1846 _ => self
1847 .super_type()
1848 .unwrap()
1849 .parse_plain_attribute(name, value),
1850 }
1851 }
1852
1853 fn handle_event(&self, event: &Event, can_gc: CanGc) {
1854 if event.type_() != atom!("click") {
1855 return;
1856 }
1857
1858 let area_elements = self.areas();
1859 let elements = match area_elements {
1860 Some(x) => x,
1861 None => return,
1862 };
1863
1864 let mouse_event = match event.downcast::<MouseEvent>() {
1866 Some(x) => x,
1867 None => return,
1868 };
1869
1870 let point = Point2D::new(
1871 mouse_event.ClientX().to_f32().unwrap(),
1872 mouse_event.ClientY().to_f32().unwrap(),
1873 );
1874 let bcr = self.upcast::<Element>().GetBoundingClientRect(can_gc);
1875 let bcr_p = Point2D::new(bcr.X() as f32, bcr.Y() as f32);
1876
1877 for element in elements {
1879 let shape = element.get_shape_from_coords();
1880 let shp = match shape {
1881 Some(x) => x.absolute_coords(bcr_p),
1882 None => return,
1883 };
1884 if shp.hit_test(&point) {
1885 element.activation_behavior(event, self.upcast(), can_gc);
1886 return;
1887 }
1888 }
1889 }
1890
1891 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
1892 if let Some(s) = self.super_type() {
1893 s.bind_to_tree(context, can_gc);
1894 }
1895 let document = self.owner_document();
1896 if context.tree_connected {
1897 document.register_responsive_image(self);
1898 }
1899
1900 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
1903 if parent.is::<HTMLPictureElement>() {
1904 self.update_the_image_data(can_gc);
1905 }
1906 }
1907 }
1908
1909 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
1910 self.super_type().unwrap().unbind_from_tree(context, can_gc);
1911 let document = self.owner_document();
1912 document.unregister_responsive_image(self);
1913
1914 if context.parent.is::<HTMLPictureElement>() {
1917 self.update_the_image_data(can_gc);
1918 }
1919 }
1920}
1921
1922impl FormControl for HTMLImageElement {
1923 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
1924 self.form_owner.get()
1925 }
1926
1927 fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
1928 self.form_owner.set(form);
1929 }
1930
1931 fn to_element(&self) -> &Element {
1932 self.upcast::<Element>()
1933 }
1934
1935 fn is_listed(&self) -> bool {
1936 false
1937 }
1938}
1939
1940fn image_dimension_setter(element: &Element, attr: LocalName, value: u32, can_gc: CanGc) {
1941 let value = if value > UNSIGNED_LONG_MAX { 0 } else { value };
1944
1945 let pixel_value = if value > (i32::MAX / AU_PER_PX) as u32 {
1951 0
1952 } else {
1953 value
1954 };
1955
1956 let dim = LengthOrPercentageOrAuto::Length(Au::from_px(pixel_value as i32));
1957 let value = AttrValue::Dimension(value.to_string(), dim);
1958 element.set_attribute(&attr, value, can_gc);
1959}
1960
1961pub(crate) fn collect_sequence_characters(
1963 s: &str,
1964 mut predicate: impl FnMut(&char) -> bool,
1965) -> (&str, &str) {
1966 let i = s.find(|ch| !predicate(&ch)).unwrap_or(s.len());
1967 (&s[0..i], &s[i..])
1968}
1969
1970pub fn parse_a_srcset_attribute(input: &str) -> Vec<ImageSource> {
1973 let mut current_index = 0;
1976
1977 let mut candidates = vec![];
1979 while current_index < input.len() {
1980 let remaining_string = &input[current_index..];
1981
1982 let mut collected_comma = false;
1986 let (collected_characters, string_after_whitespace) =
1987 collect_sequence_characters(remaining_string, |character| {
1988 if *character == ',' {
1989 collected_comma = true;
1990 }
1991 *character == ',' || character.is_ascii_whitespace()
1992 });
1993 if collected_comma {
1994 return Vec::new();
1995 }
1996
1997 current_index += collected_characters.len();
2000
2001 if string_after_whitespace.is_empty() {
2003 return candidates;
2004 }
2005
2006 let (url, _) =
2009 collect_sequence_characters(string_after_whitespace, |c| !char::is_ascii_whitespace(c));
2010
2011 current_index += url.len();
2014
2015 let mut descriptors = Vec::new();
2017
2018 if url.ends_with(',') {
2022 let image_source = ImageSource {
2023 url: url.trim_end_matches(',').into(),
2024 descriptor: Descriptor {
2025 width: None,
2026 density: None,
2027 },
2028 };
2029 candidates.push(image_source);
2030 continue;
2031 }
2032
2033 let descriptors_string = &input[current_index..];
2036 let (spaces, descriptors_string) =
2037 collect_sequence_characters(descriptors_string, |character| {
2038 character.is_ascii_whitespace()
2039 });
2040 current_index += spaces.len();
2041
2042 let mut current_descriptor = String::new();
2044
2045 let mut state = ParseState::InDescriptor;
2047
2048 let mut characters = descriptors_string.chars();
2052 let mut character = characters.next();
2053 if let Some(character) = character {
2054 current_index += character.len_utf8();
2055 }
2056
2057 loop {
2058 match (state, character) {
2059 (ParseState::InDescriptor, Some(character)) if character.is_ascii_whitespace() => {
2060 if !current_descriptor.is_empty() {
2064 descriptors.push(current_descriptor);
2065 current_descriptor = String::new();
2066 state = ParseState::AfterDescriptor;
2067 }
2068 },
2069 (ParseState::InDescriptor, Some(',')) => {
2070 if !current_descriptor.is_empty() {
2074 descriptors.push(current_descriptor);
2075 }
2076 break;
2077 },
2078 (ParseState::InDescriptor, Some('(')) => {
2079 current_descriptor.push('(');
2081 state = ParseState::InParens;
2082 },
2083 (ParseState::InDescriptor, Some(character)) => {
2084 current_descriptor.push(character);
2086 },
2087 (ParseState::InDescriptor, None) => {
2088 if !current_descriptor.is_empty() {
2091 descriptors.push(current_descriptor);
2092 }
2093 break;
2094 },
2095 (ParseState::InParens, Some(')')) => {
2096 current_descriptor.push(')');
2098 state = ParseState::InDescriptor;
2099 },
2100 (ParseState::InParens, Some(character)) => {
2101 current_descriptor.push(character);
2103 },
2104 (ParseState::InParens, None) => {
2105 descriptors.push(current_descriptor);
2108 break;
2109 },
2110 (ParseState::AfterDescriptor, Some(character))
2111 if character.is_ascii_whitespace() =>
2112 {
2113 },
2115 (ParseState::AfterDescriptor, Some(_)) => {
2116 state = ParseState::InDescriptor;
2119 continue;
2120 },
2121 (ParseState::AfterDescriptor, None) => {
2122 break;
2124 },
2125 }
2126
2127 character = characters.next();
2128 if let Some(character) = character {
2129 current_index += character.len_utf8();
2130 }
2131 }
2132
2133 let mut error = false;
2135 let mut width: Option<u32> = None;
2137 let mut density: Option<f64> = None;
2139 let mut future_compat_h: Option<u32> = None;
2141
2142 for descriptor in descriptors.into_iter() {
2145 let Some(last_character) = descriptor.chars().last() else {
2146 break;
2147 };
2148
2149 let first_part_of_string = &descriptor[0..descriptor.len() - last_character.len_utf8()];
2150 match last_character {
2151 'w' if density.is_none() && width.is_none() => {
2158 match parse_integer(first_part_of_string.chars()) {
2159 Ok(number) if number > 0 => {
2160 width = Some(number as u32);
2161 continue;
2162 },
2163 _ => error = true,
2164 }
2165 },
2166
2167 'x' if width.is_none() && density.is_none() && future_compat_h.is_none() => {
2182 match first_part_of_string.parse::<f64>() {
2183 Ok(number) if number.is_normal() && number > 0. => {
2184 density = Some(number);
2185 continue;
2186 },
2187 _ => error = true,
2188 }
2189 },
2190
2191 'h' if future_compat_h.is_none() && density.is_none() => {
2200 match parse_integer(first_part_of_string.chars()) {
2201 Ok(number) if number > 0 => {
2202 future_compat_h = Some(number as u32);
2203 continue;
2204 },
2205 _ => error = true,
2206 }
2207 },
2208
2209 _ => error = true,
2212 }
2213
2214 if error {
2215 break;
2216 }
2217 }
2218
2219 if future_compat_h.is_some() && width.is_none() {
2221 error = true;
2222 }
2223
2224 if !error {
2225 let image_source = ImageSource {
2226 url: url.into(),
2227 descriptor: Descriptor { width, density },
2228 };
2229 candidates.push(image_source);
2230 }
2231 }
2232 candidates
2233}
2234
2235#[derive(Clone)]
2236enum ChangeType {
2237 Environment {
2238 selected_source: USVString,
2239 selected_pixel_density: f64,
2240 },
2241 Element,
2242}