void ResponsiveImageSelector::MaybeAppendDefaultCandidate() { if (mDefaultSourceURL.IsEmpty()) { return; } int numCandidates = mCandidates.Length(); // https://html.spec.whatwg.org/multipage/embedded-content.html#update-the-source-set // step 4.1.3: // If child has a src attribute whose value is not the empty string and source // set does not contain an image source with a density descriptor value of 1, // and no image source with a width descriptor, append child's src attribute // value to source set. for (int i = 0; i < numCandidates; i++) { if (mCandidates[i].IsComputedFromWidth()) { return; } else if (mCandidates[i].Density(this) == 1.0) { return; } } ResponsiveImageCandidate defaultCandidate; defaultCandidate.SetParameterDefault(); defaultCandidate.SetURLSpec(mDefaultSourceURL); // We don't use MaybeAppend since we want to keep this even if it can never // match, as it may if the source set changes. mCandidates.AppendElement(defaultCandidate); }
void ResponsiveImageDescriptors::FillCandidate(ResponsiveImageCandidate &aCandidate) { if (!Valid()) { aCandidate.SetParameterInvalid(); } else if (mWidth.isSome()) { MOZ_ASSERT(mDensity.isNothing()); // Shouldn't be valid aCandidate.SetParameterAsComputedWidth(*mWidth); } else if (mDensity.isSome()) { MOZ_ASSERT(mWidth.isNothing()); // Shouldn't be valid aCandidate.SetParameterAsDensity(*mDensity); } else { // A valid set of descriptors with no density nor width (e.g. an empty set) // becomes 1.0 density, per spec aCandidate.SetParameterAsDensity(1.0); } }
void ResponsiveImageSelector::AppendCandidateIfUnique(const ResponsiveImageCandidate & aCandidate) { int numCandidates = mCandidates.Length(); // With the exception of Default, which should not be added until we are done // building the list. if (aCandidate.Type() == ResponsiveImageCandidate::eCandidateType_Default) { return; } // Discard candidates with identical parameters, they will never match for (int i = 0; i < numCandidates; i++) { if (mCandidates[i].HasSameParameter(aCandidate)) { return; } } mCandidates.AppendElement(aCandidate); }
void ResponsiveImageSelector::AppendCandidateIfUnique(const ResponsiveImageCandidate & aCandidate) { int numCandidates = mCandidates.Length(); // With the exception of Default, which should not be added until we are done // building the list, the spec forbids mixing width and explicit density // selectors in the same set. if (numCandidates && mCandidates[0].Type() != aCandidate.Type()) { return; } // Discard candidates with identical parameters, they will never match for (int i = 0; i < numCandidates; i++) { if (mCandidates[i].HasSameParameter(aCandidate)) { return; } } mCandidates.AppendElement(aCandidate); }
// http://www.whatwg.org/specs/web-apps/current-work/#processing-the-image-candidates bool ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet) { ClearSelectedCandidate(); nsCOMPtr<nsIURI> docBaseURI = mOwnerNode ? mOwnerNode->GetBaseURI() : nullptr; if (!docBaseURI) { MOZ_ASSERT(false, "Should not be parsing SourceSet without a document"); return false; } mCandidates.Clear(); nsAString::const_iterator iter, end; aSrcSet.BeginReading(iter); aSrcSet.EndReading(end); // Read URL / descriptor pairs while (iter != end) { nsAString::const_iterator url, urlEnd, descriptor; // Skip whitespace and commas. // Extra commas at this point are a non-fatal syntax error. for (; iter != end && (nsContentUtils::IsHTMLWhitespace(*iter) || *iter == char16_t(',')); ++iter); if (iter == end) { break; } url = iter; // Find end of url for (;iter != end && !nsContentUtils::IsHTMLWhitespace(*iter); ++iter); // Omit trailing commas from URL. // Multiple commas are a non-fatal error. while (iter != url) { if (*(--iter) != char16_t(',')) { iter++; break; } } const nsDependentSubstring &urlStr = Substring(url, iter); MOZ_ASSERT(url != iter, "Shouldn't have empty URL at this point"); ResponsiveImageCandidate candidate; if (candidate.ConsumeDescriptors(iter, end)) { candidate.SetURLSpec(urlStr); AppendCandidateIfUnique(candidate); } } bool parsedCandidates = mCandidates.Length() > 0; // Re-add default to end of list MaybeAppendDefaultCandidate(); return parsedCandidates; }