1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_responsiveimageselector_h__
8 #define mozilla_dom_responsiveimageselector_h__
10 #include "mozilla/UniquePtr.h"
11 #include "mozilla/ServoBindingTypes.h"
12 #include "mozilla/FunctionRef.h"
13 #include "nsISupports.h"
14 #include "nsIContent.h"
16 #include "nsCycleCollectionParticipant.h"
21 namespace mozilla::dom
{
23 class ResponsiveImageCandidate
;
25 class ResponsiveImageSelector
{
26 friend class ResponsiveImageCandidate
;
29 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ResponsiveImageSelector
)
30 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ResponsiveImageSelector
)
32 explicit ResponsiveImageSelector(nsIContent
* aContent
);
33 explicit ResponsiveImageSelector(dom::Document
* aDocument
);
35 // Parses the raw candidates and calls into the callback for each one of them.
36 static void ParseSourceSet(const nsAString
& aSrcSet
,
37 FunctionRef
<void(ResponsiveImageCandidate
&&)>);
39 // NOTE ABOUT CURRENT SELECTION
41 // The best candidate is selected lazily when GetSelectedImage*() is
42 // called, or when SelectImage() is called explicitly. This result
43 // is then cached until either invalidated by further Set*() calls,
44 // or explicitly by replaced by SelectImage(aReselect = true).
46 // Because the selected image depends on external variants like
47 // viewport size and device pixel ratio, the time at which image
48 // selection occurs can affect the result.
50 // Given a srcset string, parse and replace current candidates (does not
51 // replace default source)
52 bool SetCandidatesFromSourceSet(const nsAString
& aSrcSet
,
53 nsIPrincipal
* aTriggeringPrincipal
= nullptr);
55 // Fill the source sizes from a valid sizes descriptor. Returns false if
56 // descriptor is invalid.
57 bool SetSizesFromDescriptor(const nsAString
& aSizesDescriptor
);
59 // Set the default source, treated as the least-precedence 1.0 density source.
60 void SetDefaultSource(const nsAString
& aURLString
, nsIPrincipal
* = nullptr);
61 void SetDefaultSource(nsIURI
* aURI
, nsIPrincipal
* = nullptr);
62 void ClearDefaultSource();
64 uint32_t NumCandidates(bool aIncludeDefault
= true);
66 // If this was created for a specific content. May be null if we were only
67 // created for a document.
68 nsIContent
* Content();
70 // The document we were created for, or the owner document of the content if
71 // we were created for a specific nsIContent.
72 dom::Document
* Document();
74 // Get the url and density for the selected best candidate. These
75 // implicitly cause an image to be selected if necessary.
76 already_AddRefed
<nsIURI
> GetSelectedImageURL();
77 // Returns false if there is no selected image
78 bool GetSelectedImageURLSpec(nsAString
& aResult
);
79 double GetSelectedImageDensity();
80 nsIPrincipal
* GetSelectedImageTriggeringPrincipal();
82 // Runs image selection now if necessary. If an image has already
83 // been choosen, takes no action unless aReselect is true.
85 // aReselect - Always re-run selection, replacing the previously
87 // return - true if the selected image result changed.
88 bool SelectImage(bool aReselect
= false);
91 virtual ~ResponsiveImageSelector();
94 // Append a candidate unless its selector is duplicated by a higher priority
96 void AppendCandidateIfUnique(ResponsiveImageCandidate
&& aCandidate
);
98 // Append a default candidate with this URL if necessary. Does not check if
99 // the array already contains one, use SetDefaultSource instead.
100 void MaybeAppendDefaultCandidate();
102 // Get index of selected candidate, triggering selection if necessary.
103 int GetSelectedCandidateIndex();
105 // Forget currently selected candidate. (See "NOTE ABOUT CURRENT SELECTION"
107 void ClearSelectedCandidate();
109 // Compute a density from a Candidate width. Returns false if sizes were not
110 // specified for this selector.
112 // aContext is the presContext to use for current viewport sizing, null will
113 // use the associated content's context.
114 bool ComputeFinalWidthForCurrentViewport(double* aWidth
);
116 nsCOMPtr
<nsINode
> mOwnerNode
;
117 // The cached URL for default candidate.
118 nsString mDefaultSourceURL
;
119 nsCOMPtr
<nsIPrincipal
> mDefaultSourceTriggeringPrincipal
;
120 // If this array contains an eCandidateType_Default, it should be the last
121 // element, such that the Setters can preserve/replace it respectively.
122 nsTArray
<ResponsiveImageCandidate
> mCandidates
;
123 int mSelectedCandidateIndex
;
124 // The cached resolved URL for mSelectedCandidateIndex, such that we only
125 // resolve the absolute URL at selection time
126 nsCOMPtr
<nsIURI
> mSelectedCandidateURL
;
129 UniquePtr
<StyleSourceSizeList
> mServoSourceSizeList
;
132 class ResponsiveImageCandidate
{
134 ResponsiveImageCandidate();
135 ResponsiveImageCandidate(const ResponsiveImageCandidate
&) = delete;
136 ResponsiveImageCandidate(ResponsiveImageCandidate
&&) = default;
138 void SetURLSpec(const nsAString
& aURLString
);
139 void SetTriggeringPrincipal(nsIPrincipal
* aPrincipal
);
140 // Set this as a default-candidate. This behaves the same as density 1.0, but
141 // has a differing type such that it can be replaced by subsequent
142 // SetDefaultSource calls.
143 void SetParameterDefault();
145 // Set this candidate as a by-density candidate with specified density.
146 void SetParameterAsDensity(double aDensity
);
147 void SetParameterAsComputedWidth(int32_t aWidth
);
149 void SetParameterInvalid();
151 // Consume descriptors from a string defined by aIter and aIterEnd, adjusts
152 // aIter to the end of data consumed.
153 // Returns false if descriptors string is invalid, but still parses to the end
154 // of descriptors microsyntax.
155 bool ConsumeDescriptors(nsAString::const_iterator
& aIter
,
156 const nsAString::const_iterator
& aIterEnd
);
158 // Check if our parameter (which does not include the url) is identical
159 bool HasSameParameter(const ResponsiveImageCandidate
& aOther
) const;
161 const nsAString
& URLString() const { return mURLString
; }
162 nsIPrincipal
* TriggeringPrincipal() const { return mTriggeringPrincipal
; }
164 // Compute and return the density relative to a selector.
165 double Density(ResponsiveImageSelector
* aSelector
) const;
166 // If the width is already known. Useful when iterating over candidates to
167 // avoid having each call re-compute the width.
168 double Density(double aMatchingWidth
) const;
170 // Append the descriptors for this candidate serialized as a string.
171 void AppendDescriptors(nsAString
&) const;
173 bool IsValid() const { return mType
!= CandidateType::Invalid
; }
175 // If this selector is computed from the selector's matching width.
176 bool IsComputedFromWidth() const {
177 return mType
== CandidateType::ComputedFromWidth
;
180 bool IsDefault() const { return mType
== CandidateType::Default
; }
182 enum class CandidateType
: uint8_t {
185 // Treated as 1.0 density, but a separate type so we can update the
186 // responsive candidates and default separately
191 CandidateType
Type() const { return mType
; }
195 nsCOMPtr
<nsIPrincipal
> mTriggeringPrincipal
;
203 } // namespace mozilla::dom
205 #endif // mozilla_dom_responsiveimageselector_h__