Line data Source code
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/. */
6 :
7 : #ifndef mozilla_dom_responsiveimageselector_h__
8 : #define mozilla_dom_responsiveimageselector_h__
9 :
10 : #include "nsAutoPtr.h"
11 : #include "nsISupports.h"
12 : #include "nsIContent.h"
13 : #include "nsString.h"
14 : #include "nsCycleCollectionParticipant.h"
15 :
16 : class nsMediaQuery;
17 : class nsCSSValue;
18 :
19 : namespace mozilla {
20 : namespace dom {
21 :
22 : class ResponsiveImageCandidate;
23 :
24 : class ResponsiveImageSelector
25 : {
26 : friend class ResponsiveImageCandidate;
27 : public:
28 0 : NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ResponsiveImageSelector)
29 0 : NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ResponsiveImageSelector)
30 :
31 : explicit ResponsiveImageSelector(nsIContent* aContent);
32 : explicit ResponsiveImageSelector(nsIDocument* aDocument);
33 :
34 : // NOTE ABOUT CURRENT SELECTION
35 : //
36 : // The best candidate is selected lazily when GetSelectedImage*() is
37 : // called, or when SelectImage() is called explicitly. This result
38 : // is then cached until either invalidated by further Set*() calls,
39 : // or explicitly by replaced by SelectImage(aReselect = true).
40 : //
41 : // Because the selected image depends on external variants like
42 : // viewport size and device pixel ratio, the time at which image
43 : // selection occurs can affect the result.
44 :
45 :
46 : // Given a srcset string, parse and replace current candidates (does not
47 : // replace default source)
48 : bool SetCandidatesFromSourceSet(const nsAString & aSrcSet);
49 :
50 : // Fill the source sizes from a valid sizes descriptor. Returns false if
51 : // descriptor is invalid.
52 : bool SetSizesFromDescriptor(const nsAString & aSizesDescriptor);
53 :
54 : // Set the default source, treated as the least-precedence 1.0 density source.
55 : void SetDefaultSource(const nsAString& aURLString);
56 :
57 : uint32_t NumCandidates(bool aIncludeDefault = true);
58 :
59 : // If this was created for a specific content. May be null if we were only
60 : // created for a document.
61 : nsIContent *Content();
62 :
63 : // The document we were created for, or the owner document of the content if
64 : // we were created for a specific nsIContent.
65 : nsIDocument *Document();
66 :
67 : // Get the url and density for the selected best candidate. These
68 : // implicitly cause an image to be selected if necessary.
69 : already_AddRefed<nsIURI> GetSelectedImageURL();
70 : // Returns false if there is no selected image
71 : bool GetSelectedImageURLSpec(nsAString& aResult);
72 : double GetSelectedImageDensity();
73 :
74 : // Runs image selection now if necessary. If an image has already
75 : // been choosen, takes no action unless aReselect is true.
76 : //
77 : // aReselect - Always re-run selection, replacing the previously
78 : // choosen image.
79 : // return - true if the selected image result changed.
80 : bool SelectImage(bool aReselect = false);
81 :
82 : protected:
83 : virtual ~ResponsiveImageSelector();
84 :
85 : private:
86 : // Append a candidate unless its selector is duplicated by a higher priority
87 : // candidate
88 : void AppendCandidateIfUnique(const ResponsiveImageCandidate &aCandidate);
89 :
90 : // Append a default candidate with this URL if necessary. Does not check if
91 : // the array already contains one, use SetDefaultSource instead.
92 : void MaybeAppendDefaultCandidate();
93 :
94 : // Get index of selected candidate, triggering selection if necessary.
95 : int GetSelectedCandidateIndex();
96 :
97 : // Forget currently selected candidate. (See "NOTE ABOUT CURRENT SELECTION"
98 : // above.)
99 : void ClearSelectedCandidate();
100 :
101 : // Compute a density from a Candidate width. Returns false if sizes were not
102 : // specified for this selector.
103 : //
104 : // aContext is the presContext to use for current viewport sizing, null will
105 : // use the associated content's context.
106 : bool ComputeFinalWidthForCurrentViewport(double* aWidth);
107 :
108 : nsCOMPtr<nsINode> mOwnerNode;
109 : // The cached URL for default candidate.
110 : nsString mDefaultSourceURL;
111 : // If this array contains an eCandidateType_Default, it should be the last
112 : // element, such that the Setters can preserve/replace it respectively.
113 : nsTArray<ResponsiveImageCandidate> mCandidates;
114 : int mSelectedCandidateIndex;
115 : // The cached resolved URL for mSelectedCandidateIndex, such that we only
116 : // resolve the absolute URL at selection time
117 : nsCOMPtr<nsIURI> mSelectedCandidateURL;
118 :
119 : nsTArray< nsAutoPtr<nsMediaQuery> > mSizeQueries;
120 : nsTArray<nsCSSValue> mSizeValues;
121 : };
122 :
123 0 : class ResponsiveImageCandidate {
124 : public:
125 : ResponsiveImageCandidate();
126 : ResponsiveImageCandidate(const nsAString& aURLString, double aDensity);
127 :
128 : void SetURLSpec(const nsAString& aURLString);
129 : // Set this as a default-candidate. This behaves the same as density 1.0, but
130 : // has a differing type such that it can be replaced by subsequent
131 : // SetDefaultSource calls.
132 : void SetParameterDefault();
133 :
134 : // Set this candidate as a by-density candidate with specified density.
135 : void SetParameterAsDensity(double aDensity);
136 : void SetParameterAsComputedWidth(int32_t aWidth);
137 :
138 : void SetParameterInvalid();
139 :
140 : // Consume descriptors from a string defined by aIter and aIterEnd, adjusts
141 : // aIter to the end of data consumed.
142 : // Returns false if descriptors string is invalid, but still parses to the end
143 : // of descriptors microsyntax.
144 : bool ConsumeDescriptors(nsAString::const_iterator& aIter,
145 : const nsAString::const_iterator& aIterEnd);
146 :
147 : // Check if our parameter (which does not include the url) is identical
148 : bool HasSameParameter(const ResponsiveImageCandidate & aOther) const;
149 :
150 : const nsAString& URLString() const;
151 :
152 : // Compute and return the density relative to a selector.
153 : double Density(ResponsiveImageSelector *aSelector) const;
154 : // If the width is already known. Useful when iterating over candidates to
155 : // avoid having each call re-compute the width.
156 : double Density(double aMatchingWidth) const;
157 :
158 : // If this selector is computed from the selector's matching width.
159 : bool IsComputedFromWidth() const;
160 :
161 : enum eCandidateType {
162 : eCandidateType_Invalid,
163 : eCandidateType_Density,
164 : // Treated as 1.0 density, but a separate type so we can update the
165 : // responsive candidates and default separately
166 : eCandidateType_Default,
167 : eCandidateType_ComputedFromWidth
168 : };
169 :
170 0 : eCandidateType Type() const { return mType; }
171 :
172 : private:
173 :
174 : nsString mURLString;
175 : eCandidateType mType;
176 : union {
177 : double mDensity;
178 : int32_t mWidth;
179 : } mValue;
180 : };
181 :
182 : } // namespace dom
183 : } // namespace mozilla
184 :
185 : #endif // mozilla_dom_responsiveimageselector_h__
|