mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
09bea9b394
- Bug 1215921 - Range Analysis: Recover observable operands if they are recoverable. r=jandem,sunfish (5d0387ba66)
- Bug 1221923 - Remove pointless "initialized" static in VMFunction::addToFunctions; r=Waldo (fbf61fff54)
- Bug 12228397 - Bail out when dividing large unsigned integer by one. r=sunfish (cbd9d34bcf)
- Bug 1229292 - IonMonkey: MIPS64: Fix skip nops in conditional branches. r=huangwenjun06 (2244600084)
- Bug 1090957 - IonMonkey: MIPS: Implement atomics in MacroAssembler. r=lth (29399e4a33)
- Bug 1229989 - IonMonkey: MIPS: Fix patchCall for mips32. r=luke (1ae6f20686)
- Bug 1213747 - IonMonkey: MIPS: Import MIPS64 support into MoveEmitter-mips-shared. r=nbp f=rankov (16d46fe32e)
- Bug 1233863 - ARM64: Record the correct branch offset. r=sstangl (b2f940056e)
- Bug 1233884 - Remove unused CompactBufferWriters from MozBaseAssembler. r=jolesen (e37860be67)
- Bug 1233863 - ARM64: Avoid BumpSystemStackPointer(). r=sstangl (5c06e601c1)
- Bug 1229802 - Simplify MacroAssemblerARMCompat::decBranchPtr. r=nbp (a908c62e5b)
- bit of Bug 1217515 - Clean up the way touch event support is configured (2cfd0e4c65)
- Bug 1221459 - Remove SelectionStateChangedEvent. r=mtseng, r=smaug (9a827ab9fc)
- Bug 1209479 - Map Android back button to nsIWebNavigation::GoBack() for the current active frame r=fabrice (be41e7b8da)
- Bug 1165841 - Part 1: add window into nsINfcEventListener. r=dimi (475a56ab28)
- Bug 1165841 - Part 2: move window-related code to nsNfc.js. r=dimi (e2a0487b75)
- Bug 1165841 - Part 3: remove _rfState and init from NfcContentHelper. r=dimi (b8be95012d)
- Bug 1165841 - Part 4: using eventListeners. r=dimi (a22ff6d56c)
- Bug 1165841 - Part 5: remove listener when window is destroyed. r=dimi (48716e2ba1)
- Bug 1168292 - Part 1: update SYSTEM_APP_ID. r=dimi (ecdbbefb03)
- Bug 1168292 - Part 2: notify listener with correct tabId. r=dimi (4fb26c705e)
- Bug 1168292 - Part 3: add tabId in notifyUserAccepted. r=dimi (1b36a15b65)
- Bug 1170053 - [Aries] Not able to share a picture using NFC. r=yoshi (0b80df2866)
- Bug 1172159 - [NFC] Introduce getFocusTabId function. r=allstars.chh (b917d0dac7)
- Bug 1168704 - Rename setFocusApp in nslNfcContentHelper. r=yoshi (9918707442)
- more missing of Bug 1209479 (6480ccc315)
- Bug 1166210 - Remove ServicesSetting changes listener in NfcContentHelper. r=yoshi (6e8f388637)
- Bug 1121900 - [flatfish] build break by "error: undefined reference to 'mozilla::dom::MozIsoDepTech::mTechnology'". r=yoshi (b5aaaada08)
- Bug 976457 - B2G NFC: API for supporting NFC_A tags. r=yoshi r=smaug (b908a5d60a)
- Bug 1156208 - this.nfc.getErrorMessage is not a function. r=dimi (42e33fcfc9)
- Bug 1225701 - Add comments in TouchCaret and SelectionCarets for their obsolescence. r=mtseng (ba85234c0e)
- Bug 1210341 - (v3) Reduce accessiblecaret size. r=TYLin Bug 1221459 - Remove TouchCaret and SelectionCarets. r=mtseng, r=roc (ad6282ff96)
- Bug 1216986 - Fix usage of nsIURI.host in password manager and prompt code to support IPv6. r=dolske,liuche,kanru (cec90a6251)
- Bug 962249 part 1 - Add Element.scroll{Top,Left}Min (chrome-only) and convert most of scrollLeftMax uses and part of scrollTopMax uses to combinations with the new properties. r=roc,bz (13ed8ee58f)
- Bug 962249 part 3 - Add Window.scrollMin{X,Y} (chrome-only) and conve… (b9b6e6aa8f)
- Bug 918771 - Part 1: Move Fragment Serialization logic into nsContentUtils::SerializeNodeToMarkup, r=bz (865ea1d334)
- Bug 918771 - Part 2: Send text/html as MIME type for XHR send() of HTML document, r=bz (129b8d4115)
- Bug 918771 - Part 3: Update Web Platform tests to check for correct behavior, r=bz (ed0536f5b8)
- Bug 1085284 - Implement URLSearchParams iterable<>, r=bz (db1edd6d74)
- Bug 1224643. Fix handling of U+0000 in URLSearchParams serialization. r=baku (55856e5353)
- Bug 1224580. Copy of URLSearchParams should not copy its observer pointer. r=baku (1a5d859de5)
- Bug 1153145 - Ensure trusted focus events from web content focus plugins. r=smaug (d79fb35d4b)
- Bug 1183901, properly support WrapperCache on DistributedContentList, r=wchen (f15879c8ca)
- Bug 1188887: P1. Allow seeking when readyState is HAVE_NOTHING. r=jwwang (aa33721a44)
- Bug 1188887: P2. Add mochitest testing new seek behavior. r=jwwang (0520088343)
- Bug 1232223 - Part 6: Remove function prototype for undefined function IsAudioAPIEnabled(). r=jya (5126eb83ed)
- Bug 1232223 - Part 5: Run wave tests unconditionally. r=jya (668e6b9b77)
- Bug 1232223 - Part 1: Remove MOZ_WEBM #ifdefs because WebM is always supported, though not necessarily enabled. r=jya r=glandium (b3ec44f5bc)
- Bug 1232223 - Part 2: Remove MOZ_VPX #ifdefs because VPx is always supported, though not necessarily enabled. r=jya (c8853a16c4)
- Bug 1232223 - Part 3: Remove MOZ_WAVE #ifdefs because Wave is always supported. r=jya (e5c18f912c)
- Bug 1232223 - Part 4: Run webm tests unconditionally. r=jya (a81ab83b00)
- fix (9d9acad7f8)
- bug 1169640 - use nsIPrompt instead of nsIPromptService for insecure form submission r=mrbkap (1091d0d839)
- Bug 1231919 - crash in mozilla::a11y::DocAccessible::ValidateARIAOwned, r=davidb (3466d77e14)
- bug 1172538 - make sure a document has an IPC actor before shutting it down r=davidb, lsocks (823a447f7f)
- Bug 1147646 - Crash in mozilla::a11y::DocAccessible::ProcessContentInserted while stability testing, r=davidb (c9e4e7ef2f)
- Bug 1230118 - added asserts on aOwner and aOwner->Elm() r=surkov (94295ffd61)
- Bug 1213281 - crash in mozilla::a11y::DocAccessible::UpdateTreeOnInsertion, r=davidb (6442f927cd)
- bug 1196460 - add method to get wrapper of proxy for document containing this proxied accessible r=surkov (0cc7ff8758)
- Bug 1222174 - add override declarations in AccessibleWrap.h; r=tbsaunde (a8c1d0d3f3)
- bug 1187055 - check the proxy being destroyed has a wrapper before cleaning it up r=davidb (b73966446c)
- bug 1196460 - remove proxy's ids when they are destroyed r=surkov (3cbc9a8536)
- bug 1196372 - make GetHWNDFor() work with proxied accessibles r=surkov (28a6057913)
- Bug 1196460 - teach GetChildIDFor() to deal with proxied accessibles r=surkov (4746bfa128)
- bug 1199735 - remove event logging from the windows AccessibleWrap::HandleAccEvent r=davidb (869e18d13f)
- bug 1199735 - factor win event dispatch logic into its own function r=davidb (0a9704aa9d)
- bug 1196460 - create different proxy wrappers depending on the type of the proxy r=surkov (cd2d18ebdc)
- bug 1213327 - store interfaces a proxy implements on the Accessible wrapping it (406c9a3715)
- bug 1213606 - work around proxy's that don't have a wrapper for their document r=davidb (252a3ff2e7)
- bug 1192330 - update text change data for proxied text change events r=surkov (4deb371062)
- bug 1199735 - fire windows events on proxies r=davidb (6400387e71)
- bug 1186536 - Bail out of ProxyTextChangeEvent() if the proxy doesn't have a wrapper r=davidb (b40f69c77b)
- bug 1207862 - make WrapperFor() take a const ProxyAccessible * r=davidb (8e79dc6d75)
- bug 1213402 - fixup silly array , on windows r=me landing on a CLOSED TREE (33368af3af)
- bug 606080 - add class to generate unique 32 bit ids r=froydnj (ebf0888dcc)
- Bug 1231148 - Avoid requiring IDL files installed in $DIST/idl to run AccEventGen.py. r=ted (22078343ce)
- Bug 1229838 - rel=apple-touch-icon-precomposed should fire mozbrowsericonchange. r=fabrice (2a3e93da96)
- Bug 1231040 - Check for premulting better. - r=jrmuizel (811609bbb3)
- Bug 1224475 - Start agent after seeking. r=baku (a009b58f2c)
- Bug 1231557 - Use the URL Classifier in Media elements. r=cpearce,r=gcp (9f5503581d)
- bug 1228484 throw instead of capturing a second stream to a different graph r=roc (e762799424)
- Bug 1198435 - MediaElementTableCount now checks that the element is not present for URIs other than the expected one. r=rillian (838b1b886b)
- Bug 1224991 - Log format string mismatch the number of parameters. r=cpearce. (9cd2770bd2)
- Bug 1144409 - Encrypted event should be fired once per initData. r=cpearce (e50b380feb)
- Bug 1213589 part.1 Make ContentEventHandler::GetTextLength() and GetNativeTextLength() called only with a text node r=smaug (10955440a9)
- Bug 1213589 part.2 Clean up GenerateFlatTextContent(), GelerateFlatFontRanges() and GetFlatTextOffsetOfRange() of ContentEventHandler r=smaug (3f6bf987ff)
- Bug 1213589 part.3 ContentEventHandler::GetFlatTextLengthInRange() should handle specially when it's called by nsIMutationObserver::ContentRemoved() r=smaug (ed03499803)
- Bug 1213859 part.4 ContentEventHandler should use NS_NewPreContentIterator rathr than NS_NewContentIterator at converting between DOM tree and flattened text r=smaug (fe6e3b1114)
- Bug 1213589 part.5 Redesign the rules to create range in ContentEventHandler::SetRangeFromFlatTextOffset() r=smaug (edaa7baf87)
- Bug 1213589 part.6 ContentEventHandler should insert line breaks at open tag of elements except non-replaced inline elements r=smaug (c2e9cc11dc)
- Bug 1213589 part.7 Add new testcases to runSetSelectionEventTest() and runQueryTextContentEventTest() for checking the behavior with open tag r=smaug (bcea465e5e)
- Bug 1213589 part.8 When there are no nodes causing text, ContentEventHandler should set start of the editor root to start of the range r=smaug (a6d6b4d8d5)
- Bug 1213589 part.9 ContentEventHandler::ShouldBreakLineBefore() should return false if the content is unknown HTML element r=smaug (960936477f)
- Bug 1214164 - Don't honor all <option> descendants of <select>; r=bz (188bfe2b89)
- Bug 1228876. Correctly ignore nested optgroups even if an optgroup is inserted into another, existing, optgroup. r=mats (f2058c8b68)
- Bug 1193637 - Use IsMap() in HTMLImageElement::PreHandleEvent; r=mrbkap (6f2ef9da61)
- Bug 1160819 - ResponsiveImageSelector - improve some over-aggressive assertions (b5d40119ac)
- Bug 1233259, only in-document images should respond to viewport changes, r=mystor (eb448e258c)
- Bug 773429 - Remove dom.disable_image_src_set. r=khuey (fa06677726)
- Bug 1230110 - HTMLImageElement should call its superclass's DestroyContent(). r=smaug (bac1d12c65)
- Bug 1231245 - Fix logging of Matrix4x4. r=botond (f5c93b67cb)
- Bug 1208661 - Remove some no-longer-used debugging code. r=BenWa (2c86e3efd2)
- Bug 1228602 - Ensure that we pick up the presShell resolution from the layer if there isn't a metrics. r=botond (3c1835a022)
- Annotate FrameMetrics that are created for ScrollInfoLayers. (bug 1192919 part 1, r=kats) (5be0234333)
- Minimize the displayport for frames that must animate synchronously. (bug 1192919 part 2, r=kats) (5abc63e72d)
- Force a paint to be scheduled for scroll info layers. (bug 1192919 part 3, r=kats) (4ed61248c7)
- Bug 1141127 - When inside a slop area around the first touchstart, prevent touchmove events from going to content. r=botond (18fa91d74e)
- Bug 1174532 - Even if the APZC is not pannable, have a small slop area to consume touchmove events. r=botond (ff8e6f46fe)
- Bug 1208636 - Adjust displayport size based on available system memory. r=kats (d1ff9798b2)
- Bug 1232094 - Make some APZ prefs live. r=botond (d45207bc5b)
- Bug 1231168 - Disable memory-based displayport size adjustment by default. r=mchang (c17b445171)
- Turn apz.use_paint_duration off. (bug 1192919 part 4, r=kats) (dc094c9617)
- Bug 1170325 - Undo an unnecessary signature change to AsyncPanZoomAnimation::TakeDeferredTasks(). r=Waldo (62eafb38ef)
- Bug 1216355 - Ensure that if a repaint request is ignored due to a stale generation number the next repaint request doesn't get dropped. r=botond (c070172b48)
- Bug 1228407 - Rearrange some code by extracting a helper function. r=botond (ae53af7449)
- Bug 1228407 - Update existing smooth scroll animations with new destinations when possible, rather than canceling and restarting them. r=kip (c15022d920)
- Dispatch all APZ repaint requests immediately, and rely on content vsync. (bug 1192919 part 5, r=kats) (53ea2674c8)
- Bug 1230552 - Update some out-of-date comments and remove an old #undef. r=kats (16ba5a82e1)
- Bug 1230552 - Introduce a structure to group fling handoff state. r=kats (4f98893742)
- Bug 1230552 - Extend the immediate scroll handoff pref to apply to flings. r=kats (6b3d4fb0e5)
- Bug 1231228 - Correctly check for whether an APZC along the handoff chain is panned into overscroll. r=kats (bbaeb881af)
- Bug 1226920 - For instances of ForEachNode where we want to traverse the entire tree, use an action that returns void. r=botond (e42de54aea)
- Bug 1230552 - Make immediate scroll handoff for panning prefable. r=kats (89ddb8853a)
- Bug 1230552 - Fuzz a floating-point comparison to avoid an intermittent test failure. r=bustage (839bee076d)
- Bug 1231228 - Gtest. r=kats (e141ee97ef)
- Bug 1208973 - Move function bodies into .cpp file, and remove an unused one. r=botond (ef89b08738)
- Bug 1208973 - Refactor and add logging to TaskThrottler. r=botond (0a88091e20)
- Bug 1208973 - Ensure all code in TaskThrottler is threadsafe since it gets called from various threads. r=botond (9735621fd1)
- Bug 1213273 - Use a chromium Task instead of an nsITimer for the timeout in TaskThrottler. r=mstange (6cc9a9369e)
- Bug 1217251 - In TaskThrottler, dispatch the timeout task correctly from the Java UI thread on Android. r=kats (ee64d9458e)
- Bug 1230552 - Const-correctness improvements. r=kats (cc56f3404a)
- Bug 1230552 - Introduce a helper AsyncPanZoomController::CurrentInputBlock(). r=kats (4cef12a744)
- Remove the TaskThrottler. (bug 1192919 part 6, r=kats) (534312c146)
- Bug 1169695 - Advance the stored time when sampling the transform for a future frame. r=botod (3b08c07827)
- Bug 1169695 - Remove as many manual calls to spin the task queue as possible. r=botond (80c390ec7a)
- Bug 1218618 - Assert that the hit-testing tree's root node doesn't have siblings. r=kats (95ec1d07a7)
- Bug 1225178 - Don't start APZ drag if we don't have a displayport to handle it. r=kats (c29d4f962d)
- bit of End APZ wheel transactions when the mouse moves out of frame. (bug 1142866 part 2, r=kats,botond) (5a0c79d052)
- Bug 1226320 - Fix a refactoring in APZCTreeManager that didn't preserve semantics correctly. r=kats (35b92bd4a1)
733 lines
21 KiB
C++
733 lines
21 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "mozilla/dom/ResponsiveImageSelector.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsCSSParser.h"
|
|
#include "nsCSSProps.h"
|
|
#include "nsIMediaList.h"
|
|
#include "nsRuleNode.h"
|
|
#include "nsRuleData.h"
|
|
|
|
// For IsPictureEnabled() -- the candidate parser needs to be aware of sizes
|
|
// support being enabled
|
|
#include "HTMLPictureElement.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION(ResponsiveImageSelector, mOwnerNode)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ResponsiveImageSelector, AddRef)
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ResponsiveImageSelector, Release)
|
|
|
|
static bool
|
|
ParseInteger(const nsAString& aString, int32_t& aInt)
|
|
{
|
|
nsContentUtils::ParseHTMLIntegerResultFlags parseResult;
|
|
aInt = nsContentUtils::ParseHTMLInteger(aString, &parseResult);
|
|
return !(parseResult &
|
|
( nsContentUtils::eParseHTMLInteger_Error |
|
|
nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput |
|
|
nsContentUtils::eParseHTMLInteger_IsPercent |
|
|
nsContentUtils::eParseHTMLInteger_NonStandard ));
|
|
}
|
|
|
|
ResponsiveImageSelector::ResponsiveImageSelector(nsIContent *aContent)
|
|
: mOwnerNode(aContent),
|
|
mSelectedCandidateIndex(-1)
|
|
{
|
|
}
|
|
|
|
ResponsiveImageSelector::ResponsiveImageSelector(nsIDocument *aDocument)
|
|
: mOwnerNode(aDocument),
|
|
mSelectedCandidateIndex(-1)
|
|
{
|
|
}
|
|
|
|
ResponsiveImageSelector::~ResponsiveImageSelector()
|
|
{}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Preserve the default source if we have one, it has a separate setter.
|
|
uint32_t prevNumCandidates = mCandidates.Length();
|
|
nsString defaultURLString;
|
|
if (prevNumCandidates && (mCandidates[prevNumCandidates - 1].Type() ==
|
|
ResponsiveImageCandidate::eCandidateType_Default)) {
|
|
defaultURLString = mCandidates[prevNumCandidates - 1].URLString();
|
|
}
|
|
|
|
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
|
|
if (!defaultURLString.IsEmpty()) {
|
|
AppendDefaultCandidate(defaultURLString);
|
|
}
|
|
|
|
return parsedCandidates;
|
|
}
|
|
|
|
uint32_t
|
|
ResponsiveImageSelector::NumCandidates(bool aIncludeDefault)
|
|
{
|
|
uint32_t candidates = mCandidates.Length();
|
|
|
|
// If present, the default candidate is the last item
|
|
if (!aIncludeDefault && candidates &&
|
|
(mCandidates[candidates - 1].Type() ==
|
|
ResponsiveImageCandidate::eCandidateType_Default)) {
|
|
candidates--;
|
|
}
|
|
|
|
return candidates;
|
|
}
|
|
|
|
nsIContent*
|
|
ResponsiveImageSelector::Content()
|
|
{
|
|
return mOwnerNode->IsContent() ? mOwnerNode->AsContent() : nullptr;
|
|
}
|
|
|
|
nsIDocument*
|
|
ResponsiveImageSelector::Document()
|
|
{
|
|
return mOwnerNode->OwnerDoc();
|
|
}
|
|
|
|
void
|
|
ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString)
|
|
{
|
|
ClearSelectedCandidate();
|
|
|
|
// Check if the last element of our candidates is a default
|
|
int32_t candidates = mCandidates.Length();
|
|
if (candidates && (mCandidates[candidates - 1].Type() ==
|
|
ResponsiveImageCandidate::eCandidateType_Default)) {
|
|
mCandidates.RemoveElementAt(candidates - 1);
|
|
}
|
|
|
|
// Add new default if set
|
|
if (!aURLString.IsEmpty()) {
|
|
AppendDefaultCandidate(aURLString);
|
|
}
|
|
}
|
|
|
|
void
|
|
ResponsiveImageSelector::ClearSelectedCandidate()
|
|
{
|
|
mSelectedCandidateIndex = -1;
|
|
mSelectedCandidateURL = nullptr;
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageSelector::SetSizesFromDescriptor(const nsAString & aSizes)
|
|
{
|
|
ClearSelectedCandidate();
|
|
mSizeQueries.Clear();
|
|
mSizeValues.Clear();
|
|
|
|
nsCSSParser cssParser;
|
|
|
|
if (!cssParser.ParseSourceSizeList(aSizes, nullptr, 0,
|
|
mSizeQueries, mSizeValues, true)) {
|
|
return false;
|
|
}
|
|
|
|
return mSizeQueries.Length() > 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, 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);
|
|
}
|
|
|
|
void
|
|
ResponsiveImageSelector::AppendDefaultCandidate(const nsAString& aURLString)
|
|
{
|
|
NS_ENSURE_TRUE(!aURLString.IsEmpty(), /* void */);
|
|
|
|
ResponsiveImageCandidate defaultCandidate;
|
|
defaultCandidate.SetParameterDefault();
|
|
defaultCandidate.SetURLSpec(aURLString);
|
|
// 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);
|
|
}
|
|
|
|
already_AddRefed<nsIURI>
|
|
ResponsiveImageSelector::GetSelectedImageURL()
|
|
{
|
|
SelectImage();
|
|
|
|
nsCOMPtr<nsIURI> url = mSelectedCandidateURL;
|
|
return url.forget();
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageSelector::GetSelectedImageURLSpec(nsAString& aResult)
|
|
{
|
|
SelectImage();
|
|
|
|
if (mSelectedCandidateIndex == -1) {
|
|
return false;
|
|
}
|
|
|
|
aResult.Assign(mCandidates[mSelectedCandidateIndex].URLString());
|
|
return true;
|
|
}
|
|
|
|
double
|
|
ResponsiveImageSelector::GetSelectedImageDensity()
|
|
{
|
|
int bestIndex = GetSelectedCandidateIndex();
|
|
if (bestIndex < 0) {
|
|
return 1.0;
|
|
}
|
|
|
|
return mCandidates[bestIndex].Density(this);
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageSelector::SelectImage(bool aReselect)
|
|
{
|
|
if (!aReselect && mSelectedCandidateIndex != -1) {
|
|
// Already have selection
|
|
return false;
|
|
}
|
|
|
|
int oldBest = mSelectedCandidateIndex;
|
|
ClearSelectedCandidate();
|
|
|
|
int numCandidates = mCandidates.Length();
|
|
if (!numCandidates) {
|
|
return oldBest != -1;
|
|
}
|
|
|
|
nsIDocument* doc = Document();
|
|
nsIPresShell *shell = doc ? doc->GetShell() : nullptr;
|
|
nsPresContext *pctx = shell ? shell->GetPresContext() : nullptr;
|
|
nsCOMPtr<nsIURI> baseURI = mOwnerNode ? mOwnerNode->GetBaseURI() : nullptr;
|
|
|
|
if (!pctx || !doc || !baseURI) {
|
|
MOZ_ASSERT(false, "Unable to find document prescontext and base URI");
|
|
return oldBest != -1;
|
|
}
|
|
|
|
double displayDensity = pctx->CSSPixelsToDevPixels(1.0f);
|
|
|
|
// 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. Note that we currently disallow both computed and
|
|
// static density candidates in the same selector, so checking the first
|
|
// candidate is sufficient.
|
|
int32_t computedWidth = -1;
|
|
if (numCandidates && mCandidates[0].IsComputedFromWidth()) {
|
|
DebugOnly<bool> computeResult = \
|
|
ComputeFinalWidthForCurrentViewport(&computedWidth);
|
|
MOZ_ASSERT(computeResult,
|
|
"Computed candidates not allowed without sizes data");
|
|
|
|
// If we have a default candidate in the list, don't consider it when using
|
|
// computed widths. (It has a static 1.0 density that is inapplicable to a
|
|
// sized-image)
|
|
if (numCandidates > 1 && mCandidates[numCandidates - 1].Type() ==
|
|
ResponsiveImageCandidate::eCandidateType_Default) {
|
|
numCandidates--;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
MOZ_ASSERT(bestIndex >= 0 && bestIndex < numCandidates);
|
|
|
|
// Resolve URL
|
|
nsresult rv;
|
|
const nsAString& urlStr = mCandidates[bestIndex].URLString();
|
|
nsCOMPtr<nsIURI> candidateURL;
|
|
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(candidateURL),
|
|
urlStr, doc, baseURI);
|
|
|
|
mSelectedCandidateURL = NS_SUCCEEDED(rv) ? candidateURL : nullptr;
|
|
mSelectedCandidateIndex = bestIndex;
|
|
|
|
return mSelectedCandidateIndex != oldBest;
|
|
}
|
|
|
|
int
|
|
ResponsiveImageSelector::GetSelectedCandidateIndex()
|
|
{
|
|
SelectImage();
|
|
|
|
return mSelectedCandidateIndex;
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageSelector::ComputeFinalWidthForCurrentViewport(int32_t *aWidth)
|
|
{
|
|
unsigned int numSizes = mSizeQueries.Length();
|
|
nsIDocument* doc = Document();
|
|
nsIPresShell *presShell = doc ? doc->GetShell() : nullptr;
|
|
nsPresContext *pctx = presShell ? presShell->GetPresContext() : nullptr;
|
|
|
|
if (!pctx) {
|
|
MOZ_ASSERT(false, "Unable to find presContext for this content");
|
|
return false;
|
|
}
|
|
|
|
MOZ_ASSERT(numSizes == mSizeValues.Length(),
|
|
"mSizeValues length differs from mSizeQueries");
|
|
|
|
unsigned int i;
|
|
for (i = 0; i < numSizes; i++) {
|
|
if (mSizeQueries[i]->Matches(pctx, nullptr)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
nscoord effectiveWidth;
|
|
if (i == numSizes) {
|
|
// No match defaults to 100% viewport
|
|
nsCSSValue defaultWidth(100.0f, eCSSUnit_ViewportWidth);
|
|
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
|
|
defaultWidth);
|
|
} else {
|
|
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
|
|
mSizeValues[i]);
|
|
}
|
|
|
|
MOZ_ASSERT(effectiveWidth >= 0);
|
|
*aWidth = nsPresContext::AppUnitsToIntCSSPixels(std::max(effectiveWidth, 0));
|
|
return true;
|
|
}
|
|
|
|
ResponsiveImageCandidate::ResponsiveImageCandidate()
|
|
{
|
|
mType = eCandidateType_Invalid;
|
|
mValue.mDensity = 1.0;
|
|
}
|
|
|
|
ResponsiveImageCandidate::ResponsiveImageCandidate(const nsAString& aURLString,
|
|
double aDensity)
|
|
: mURLString(aURLString)
|
|
{
|
|
mType = eCandidateType_Density;
|
|
mValue.mDensity = aDensity;
|
|
}
|
|
|
|
|
|
void
|
|
ResponsiveImageCandidate::SetURLSpec(const nsAString& aURLString)
|
|
{
|
|
mURLString = aURLString;
|
|
}
|
|
|
|
void
|
|
ResponsiveImageCandidate::SetParameterAsComputedWidth(int32_t aWidth)
|
|
{
|
|
mType = eCandidateType_ComputedFromWidth;
|
|
mValue.mWidth = aWidth;
|
|
}
|
|
|
|
void
|
|
ResponsiveImageCandidate::SetParameterDefault()
|
|
{
|
|
MOZ_ASSERT(mType == eCandidateType_Invalid, "double setting candidate type");
|
|
|
|
mType = eCandidateType_Default;
|
|
// mValue shouldn't actually be used for this type, but set it to default
|
|
// anyway
|
|
mValue.mDensity = 1.0;
|
|
}
|
|
|
|
void
|
|
ResponsiveImageCandidate::SetParameterInvalid()
|
|
{
|
|
mType = eCandidateType_Invalid;
|
|
// mValue shouldn't actually be used for this type, but set it to default
|
|
// anyway
|
|
mValue.mDensity = 1.0;
|
|
}
|
|
|
|
void
|
|
ResponsiveImageCandidate::SetParameterAsDensity(double aDensity)
|
|
{
|
|
MOZ_ASSERT(mType == eCandidateType_Invalid, "double setting candidate type");
|
|
|
|
mType = eCandidateType_Density;
|
|
mValue.mDensity = aDensity;
|
|
}
|
|
|
|
// 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)
|
|
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 && HTMLPictureElement::IsPictureEnabled() &&
|
|
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;
|
|
}
|
|
} else if (*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;
|
|
}
|
|
} else if (*descType == char16_t('x')) {
|
|
// If the value is not a valid floating point number, it doesn't match this
|
|
// descriptor, fall through.
|
|
nsresult rv;
|
|
double possibleDensity = PromiseFlatString(valueStr).ToDouble(&rv);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
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;
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageDescriptors::Valid()
|
|
{
|
|
return !mInvalid && !(mFutureCompatHeight.isSome() && mWidth.isNothing());
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageCandidate::ConsumeDescriptors(nsAString::const_iterator& aIter,
|
|
const nsAString::const_iterator& aIterEnd)
|
|
{
|
|
nsAString::const_iterator &iter = aIter;
|
|
const nsAString::const_iterator &end = aIterEnd;
|
|
|
|
bool inParens = false;
|
|
|
|
ResponsiveImageDescriptors descriptors;
|
|
|
|
// Parse descriptor list.
|
|
// This corresponds to the descriptor parsing loop from:
|
|
// https://html.spec.whatwg.org/#parse-a-srcset-attribute
|
|
|
|
// Skip initial whitespace
|
|
for (; iter != end && nsContentUtils::IsHTMLWhitespace(*iter); ++iter);
|
|
|
|
nsAString::const_iterator currentDescriptor = iter;
|
|
|
|
for (;; iter++) {
|
|
if (iter == end) {
|
|
descriptors.AddDescriptor(Substring(currentDescriptor, iter));
|
|
break;
|
|
} else if (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;
|
|
} else 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--;
|
|
} else if (*iter == char16_t('(')) {
|
|
inParens = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
descriptors.FillCandidate(*this);
|
|
|
|
return Type() != eCandidateType_Invalid;
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageCandidate::HasSameParameter(const ResponsiveImageCandidate & aOther) const
|
|
{
|
|
if (aOther.mType != mType) {
|
|
return false;
|
|
}
|
|
|
|
if (mType == eCandidateType_Default) {
|
|
return true;
|
|
}
|
|
|
|
if (mType == eCandidateType_Density) {
|
|
return aOther.mValue.mDensity == mValue.mDensity;
|
|
}
|
|
|
|
if (mType == eCandidateType_Invalid) {
|
|
MOZ_ASSERT(false, "Comparing invalid candidates?");
|
|
return true;
|
|
} else if (mType == eCandidateType_ComputedFromWidth) {
|
|
return aOther.mValue.mWidth == mValue.mWidth;
|
|
}
|
|
|
|
MOZ_ASSERT(false, "Somebody forgot to check for all uses of this enum");
|
|
return false;
|
|
}
|
|
|
|
const nsAString&
|
|
ResponsiveImageCandidate::URLString() const
|
|
{
|
|
return mURLString;
|
|
}
|
|
|
|
double
|
|
ResponsiveImageCandidate::Density(ResponsiveImageSelector *aSelector) const
|
|
{
|
|
if (mType == eCandidateType_ComputedFromWidth) {
|
|
int32_t width;
|
|
if (!aSelector->ComputeFinalWidthForCurrentViewport(&width)) {
|
|
return 1.0;
|
|
}
|
|
return Density(width);
|
|
}
|
|
|
|
// Other types don't need matching width
|
|
MOZ_ASSERT(mType == eCandidateType_Default || mType == eCandidateType_Density,
|
|
"unhandled candidate type");
|
|
return Density(-1);
|
|
}
|
|
|
|
double
|
|
ResponsiveImageCandidate::Density(int32_t aMatchingWidth) const
|
|
{
|
|
if (mType == eCandidateType_Invalid) {
|
|
MOZ_ASSERT(false, "Getting density for uninitialized candidate");
|
|
return 1.0;
|
|
}
|
|
|
|
if (mType == eCandidateType_Default) {
|
|
return 1.0;
|
|
}
|
|
|
|
if (mType == eCandidateType_Density) {
|
|
return mValue.mDensity;
|
|
} else if (mType == eCandidateType_ComputedFromWidth) {
|
|
if (aMatchingWidth < 0) {
|
|
MOZ_ASSERT(false, "Don't expect to have a negative matching width at this point");
|
|
return 1.0;
|
|
}
|
|
double density = double(mValue.mWidth) / double(aMatchingWidth);
|
|
MOZ_ASSERT(density > 0.0);
|
|
return density;
|
|
}
|
|
|
|
MOZ_ASSERT(false, "Unknown candidate type");
|
|
return 1.0;
|
|
}
|
|
|
|
bool
|
|
ResponsiveImageCandidate::IsComputedFromWidth() const
|
|
{
|
|
if (mType == eCandidateType_ComputedFromWidth) {
|
|
return true;
|
|
}
|
|
|
|
MOZ_ASSERT(mType == eCandidateType_Default || mType == eCandidateType_Density,
|
|
"Unknown candidate type");
|
|
return false;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|