/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
staticbool ParseFloat(const nsAString& aString, double& aDouble) { // Check if it is a valid floating-point number first since the result of // nsString.ToDouble() is more lenient than the spec, // https://html.spec.whatwg.org/#valid-floating-point-number
nsAString::const_iterator iter, end;
aString.BeginReading(iter);
aString.EndReading(end);
if (IsAsciiDigit(*iter)) { for (; iter != end && IsAsciiDigit(*iter); ++iter);
} elseif (*iter == char16_t('.')) { // Do nothing, jumps to fraction part
} else { returnfalse;
}
// Fraction if (*iter == char16_t('.')) {
++iter; if (iter == end || !IsAsciiDigit(*iter)) { // U+002E FULL STOP character (.) must be followed by one or more ASCII // digits returnfalse;
}
for (; iter != end && IsAsciiDigit(*iter); ++iter);
}
if (iter != end && (*iter == char16_t('e') || *iter == char16_t('E'))) {
++iter; if (*iter == char16_t('-') || *iter == char16_t('+')) {
++iter;
}
if (iter == end || !IsAsciiDigit(*iter)) { // Should have one or more ASCII digits returnfalse;
}
for (; iter != end && IsAsciiDigit(*iter); ++iter);
}
// 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;
}
}
void ResponsiveImageSelector::ClearDefaultSource() {
ClearSelectedCandidate(); // Check if the last element of our candidates is a default if (!mCandidates.IsEmpty() && mCandidates.LastElement().IsDefault()) {
mCandidates.RemoveLastElement();
}
}
void ResponsiveImageSelector::AppendCandidateIfUnique(
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.IsDefault()) { return;
}
// Discard candidates with identical parameters, they will never match for (int i = 0; i < numCandidates; i++) { if (mCandidates[i].HasSameParameter(aCandidate)) { return;
}
}
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;
} elseif (mCandidates[i].Density(this) == 1.0) { return;
}
}
ResponsiveImageCandidate defaultCandidate;
defaultCandidate.SetParameterDefault();
defaultCandidate.SetURLSpec(mDefaultSourceURL);
defaultCandidate.SetTriggeringPrincipal(mDefaultSourceTriggeringPrincipal); // 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(std::move(defaultCandidate));
}
if (overrideDPPX > 0) {
displayDensity = overrideDPPX;
} if (doc->ShouldResistFingerprinting(RFPTarget::WindowDevicePixelRatio)) {
displayDensity = nsRFPService::GetDevicePixelRatioAtZoom(1);
}
// Per spec, "In a UA-specific manner, choose one image source" // - For now, select the lowest density greater than displayDensity, otherwise // the greatest density available
// If the list contains computed width candidates, compute the current // effective image width. double computedWidth = -1; for (int i = 0; i < numCandidates; i++) { if (mCandidates[i].IsComputedFromWidth()) {
DebugOnly<bool> computeResult =
ComputeFinalWidthForCurrentViewport(&computedWidth);
MOZ_ASSERT(computeResult, "Computed candidates not allowed without sizes data"); break;
}
}
int bestIndex = -1; double bestDensity = -1.0; for (int i = 0; i < numCandidates; i++) { double candidateDensity = (computedWidth == -1)
? mCandidates[i].Density(this)
: mCandidates[i].Density(computedWidth); // - If bestIndex is below display density, pick anything larger. // - Otherwise, prefer if less dense than bestDensity but still above // displayDensity. if (bestIndex == -1 ||
(bestDensity < displayDensity && candidateDensity > bestDensity) ||
(candidateDensity >= displayDensity &&
candidateDensity < bestDensity)) {
bestIndex = i;
bestDensity = candidateDensity;
}
}
mType = CandidateType::Default; // mValue shouldn't actually be used for this type, but set it to default // anyway
mValue.mDensity = 1.0;
}
void ResponsiveImageCandidate::SetParameterInvalid() {
mType = CandidateType::Invalid; // mValue shouldn't actually be used for this type, but set it to default // anyway
mValue.mDensity = 1.0;
}
// Represents all supported descriptors for a ResponsiveImageCandidate, though // there is no candidate type that uses all of these. This should generally // match the mValue union of ResponsiveImageCandidate. struct ResponsiveImageDescriptors {
ResponsiveImageDescriptors() : mInvalid(false) {};
Maybe<double> mDensity;
Maybe<int32_t> mWidth; // We don't support "h" descriptors yet and they are not spec'd, but the // current spec does specify that they can be silently ignored (whereas // entirely unknown descriptors cause us to invalidate the candidate) // // If we ever start honoring them we should serialize them in // AppendDescriptors.
Maybe<int32_t> mFutureCompatHeight; // If this descriptor set is bogus, e.g. a value was added twice (and thus // dropped) or an unknown descriptor was added. bool mInvalid;
void AddDescriptor(const nsAString& aDescriptor); bool Valid(); // Use the current set of descriptors to configure a candidate void FillCandidate(ResponsiveImageCandidate& aCandidate);
};
// Try to parse a single descriptor from a string. If value already set or // unknown, sets invalid flag. // This corresponds to the descriptor "Descriptor parser" step in: // https://html.spec.whatwg.org/#parse-a-srcset-attribute void ResponsiveImageDescriptors::AddDescriptor(const nsAString& aDescriptor) { if (aDescriptor.IsEmpty()) { return;
}
// All currently supported descriptors end with an identifying character.
nsAString::const_iterator descStart, descType;
aDescriptor.BeginReading(descStart);
aDescriptor.EndReading(descType);
descType--; const nsDependentSubstring& valueStr = Substring(descStart, descType); if (*descType == char16_t('w')) {
int32_t possibleWidth; // If the value is not a valid non-negative integer, it doesn't match this // descriptor, fall through. if (ParseInteger(valueStr, possibleWidth) && possibleWidth >= 0) { if (possibleWidth != 0 && mWidth.isNothing() && mDensity.isNothing()) {
mWidth.emplace(possibleWidth);
} else { // Valid width descriptor, but width or density were already seen, sizes // support isn't enabled, or it parsed to 0, which is an error per spec
mInvalid = true;
}
return;
}
} elseif (*descType == char16_t('h')) {
int32_t possibleHeight; // If the value is not a valid non-negative integer, it doesn't match this // descriptor, fall through. if (ParseInteger(valueStr, possibleHeight) && possibleHeight >= 0) { if (possibleHeight != 0 && mFutureCompatHeight.isNothing() &&
mDensity.isNothing()) {
mFutureCompatHeight.emplace(possibleHeight);
} else { // Valid height descriptor, but height or density were already seen, or // it parsed to zero, which is an error per spec
mInvalid = true;
}
return;
}
} elseif (*descType == char16_t('x')) { // If the value is not a valid floating point number, it doesn't match this // descriptor, fall through. double possibleDensity = 0.0; if (ParseFloat(valueStr, possibleDensity)) { if (possibleDensity >= 0.0 && mWidth.isNothing() &&
mDensity.isNothing() && mFutureCompatHeight.isNothing()) {
mDensity.emplace(possibleDensity);
} else { // Valid density descriptor, but height or width or density were already // seen, or it parsed to less than zero, which is an error per spec
mInvalid = true;
}
return;
}
}
// Matched no known descriptor, mark this descriptor set invalid
mInvalid = true;
}
void ResponsiveImageDescriptors::FillCandidate(
ResponsiveImageCandidate& aCandidate) { if (!Valid()) {
aCandidate.SetParameterInvalid();
} elseif (mWidth.isSome()) {
MOZ_ASSERT(mDensity.isNothing()); // Shouldn't be valid
aCandidate.SetParameterAsComputedWidth(*mWidth);
} elseif (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);
}
}
bool ResponsiveImageCandidate::ConsumeDescriptors(
nsAString::const_iterator& aIter, const nsAString::const_iterator& aIterEnd) {
nsAString::const_iterator& iter = aIter; const nsAString::const_iterator& end = aIterEnd;
for (;; iter++) { if (iter == end) {
descriptors.AddDescriptor(Substring(currentDescriptor, iter)); break;
} elseif (inParens) { if (*iter == char16_t(')')) {
inParens = false;
}
} else { if (*iter == char16_t(',')) { // End of descriptors, flush current descriptor and advance past comma // before breaking
descriptors.AddDescriptor(Substring(currentDescriptor, iter));
iter++; break;
} if (nsContentUtils::IsHTMLWhitespace(*iter)) { // End of current descriptor, consume it, skip spaces // ("After descriptor" state in spec) before continuing
descriptors.AddDescriptor(Substring(currentDescriptor, iter)); for (; iter != end && nsContentUtils::IsHTMLWhitespace(*iter); ++iter); if (iter == end) { break;
}
currentDescriptor = iter; // Leave one whitespace so the loop advances to this position next // iteration
iter--;
} elseif (*iter == char16_t('(')) {
inParens = true;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.