Merge pull request #8 from classilla/master

keep sync with master
This commit is contained in:
Riccardo 2018-03-23 09:22:51 +01:00 committed by GitHub
commit b61caed0c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
95 changed files with 2546 additions and 1364 deletions

View File

@ -18,6 +18,9 @@
<preference id="tenfourfox.ua.template" <preference id="tenfourfox.ua.template"
name="tenfourfox.ua.template" name="tenfourfox.ua.template"
type="string"/> type="string"/>
<preference id="tenfourfox.adblock.enabled"
name="tenfourfox.adblock.enabled"
type="bool"/>
</preferences> </preferences>
@ -69,3 +72,12 @@
</menulist> </menulist>
</hbox> </hbox>
</groupbox> </groupbox>
<groupbox id="adBlockGroup" data-category="paneTenFourFox" hidden="true">
<caption><label>&TFFadBlock.title;</label></caption>
<vbox>
<checkbox id="tenFourFoxAdBlockCheckbox"
label="&TFFadBlock.prompt;"
preference="tenfourfox.adblock.enabled"/>
</vbox>
</groupbox>

View File

@ -1 +1 @@
45.15.0 45.16.0

View File

@ -1 +1 @@
Feature Parity Release 6 Feature Parity Release 7

View File

@ -705,7 +705,17 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
// blocking zdbb.net seems to be problematic // blocking zdbb.net seems to be problematic
// https://github.com/AdguardTeam/AdguardFilters/issues/1278 // https://github.com/AdguardTeam/AdguardFilters/issues/1278
// this may also be true for adziff.com
// don't block kxcdn
// https://github.com/EFForg/privacybadger/issues/1381
// miners
BLOK("coinhive.com") ||
BLOK("www.freecontent.stream") ||
BLOK("www.freecontent.stream.") ||
// other obnoxious things
BLOK("c.amazon-adsystem.com") || BLOK("c.amazon-adsystem.com") ||
BLOK("google-analytics.com") || BLOK("google-analytics.com") ||
@ -793,6 +803,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("cdn.segment.com") || BLOK("cdn.segment.com") ||
BLOK("cdn-gl.imrworldwide.com") || BLOK("cdn-gl.imrworldwide.com") ||
BLOK("secure-us.imrworldwide.com") ||
BLOK("secure-dcr.imrworldwide.com") || BLOK("secure-dcr.imrworldwide.com") ||
BLOK("labs-cdn.revcontent.com") || BLOK("labs-cdn.revcontent.com") ||
@ -800,6 +811,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("cdn.revcontent.com") || BLOK("cdn.revcontent.com") ||
BLOK("cas.criteo.com") || BLOK("cas.criteo.com") ||
BLOK("rtax.criteo.com") ||
BLOK("static.criteo.net") || BLOK("static.criteo.net") ||
BLOK("jsc.idealmedia.com") || BLOK("jsc.idealmedia.com") ||
@ -848,6 +860,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("www.npttech.com") || BLOK("www.npttech.com") ||
BLOK("fw.adsafeprotected.com") ||
BLOK("cdn.adsafeprotected.com") || BLOK("cdn.adsafeprotected.com") ||
BLOK("pixel.adsafeprotected.com") || BLOK("pixel.adsafeprotected.com") ||
BLOK("static.adsafeprotected.com") || BLOK("static.adsafeprotected.com") ||
@ -902,6 +915,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("se.monetate.net") || BLOK("se.monetate.net") ||
BLOK("ad.crwdcntrl.net") || BLOK("ad.crwdcntrl.net") ||
BLOK("bcp.crwdcntrl.net") ||
BLOK("tags.crwdcntrl.net") || BLOK("tags.crwdcntrl.net") ||
BLOK("cdn.nsstatic.net") || BLOK("cdn.nsstatic.net") ||
@ -917,6 +931,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("stats.cloudwp.io") || BLOK("stats.cloudwp.io") ||
BLOK("ap.lijit.com") || BLOK("ap.lijit.com") ||
BLOK("ce.lijit.com") ||
BLOK("tlx.3lift.com") || BLOK("tlx.3lift.com") ||
@ -982,14 +997,12 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("cdata.carambo.la") || BLOK("cdata.carambo.la") ||
BLOK("route.carambo.la") || BLOK("route.carambo.la") ||
BLOK("us-u.openx.net") ||
BLOK("uk-ads.openx.net") ||
BLOK("us-ads.openx.net") || BLOK("us-ads.openx.net") ||
BLOK("s-static.innovid.com") || BLOK("s-static.innovid.com") ||
// This is controversial, but I'm pretty sure we
// don't want this.
BLOK("coinhive.com") ||
BLOK("ustatik.com") || BLOK("ustatik.com") ||
BLOK("cdn.ustatik.com") || BLOK("cdn.ustatik.com") ||
@ -997,6 +1010,43 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("s.spoutable.com") || BLOK("s.spoutable.com") ||
BLOK("cdn.spoutable.com") || BLOK("cdn.spoutable.com") ||
BLOK("ads.pubmatic.com") ||
BLOK("track.netshelter.net") ||
BLOK("t.neodatagroup.com") ||
BLOK("ads.servebom.com") ||
BLOK("a.mailmunch.co") ||
BLOK("ads.adthrive.com") ||
BLOK("js.agkn.com") ||
BLOK("htl.bid") ||
BLOK("rtb.districtm.io") ||
BLOK("prebid.districtm.ca") ||
BLOK("speednetwork14.adk2.co") ||
BLOK("speednetwork14.adk2x.com") ||
BLOK("deloton.com") ||
BLOK("clickiocdn.com") ||
BLOK("clickioadve.com") ||
BLOK("cti.w55c.net") ||
BLOK("cdn.w55c.net") ||
BLOK("mobpushup.com") ||
BLOK("sc.iasds01.com") ||
BLOK("cdn.optimizely.com") ||
BLOK("cdn3.optimizely.com") ||
0) { 0) {
#undef BLOK #undef BLOK
// Yup. // Yup.

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files. # hardcoded milestones in the tree from these two files.
#-------------------------------------------------------- #--------------------------------------------------------
45.15.0 45.16.0

View File

@ -6630,9 +6630,17 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, int32_t aDelay, bool aMetaRefresh, nsI
*/ */
loadInfo->SetReferrer(mCurrentURI); loadInfo->SetReferrer(mCurrentURI);
/* Don't ever "guess" on which owner to use to avoid picking // Set the triggering pricipal to aPrincipal if available, or current
* the current owner. // document's principal otherwise.
*/ nsCOMPtr<nsIPrincipal> principal = aPrincipal;
if (!principal) {
nsCOMPtr<nsIDocument> doc = GetDocument();
if (MOZ_UNLIKELY(!doc)) {
return NS_ERROR_FAILURE;
}
principal = doc->NodePrincipal();
}
loadInfo->SetOwner(principal); // equivalent for SetTriggeringPrincipal
loadInfo->SetOwnerIsExplicit(true); loadInfo->SetOwnerIsExplicit(true);
/* Check if this META refresh causes a redirection /* Check if this META refresh causes a redirection
@ -6660,13 +6668,6 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, int32_t aDelay, bool aMetaRefresh, nsI
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
} }
// If the principal is null, the refresh will have a triggeringPrincipal
// derived from the referrer URI, or will be set to the system principal
// if there is no refererrer. See LoadURI()
if (aPrincipal) {
loadInfo->SetOwner(aPrincipal); // as called prior to bug 1286472
}
/* /*
* LoadURI(...) will cancel all refresh timers... This causes the * LoadURI(...) will cancel all refresh timers... This causes the
* Timer and its refreshData instance to be released... * Timer and its refreshData instance to be released...

View File

@ -19,9 +19,8 @@ interface nsIRefreshURI : nsISupports {
* *
* @param aUri The uri to refresh. * @param aUri The uri to refresh.
* @param aPrincipal The triggeringPrincipal for the refresh load * @param aPrincipal The triggeringPrincipal for the refresh load
* May be null, in which case a principal will be built based on the * May be null, in which case the principal of current document will be
* referrer URI of the previous docshell load, or will use the system * applied.
* principal when there is no referrer.
* @param aMillis The number of milliseconds to wait. * @param aMillis The number of milliseconds to wait.
* @param aRepeat Flag to indicate if the uri is to be * @param aRepeat Flag to indicate if the uri is to be
* repeatedly refreshed every aMillis milliseconds. * repeatedly refreshed every aMillis milliseconds.
@ -37,9 +36,8 @@ interface nsIRefreshURI : nsISupports {
* *
* @param aURI The URI to refresh. * @param aURI The URI to refresh.
* @param aPrincipal The triggeringPrincipal for the refresh load * @param aPrincipal The triggeringPrincipal for the refresh load
* May be null, in which case a principal will be built based on the * May be null, in which case the principal of current document will be
* referrer URI of the previous docshell load, or will use the system * applied.
* principal when there is no referrer.
* @param aMillis The number of milliseconds by which this refresh would * @param aMillis The number of milliseconds by which this refresh would
* be delayed if it were not being forced. * be delayed if it were not being forced.
* @param aMetaRefresh Flag to indicate if this is a meta refresh. * @param aMetaRefresh Flag to indicate if this is a meta refresh.
@ -70,9 +68,8 @@ interface nsIRefreshURI : nsISupports {
* *
* @param aBaseURI base URI to resolve refresh uri with. * @param aBaseURI base URI to resolve refresh uri with.
* @param aPrincipal The triggeringPrincipal for the refresh load * @param aPrincipal The triggeringPrincipal for the refresh load
* May be null, in which case a principal will be built based on the * May be null, in which case the principal of current document will be
* referrer URI of the previous docshell load, or will use the system * applied.
* principal when there is no referrer.
* @param aHeader The meta refresh header string. * @param aHeader The meta refresh header string.
*/ */
void setupRefreshURIFromHeader(in nsIURI aBaseURI, void setupRefreshURIFromHeader(in nsIURI aBaseURI,

View File

@ -0,0 +1,31 @@
/* -*- 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/. */
/*
* Definitions of supported tokens data types for nsDOMTokenList. This is in a
* separate header so Element.h can include it too.
*/
#ifndef mozilla_dom_DOMTokenListSupportedTokens_h
#define mozilla_dom_DOMTokenListSupportedTokens_h
namespace mozilla {
namespace dom {
// A single supported token.
typedef const char* const DOMTokenListSupportedToken;
// An array of supported tokens. This should end with a null
// DOMTokenListSupportedToken to indicate array termination. A null value for
// the DOMTokenListSupportedTokenArray means there is no definition of supported
// tokens for the given DOMTokenList. This should generally be a static table,
// or at least outlive the DOMTokenList whose constructor it's passed to.
typedef DOMTokenListSupportedToken* DOMTokenListSupportedTokenArray;
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_DOMTokenListSupportedTokens_h

View File

@ -44,7 +44,6 @@
#include "nsNameSpaceManager.h" #include "nsNameSpaceManager.h"
#include "nsContentList.h" #include "nsContentList.h"
#include "nsVariant.h" #include "nsVariant.h"
#include "nsDOMSettableTokenList.h"
#include "nsDOMTokenList.h" #include "nsDOMTokenList.h"
#include "nsXBLPrototypeBinding.h" #include "nsXBLPrototypeBinding.h"
#include "nsError.h" #include "nsError.h"
@ -3086,11 +3085,11 @@ Element::GetLinkTarget(nsAString& aTarget)
} }
static void static void
nsDOMSettableTokenListPropertyDestructor(void *aObject, nsIAtom *aProperty, nsDOMTokenListPropertyDestructor(void *aObject, nsIAtom *aProperty,
void *aPropertyValue, void *aData) void *aPropertyValue, void *aData)
{ {
nsDOMSettableTokenList* list = nsDOMTokenList* list =
static_cast<nsDOMSettableTokenList*>(aPropertyValue); static_cast<nsDOMTokenList*>(aPropertyValue);
NS_RELEASE(list); NS_RELEASE(list);
} }
@ -3113,8 +3112,9 @@ Element::HTMLSVGPropertiesToTraverseAndUnlink()
return sPropertiesToTraverseAndUnlink; return sPropertiesToTraverseAndUnlink;
} }
nsDOMSettableTokenList* nsDOMTokenList*
Element::GetTokenList(nsIAtom* aAtom) Element::GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens)
{ {
#ifdef DEBUG #ifdef DEBUG
nsIAtom*** props = nsIAtom*** props =
@ -3129,14 +3129,14 @@ Element::GetTokenList(nsIAtom* aAtom)
MOZ_ASSERT(found, "Trying to use an unknown tokenlist!"); MOZ_ASSERT(found, "Trying to use an unknown tokenlist!");
#endif #endif
nsDOMSettableTokenList* list = nullptr; nsDOMTokenList* list = nullptr;
if (HasProperties()) { if (HasProperties()) {
list = static_cast<nsDOMSettableTokenList*>(GetProperty(aAtom)); list = static_cast<nsDOMTokenList*>(GetProperty(aAtom));
} }
if (!list) { if (!list) {
list = new nsDOMSettableTokenList(this, aAtom); list = new nsDOMTokenList(this, aAtom, aSupportedTokens);
NS_ADDREF(list); NS_ADDREF(list);
SetProperty(aAtom, list, nsDOMSettableTokenListPropertyDestructor); SetProperty(aAtom, list, nsDOMTokenListPropertyDestructor);
} }
return list; return list;
} }
@ -3153,7 +3153,7 @@ Element::GetTokenList(nsIAtom* aAtom, nsIVariant** aResult)
nsresult nsresult
Element::SetTokenList(nsIAtom* aAtom, nsIVariant* aValue) Element::SetTokenList(nsIAtom* aAtom, nsIVariant* aValue)
{ {
nsDOMSettableTokenList* itemType = GetTokenList(aAtom); nsDOMTokenList* itemType = GetTokenList(aAtom);
nsAutoString string; nsAutoString string;
aValue->GetAsAString(string); aValue->GetAsAString(string);
ErrorResult rv; ErrorResult rv;

View File

@ -34,6 +34,7 @@
#include "nsAttrValue.h" #include "nsAttrValue.h"
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/DOMTokenListSupportedTokens.h"
#include "mozilla/dom/WindowBinding.h" #include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/ElementBinding.h" #include "mozilla/dom/ElementBinding.h"
#include "Units.h" #include "Units.h"
@ -44,7 +45,6 @@ class nsIURI;
class nsIScrollableFrame; class nsIScrollableFrame;
class nsAttrValueOrString; class nsAttrValueOrString;
class nsContentList; class nsContentList;
class nsDOMSettableTokenList;
class nsDOMTokenList; class nsDOMTokenList;
struct nsRect; struct nsRect;
class nsFocusManager; class nsFocusManager;
@ -1342,7 +1342,8 @@ protected:
*/ */
virtual void GetLinkTarget(nsAString& aTarget); virtual void GetLinkTarget(nsAString& aTarget);
nsDOMSettableTokenList* GetTokenList(nsIAtom* aAtom); nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
void GetTokenList(nsIAtom* aAtom, nsIVariant** aResult); void GetTokenList(nsIAtom* aAtom, nsIVariant** aResult);
nsresult SetTokenList(nsIAtom* aAtom, nsIVariant* aValue); nsresult SetTokenList(nsIAtom* aAtom, nsIVariant* aValue);

View File

@ -25,11 +25,11 @@
class ContentUnbinder; class ContentUnbinder;
class nsContentList; class nsContentList;
class nsDOMAttributeMap; class nsDOMAttributeMap;
class nsDOMTokenList;
class nsIControllers; class nsIControllers;
class nsICSSDeclaration; class nsICSSDeclaration;
class nsIDocument; class nsIDocument;
class nsDOMStringMap; class nsDOMStringMap;
class nsDOMTokenList;
class nsIURI; class nsIURI;
namespace mozilla { namespace mozilla {

View File

@ -0,0 +1,24 @@
/* -*- 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/. */
/* NOTE: no include guard; this file is meant to maybe be included multiple
times. It has a list of the sandbox keywords we support, with their
corresponding sandbox flags. */
#include "nsSandboxFlags.h"
// Each entry has the sandbox keyword as a string, the corresponding nsGkAtoms
// atom name, and the corresponding sandbox flags.
SANDBOX_KEYWORD("allow-same-origin", allowsameorigin, SANDBOXED_ORIGIN)
SANDBOX_KEYWORD("allow-forms", allowforms, SANDBOXED_FORMS)
SANDBOX_KEYWORD("allow-scripts", allowscripts,
SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES)
SANDBOX_KEYWORD("allow-top-navigation", allowtopnavigation,
SANDBOXED_TOPLEVEL_NAVIGATION)
SANDBOX_KEYWORD("allow-pointer-lock", allowpointerlock, SANDBOXED_POINTER_LOCK)
SANDBOX_KEYWORD("allow-orientation-lock", alloworientationlock,
SANDBOXED_ORIENTATION_LOCK)
SANDBOX_KEYWORD("allow-popups", allowpopups, SANDBOXED_AUXILIARY_NAVIGATION)

View File

@ -45,6 +45,7 @@ EXPORTS += [
'AutocompleteFieldList.h', 'AutocompleteFieldList.h',
'Crypto.h', 'Crypto.h',
'HTMLSplitOnSpacesTokenizer.h', 'HTMLSplitOnSpacesTokenizer.h',
'IframeSandboxKeywordList.h',
'mozAutoDocUpdate.h', 'mozAutoDocUpdate.h',
'mozFlushType.h', 'mozFlushType.h',
'nsAtomListUtils.h', 'nsAtomListUtils.h',
@ -74,6 +75,7 @@ EXPORTS += [
'nsDOMJSUtils.h', 'nsDOMJSUtils.h',
'nsDOMNavigationTiming.h', 'nsDOMNavigationTiming.h',
'nsDOMString.h', 'nsDOMString.h',
'nsDOMTokenList.h',
'nsFocusManager.h', 'nsFocusManager.h',
'nsFormData.h', 'nsFormData.h',
'nsFrameMessageManager.h', 'nsFrameMessageManager.h',
@ -174,6 +176,7 @@ EXPORTS.mozilla.dom += [
'DOMRect.h', 'DOMRect.h',
'DOMRequest.h', 'DOMRequest.h',
'DOMStringList.h', 'DOMStringList.h',
'DOMTokenListSupportedTokens.h',
'Element.h', 'Element.h',
'ElementInlines.h', 'ElementInlines.h',
'EventSource.h', 'EventSource.h',
@ -278,7 +281,6 @@ UNIFIED_SOURCES += [
'nsDOMNavigationTiming.cpp', 'nsDOMNavigationTiming.cpp',
'nsDOMScriptObjectFactory.cpp', 'nsDOMScriptObjectFactory.cpp',
'nsDOMSerializer.cpp', 'nsDOMSerializer.cpp',
'nsDOMSettableTokenList.cpp',
'nsDOMTokenList.cpp', 'nsDOMTokenList.cpp',
'nsDOMWindowList.cpp', 'nsDOMWindowList.cpp',
'nsFocusManager.cpp', 'nsFocusManager.cpp',

View File

@ -1362,19 +1362,13 @@ nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr)
| SANDBOXED_DOMAIN; | SANDBOXED_DOMAIN;
// Macro for updating the flag according to the keywords // Macro for updating the flag according to the keywords
#define IF_KEYWORD(atom, flags) \ #define SANDBOX_KEYWORD(string, atom, flags) \
if (sandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { out &= ~(flags); } if (sandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { out &= ~(flags); }
IF_KEYWORD(allowsameorigin, SANDBOXED_ORIGIN) #include "IframeSandboxKeywordList.h"
IF_KEYWORD(allowforms, SANDBOXED_FORMS)
IF_KEYWORD(allowscripts, SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES)
IF_KEYWORD(allowtopnavigation, SANDBOXED_TOPLEVEL_NAVIGATION)
IF_KEYWORD(allowpointerlock, SANDBOXED_POINTER_LOCK)
IF_KEYWORD(alloworientationlock, SANDBOXED_ORIENTATION_LOCK)
IF_KEYWORD(allowpopups, SANDBOXED_AUXILIARY_NAVIGATION)
return out; return out;
#undef IF_KEYWORD #undef SANDBOX_KEYWORD
} }
nsIBidiKeyboard* nsIBidiKeyboard*

View File

@ -9,20 +9,25 @@
*/ */
#include "nsDOMTokenList.h" #include "nsDOMTokenList.h"
#include "nsAttrValueInlines.h"
#include "nsDataHashtable.h"
#include "nsAttrValue.h" #include "nsAttrValue.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsError.h" #include "nsError.h"
#include "nsHashKeys.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/DOMTokenListBinding.h" #include "mozilla/dom/DOMTokenListBinding.h"
#include "mozilla/BloomFilter.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom) nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens)
: mElement(aElement), : mElement(aElement),
mAttrAtom(aAttrAtom) mAttrAtom(aAttrAtom),
mSupportedTokens(aSupportedTokens)
{ {
// We don't add a reference to our element. If it goes away, // We don't add a reference to our element. If it goes away,
// we'll be told to drop our reference // we'll be told to drop our reference
@ -50,6 +55,45 @@ nsDOMTokenList::GetParsedAttr()
return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue; return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue;
} }
void
nsDOMTokenList::RemoveDuplicates(const nsAttrValue* aAttr)
{
if (!aAttr || aAttr->Type() != nsAttrValue::eAtomArray) {
return;
}
BloomFilter<8, nsIAtom> filter;
nsAttrValue::AtomArray* array = aAttr->GetAtomArrayValue();
for (uint32_t i = 0; i < array->Length(); i++) {
nsIAtom* atom = array->ElementAt(i);
if (filter.mightContain(atom)) {
// Start again, with a hashtable
RemoveDuplicatesInternal(array, i);
return;
} else {
filter.add(atom);
}
}
}
void
nsDOMTokenList::RemoveDuplicatesInternal(nsAttrValue::AtomArray* aArray,
uint32_t aStart)
{
nsDataHashtable<nsPtrHashKey<nsIAtom>, bool> tokens;
for (uint32_t i = 0; i < aArray->Length(); i++) {
nsIAtom* atom = aArray->ElementAt(i);
// No need to check the hashtable below aStart
if (i >= aStart && tokens.Get(atom)) {
aArray->RemoveElementAt(i);
i--;
} else {
tokens.Put(atom, true);
}
}
}
uint32_t uint32_t
nsDOMTokenList::Length() nsDOMTokenList::Length()
{ {
@ -58,6 +102,7 @@ nsDOMTokenList::Length()
return 0; return 0;
} }
RemoveDuplicates(attr);
return attr->GetAtomCount(); return attr->GetAtomCount();
} }
@ -66,6 +111,13 @@ nsDOMTokenList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult)
{ {
const nsAttrValue* attr = GetParsedAttr(); const nsAttrValue* attr = GetParsedAttr();
if (!attr || aIndex >= static_cast<uint32_t>(attr->GetAtomCount())) {
aFound = false;
return;
}
RemoveDuplicates(attr);
if (attr && aIndex < static_cast<uint32_t>(attr->GetAtomCount())) { if (attr && aIndex < static_cast<uint32_t>(attr->GetAtomCount())) {
aFound = true; aFound = true;
attr->AtomAt(aIndex)->ToString(aResult); attr->AtomAt(aIndex)->ToString(aResult);
@ -74,6 +126,16 @@ nsDOMTokenList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult)
} }
} }
void
nsDOMTokenList::SetValue(const nsAString& aValue, ErrorResult& rv)
{
if (!mElement) {
return;
}
rv = mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
}
nsresult nsresult
nsDOMTokenList::CheckToken(const nsAString& aStr) nsDOMTokenList::CheckToken(const nsAString& aStr)
{ {
@ -130,10 +192,15 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
nsAutoString resultStr; nsAutoString resultStr;
if (aAttr) { if (aAttr) {
aAttr->ToString(resultStr); RemoveDuplicates(aAttr);
for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
if (i != 0) {
resultStr.AppendLiteral(" ");
}
resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
}
} }
bool oneWasAdded = false;
nsAutoTArray<nsString, 10> addedClasses; nsAutoTArray<nsString, 10> addedClasses;
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) { for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
@ -144,16 +211,11 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
continue; continue;
} }
if (oneWasAdded || if (!resultStr.IsEmpty()) {
(!resultStr.IsEmpty() &&
!nsContentUtils::IsHTMLWhitespace(resultStr.Last()))) {
resultStr.Append(' '); resultStr.Append(' ');
resultStr.Append(aToken);
} else {
resultStr.Append(aToken);
} }
resultStr.Append(aToken);
oneWasAdded = true;
addedClasses.AppendElement(aToken); addedClasses.AppendElement(aToken);
} }
@ -186,60 +248,20 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
{ {
MOZ_ASSERT(aAttr, "Need an attribute"); MOZ_ASSERT(aAttr, "Need an attribute");
nsAutoString input; RemoveDuplicates(aAttr);
aAttr->ToString(input);
nsAString::const_iterator copyStart, tokenStart, iter, end; nsAutoString resultStr;
input.BeginReading(iter); for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
input.EndReading(end); if (aTokens.Contains(nsDependentAtomString(aAttr->AtomAt(i)))) {
copyStart = iter; continue;
}
nsAutoString output; if (!resultStr.IsEmpty()) {
bool lastTokenRemoved = false; resultStr.AppendLiteral(" ");
}
while (iter != end) { resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
// skip whitespace.
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
++iter;
} }
if (iter == end) { mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
// At this point we're sure the last seen token (if any) wasn't to be
// removed. So the trailing spaces will need to be kept.
MOZ_ASSERT(!lastTokenRemoved, "How did this happen?");
output.Append(Substring(copyStart, end));
break;
}
tokenStart = iter;
do {
++iter;
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
if (aTokens.Contains(Substring(tokenStart, iter))) {
// Skip whitespace after the token, it will be collapsed.
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
++iter;
}
copyStart = iter;
lastTokenRemoved = true;
} else {
if (lastTokenRemoved && !output.IsEmpty()) {
MOZ_ASSERT(!nsContentUtils::IsHTMLWhitespace(output.Last()),
"Invalid last output token");
output.Append(char16_t(' '));
}
lastTokenRemoved = false;
output.Append(Substring(copyStart, iter));
copyStart = iter;
}
}
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
} }
void void
@ -299,6 +321,93 @@ nsDOMTokenList::Toggle(const nsAString& aToken,
return isPresent; return isPresent;
} }
void
nsDOMTokenList::Replace(const nsAString& aToken,
const nsAString& aNewToken,
ErrorResult& aError)
{
// Doing this here instead of using `CheckToken` because if aToken had invalid
// characters, and aNewToken is empty, the returned error should be a
// SyntaxError, not an InvalidCharacterError.
if (aNewToken.IsEmpty()) {
aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
}
aError = CheckToken(aToken);
if (aError.Failed()) {
return;
}
aError = CheckToken(aNewToken);
if (aError.Failed()) {
return;
}
const nsAttrValue* attr = GetParsedAttr();
if (!attr) {
return;
}
ReplaceInternal(attr, aToken, aNewToken);
}
void
nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
const nsAString& aToken,
const nsAString& aNewToken)
{
RemoveDuplicates(aAttr);
bool sawIt = false;
nsAutoString resultStr;
for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
if (aAttr->AtomAt(i)->Equals(aToken) ||
aAttr->AtomAt(i)->Equals(aNewToken)) {
if (sawIt) {
// We keep only the first
continue;
}
sawIt = true;
if (!resultStr.IsEmpty()) {
resultStr.AppendLiteral(" ");
}
resultStr.Append(aNewToken);
continue;
}
if (!resultStr.IsEmpty()) {
resultStr.AppendLiteral(" ");
}
resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
}
if (sawIt) {
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
}
}
bool
nsDOMTokenList::Supports(const nsAString& aToken,
ErrorResult& aError)
{
if (!mSupportedTokens) {
aError.ThrowTypeError<MSG_TOKENLIST_NO_SUPPORTED_TOKENS>(
mElement->LocalName(),
nsDependentAtomString(mAttrAtom));
return false;
}
for (DOMTokenListSupportedToken* supportedToken = mSupportedTokens;
*supportedToken;
++supportedToken) {
if (aToken.LowerCaseEqualsASCII(*supportedToken)) {
return true;
}
}
return false;
}
void void
nsDOMTokenList::Stringify(nsAString& aResult) nsDOMTokenList::Stringify(nsAString& aResult)
{ {

View File

@ -13,9 +13,11 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsDOMString.h" #include "nsDOMString.h"
#include "nsDOMString.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/DOMTokenListSupportedTokens.h"
namespace mozilla { namespace mozilla {
class ErrorResult; class ErrorResult;
@ -26,7 +28,7 @@ class nsAttrValue;
class nsIAtom; class nsIAtom;
// nsISupports must be on the primary inheritance chain // nsISupports must be on the primary inheritance chain
// because nsDOMSettableTokenList is traversed by Element.
class nsDOMTokenList : public nsISupports, class nsDOMTokenList : public nsISupports,
public nsWrapperCache public nsWrapperCache
{ {
@ -37,7 +39,8 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList)
nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom); nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom,
const mozilla::dom::DOMTokenListSupportedTokenArray = nullptr);
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override; virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
@ -46,6 +49,7 @@ public:
return mElement; return mElement;
} }
void RemoveDuplicates(const nsAttrValue* aAttr);
uint32_t Length(); uint32_t Length();
void Item(uint32_t aIndex, nsAString& aResult) void Item(uint32_t aIndex, nsAString& aResult)
{ {
@ -63,9 +67,17 @@ public:
void Remove(const nsAString& aToken, mozilla::ErrorResult& aError); void Remove(const nsAString& aToken, mozilla::ErrorResult& aError);
void Remove(const nsTArray<nsString>& aTokens, void Remove(const nsTArray<nsString>& aTokens,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
void Replace(const nsAString& aToken,
const nsAString& aNewToken,
mozilla::ErrorResult& aError);
bool Toggle(const nsAString& aToken, bool Toggle(const nsAString& aToken,
const mozilla::dom::Optional<bool>& force, const mozilla::dom::Optional<bool>& force,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
bool Supports(const nsAString& aToken,
mozilla::ErrorResult& aError);
void GetValue(nsAString& aResult) { Stringify(aResult); }
void SetValue(const nsAString& aValue, mozilla::ErrorResult& rv);
void Stringify(nsAString& aResult); void Stringify(nsAString& aResult);
protected: protected:
@ -73,14 +85,20 @@ protected:
nsresult CheckToken(const nsAString& aStr); nsresult CheckToken(const nsAString& aStr);
nsresult CheckTokens(const nsTArray<nsString>& aStr); nsresult CheckTokens(const nsTArray<nsString>& aStr);
void RemoveDuplicatesInternal(nsTArray<nsCOMPtr<nsIAtom>>* aArray,
uint32_t aStart);
void AddInternal(const nsAttrValue* aAttr, void AddInternal(const nsAttrValue* aAttr,
const nsTArray<nsString>& aTokens); const nsTArray<nsString>& aTokens);
void RemoveInternal(const nsAttrValue* aAttr, void RemoveInternal(const nsAttrValue* aAttr,
const nsTArray<nsString>& aTokens); const nsTArray<nsString>& aTokens);
void ReplaceInternal(const nsAttrValue* aAttr,
const nsAString& aToken,
const nsAString& aNewToken);
inline const nsAttrValue* GetParsedAttr(); inline const nsAttrValue* GetParsedAttr();
nsCOMPtr<Element> mElement; nsCOMPtr<Element> mElement;
nsCOMPtr<nsIAtom> mAttrAtom; nsCOMPtr<nsIAtom> mAttrAtom;
const mozilla::dom::DOMTokenListSupportedTokenArray mSupportedTokens;
}; };
#endif // nsDOMTokenList_h___ #endif // nsDOMTokenList_h___

View File

@ -562,7 +562,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
} }
if (!aDontSerializeRoot) { if (!aDontSerializeRoot) {
rv = SerializeNodeEnd(node, aStr); rv = SerializeNodeEnd(maybeFixedNode, aStr);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }

View File

@ -347,17 +347,32 @@ public:
} }
/** /**
* Return the base URI for relative URIs in the document (the document uri * Return the fallback base URL for this document, as defined in the HTML
* unless it's overridden by SetBaseURI, HTML <base> tags, etc.). The * specification. Note that this can return null if there is no document URI.
* returned URI could be null if there is no document URI. If the document *
* is a srcdoc document, return the parent document's base URL. * XXXbz: This doesn't implement the bits for about:blank yet.
*/ */
nsIURI* GetDocBaseURI() const nsIURI* GetFallbackBaseURI() const
{ {
if (mIsSrcdocDocument && mParentDocument) { if (mIsSrcdocDocument && mParentDocument) {
return mParentDocument->GetDocBaseURI(); return mParentDocument->GetDocBaseURI();
} }
return mDocumentBaseURI ? mDocumentBaseURI : mDocumentURI; return mDocumentURI;
}
/**
* Return the base URI for relative URIs in the document (the document uri
* unless it's overridden by SetBaseURI, HTML <base> tags, etc.). The
* returned URI could be null if there is no document URI. If the document is
* a srcdoc document and has no explicit base URL, return the parent
* document's base URL.
*/
nsIURI* GetDocBaseURI() const
{
if (mDocumentBaseURI) {
return mDocumentBaseURI;
}
return GetFallbackBaseURI();
} }
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override; virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;

View File

@ -93,16 +93,16 @@ const size_t gStackSize = 8192;
// The amount of time we wait from the first request to GC to actually // The amount of time we wait from the first request to GC to actually
// doing the first GC. // doing the first GC.
#define NS_FIRST_GC_DELAY 10000 // ms #define NS_FIRST_GC_DELAY 30000 // ms
#define NS_FULL_GC_DELAY 60000 // ms #define NS_FULL_GC_DELAY 100000 // ms
// The default amount of time to wait from the user being idle to starting a // The default amount of time to wait from the user being idle to starting a
// shrinking GC. // shrinking GC.
#define NS_DEAULT_INACTIVE_GC_DELAY 300000 // ms #define NS_DEAULT_INACTIVE_GC_DELAY 300000 // ms
// Maximum amount of time that should elapse between incremental GC slices // Maximum amount of time that should elapse between incremental GC slices
#define NS_INTERSLICE_GC_DELAY 100 // ms #define NS_INTERSLICE_GC_DELAY 1000 // ms
// If we haven't painted in 100ms, we allow for a longer GC budget // If we haven't painted in 100ms, we allow for a longer GC budget
#define NS_INTERSLICE_GC_BUDGET 40 // ms #define NS_INTERSLICE_GC_BUDGET 40 // ms
@ -111,13 +111,13 @@ const size_t gStackSize = 8192;
// and doing the actual CC. // and doing the actual CC.
#define NS_CC_DELAY 6000 // ms #define NS_CC_DELAY 6000 // ms
#define NS_CC_SKIPPABLE_DELAY 250 // ms #define NS_CC_SKIPPABLE_DELAY 2500 // ms
// Maximum amount of time that should elapse between incremental CC slices // Maximum amount of time that should elapse between incremental CC slices
static const int64_t kICCIntersliceDelay = 32; // ms static const int64_t kICCIntersliceDelay = 1000; // ms
// Time budget for an incremental CC slice // Time budget for an incremental CC slice
static const int64_t kICCSliceBudget = 5; // ms static const int64_t kICCSliceBudget = 100; // ms
// Maximum total duration for an ICC // Maximum total duration for an ICC
static const uint32_t kMaxICCDuration = 2000; // ms static const uint32_t kMaxICCDuration = 2000; // ms
@ -125,7 +125,7 @@ static const uint32_t kMaxICCDuration = 2000; // ms
// Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
// objects in the purple buffer. // objects in the purple buffer.
#define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min #define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
#define NS_CC_FORCED_PURPLE_LIMIT 10 #define NS_CC_FORCED_PURPLE_LIMIT 9
// Don't allow an incremental GC to lock out the CC for too long. // Don't allow an incremental GC to lock out the CC for too long.
#define NS_MAX_CC_LOCKEDOUT_TIME (30 * PR_USEC_PER_SEC) // 30 seconds #define NS_MAX_CC_LOCKEDOUT_TIME (30 * PR_USEC_PER_SEC) // 30 seconds

View File

@ -150,6 +150,8 @@ nsStyleLinkElement::IsImportEnabled()
static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal) static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
{ {
// Keep this in sync with sRelValues in HTMLLinkElement.cpp
// XXX: "icon" and "search" are supported, but not listed here.
if (aLink.EqualsLiteral("prefetch")) if (aLink.EqualsLiteral("prefetch"))
return nsStyleLinkElement::ePREFETCH; return nsStyleLinkElement::ePREFETCH;
else if (aLink.EqualsLiteral("dns-prefetch")) else if (aLink.EqualsLiteral("dns-prefetch"))

View File

@ -345,22 +345,22 @@ nsTextFragment::Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBi
// Should we optimize for aData.Length() == 0? // Should we optimize for aData.Length() == 0?
CheckedUint32 length = mState.mLength; // FYI: Don't use CheckedInt in this method since here is very hot path
length += aLength; // in some performance tests.
if (MOZ_UNLIKELY(NS_MAX_TEXT_FRAGMENT_LENGTH - mState.mLength < aLength)) {
if (!length.isValid()) { return false; // Would be overflown if we'd keep handling.
return false;
} }
if (mState.mIs2b) { if (mState.mIs2b) {
length *= sizeof(char16_t); size_t size = mState.mLength + aLength;
if (!length.isValid()) { if (MOZ_UNLIKELY(SIZE_MAX / sizeof(char16_t) < size)) {
return false; return false; // Would be overflown if we'd keep handling.
} }
size *= sizeof(char16_t);
// Already a 2-byte string so the result will be too // Already a 2-byte string so the result will be too
char16_t* buff = static_cast<char16_t*>(realloc(m2b, length.value())); char16_t* buff = static_cast<char16_t*>(realloc(m2b, size));
if (!buff) { if (MOZ_UNLIKELY(!buff)) {
return false; return false;
} }
@ -379,15 +379,16 @@ nsTextFragment::Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBi
int32_t first16bit = FirstNon8Bit(aBuffer, aBuffer + aLength); int32_t first16bit = FirstNon8Bit(aBuffer, aBuffer + aLength);
if (first16bit != -1) { // aBuffer contains no non-8bit character if (first16bit != -1) { // aBuffer contains no non-8bit character
length *= sizeof(char16_t); size_t size = mState.mLength + aLength;
if (!length.isValid()) { if (MOZ_UNLIKELY((SIZE_MAX / sizeof(char16_t)) < size)) {
return false; return false; // Would be overflown if we'd keep handling.
} }
size *= sizeof(char16_t);
// The old data was 1-byte, but the new is not so we have to expand it // The old data was 1-byte, but the new is not so we have to expand it
// all to 2-byte // all to 2-byte
char16_t* buff = static_cast<char16_t*>(malloc(length.value())); char16_t* buff = static_cast<char16_t*>(malloc(size));
if (!buff) { if (MOZ_UNLIKELY(!buff)) {
return false; return false;
} }
@ -414,16 +415,18 @@ nsTextFragment::Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBi
} }
// The new and the old data is all 1-byte // The new and the old data is all 1-byte
size_t size = mState.mLength + aLength;
MOZ_ASSERT(sizeof(char) == 1);
char* buff; char* buff;
if (mState.mInHeap) { if (mState.mInHeap) {
buff = static_cast<char*>(realloc(const_cast<char*>(m1b), length.value())); buff = static_cast<char*>(realloc(const_cast<char*>(m1b), size));
if (!buff) { if (MOZ_UNLIKELY(!buff)) {
return false; return false;
} }
} }
else { else {
buff = static_cast<char*>(malloc(length.value())); buff = static_cast<char*>(malloc(size));
if (!buff) { if (MOZ_UNLIKELY(!buff)) {
return false; return false;
} }
@ -461,21 +464,8 @@ void
nsTextFragment::UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength) nsTextFragment::UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength)
{ {
if (mState.mIs2b && !mState.mIsBidi) { if (mState.mIs2b && !mState.mIsBidi) {
const char16_t* cp = aBuffer; if (HasRTLChars(aBuffer, aLength)) {
const char16_t* end = cp + aLength;
while (cp < end) {
char16_t ch1 = *cp++;
uint32_t utf32Char = ch1;
if (NS_IS_HIGH_SURROGATE(ch1) &&
cp < end &&
NS_IS_LOW_SURROGATE(*cp)) {
char16_t ch2 = *cp++;
utf32Char = SURROGATE_TO_UCS4(ch1, ch2);
}
if (UTF32_CHAR_IS_BIDI(utf32Char) || IsBidiControl(utf32Char)) {
mState.mIsBidi = true; mState.mIsBidi = true;
break;
}
} }
} }
} }

View File

@ -213,9 +213,13 @@ public:
uint32_t mInHeap : 1; uint32_t mInHeap : 1;
uint32_t mIs2b : 1; uint32_t mIs2b : 1;
uint32_t mIsBidi : 1; uint32_t mIsBidi : 1;
// Note that when you change the bits of mLength, you also need to change
// NS_MAX_TEXT_FRAGMENT_LENGTH.
uint32_t mLength : 29; uint32_t mLength : 29;
}; };
#define NS_MAX_TEXT_FRAGMENT_LENGTH (static_cast<uint32_t>(0x1FFFFFFF))
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private: private:

View File

@ -441,10 +441,6 @@ DOMInterfaces = {
'implicitJSContext': [ 'then' ], 'implicitJSContext': [ 'then' ],
}, },
'DOMSettableTokenList': {
'nativeType': 'nsDOMSettableTokenList',
},
'DOMStringMap': { 'DOMStringMap': {
'nativeType': 'nsDOMStringMap' 'nativeType': 'nsDOMStringMap'
}, },

View File

@ -1136,11 +1136,13 @@ class CGHeaders(CGWrapper):
if desc.interface.maplikeOrSetlikeOrIterable: if desc.interface.maplikeOrSetlikeOrIterable:
# We need ToJSValue.h for maplike/setlike type conversions # We need ToJSValue.h for maplike/setlike type conversions
bindingHeaders.add("mozilla/dom/ToJSValue.h") bindingHeaders.add("mozilla/dom/ToJSValue.h")
# Add headers for the key and value types of the maplike, since # Add headers for the key and value types of the
# they'll be needed for convenience functions # maplike/setlike/iterable, since they'll be needed for
# convenience functions
if desc.interface.maplikeOrSetlikeOrIterable.hasKeyType():
addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType, addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType,
desc, None)) desc, None))
if desc.interface.maplikeOrSetlikeOrIterable.valueType: if desc.interface.maplikeOrSetlikeOrIterable.hasValueType():
addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.valueType, addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.valueType,
desc, None)) desc, None))
@ -2269,34 +2271,50 @@ class MethodDefiner(PropertyDefiner):
"condition": MemberCondition() "condition": MemberCondition()
}) })
# Generate the maplike/setlike iterator, if one wasn't already # Generate the keys/values/entries aliases for value iterables.
# generated by a method. If we already have an @@iterator symbol, fail. maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
if descriptor.interface.maplikeOrSetlikeOrIterable: if (not static and
if hasIterator(methods, self.regular): not unforgeable and
raise TypeError("Cannot have maplike/setlike/iterable interface with " maplikeOrSetlikeOrIterable and
"other members that generate @@iterator " maplikeOrSetlikeOrIterable.isIterable() and
"on interface %s, such as indexed getters " maplikeOrSetlikeOrIterable.isValueIterator()):
"or aliased functions." % # Add our keys/values/entries/forEach
self.descriptor.interface.identifier.name)
for m in methods:
if (m.isMaplikeOrSetlikeOrIterableMethod() and
(((m.maplikeOrSetlikeOrIterable.isMaplike() or
(m.maplikeOrSetlikeOrIterable.isIterable() and
m.maplikeOrSetlikeOrIterable.hasValueType())) and
m.identifier.name == "entries") or
(((m.maplikeOrSetlikeOrIterable.isSetlike() or
(m.maplikeOrSetlikeOrIterable.isIterable() and
not m.maplikeOrSetlikeOrIterable.hasValueType()))) and
m.identifier.name == "values"))):
self.regular.append({ self.regular.append({
"name": "@@iterator", "name": "keys",
"methodName": m.identifier.name, "methodInfo": False,
"length": methodLength(m), "selfHostedName": "ArrayKeys",
"flags": "0", "length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m, "condition": PropertyDefiner.getControllingCondition(m,
descriptor), descriptor)
})
self.regular.append({
"name": "values",
"methodInfo": False,
"selfHostedName": "ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "entries",
"methodInfo": False,
"selfHostedName": "ArrayEntries",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "forEach",
"methodInfo": False,
"selfHostedName": "ArrayForEach",
"length": 1,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
}) })
break
if not static: if not static:
stringifier = descriptor.operations['Stringifier'] stringifier = descriptor.operations['Stringifier']
@ -13008,6 +13026,7 @@ class CGForwardDeclarations(CGWrapper):
# arguments to helper functions, and they'll need to be forward # arguments to helper functions, and they'll need to be forward
# declared in the header. # declared in the header.
if d.interface.maplikeOrSetlikeOrIterable: if d.interface.maplikeOrSetlikeOrIterable:
if d.interface.maplikeOrSetlikeOrIterable.hasKeyType():
builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType, builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType,
config) config)
if d.interface.maplikeOrSetlikeOrIterable.hasValueType(): if d.interface.maplikeOrSetlikeOrIterable.hasValueType():
@ -15735,6 +15754,31 @@ class CGIterableMethodGenerator(CGGeneric):
using CGCallGenerator. using CGCallGenerator.
""" """
def __init__(self, descriptor, iterable, methodName): def __init__(self, descriptor, iterable, methodName):
if methodName == "forEach":
CGGeneric.__init__(self, fill(
"""
if (!JS::IsCallable(arg0)) {
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of ${ifaceName}.forEach");
return false;
}
JS::AutoValueArray<3> callArgs(cx);
callArgs[2].setObject(*obj);
JS::Rooted<JS::Value> ignoredReturnVal(cx);
for (size_t i = 0; i < self->GetIterableLength(); ++i) {
if (!ToJSValue(cx, self->GetValueAtIndex(i), callArgs[0])) {
return false;
}
if (!ToJSValue(cx, self->GetKeyAtIndex(i), callArgs[1])) {
return false;
}
if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
&ignoredReturnVal)) {
return false;
}
}
""",
ifaceName=descriptor.interface.identifier.name))
return
CGGeneric.__init__(self, fill( CGGeneric.__init__(self, fill(
""" """
typedef ${iterClass} itrType; typedef ${iterClass} itrType;

View File

@ -893,8 +893,5 @@ def getAllTypes(descriptors, dictionaries, callbacks):
def iteratorNativeType(descriptor): def iteratorNativeType(descriptor):
assert descriptor.interface.isIterable() assert descriptor.interface.isIterable()
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
if iterableDecl.valueType is None: assert iterableDecl.isPairIterator()
iterClass = "OneTypeIterableIterator" return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
else:
iterClass = "TwoTypeIterableIterator"
return "mozilla::dom::%s<%s>" % (iterClass, descriptor.nativeType)

View File

@ -92,3 +92,4 @@ MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.") MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.") MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer") MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")

View File

@ -6,19 +6,17 @@
/** /**
* The IterableIterator class is used for WebIDL interfaces that have a * The IterableIterator class is used for WebIDL interfaces that have a
* iterable<> member defined. It handles the ES6 Iterator-like functions that * iterable<> member defined with two types (so a pair iterator). It handles
* are generated for the iterable interface. * the ES6 Iterator-like functions that are generated for the iterable
* interface.
* *
* For iterable interfaces, the implementation class will need to * For iterable interfaces with a pair iterator, the implementation class will
* implement these two functions: * need to implement these two functions:
* *
* - size_t GetIterableLength() * - size_t GetIterableLength()
* - Returns the number of elements available to iterate over * - Returns the number of elements available to iterate over
* - [type] GetValueAtIndex(size_t index) * - [type] GetValueAtIndex(size_t index)
* - Returns the value at the requested index. * - Returns the value at the requested index.
*
* If this is a two-type iterator, then the implementation class will also need to implement:
*
* - [type] GetKeyAtIndex(size_t index) * - [type] GetKeyAtIndex(size_t index)
* - Returns the key at the requested index * - Returns the key at the requested index
* *
@ -60,13 +58,77 @@ protected:
}; };
template <typename T> template <typename T>
class IterableIterator : public IterableIteratorBase class IterableIterator final : public IterableIteratorBase
{ {
public: public:
explicit IterableIterator(T* aIterableObj) typedef bool (*WrapFunc)(JSContext* aCx,
IterableIterator<T>* aObject,
JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aReflector);
explicit IterableIterator(T* aIterableObj,
IterableIteratorType aIteratorType,
WrapFunc aWrapFunc)
: mIterableObj(aIterableObj) : mIterableObj(aIterableObj)
, mIteratorType(aIteratorType)
, mWrapFunc(aWrapFunc)
, mIndex(0)
{ {
MOZ_ASSERT(mIterableObj); MOZ_ASSERT(mIterableObj);
MOZ_ASSERT(mWrapFunc);
}
void
Next(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv)
{
JS::Rooted<JS::Value> value(aCx, JS::UndefinedValue());
if (mIndex >= this->mIterableObj->GetIterableLength()) {
DictReturn(aCx, aResult, true, value, aRv);
return;
}
switch (mIteratorType) {
case IterableIteratorType::Keys:
{
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
DictReturn(aCx, aResult, false, value, aRv);
break;
}
case IterableIteratorType::Values:
{
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
DictReturn(aCx, aResult, false, value, aRv);
break;
}
case IterableIteratorType::Entries:
{
JS::Rooted<JS::Value> key(aCx);
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &key)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
KeyAndValueReturn(aCx, key, value, aResult, aRv);
break;
}
default:
MOZ_CRASH("Invalid iterator type!");
}
++mIndex;
}
bool
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aObj)
{
return (*mWrapFunc)(aCx, this, aGivenProto, aObj);
} }
protected: protected:
@ -128,161 +190,6 @@ protected:
// Binding Implementation object that we're iterating over. // Binding Implementation object that we're iterating over.
RefPtr<T> mIterableObj; RefPtr<T> mIterableObj;
};
template<typename T>
class OneTypeIterableIterator final : public IterableIterator<T>
{
public:
typedef typename IterableIterator<T>::IterableIteratorType IterableIteratorType;
using IterableIterator<T>::DictReturn;
using IterableIterator<T>::KeyAndValueReturn;
typedef bool (*WrapFunc)(JSContext* aCx,
OneTypeIterableIterator<T>* aObject,
JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aReflector);
OneTypeIterableIterator(T* aIterableObj,
IterableIteratorType aIteratorType,
WrapFunc aWrapFunc)
: IterableIterator<T>(aIterableObj)
, mIteratorType(aIteratorType)
, mWrapFunc(aWrapFunc)
, mIndex(0)
{
MOZ_ASSERT(mWrapFunc);
}
void
Next(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv)
{
JS::Rooted<JS::Value> value(aCx, JS::UndefinedValue());
if (mIndex >= this->mIterableObj->GetIterableLength()) {
DictReturn(aCx, aResult, true, value, aRv);
return;
}
switch (mIteratorType) {
case IterableIteratorType::Keys:
case IterableIteratorType::Values:
{
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
DictReturn(aCx, aResult, false, value, aRv);
break;
}
case IterableIteratorType::Entries:
{
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
KeyAndValueReturn(aCx, value, value, aResult, aRv);
break;
}
default:
MOZ_CRASH("Invalid iterator type!");
}
++mIndex;
}
bool
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aObj)
{
return (*mWrapFunc)(aCx, this, aGivenProto, aObj);
}
protected:
virtual ~OneTypeIterableIterator() {}
// Tells whether this is a key, value, or entries iterator.
IterableIteratorType mIteratorType;
// Function pointer to binding-type-specific Wrap() call for this iterator.
WrapFunc mWrapFunc;
// Current index of iteration.
uint32_t mIndex;
};
template<typename T>
class TwoTypeIterableIterator final : public IterableIterator<T>
{
public:
typedef typename IterableIterator<T>::IterableIteratorType IterableIteratorType;
using IterableIterator<T>::DictReturn;
using IterableIterator<T>::KeyAndValueReturn;
typedef bool (*WrapFunc)(JSContext* aCx,
TwoTypeIterableIterator<T>* aObject,
JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aReflector);
TwoTypeIterableIterator(T* aIterableObj, IterableIteratorType aIteratorType,
WrapFunc aWrapFunc)
: IterableIterator<T>(aIterableObj)
, mIteratorType(aIteratorType)
, mWrapFunc(aWrapFunc)
, mIndex(0)
{
MOZ_ASSERT(mWrapFunc);
}
void
Next(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv)
{
JS::Rooted<JS::Value> value(aCx, JS::UndefinedValue());
if (mIndex >= this->mIterableObj->GetIterableLength()) {
DictReturn(aCx, aResult, true, value, aRv);
return;
}
switch (mIteratorType) {
case IterableIteratorType::Keys:
{
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
DictReturn(aCx, aResult, false, value, aRv);
break;
}
case IterableIteratorType::Values:
{
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
DictReturn(aCx, aResult, false, value, aRv);
break;
}
case IterableIteratorType::Entries:
{
JS::Rooted<JS::Value> key(aCx);
if (!ToJSValue(aCx, this->mIterableObj->GetKeyAtIndex(mIndex), &key)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!ToJSValue(aCx, this->mIterableObj->GetValueAtIndex(mIndex), &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
KeyAndValueReturn(aCx, key, value, aResult, aRv);
break;
}
default:
MOZ_CRASH("Invalid iterator type!");
}
++mIndex;
}
bool
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aObj)
{
return (*mWrapFunc)(aCx, this, aGivenProto, aObj);
}
protected:
virtual ~TwoTypeIterableIterator() {}
// Tells whether this is a key, value, or entries iterator. // Tells whether this is a key, value, or entries iterator.
IterableIteratorType mIteratorType; IterableIteratorType mIteratorType;
// Function pointer to binding-type-specific Wrap() call for this iterator. // Function pointer to binding-type-specific Wrap() call for this iterator.

View File

@ -1089,7 +1089,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
def validate(self): def validate(self):
# We don't support consequential unforgeable interfaces. Need to check # We don't support consequential unforgeable interfaces. Need to check
# this here, becaue in finish() an interface might not know yet that # this here, because in finish() an interface might not know yet that
# it's consequential. # it's consequential.
if self.getExtendedAttribute("Unforgeable") and self.isConsequential(): if self.getExtendedAttribute("Unforgeable") and self.isConsequential():
raise WebIDLError( raise WebIDLError(
@ -1108,6 +1108,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
self.identifier.name, self.identifier.name,
locations) locations)
indexedGetter = None
hasLengthAttribute = False
for member in self.members: for member in self.members:
member.validate() member.validate()
@ -1118,8 +1120,13 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
[self.location, member.location]) [self.location, member.location])
# Check that PutForwards refers to another attribute and that no # Check that PutForwards refers to another attribute and that no
# cycles exist in forwarded assignments. # cycles exist in forwarded assignments. Also check for a
# integer-typed "length" attribute.
if member.isAttr(): if member.isAttr():
if (member.identifier.name == "length" and
member.type.isInteger()):
hasLengthAttribute = True
iface = self iface = self
attr = member attr = member
putForwards = attr.getExtendedAttribute("PutForwards") putForwards = attr.getExtendedAttribute("PutForwards")
@ -1157,8 +1164,11 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
putForwards = attr.getExtendedAttribute("PutForwards") putForwards = attr.getExtendedAttribute("PutForwards")
# Check that the name of an [Alias] doesn't conflict with an # Check that the name of an [Alias] doesn't conflict with an
# interface member. # interface member and whether we support indexed properties.
if member.isMethod(): if member.isMethod():
if member.isGetter() and member.isIndexed():
indexedGetter = member
for alias in member.aliases: for alias in member.aliases:
if self.isOnGlobalProtoChain(): if self.isOnGlobalProtoChain():
raise WebIDLError("[Alias] must not be used on a " raise WebIDLError("[Alias] must not be used on a "
@ -1219,6 +1229,35 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
"exposed conditionally", "exposed conditionally",
[self.location]) [self.location])
# Value iterators are only allowed on interfaces with indexed getters,
# and pair iterators are only allowed on interfaces without indexed
# getters.
if self.isIterable():
iterableDecl = self.maplikeOrSetlikeOrIterable
if iterableDecl.isValueIterator():
if not indexedGetter:
raise WebIDLError("Interface with value iterator does not "
"support indexed properties",
[self.location])
if iterableDecl.valueType != indexedGetter.signatures()[0][0]:
raise WebIDLError("Iterable type does not match indexed "
"getter type",
[iterableDecl.location,
indexedGetter.location])
if not hasLengthAttribute:
raise WebIDLError('Interface with value iterator does not '
'have an integer-typed "length" attribute',
[self.location])
else:
assert iterableDecl.isPairIterator()
if indexedGetter:
raise WebIDLError("Interface with pair iterator supports "
"indexed properties",
[self.location, iterableDecl.location,
indexedGetter.location])
def isInterface(self): def isInterface(self):
return True return True
@ -3408,7 +3447,10 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind):
IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) IDLInterfaceMember.__init__(self, location, identifier, ifaceKind)
if keyType is not None:
assert isinstance(keyType, IDLType) assert isinstance(keyType, IDLType)
else:
assert valueType is not None
assert ifaceType in ['maplike', 'setlike', 'iterable'] assert ifaceType in ['maplike', 'setlike', 'iterable']
if valueType is not None: if valueType is not None:
assert isinstance(valueType, IDLType) assert isinstance(valueType, IDLType)
@ -3427,6 +3469,9 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
def isIterable(self): def isIterable(self):
return self.maplikeOrSetlikeOrIterableType == "iterable" return self.maplikeOrSetlikeOrIterableType == "iterable"
def hasKeyType(self):
return self.keyType is not None
def hasValueType(self): def hasValueType(self):
return self.valueType is not None return self.valueType is not None
@ -3451,7 +3496,8 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
[self.location, member.location]) [self.location, member.location])
def addMethod(self, name, members, allowExistingOperations, returnType, args=[], def addMethod(self, name, members, allowExistingOperations, returnType, args=[],
chromeOnly=False, isPure=False, affectsNothing=False, newObject=False): chromeOnly=False, isPure=False, affectsNothing=False, newObject=False,
isIteratorAlias=False):
""" """
Create an IDLMethod based on the parameters passed in. Create an IDLMethod based on the parameters passed in.
@ -3511,16 +3557,20 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
if newObject: if newObject:
method.addExtendedAttributes( method.addExtendedAttributes(
[IDLExtendedAttribute(self.location, ("NewObject",))]) [IDLExtendedAttribute(self.location, ("NewObject",))])
if isIteratorAlias:
method.addExtendedAttributes(
[IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))])
members.append(method) members.append(method)
def resolve(self, parentScope): def resolve(self, parentScope):
if self.keyType:
self.keyType.resolveType(parentScope) self.keyType.resolveType(parentScope)
if self.valueType: if self.valueType:
self.valueType.resolveType(parentScope) self.valueType.resolveType(parentScope)
def finish(self, scope): def finish(self, scope):
IDLInterfaceMember.finish(self, scope) IDLInterfaceMember.finish(self, scope)
if not self.keyType.isComplete(): if self.keyType and not self.keyType.isComplete():
t = self.keyType.complete(scope) t = self.keyType.complete(scope)
assert not isinstance(t, IDLUnresolvedType) assert not isinstance(t, IDLUnresolvedType)
@ -3542,9 +3592,23 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
IDLInterfaceMember.handleExtendedAttribute(self, attr) IDLInterfaceMember.handleExtendedAttribute(self, attr)
def _getDependentObjects(self): def _getDependentObjects(self):
deps = set()
if self.keyType:
deps.add(self.keyType)
if self.valueType: if self.valueType:
return set([self.keyType, self.valueType]) deps.add(self.valueType)
return set([self.keyType]) return deps
def getForEachArguments(self):
return [IDLArgument(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
"callback"),
BuiltinTypes[IDLBuiltinType.Types.object]),
IDLArgument(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
"thisArg"),
BuiltinTypes[IDLBuiltinType.Types.any],
optional=True)]
# Iterable adds ES6 iterator style functions and traits # Iterable adds ES6 iterator style functions and traits
# (keys/values/entries/@@iterator) to an interface. # (keys/values/entries/@@iterator) to an interface.
@ -3565,9 +3629,15 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
we generate our functions as if they were part of the interface we generate our functions as if they were part of the interface
specification during parsing. specification during parsing.
""" """
# We only need to add entries/keys/values here if we're a pair iterator.
# Value iterators just copy these from %ArrayPrototype% instead.
if not self.isPairIterator():
return
# object entries() # object entries()
self.addMethod("entries", members, False, self.iteratorType, self.addMethod("entries", members, False, self.iteratorType,
affectsNothing=True, newObject=True) affectsNothing=True, newObject=True,
isIteratorAlias=True)
# object keys() # object keys()
self.addMethod("keys", members, False, self.iteratorType, self.addMethod("keys", members, False, self.iteratorType,
affectsNothing=True, newObject=True) affectsNothing=True, newObject=True)
@ -3575,6 +3645,17 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
self.addMethod("values", members, False, self.iteratorType, self.addMethod("values", members, False, self.iteratorType,
affectsNothing=True, newObject=True) affectsNothing=True, newObject=True)
# void forEach(callback(valueType, keyType), optional any thisArg)
self.addMethod("forEach", members, False,
BuiltinTypes[IDLBuiltinType.Types.void],
self.getForEachArguments())
def isValueIterator(self):
return not self.isPairIterator()
def isPairIterator(self):
return self.hasKeyType()
# MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
@ -3611,26 +3692,17 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
# object entries() # object entries()
self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object], self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object],
affectsNothing=True) affectsNothing=True, isIteratorAlias=self.isMaplike())
# object keys() # object keys()
self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object], self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object],
affectsNothing=True) affectsNothing=True)
# object values() # object values()
self.addMethod("values", members, False, BuiltinTypes[IDLBuiltinType.Types.object], self.addMethod("values", members, False, BuiltinTypes[IDLBuiltinType.Types.object],
affectsNothing=True) affectsNothing=True, isIteratorAlias=self.isSetlike())
# void forEach(callback(valueType, keyType), thisVal) # void forEach(callback(valueType, keyType), thisVal)
foreachArguments = [IDLArgument(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
"callback"),
BuiltinTypes[IDLBuiltinType.Types.object]),
IDLArgument(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
"thisArg"),
BuiltinTypes[IDLBuiltinType.Types.any],
optional=True)]
self.addMethod("forEach", members, False, BuiltinTypes[IDLBuiltinType.Types.void], self.addMethod("forEach", members, False, BuiltinTypes[IDLBuiltinType.Types.void],
foreachArguments) self.getForEachArguments())
def getKeyArg(): def getKeyArg():
return IDLArgument(self.location, return IDLArgument(self.location,
@ -5436,10 +5508,13 @@ class Parser(Tokenizer):
location = self.getLocation(p, 2) location = self.getLocation(p, 2)
identifier = IDLUnresolvedIdentifier(location, "__iterable", identifier = IDLUnresolvedIdentifier(location, "__iterable",
allowDoubleUnderscore=True) allowDoubleUnderscore=True)
keyType = p[3]
valueType = None
if (len(p) > 6): if (len(p) > 6):
keyType = p[3]
valueType = p[5] valueType = p[5]
else:
keyType = None
valueType = p[3]
p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope()) p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope())
def p_Setlike(self, p): def p_Setlike(self, p):
@ -6509,7 +6584,7 @@ class Parser(Tokenizer):
if isinstance(m, IDLIterable): if isinstance(m, IDLIterable):
iterable = m iterable = m
break break
if iterable: if iterable and iterable.isPairIterator():
def simpleExtendedAttr(str): def simpleExtendedAttr(str):
return IDLExtendedAttribute(iface.location, (str, )) return IDLExtendedAttribute(iface.location, (str, ))
nextMethod = IDLMethod( nextMethod = IDLMethod(

View File

@ -55,17 +55,22 @@ TestInterfaceIterableSingle::GetParentObject() const
return mParent; return mParent;
} }
size_t uint32_t
TestInterfaceIterableSingle::GetIterableLength() const TestInterfaceIterableSingle::Length() const
{ {
return mValues.Length(); return mValues.Length();
} }
uint32_t int32_t
TestInterfaceIterableSingle::GetValueAtIndex(uint32_t index) const TestInterfaceIterableSingle::IndexedGetter(uint32_t aIndex, bool& aFound) const
{ {
MOZ_ASSERT(index < mValues.Length()); if (aIndex >= mValues.Length()) {
return mValues.ElementAt(index); aFound = false;
return 0;
}
aFound = true;
return mValues[aIndex];
} }
} // namespace dom } // namespace dom

View File

@ -36,12 +36,13 @@ public:
static already_AddRefed<TestInterfaceIterableSingle> static already_AddRefed<TestInterfaceIterableSingle>
Constructor(const GlobalObject& aGlobal, ErrorResult& rv); Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
size_t GetIterableLength() const; uint32_t Length() const;
uint32_t GetValueAtIndex(uint32_t aIndex) const; int32_t IndexedGetter(uint32_t aIndex, bool& aFound) const;
private: private:
virtual ~TestInterfaceIterableSingle() {} virtual ~TestInterfaceIterableSingle() {}
nsCOMPtr<nsPIDOMWindow> mParent; nsCOMPtr<nsPIDOMWindow> mParent;
nsTArray<uint32_t> mValues; nsTArray<int32_t> mValues;
}; };
} // namespace dom } // namespace dom

View File

@ -39,6 +39,12 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
#undef ANCHOR_ELEMENT_FLAG_BIT #undef ANCHOR_ELEMENT_FLAG_BIT
// static
const DOMTokenListSupportedToken HTMLAnchorElement::sSupportedRelValues[] = {
"noreferrer",
nullptr
};
HTMLAnchorElement::~HTMLAnchorElement() HTMLAnchorElement::~HTMLAnchorElement()
{ {
} }
@ -302,7 +308,7 @@ nsDOMTokenList*
HTMLAnchorElement::RelList() HTMLAnchorElement::RelList()
{ {
if (!mRelList) { if (!mRelList) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel); mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
} }
return mRelList; return mRelList;
} }

View File

@ -227,6 +227,8 @@ public:
GetHref(aResult); GetHref(aResult);
} }
static DOMTokenListSupportedToken sSupportedRelValues[];
protected: protected:
virtual ~HTMLAnchorElement(); virtual ~HTMLAnchorElement();

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/HTMLAreaElement.h" #include "mozilla/dom/HTMLAreaElement.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/dom/HTMLAreaElementBinding.h" #include "mozilla/dom/HTMLAreaElementBinding.h"
#include "mozilla/EventDispatcher.h" #include "mozilla/EventDispatcher.h"
#include "mozilla/EventStates.h" #include "mozilla/EventStates.h"
@ -122,7 +123,8 @@ nsDOMTokenList*
HTMLAreaElement::RelList() HTMLAreaElement::RelList()
{ {
if (!mRelList) { if (!mRelList) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel); mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
HTMLAnchorElement::sSupportedRelValues);
} }
return mRelList; return mRelList;
} }

View File

@ -18,6 +18,15 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
// static
const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] =
{
#define SANDBOX_KEYWORD(string, atom, flags) string,
#include "IframeSandboxKeywordList.h"
#undef SANDBOX_KEYWORD
nullptr
};
HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
FromParser aFromParser) FromParser aFromParser)
: nsGenericHTMLFrameElement(aNodeInfo, aFromParser) : nsGenericHTMLFrameElement(aNodeInfo, aFromParser)

View File

@ -10,7 +10,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "nsGenericHTMLFrameElement.h" #include "nsGenericHTMLFrameElement.h"
#include "nsIDOMHTMLIFrameElement.h" #include "nsIDOMHTMLIFrameElement.h"
#include "nsDOMSettableTokenList.h" #include "nsDOMTokenList.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -84,9 +84,9 @@ public:
{ {
SetHTMLAttr(nsGkAtoms::name, aName, aError); SetHTMLAttr(nsGkAtoms::name, aName, aError);
} }
nsDOMSettableTokenList* Sandbox() nsDOMTokenList* Sandbox()
{ {
return GetTokenList(nsGkAtoms::sandbox); return GetTokenList(nsGkAtoms::sandbox, sSupportedSandboxTokens);
} }
bool AllowFullscreen() const bool AllowFullscreen() const
{ {
@ -202,6 +202,8 @@ protected:
private: private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData); nsRuleData* aData);
static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
}; };
} // namespace dom } // namespace dom

View File

@ -26,6 +26,7 @@
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
#include "nsStyleConsts.h" #include "nsStyleConsts.h"
#include "nsStyleLinkElement.h"
#include "nsUnicharUtils.h" #include "nsUnicharUtils.h"
#define LINK_ELEMENT_FLAG_BIT(n_) \ #define LINK_ELEMENT_FLAG_BIT(n_) \
@ -499,11 +500,30 @@ HTMLLinkElement::GetLinkTarget(nsAString& aTarget)
} }
} }
static const DOMTokenListSupportedToken sSupportedRelValues[] = {
// Keep this in sync with ToLinkMask in nsStyleLinkElement.cpp.
// "import" must come first because it's conditional.
"import"
"prefetch",
"dns-prefetch",
"stylesheet",
"next",
"alternate",
"preconnect",
"icon",
"search",
nullptr
};
nsDOMTokenList* nsDOMTokenList*
HTMLLinkElement::RelList() HTMLLinkElement::RelList()
{ {
if (!mRelList) { if (!mRelList) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel); const DOMTokenListSupportedTokenArray relValues =
nsStyleLinkElement::IsImportEnabled() ?
sSupportedRelValues : &sSupportedRelValues[1];
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, relValues);
} }
return mRelList; return mRelList;
} }

View File

@ -119,7 +119,7 @@ public:
{ {
SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv); SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv);
} }
nsDOMSettableTokenList* Sizes() nsDOMTokenList* Sizes()
{ {
return GetTokenList(nsGkAtoms::sizes); return GetTokenList(nsGkAtoms::sizes);
} }

View File

@ -11,6 +11,7 @@
#include "mozilla/dom/HTMLMenuItemElementBinding.h" #include "mozilla/dom/HTMLMenuItemElementBinding.h"
#include "nsAttrValueInlines.h" #include "nsAttrValueInlines.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMTokenList.h"
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(MenuItem) NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(MenuItem)

View File

@ -11,7 +11,6 @@
#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/HTMLFormElement.h"
#include "mozilla/dom/HTMLOutputElementBinding.h" #include "mozilla/dom/HTMLOutputElementBinding.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMSettableTokenList.h"
#include "nsFormSubmission.h" #include "nsFormSubmission.h"
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output) NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output)
@ -166,11 +165,11 @@ HTMLOutputElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult&
} }
} }
nsDOMSettableTokenList* nsDOMTokenList*
HTMLOutputElement::HtmlFor() HTMLOutputElement::HtmlFor()
{ {
if (!mTokenList) { if (!mTokenList) {
mTokenList = new nsDOMSettableTokenList(this, nsGkAtoms::_for); mTokenList = new nsDOMTokenList(this, nsGkAtoms::_for);
} }
return mTokenList; return mTokenList;
} }

View File

@ -64,7 +64,7 @@ public:
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// WebIDL // WebIDL
nsDOMSettableTokenList* HtmlFor(); nsDOMTokenList* HtmlFor();
// nsGenericHTMLFormElement::GetForm is fine. // nsGenericHTMLFormElement::GetForm is fine.
void GetName(nsAString& aName) void GetName(nsAString& aName)
{ {
@ -108,7 +108,7 @@ protected:
ValueModeFlag mValueModeFlag; ValueModeFlag mValueModeFlag;
bool mIsDoneAddingChildren; bool mIsDoneAddingChildren;
nsString mDefaultValue; nsString mDefaultValue;
RefPtr<nsDOMSettableTokenList> mTokenList; RefPtr<nsDOMTokenList> mTokenList;
}; };
} // namespace dom } // namespace dom

View File

@ -9,7 +9,7 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsGenericHTMLElement.h" #include "nsGenericHTMLElement.h"
#include "nsVariant.h" #include "nsVariant.h"
#include "nsDOMSettableTokenList.h" #include "nsDOMTokenList.h"
#include "nsAttrValue.h" #include "nsAttrValue.h"
#include "nsWrapperCacheInlines.h" #include "nsWrapperCacheInlines.h"
#include "mozilla/dom/HTMLPropertiesCollectionBinding.h" #include "mozilla/dom/HTMLPropertiesCollectionBinding.h"

View File

@ -164,14 +164,15 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
return; return;
} }
// Resolve the <base> element's href relative to our document URI // Resolve the <base> element's href relative to our document's
// fallback base URI.
nsAutoString href; nsAutoString href;
child->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href); child->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
nsCOMPtr<nsIURI> newBaseURI; nsCOMPtr<nsIURI> newBaseURI;
nsContentUtils::NewURIWithDocumentCharset( nsContentUtils::NewURIWithDocumentCharset(
getter_AddRefs(newBaseURI), href, aDocument, getter_AddRefs(newBaseURI), href, aDocument,
aDocument->GetDocumentURI()); aDocument->GetFallbackBaseURI());
// Try to set our base URI. If that fails, try to set base URI to null // Try to set our base URI. If that fails, try to set base URI to null
nsresult rv = aDocument->SetBaseURI(newBaseURI); nsresult rv = aDocument->SetBaseURI(newBaseURI);

View File

@ -47,7 +47,7 @@ public:
{ {
SetUnsignedIntAttr(nsGkAtoms::rowspan, aRowSpan, aError); SetUnsignedIntAttr(nsGkAtoms::rowspan, aRowSpan, aError);
} }
//already_AddRefed<nsDOMSettableTokenList> Headers() const; //already_AddRefed<nsDOMTokenList> Headers() const;
void GetHeaders(DOMString& aHeaders) void GetHeaders(DOMString& aHeaders)
{ {
GetHTMLAttr(nsGkAtoms::headers, aHeaders); GetHTMLAttr(nsGkAtoms::headers, aHeaders);

View File

@ -96,7 +96,7 @@
#include "HTMLPropertiesCollection.h" #include "HTMLPropertiesCollection.h"
#include "nsVariant.h" #include "nsVariant.h"
#include "nsDOMSettableTokenList.h" #include "nsDOMTokenList.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsTextFragment.h" #include "nsTextFragment.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"

View File

@ -20,7 +20,7 @@
#include "mozilla/dom/ValidityState.h" #include "mozilla/dom/ValidityState.h"
#include "mozilla/dom/ElementInlines.h" #include "mozilla/dom/ElementInlines.h"
class nsDOMSettableTokenList; class nsDOMTokenList;
class nsIDOMHTMLMenuElement; class nsIDOMHTMLMenuElement;
class nsIEditor; class nsIEditor;
class nsIFormControlFrame; class nsIFormControlFrame;
@ -104,7 +104,7 @@ public:
{ {
SetHTMLBoolAttr(nsGkAtoms::itemscope, aItemScope, aError); SetHTMLBoolAttr(nsGkAtoms::itemscope, aItemScope, aError);
} }
nsDOMSettableTokenList* ItemType() nsDOMTokenList* ItemType()
{ {
return GetTokenList(nsGkAtoms::itemtype); return GetTokenList(nsGkAtoms::itemtype);
} }
@ -116,11 +116,11 @@ public:
{ {
SetHTMLAttr(nsGkAtoms::itemid, aItemID, aError); SetHTMLAttr(nsGkAtoms::itemid, aItemID, aError);
} }
nsDOMSettableTokenList* ItemRef() nsDOMTokenList* ItemRef()
{ {
return GetTokenList(nsGkAtoms::itemref); return GetTokenList(nsGkAtoms::itemref);
} }
nsDOMSettableTokenList* ItemProp() nsDOMTokenList* ItemProp()
{ {
return GetTokenList(nsGkAtoms::itemprop); return GetTokenList(nsGkAtoms::itemprop);
} }

View File

@ -32,7 +32,7 @@ interface nsIDOMHTMLElement : nsIDOMElement
attribute nsIVariant itemType; attribute nsIVariant itemType;
attribute DOMString itemId; attribute DOMString itemId;
readonly attribute nsISupports properties; readonly attribute nsISupports properties;
// The following attributes are really nsDOMSettableTokenList, which has // The following attributes are really nsDOMTokenList, which has
// PutForwards, so we express them as nsIVariants to deal with this. // PutForwards, so we express them as nsIVariants to deal with this.
attribute nsIVariant itemValue; attribute nsIVariant itemValue;
attribute nsIVariant itemProp; attribute nsIVariant itemProp;

View File

@ -79,7 +79,7 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION && return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION && aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT && aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPlane.mStride > 0; aPlane.mStride > 0 && aPlane.mWidth <= aPlane.mStride;
} }
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK

View File

@ -460,6 +460,18 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS]; float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
domItem->ToSVGPathSegEncodedData(segAsRaw); domItem->ToSVGPathSegEncodedData(segAsRaw);
if (AnimListMirrorsBaseList()) {
// The anim val list is in sync with the base val list - remove mirroring
// animVal item if necessary. We do this *before* touching InternalList()
// so the removed item can correctly store its internal value.
DOMSVGPathSegList* animVal =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
if (animVal->ItemAt(aIndex)) {
animVal->ItemAt(aIndex)->RemovingFromList();
animVal->ItemAt(aIndex) = nullptr;
}
}
if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount, if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount,
segAsRaw, 1 + newArgCount, segAsRaw, 1 + newArgCount,
fallible)) { fallible)) {
@ -474,8 +486,13 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
int32_t delta = newArgCount - oldArgCount; int32_t delta = newArgCount - oldArgCount;
if (delta != 0) { if (delta != 0) {
for (uint32_t i = aIndex + 1; i < LengthNoFlush(); ++i) { // Sync up the internal indexes of all ItemProxys that come after aIndex:
mItems[i].mInternalDataIndex += delta; UpdateListIndicesFromIndex(aIndex + 1, delta);
if (AnimListMirrorsBaseList()) {
// The anim val list is in sync with the base val list
DOMSVGPathSegList* animVal =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
animVal->UpdateListIndicesFromIndex(aIndex + 1, delta);
} }
} }

View File

@ -20,6 +20,13 @@ interface DOMTokenList {
[Throws] [Throws]
void remove(DOMString... tokens); void remove(DOMString... tokens);
[Throws] [Throws]
void replace(DOMString token, DOMString newToken);
[Throws]
boolean toggle(DOMString token, optional boolean force); boolean toggle(DOMString token, optional boolean force);
[Throws]
boolean supports(DOMString token);
[SetterThrows]
attribute DOMString value;
stringifier DOMString (); stringifier DOMString ();
iterable<DOMString?>;
}; };

View File

@ -30,7 +30,7 @@ interface Element : Node {
attribute DOMString id; attribute DOMString id;
[Pure] [Pure]
attribute DOMString className; attribute DOMString className;
[Constant] [Constant, PutForwards=value]
readonly attribute DOMTokenList classList; readonly attribute DOMTokenList classList;
[SameObject] [SameObject]

View File

@ -23,6 +23,7 @@ interface HTMLAnchorElement : HTMLElement {
attribute DOMString rel; attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"] [SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrerPolicy; attribute DOMString referrerPolicy;
[PutForwards=value]
readonly attribute DOMTokenList relList; readonly attribute DOMTokenList relList;
[SetterThrows] [SetterThrows]
attribute DOMString hreflang; attribute DOMString hreflang;

View File

@ -30,6 +30,7 @@ interface HTMLAreaElement : HTMLElement {
attribute DOMString rel; attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"] [SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrerPolicy; attribute DOMString referrerPolicy;
[PutForwards=value]
readonly attribute DOMTokenList relList; readonly attribute DOMTokenList relList;
}; };

View File

@ -28,11 +28,11 @@ interface HTMLElement : Element {
// microdata // microdata
[SetterThrows, Pure] [SetterThrows, Pure]
attribute boolean itemScope; attribute boolean itemScope;
[PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemType; [PutForwards=value,Constant] readonly attribute DOMTokenList itemType;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString itemId; attribute DOMString itemId;
[PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemRef; [PutForwards=value,Constant] readonly attribute DOMTokenList itemRef;
[PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemProp; [PutForwards=value,Constant] readonly attribute DOMTokenList itemProp;
[Constant] [Constant]
readonly attribute HTMLPropertiesCollection properties; readonly attribute HTMLPropertiesCollection properties;
[Throws] [Throws]
@ -54,7 +54,7 @@ interface HTMLElement : Element {
readonly attribute DOMString accessKeyLabel; readonly attribute DOMString accessKeyLabel;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute boolean draggable; attribute boolean draggable;
//[PutForwards=value] readonly attribute DOMSettableTokenList dropzone; //[PutForwards=value] readonly attribute DOMTokenList dropzone;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString contentEditable; attribute DOMString contentEditable;
[Pure] [Pure]

View File

@ -18,7 +18,7 @@ interface HTMLIFrameElement : HTMLElement {
attribute DOMString srcdoc; attribute DOMString srcdoc;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString name; attribute DOMString name;
[PutForwards=value] readonly attribute DOMSettableTokenList sandbox; [PutForwards=value] readonly attribute DOMTokenList sandbox;
// attribute boolean seamless; // attribute boolean seamless;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute boolean allowFullscreen; attribute boolean allowFullscreen;

View File

@ -21,6 +21,7 @@ interface HTMLLinkElement : HTMLElement {
attribute DOMString? crossOrigin; attribute DOMString? crossOrigin;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString rel; attribute DOMString rel;
[PutForwards=value]
readonly attribute DOMTokenList relList; readonly attribute DOMTokenList relList;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString media; attribute DOMString media;
@ -28,7 +29,7 @@ interface HTMLLinkElement : HTMLElement {
attribute DOMString hreflang; attribute DOMString hreflang;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString type; attribute DOMString type;
[PutForwards=value] readonly attribute DOMSettableTokenList sizes; [PutForwards=value] readonly attribute DOMTokenList sizes;
}; };
HTMLLinkElement implements LinkStyle; HTMLLinkElement implements LinkStyle;

View File

@ -14,7 +14,7 @@
// http://www.whatwg.org/specs/web-apps/current-work/#the-output-element // http://www.whatwg.org/specs/web-apps/current-work/#the-output-element
interface HTMLOutputElement : HTMLElement { interface HTMLOutputElement : HTMLElement {
[PutForwards=value, Constant] [PutForwards=value, Constant]
readonly attribute DOMSettableTokenList htmlFor; readonly attribute DOMTokenList htmlFor;
readonly attribute HTMLFormElement? form; readonly attribute HTMLFormElement? form;
[SetterThrows, Pure] [SetterThrows, Pure]
attribute DOMString name; attribute DOMString name;

View File

@ -16,7 +16,7 @@ interface HTMLTableCellElement : HTMLElement {
attribute unsigned long colSpan; attribute unsigned long colSpan;
[SetterThrows] [SetterThrows]
attribute unsigned long rowSpan; attribute unsigned long rowSpan;
//[PutForwards=value] readonly attribute DOMSettableTokenList headers; //[PutForwards=value] readonly attribute DOMTokenList headers;
[SetterThrows] [SetterThrows]
attribute DOMString headers; attribute DOMString headers;
readonly attribute long cellIndex; readonly attribute long cellIndex;

View File

@ -13,4 +13,5 @@
interface NodeList { interface NodeList {
getter Node? item(unsigned long index); getter Node? item(unsigned long index);
readonly attribute unsigned long length; readonly attribute unsigned long length;
iterable<Node?>;
}; };

View File

@ -50,6 +50,8 @@ interface TestInterfaceSetlikeNode {
Pref="dom.expose_test_interfaces"] Pref="dom.expose_test_interfaces"]
interface TestInterfaceIterableSingle { interface TestInterfaceIterableSingle {
iterable<long>; iterable<long>;
getter long(unsigned long index);
readonly attribute unsigned long length;
}; };
[Constructor(), [Constructor(),

View File

@ -132,7 +132,6 @@ WEBIDL_FILES = [
'DOMRect.webidl', 'DOMRect.webidl',
'DOMRectList.webidl', 'DOMRectList.webidl',
'DOMRequest.webidl', 'DOMRequest.webidl',
'DOMSettableTokenList.webidl',
'DOMStringList.webidl', 'DOMStringList.webidl',
'DOMStringMap.webidl', 'DOMStringMap.webidl',
'DOMTokenList.webidl', 'DOMTokenList.webidl',

View File

@ -176,7 +176,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventListener)
if (tmp->mEventListener) {
nsEditorEventListener* listener =
reinterpret_cast<nsEditorEventListener*>(tmp->mEventListener.get());
listener->Disconnect();
tmp->mEventListener = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor)

View File

@ -430,12 +430,15 @@ static void
CopyPlane(uint8_t *aDst, const uint8_t *aSrc, CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip) const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip)
{ {
if (!aSkip) {
// Fast path: planar input.
memcpy(aDst, aSrc, aSize.height * aStride);
} else {
int32_t height = aSize.height; int32_t height = aSize.height;
int32_t width = aSize.width; int32_t width = aSize.width;
MOZ_RELEASE_ASSERT(width <= aStride);
if (!aSkip) {
// Fast path: planar input.
memcpy(aDst, aSrc, height * aStride);
} else {
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
const uint8_t *src = aSrc; const uint8_t *src = aSrc;
uint8_t *dst = aDst; uint8_t *dst = aDst;
@ -453,13 +456,11 @@ CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
bool bool
RecyclingPlanarYCbCrImage::CopyData(const Data& aData) RecyclingPlanarYCbCrImage::CopyData(const Data& aData)
{ {
mData = aData;
// update buffer size // update buffer size
// Use uint32_t throughout to match AllocateBuffer's param and mBufferSize // Use uint32_t throughout to match AllocateBuffer's param and mBufferSize
const auto checkedSize = const auto checkedSize =
CheckedInt<uint32_t>(mData.mCbCrStride) * mData.mCbCrSize.height * 2 + CheckedInt<uint32_t>(aData.mCbCrStride) * aData.mCbCrSize.height * 2 +
CheckedInt<uint32_t>(mData.mYStride) * mData.mYSize.height; CheckedInt<uint32_t>(aData.mYStride) * aData.mYSize.height;
if (!checkedSize.isValid()) if (!checkedSize.isValid())
return false; return false;
@ -468,22 +469,24 @@ RecyclingPlanarYCbCrImage::CopyData(const Data& aData)
// get new buffer // get new buffer
mBuffer = AllocateBuffer(size); mBuffer = AllocateBuffer(size);
if (!mBuffer) if (MOZ_UNLIKELY(!mBuffer))
return false; return false;
// update buffer size // update buffer size
mBufferSize = size; mBufferSize = size;
mData = aData;
mData.mYChannel = mBuffer.get(); mData.mYChannel = mBuffer.get();
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
mData.mYSkip = mData.mCbSkip = mData.mCrSkip = 0;
CopyPlane(mData.mYChannel, aData.mYChannel, CopyPlane(mData.mYChannel, aData.mYChannel,
mData.mYSize, mData.mYStride, mData.mYSkip); aData.mYSize, aData.mYStride, aData.mYSkip);
CopyPlane(mData.mCbChannel, aData.mCbChannel, CopyPlane(mData.mCbChannel, aData.mCbChannel,
mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip); aData.mCbCrSize, aData.mCbCrStride, aData.mCbSkip);
CopyPlane(mData.mCrChannel, aData.mCrChannel, CopyPlane(mData.mCrChannel, aData.mCrChannel,
mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip); aData.mCbCrSize, aData.mCbCrStride, aData.mCrSkip);
mSize = aData.mPicSize; mSize = aData.mPicSize;
return true; return true;

View File

@ -152,7 +152,17 @@ nsBIG5ToUnicode::GetMaxLength(const char* aSrc,
{ {
// The length of the output in UTF-16 code units never exceeds the length // The length of the output in UTF-16 code units never exceeds the length
// of the input in bytes. // of the input in bytes.
*aDestLength = aSrcLength + (mPendingTrail ? 1 : 0) + (mBig5Lead ? 1 : 0); mozilla::CheckedInt32 length = aSrcLength;
if (mPendingTrail) {
length += 1;
}
if (mBig5Lead) {
length += 1;
}
if (!length.isValid()) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aDestLength = length.value();
return NS_OK; return NS_OK;
} }

View File

@ -211,12 +211,21 @@ nsUnicodeToBIG5::GetMaxLength(const char16_t* aSrc,
int32_t aSrcLength, int32_t aSrcLength,
int32_t* aDestLength) int32_t* aDestLength)
{ {
*aDestLength = (aSrcLength * 2) + mozilla::CheckedInt32 length = aSrcLength;
(mPendingTrail ? 1 : 0) + length *= 2;
if (mPendingTrail) {
length += 1;
}
// If the lead ends up being paired, the bytes produced // If the lead ends up being paired, the bytes produced
// are already included above. // are already included above.
// If not, it produces a single '?'. // If not, it produces a single '?'.
(mUtf16Lead ? 1 : 0); if (mUtf16Lead) {
length += 1;
}
if (!length.isValid()) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aDestLength = length.value();
return NS_OK; return NS_OK;
} }

View File

@ -5,6 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsBidiUtils.h" #include "nsBidiUtils.h"
namespace mozilla {
static const uint32_t kMinRTLChar = 0x0590;
} // namespace mozilla;
#define ARABIC_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_ARABIC_DIGITS) #define ARABIC_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_ARABIC_DIGITS)
#define PERSIAN_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_FARSI_DIGITS) #define PERSIAN_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_FARSI_DIGITS)
#define ARABIC_TO_PERSIAN_DIGIT_INCREMENT (START_FARSI_DIGITS - START_ARABIC_DIGITS) #define ARABIC_TO_PERSIAN_DIGIT_INCREMENT (START_FARSI_DIGITS - START_ARABIC_DIGITS)
@ -82,16 +86,18 @@ nsresult HandleNumbers(char16_t* aBuffer, uint32_t aSize, uint32_t aNumFlag)
return NS_OK; return NS_OK;
} }
bool HasRTLChars(const nsAString& aString) bool HasRTLChars(const char16_t* aText, uint32_t aLength)
{ {
// This is used to determine whether to enable bidi if a string has // This is used to determine whether a string has right-to-left characters
// right-to-left characters. To simplify things, anything that could be a // that mean it will require bidi processing.
// surrogate or RTL presentation form is covered just by testing >= 0xD800). const char16_t* cp = aText;
// It's fine to enable bidi in rare cases where it actually isn't needed. const char16_t* end = cp + aLength;
int32_t length = aString.Length(); while (cp < end) {
for (int32_t i = 0; i < length; i++) { char16_t ch = *cp++;
char16_t ch = aString.CharAt(i); if (ch < mozilla::kMinRTLChar) {
if (ch >= 0xD800 || IS_IN_BMP_RTL_BLOCK(ch)) { continue;
}
if (UTF16_CODE_UNIT_IS_BIDI(ch) || IsBidiControlRTL(ch)) {
return true; return true;
} }
} }

View File

@ -110,10 +110,19 @@ typedef enum nsCharType nsCharType;
* Return false, otherwise * Return false, otherwise
*/ */
#define LRM_CHAR 0x200e #define LRM_CHAR 0x200e
#define RLM_CHAR 0x200f
#define LRE_CHAR 0x202a #define LRE_CHAR 0x202a
#define RLE_CHAR 0x202b
#define PDF_CHAR 0x202c
#define LRO_CHAR 0x202d
#define RLO_CHAR 0x202e #define RLO_CHAR 0x202e
#define LRI_CHAR 0x2066 #define LRI_CHAR 0x2066
#define RLI_CHAR 0x2067
#define FSI_CHAR 0x2068
#define PDI_CHAR 0x2069 #define PDI_CHAR 0x2069
#define ALM_CHAR 0x061C #define ALM_CHAR 0x061C
inline bool IsBidiControl(uint32_t aChar) { inline bool IsBidiControl(uint32_t aChar) {
return ((LRE_CHAR <= aChar && aChar <= RLO_CHAR) || return ((LRE_CHAR <= aChar && aChar <= RLO_CHAR) ||
@ -123,10 +132,32 @@ typedef enum nsCharType nsCharType;
} }
/** /**
* Give an nsString. * Give a UTF-16 codepoint (changed for TenFourFox; we don't use this for
* UTF-32 characters, so the conversion is unnecessary).
* Return true if the codepoint is a Bidi control character that may result
* in RTL directionality and therefore needs to trigger bidi resolution;
* return false otherwise.
*/
inline bool IsBidiControlRTL(char16_t aChar) {
return aChar == RLM_CHAR ||
aChar == RLE_CHAR ||
aChar == RLO_CHAR ||
aChar == RLI_CHAR ||
aChar == ALM_CHAR;
}
/**
* Give a 16-bit (UTF-16) text buffer and length
* @return true if the string contains right-to-left characters * @return true if the string contains right-to-left characters
*/ */
bool HasRTLChars(const nsAString& aString); bool HasRTLChars(const char16_t* aText, uint32_t aLength);
/**
* Convenience function to call the above on an nsAString.
*/
inline bool HasRTLChars(const nsAString& aString) {
return HasRTLChars(aString.BeginReading(), aString.Length());
}
// These values are shared with Preferences dialog // These values are shared with Preferences dialog
// ------------------ // ------------------
@ -248,6 +279,17 @@ typedef enum nsCharType nsCharType;
((0xfe70 <= (c)) && ((c) <= 0xfefc))) ((0xfe70 <= (c)) && ((c) <= 0xfefc)))
#define IS_IN_SMP_RTL_BLOCK(c) (((0x10800 <= (c)) && ((c) <= 0x10fff)) || \ #define IS_IN_SMP_RTL_BLOCK(c) (((0x10800 <= (c)) && ((c) <= 0x10fff)) || \
((0x1e800 <= (c)) && ((c) <= 0x1eFFF))) ((0x1e800 <= (c)) && ((c) <= 0x1eFFF)))
// Due to the supplementary-plane RTL blocks being identifiable from the
// high surrogate without examining the low surrogate, it is correct to
// use this by-code-unit check on potentially astral text without doing
// the math to decode surrogate pairs into code points. However, unpaired
// high surrogates that are RTL high surrogates then count as RTL even
// though, if replaced by the REPLACEMENT CHARACTER, it would not be
// RTL.
#define UTF16_CODE_UNIT_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \
(IS_RTL_PRESENTATION_FORM(c)) || \
(c) == 0xD802 || (c) == 0xD803 || \
(c) == 0xD83A || (c) == 0xD83B)
#define UCS2_CHAR_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \ #define UCS2_CHAR_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \
(IS_RTL_PRESENTATION_FORM(c))) (IS_RTL_PRESENTATION_FORM(c)))
#define UTF32_CHAR_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \ #define UTF32_CHAR_IS_BIDI(c) ((IS_IN_BMP_RTL_BLOCK(c)) || \

View File

@ -3761,7 +3761,6 @@ BytecodeEmitter::emitDestructuringDeclsWithEmitter(JSOp prologueOp, ParseNode* p
continue; continue;
ParseNode* target = element; ParseNode* target = element;
if (element->isKind(PNK_SPREAD)) { if (element->isKind(PNK_SPREAD)) {
MOZ_ASSERT(element->pn_kid->isKind(PNK_NAME));
target = element->pn_kid; target = element->pn_kid;
} }
if (target->isKind(PNK_ASSIGN)) if (target->isKind(PNK_ASSIGN))

View File

@ -4276,11 +4276,6 @@ Parser<FullParseHandler>::checkDestructuringArray(BindData<FullParseHandler>* da
return false; return false;
} }
target = element->pn_kid; target = element->pn_kid;
if (handler.isUnparenthesizedDestructuringPattern(target)) {
report(ParseError, false, target, JSMSG_BAD_DESTRUCT_TARGET);
return false;
}
} else if (handler.isUnparenthesizedAssignment(element)) { } else if (handler.isUnparenthesizedAssignment(element)) {
target = element->pn_left; target = element->pn_left;
} else { } else {

View File

@ -49,6 +49,23 @@ assertIterable([5,5,4,4],
it => { var [,,...rest] = it; return rest; }, it => { var [,,...rest] = it; return rest; },
[3,4]); [3,4]);
// the iterator should be exhausted before any error is thrown
if(0) {
// XXX: this doesn't throw right now. just test syntax below.
// plan to reenable this for issue 485
assertIterable([5,5,4,4],
it => {
assertThrowsInstanceOf(function () {
"use strict";
[...{0: "".x}] = it;
}, TypeError);
return [];
},
[]);
} else {
assertIterable([5,5,4,4], it => { [...{0: "".x}] = it; return []; }, []);
}
var arraycalls = 0; var arraycalls = 0;
var ArrayIterator = Array.prototype[Symbol.iterator]; var ArrayIterator = Array.prototype[Symbol.iterator];
Array.prototype[Symbol.iterator] = function () { Array.prototype[Symbol.iterator] = function () {
@ -58,7 +75,11 @@ Array.prototype[Symbol.iterator] = function () {
// [...rest] should not call Array#@@iterator for the LHS // [...rest] should not call Array#@@iterator for the LHS
var [...rest] = iterable; var [...rest] = iterable;
assertEq(arraycalls, 0, 'calls to Array#@@iterator'); assertEq(arraycalls, 0, 'calls to Array#@@iterator');
// [...[...rest]] should do so, since it creates an implicit array for the
// first rest pattern, then destructures that again using @@iterator() for the
// second rest pattern.
var [...[...rest]] = iterable;
assertEq(arraycalls, 1, 'calls to Array#@@iterator');
// loop `fn` a few times, to get it JIT-compiled // loop `fn` a few times, to get it JIT-compiled
function loop(fn) { function loop(fn) {
@ -67,7 +88,7 @@ function loop(fn) {
} }
loop(() => { doneafter = 4; var [a] = iterable; return a; }); loop(() => { doneafter = 4; var [a] = iterable; return a; });
loop(() => { doneafter = 4; var [a,b,...rest] = iterable; return rest; }); loop(() => { doneafter = 4; var [a,b,...[...rest]] = iterable; return rest; });
// destructuring assignment should always use iterators and not optimize // destructuring assignment should always use iterators and not optimize

View File

@ -4,8 +4,6 @@ load(libdir + 'eqArrayHelper.js');
assertThrowsInstanceOf(() => new Function('[...a, ,] = []'), SyntaxError, 'trailing elision'); assertThrowsInstanceOf(() => new Function('[...a, ,] = []'), SyntaxError, 'trailing elision');
assertThrowsInstanceOf(() => new Function('[a, ...b, c] = []'), SyntaxError, 'trailing param'); assertThrowsInstanceOf(() => new Function('[a, ...b, c] = []'), SyntaxError, 'trailing param');
assertThrowsInstanceOf(() => new Function('[...[a]] = []'), SyntaxError, 'nested arraypattern');
assertThrowsInstanceOf(() => new Function('[...{a}] = []'), SyntaxError, 'nested objectpattern');
assertThrowsInstanceOf(() => new Function('[...a=b] = []'), SyntaxError, 'assignment expression'); assertThrowsInstanceOf(() => new Function('[...a=b] = []'), SyntaxError, 'assignment expression');
assertThrowsInstanceOf(() => new Function('[...a()] = []'), SyntaxError, 'call expression'); assertThrowsInstanceOf(() => new Function('[...a()] = []'), SyntaxError, 'call expression');
assertThrowsInstanceOf(() => new Function('[...(a,b)] = []'), SyntaxError, 'comma expression'); assertThrowsInstanceOf(() => new Function('[...(a,b)] = []'), SyntaxError, 'comma expression');
@ -22,6 +20,14 @@ assertThrowsInstanceOf(() =>
assertThrowsInstanceOf(() => new Function('[...b,] = []'), SyntaxError) assertThrowsInstanceOf(() => new Function('[...b,] = []'), SyntaxError)
, Error); , Error);
assertThrowsInstanceOf(() => {
try {
eval('let [...[...x]] = (() => { throw "foo"; } )();');
} catch(e) {
assertEq(e, "foo");
}
x;
}, ReferenceError);
var inputArray = [1, 2, 3]; var inputArray = [1, 2, 3];
var inputDeep = [1, inputArray]; var inputDeep = [1, inputArray];
@ -45,6 +51,11 @@ function testAll(fn) {
assertEqArray(fn('[, ...(o.prop)]', inputArray, 'o.prop'), expected); assertEqArray(fn('[, ...(o.prop)]', inputArray, 'o.prop'), expected);
o.prop = null; o.prop = null;
assertEqArray(fn('[, ...(o.call().prop)]', inputArray, 'o.prop'), expected); assertEqArray(fn('[, ...(o.call().prop)]', inputArray, 'o.prop'), expected);
o.prop = null;
assertEqArray(fn('[, ...[...(o.prop)]]', inputArray, 'o.prop'), expected);
o.prop = null;
assertEqArray(fn('[, ...[...(o.call().prop)]]', inputArray, 'o.prop'), expected);
} }
function testDeclaration(fn) { function testDeclaration(fn) {
testStr(fn); testStr(fn);
@ -53,10 +64,24 @@ function testDeclaration(fn) {
assertEqArray(fn('[, ...rest]', inputGenerator()), expected); assertEqArray(fn('[, ...rest]', inputGenerator()), expected);
assertEqArray(fn('[, [, ...rest]]', inputDeep), expected); assertEqArray(fn('[, [, ...rest]]', inputDeep), expected);
assertEqArray(fn('{a: [, ...rest]}', inputObject), expected); assertEqArray(fn('{a: [, ...rest]}', inputObject), expected);
assertEqArray(fn('[, ...[...rest]]', inputArray), expected);
assertEqArray(fn('[, ...[...rest]]', inputGenerator()), expected);
assertEqArray(fn('[, [, ...[...rest]]]', inputDeep), expected);
assertEqArray(fn('{a: [, ...[...rest]]}', inputObject), expected);
assertEqArray(fn('[, ...{0: a, 1: b}]', inputArray, '[a, b]'), expected);
assertEqArray(fn('[, ...{0: a, 1: b}]', inputGenerator(), '[a, b]'), expected);
assertEqArray(fn('[, [, ...{0: a, 1: b}]]', inputDeep, '[a, b]'), expected);
assertEqArray(fn('{a: [, ...{0: a, 1: b}]}', inputObject, '[a, b]'), expected);
} }
function testStr(fn) { function testStr(fn) {
assertEqArray(fn('[, ...rest]', inputStr), expectedStr); assertEqArray(fn('[, ...rest]', inputStr), expectedStr);
assertEqArray(fn('[, ...[...rest]]', inputStr), expectedStr);
assertEqArray(fn('[, ...{0: a, 1: b}]', inputStr, '[a, b]'), expectedStr);
} }
function testForIn(pattern, input, binding) { function testForIn(pattern, input, binding) {
@ -88,8 +113,9 @@ testAll(testGlobal);
function testClosure(pattern, input, binding) { function testClosure(pattern, input, binding) {
binding = binding || 'rest'; binding = binding || 'rest';
const decl = binding.replace('[', '').replace(']', '');
return new Function('input', return new Function('input',
'var ' + binding + '; (function () {' + 'var ' + decl + '; (function () {' +
'(' + pattern + ' = input);' + '(' + pattern + ' = input);' +
'})();' + '})();' +
'return ' + binding 'return ' + binding

View File

@ -1824,6 +1824,12 @@ jit::ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph)
bool bool
jit::MakeMRegExpHoistable(MIRGraph& graph) jit::MakeMRegExpHoistable(MIRGraph& graph)
{ {
// If we are compiling try blocks, regular expressions may be observable
// from catch blocks (which Ion does not compile). For now just disable the
// pass in this case.
if (graph.hasTryBlock())
return true;
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
for (MDefinitionIterator iter(*block); iter; iter++) { for (MDefinitionIterator iter(*block); iter; iter++) {
if (!iter->isRegExp()) if (!iter->isRegExp())

View File

@ -1124,6 +1124,10 @@ JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape ge
RootedObject self(cx, this); RootedObject self(cx, this);
Shape* existingShape = self->ensureShape(cx);
if (!existingShape)
return false;
if (isNative() && as<NativeObject>().inDictionaryMode()) { if (isNative() && as<NativeObject>().inDictionaryMode()) {
if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx)) if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx))
return false; return false;
@ -1137,10 +1141,6 @@ JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape ge
return true; return true;
} }
Shape* existingShape = self->ensureShape(cx);
if (!existingShape)
return false;
Shape* newShape = Shape::setObjectFlags(cx, flags, self->getTaggedProto(), existingShape); Shape* newShape = Shape::setObjectFlags(cx, flags, self->getTaggedProto(), existingShape);
if (!newShape) if (!newShape)
return false; return false;

View File

@ -110,6 +110,7 @@ struct BidiParagraphData {
nsTArray<nsLineBox*> mLinePerFrame; nsTArray<nsLineBox*> mLinePerFrame;
nsDataHashtable<nsISupportsHashKey, int32_t> mContentToFrameIndex; nsDataHashtable<nsISupportsHashKey, int32_t> mContentToFrameIndex;
bool mIsVisual; bool mIsVisual;
bool mRequiresBidi;
bool mReset; bool mReset;
nsBidiLevel mParaLevel; nsBidiLevel mParaLevel;
nsIContent* mPrevContent; nsIContent* mPrevContent;
@ -121,10 +122,14 @@ struct BidiParagraphData {
void Init(nsBlockFrame *aBlockFrame) void Init(nsBlockFrame *aBlockFrame)
{ {
mBidiEngine = new nsBidi(); mBidiEngine = new nsBidi();
mRequiresBidi = false;
mPrevContent = nullptr; mPrevContent = nullptr;
mParagraphDepth = 0; mParagraphDepth = 0;
mParaLevel = nsBidiPresUtils::BidiLevelFromStyle(aBlockFrame->StyleContext()); mParaLevel = nsBidiPresUtils::BidiLevelFromStyle(aBlockFrame->StyleContext());
if (mParaLevel > 0) {
mRequiresBidi = true;
}
mIsVisual = aBlockFrame->PresContext()->IsVisualMode(); mIsVisual = aBlockFrame->PresContext()->IsVisualMode();
if (mIsVisual) { if (mIsVisual) {
@ -664,14 +669,67 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
char16_t ch = GetBidiControl(aBlockFrame->StyleContext(), kOverride); char16_t ch = GetBidiControl(aBlockFrame->StyleContext(), kOverride);
if (ch != 0) { if (ch != 0) {
bpd.PushBidiControl(ch); bpd.PushBidiControl(ch);
bpd.mRequiresBidi = true;
} else if (!bpd.mRequiresBidi) {
// If there are no unicode-bidi properties and no RTL characters in the
// block's content, then it is pure LTR and we can skip the rest of bidi
// resolution.
nsIContent* currContent = nullptr;
for (nsBlockFrame* block = aBlockFrame; block;
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
if (/* !bpd.mRequiresBidi && */
ChildListMayRequireBidi(block->PrincipalChildList().FirstChild(),
&currContent)) {
bpd.mRequiresBidi = true;
// Optimization for TenFourFox issue 482:
// It's safe to break here if mRequiresBidi is true because we'll
// pull the state bits off in the loop below (if we didn't, we would
// essentially cause bug 1362423). This also allows us to reduce
// checking mRequiresBidi all the time.
break;
} }
#if(0)
// XXX: Unnecessary work given that the below isn't executed.
// If we need bidi support for overflow, we need to enable this too.
/* if (!bpd.mRequiresBidi) { */
nsBlockFrame::FrameLines* overflowLines = block->GetOverflowLines();
if (overflowLines) { // XXX: see below
if (ChildListMayRequireBidi(overflowLines->mFrames.FirstChild(),
&currContent)) {
bpd.mRequiresBidi = true;
break; // as above
}
}
/* } */
#endif
}
// Moving the below here so that we can keep partial work causes RTL
// to get munged. It seems we really do have to iterate through all the
// frames again from the beginning if any are RTL.
if (!bpd.mRequiresBidi) {
return NS_OK;
}
}
for (nsBlockFrame* block = aBlockFrame; block; for (nsBlockFrame* block = aBlockFrame; block;
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) { block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION); block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
nsBlockInFlowLineIterator lineIter(block, block->begin_lines()); nsBlockInFlowLineIterator lineIter(block, block->begin_lines());
bpd.ResetForNewBlock(); bpd.ResetForNewBlock();
TraverseFrames(aBlockFrame, &lineIter, block->GetFirstPrincipalChild(), &bpd); TraverseFrames(aBlockFrame, &lineIter, block->GetFirstPrincipalChild(), &bpd);
// XXX what about overflow lines? #if(0)
nsBlockFrame::FrameLines* overflowLines = block->GetOverflowLines();
// XXX: Not sure if this is going to break anything.
// It's safe to do above (from bug 1358275) because that doesn't actually
// bidi-process the overflow lines; it just checks if we need to.
if (overflowLines) {
nsBlockInFlowLineIterator it(block, overflowLines->mLines.begin(), true);
bpd.ResetForNewBlock();
TraverseFrames(aBlockFrame, &it, overflowLines->mFrames.FirstChild(), &bpd);
}
#endif
} }
if (ch != 0) { if (ch != 0) {
@ -1241,6 +1299,56 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
MOZ_ASSERT(initialLineContainer == aLineIter->GetContainer()); MOZ_ASSERT(initialLineContainer == aLineIter->GetContainer());
} }
bool
nsBidiPresUtils::ChildListMayRequireBidi(nsIFrame* aFirstChild,
nsIContent** aCurrContent)
{
MOZ_ASSERT(!aFirstChild || !aFirstChild->GetPrevSibling(),
"Expecting to traverse from the start of a child list");
for (nsIFrame* childFrame = aFirstChild; childFrame;
childFrame = childFrame->GetNextSibling()) {
nsIFrame* frame = childFrame;
// If the real frame for a placeholder is a first-letter frame, we need to
// consider its contents for potential Bidi resolution.
if (childFrame->GetType() == nsGkAtoms::placeholderFrame) {
nsIFrame* realFrame =
nsPlaceholderFrame::GetRealFrameForPlaceholder(childFrame);
if (realFrame->GetType() == nsGkAtoms::letterFrame) {
frame = realFrame;
}
}
// If unicode-bidi properties are present, we should do bidi resolution.
nsStyleContext* sc = frame->StyleContext();
if (GetBidiControl(sc, kOverrideOrEmbed)) {
return true;
}
if (IsBidiLeaf(frame)) {
if (frame->GetType() == nsGkAtoms::textFrame) {
// Check whether the text frame has any RTL characters; if so, bidi
// resolution will be needed.
nsIContent* content = frame->GetContent();
if (content != *aCurrContent) {
*aCurrContent = content;
const nsTextFragment* txt = content->GetText();
if (txt->Is2b() && HasRTLChars(txt->Get2b(), txt->GetLength())) {
return true;
}
}
}
} else if (ChildListMayRequireBidi(frame->PrincipalChildList().FirstChild(),
aCurrContent)) {
return true;
}
}
return false;
}
void void
nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame, nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
BidiParagraphData* aBpd) BidiParagraphData* aBpd)

View File

@ -399,6 +399,23 @@ private:
nsIFrame* aCurrentFrame, nsIFrame* aCurrentFrame,
BidiParagraphData* aBpd); BidiParagraphData* aBpd);
/**
* Perform a recursive "pre-traversal" of the child frames of a block or
* inline container frame, to determine whether full bidi resolution is
* actually needed.
* This explores the same frames as TraverseFrames (above), but is less
* expensive and may allow us to avoid performing the full TraverseFrames
* operation.
* @param aFirstChild frame to start traversal from
* @param[in/out] aCurrContent the content node that we've most recently
* scanned for RTL characters (so that when descendant frames refer
* to the same content, we can avoid repeatedly scanning it).
* @return true if it finds that bidi is (or may be) required,
* false if no potentially-bidi content is present.
*/
static bool ChildListMayRequireBidi(nsIFrame* aFirstChild,
nsIContent** aCurrContent);
/** /**
* Position ruby content frames (ruby base/text frame). * Position ruby content frames (ruby base/text frame).
* Called from RepositionRubyFrame. * Called from RepositionRubyFrame.

View File

@ -647,7 +647,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)) mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame))
{ {
MOZ_COUNT_CTOR(nsDisplayListBuilder); MOZ_COUNT_CTOR(nsDisplayListBuilder);
PL_InitArenaPool(&mPool, "displayListArena", 1024, PL_InitArenaPool(&mPool, "displayListArena", 4096,
std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1); std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
nsPresContext* pc = aReferenceFrame->PresContext(); nsPresContext* pc = aReferenceFrame->PresContext();

View File

@ -9345,9 +9345,13 @@ nsTextFrame::GetRenderedText(uint32_t aStartOffset,
startOffset = aStartOffset; startOffset = aStartOffset;
endOffset = std::min<uint32_t>(INT32_MAX, aEndOffset); endOffset = std::min<uint32_t>(INT32_MAX, aEndOffset);
} }
// If startOffset and/or endOffset are inside of trimmedOffsets' range,
// then clamp the edges of trimmedOffsets accordingly.
int32_t origTrimmedOffsetsEnd = trimmedOffsets.GetEnd();
trimmedOffsets.mStart = std::max<uint32_t>(trimmedOffsets.mStart, trimmedOffsets.mStart = std::max<uint32_t>(trimmedOffsets.mStart,
startOffset); startOffset);
trimmedOffsets.mLength = std::min<uint32_t>(trimmedOffsets.GetEnd(), trimmedOffsets.mLength = std::min<uint32_t>(origTrimmedOffsetsEnd,
endOffset) - trimmedOffsets.mStart; endOffset) - trimmedOffsets.mStart;
if (trimmedOffsets.mLength <= 0) { if (trimmedOffsets.mLength <= 0) {
offsetInRenderedString = nextOffsetInRenderedString; offsetInRenderedString = nextOffsetInRenderedString;

View File

@ -1176,10 +1176,13 @@ GetStatesForPseudoClass(const nsAString& aStatePseudo)
nsCOMPtr<nsIAtom> atom = do_GetAtom(aStatePseudo); nsCOMPtr<nsIAtom> atom = do_GetAtom(aStatePseudo);
// Ignore :moz-any-link so we don't give the element simultaneous // Ignore :any-link so we don't give the element simultaneous
// visited and unvisited style state // visited and unvisited style state
if (nsCSSPseudoClasses::GetPseudoType(atom) == if (nsCSSPseudoClasses::GetPseudoType(atom) ==
nsCSSPseudoClasses::ePseudoClass_mozAnyLink) { nsCSSPseudoClasses::ePseudoClass_mozAnyLink ||
// XXX: this could be cleaned up. do it once it's building
nsCSSPseudoClasses::GetPseudoType(atom) ==
nsCSSPseudoClasses::ePseudoClass_anyLink) {
return EventStates(); return EventStates();
} }
// Our array above is long enough that indexing into it with // Our array above is long enough that indexing into it with

View File

@ -991,7 +991,6 @@ const KTableEntry nsCSSProps::kBoxShadowTypeKTable[] = {
const KTableEntry nsCSSProps::kBoxSizingKTable[] = { const KTableEntry nsCSSProps::kBoxSizingKTable[] = {
{ eCSSKeyword_content_box, uint8_t(StyleBoxSizing::Content) }, { eCSSKeyword_content_box, uint8_t(StyleBoxSizing::Content) },
{ eCSSKeyword_border_box, uint8_t(StyleBoxSizing::Border) }, { eCSSKeyword_border_box, uint8_t(StyleBoxSizing::Border) },
{ eCSSKeyword_padding_box, uint8_t(StyleBoxSizing::Padding) },
{ eCSSKeyword_UNKNOWN, -1 } { eCSSKeyword_UNKNOWN, -1 }
}; };

View File

@ -142,6 +142,8 @@ CSS_STATE_PSEUDO_CLASS(link, ":link", 0, "", NS_EVENT_STATE_UNVISITED)
// what matches :link or :visited // what matches :link or :visited
CSS_STATE_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link", 0, "", CSS_STATE_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link", 0, "",
NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED) NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)
CSS_STATE_PSEUDO_CLASS(anyLink, ":any-link", 0, "",
NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)
CSS_STATE_PSEUDO_CLASS(visited, ":visited", 0, "", NS_EVENT_STATE_VISITED) CSS_STATE_PSEUDO_CLASS(visited, ":visited", 0, "", NS_EVENT_STATE_VISITED)
CSS_STATE_PSEUDO_CLASS(active, ":active", 0, "", NS_EVENT_STATE_ACTIVE) CSS_STATE_PSEUDO_CLASS(active, ":active", 0, "", NS_EVENT_STATE_ACTIVE)

View File

@ -387,7 +387,7 @@ long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){
t[i] = book->valuelist+entry[i]*book->dim; t[i] = book->valuelist+entry[i]*book->dim;
} }
for(i=0,o=0;i<book->dim;i++,o+=step) for(i=0,o=0;i<book->dim;i++,o+=step)
for (j=0;j<step;j++) for (j=0;o+j<n && j<step;j++)
a[o+j]+=t[j][i]; a[o+j]+=t[j][i];
} }
return(0); return(0);
@ -399,42 +399,13 @@ long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){
int i,j,entry; int i,j,entry;
float *t; float *t;
if(book->dim>8){
for(i=0;i<n;){ for(i=0;i<n;){
entry = decode_packed_entry_number(book,b); entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1); if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim; t = book->valuelist+entry*book->dim;
for (j=0;j<book->dim;) for(j=0;i<n && j<book->dim;)
a[i++]+=t[j++]; a[i++]+=t[j++];
} }
}else{
for(i=0;i<n;){
entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1);
t = book->valuelist+entry*book->dim;
j=0;
switch((int)book->dim){
case 8:
a[i++]+=t[j++];
case 7:
a[i++]+=t[j++];
case 6:
a[i++]+=t[j++];
case 5:
a[i++]+=t[j++];
case 4:
a[i++]+=t[j++];
case 3:
a[i++]+=t[j++];
case 2:
a[i++]+=t[j++];
case 1:
a[i++]+=t[j++];
case 0:
break;
}
}
}
} }
return(0); return(0);
} }
@ -471,12 +442,13 @@ long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
long i,j,entry; long i,j,entry;
int chptr=0; int chptr=0;
if(book->used_entries>0){ if(book->used_entries>0){
for(i=offset/ch;i<(offset+n)/ch;){ int m=(offset+n)/ch;
for(i=offset/ch;i<m;){
entry = decode_packed_entry_number(book,b); entry = decode_packed_entry_number(book,b);
if(entry==-1)return(-1); if(entry==-1)return(-1);
{ {
const float *t = book->valuelist+entry*book->dim; const float *t = book->valuelist+entry*book->dim;
for (j=0;j<book->dim;j++){ for (j=0;i<m && j<book->dim;j++){
a[chptr++][i]+=t[j]; a[chptr++][i]+=t[j];
if(chptr==ch){ if(chptr==ch){
chptr=0; chptr=0;

View File

@ -186,7 +186,7 @@ cglobal quantize_%1, 0, %2, 15, coeff, ncoeff, skip, zbin, round, quant, \
pshuflw m7, m8, 0x1 pshuflw m7, m8, 0x1
pmaxsw m8, m7 pmaxsw m8, m7
pextrw r6, m8, 0 pextrw r6, m8, 0
mov [r2], r6 mov [r2], r6w
RET RET
; skip-block, i.e. just write all zeroes ; skip-block, i.e. just write all zeroes

View File

@ -1412,7 +1412,7 @@ pref("network.http.bypass-cachelock-threshold", 250);
// Try and use SPDY when using SSL // Try and use SPDY when using SSL
pref("network.http.spdy.enabled", true); pref("network.http.spdy.enabled", true);
pref("network.http.spdy.enabled.v3-1", true); pref("network.http.spdy.enabled.v3-1", false);
pref("network.http.spdy.enabled.http2", true); pref("network.http.spdy.enabled.http2", true);
pref("network.http.spdy.enabled.deps", true); pref("network.http.spdy.enabled.deps", true);
pref("network.http.spdy.enforce-tls-profile", true); pref("network.http.spdy.enforce-tls-profile", true);
@ -5137,4 +5137,4 @@ pref("toolkit.pageThumbs.minWidth", 0);
pref("toolkit.pageThumbs.minHeight", 0); pref("toolkit.pageThumbs.minHeight", 0);
pref("tenfourfox.adblock.enabled", false); pref("tenfourfox.adblock.enabled", false);
pref("tenfourfox.adblock.logging.enabled", true); pref("tenfourfox.adblock.logging.enabled", false);

View File

@ -19,6 +19,7 @@ pref("security.ssl.enable_alpn", true);
pref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", true); pref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", true);
pref("security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256", true); pref("security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256", true);
pref("security.ssl3.ecdhe_rsa_aes_128_sha", true); pref("security.ssl3.ecdhe_rsa_aes_128_sha", true);
pref("security.ssl3.ecdhe_rsa_aes_128_sha256", true);
pref("security.ssl3.ecdhe_ecdsa_aes_128_sha", true); pref("security.ssl3.ecdhe_ecdsa_aes_128_sha", true);
pref("security.ssl3.ecdhe_rsa_aes_256_sha", true); pref("security.ssl3.ecdhe_rsa_aes_256_sha", true);
pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", true); pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", true);

View File

@ -1014,6 +1014,15 @@ Http2Session::CleanupStream(Http2Stream *aStream, nsresult aResult,
return; return;
} }
Http2PushedStream *pushSource = aStream->PushSource();
if (pushSource) {
// aStream is a synthetic attached to an even push
MOZ_ASSERT(pushSource->GetConsumerStream() == aStream);
MOZ_ASSERT(!aStream->StreamID());
MOZ_ASSERT(!(pushSource->StreamID() & 0x1));
aStream->ClearPushSource();
}
if (aStream->DeferCleanup(aResult)) { if (aStream->DeferCleanup(aResult)) {
LOG3(("Http2Session::CleanupStream 0x%X deferred\n", aStream->StreamID())); LOG3(("Http2Session::CleanupStream 0x%X deferred\n", aStream->StreamID()));
return; return;
@ -1024,15 +1033,6 @@ Http2Session::CleanupStream(Http2Stream *aStream, nsresult aResult,
return; return;
} }
Http2PushedStream *pushSource = aStream->PushSource();
if (pushSource) {
// aStream is a synthetic attached to an even push
MOZ_ASSERT(pushSource->GetConsumerStream() == aStream);
MOZ_ASSERT(!aStream->StreamID());
MOZ_ASSERT(!(pushSource->StreamID() & 0x1));
pushSource->SetConsumerStream(nullptr);
}
if (!aStream->RecvdFin() && !aStream->RecvdReset() && aStream->StreamID()) { if (!aStream->RecvdFin() && !aStream->RecvdReset() && aStream->StreamID()) {
LOG3(("Stream had not processed recv FIN, sending RST code %X\n", aResetCode)); LOG3(("Stream had not processed recv FIN, sending RST code %X\n", aResetCode));
GenerateRstStream(aResetCode, aStream->StreamID()); GenerateRstStream(aResetCode, aStream->StreamID());

View File

@ -101,10 +101,20 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
Http2Stream::~Http2Stream() Http2Stream::~Http2Stream()
{ {
ClearPushSource();
ClearTransactionsBlockedOnTunnel(); ClearTransactionsBlockedOnTunnel();
mStreamID = Http2Session::kDeadStreamID; mStreamID = Http2Session::kDeadStreamID;
} }
void
Http2Stream::ClearPushSource()
{
if (mPushSource) {
mPushSource->SetConsumerStream(nullptr);
mPushSource = nullptr;
}
}
// ReadSegments() is used to write data down the socket. Generally, HTTP // ReadSegments() is used to write data down the socket. Generally, HTTP
// request data is pulled from the approriate transaction and // request data is pulled from the approriate transaction and
// converted to HTTP/2 data. Sometimes control data like a window-update is // converted to HTTP/2 data. Sometimes control data like a window-update is
@ -1091,6 +1101,10 @@ Http2Stream::ConvertPushHeaders(Http2Decompressor *decompressor,
void void
Http2Stream::Close(nsresult reason) Http2Stream::Close(nsresult reason)
{ {
// In case we are connected to a push, make sure the push knows we are closed,
// so it doesn't try to give us any more DATA that comes on it after our close.
ClearPushSource();
mTransaction->Close(reason); mTransaction->Close(reason);
} }

View File

@ -47,6 +47,7 @@ public:
uint32_t StreamID() { return mStreamID; } uint32_t StreamID() { return mStreamID; }
Http2PushedStream *PushSource() { return mPushSource; } Http2PushedStream *PushSource() { return mPushSource; }
void ClearPushSource();
stateType HTTPState() { return mState; } stateType HTTPState() { return mState; }
void SetHTTPState(stateType val) { mState = val; } void SetHTTPState(stateType val) { mState = val; }

View File

@ -1032,6 +1032,7 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "goto.google.com", true, false, false, -1, &kPinset_google_root_pems }, { "goto.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "gr.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, { "gr.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "groups.google.com", true, false, false, -1, &kPinset_google_root_pems }, { "groups.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "gstatic.cn", true, false, false, -1, &kPinset_google_root_pems },
{ "gstatic.com", true, false, false, -1, &kPinset_google_root_pems }, { "gstatic.com", true, false, false, -1, &kPinset_google_root_pems },
{ "gvt1.com", true, false, false, -1, &kPinset_google_root_pems }, { "gvt1.com", true, false, false, -1, &kPinset_google_root_pems },
{ "gvt2.com", true, false, false, -1, &kPinset_google_root_pems }, { "gvt2.com", true, false, false, -1, &kPinset_google_root_pems },
@ -1179,8 +1180,8 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
}; };
// Pinning Preload List Length = 477; // Pinning Preload List Length = 478;
static const int32_t kUnknownId = -1; static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1527453921095000); static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1528837162062000);

View File

@ -30,8 +30,10 @@ using namespace mozilla::psm;
extern PRLogModuleInfo* gPIPNSSLog; extern PRLogModuleInfo* gPIPNSSLog;
#if (0) // TenFourFox issue 334
static void AccumulateCipherSuite(Telemetry::ID probe, static void AccumulateCipherSuite(Telemetry::ID probe,
const SSLChannelInfo& channelInfo); const SSLChannelInfo& channelInfo);
#endif
namespace { namespace {
@ -1027,6 +1029,7 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
return SECSuccess; return SECSuccess;
} }
#if(0) // TenFourFox issue 334
static void static void
AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits) AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits)
{ {
@ -1076,6 +1079,7 @@ AccumulateCipherSuite(Telemetry::ID probe, const SSLChannelInfo& channelInfo)
case TLS_ECDHE_RSA_WITH_RC4_128_SHA: value = 8; break; case TLS_ECDHE_RSA_WITH_RC4_128_SHA: value = 8; break;
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: value = 9; break; case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: value = 9; break;
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break; case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: value = 11; break; // just in case, issue 489
// DHE key exchange // DHE key exchange
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break; case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
@ -1114,6 +1118,7 @@ AccumulateCipherSuite(Telemetry::ID probe, const SSLChannelInfo& channelInfo)
MOZ_ASSERT(value != 0); MOZ_ASSERT(value != 0);
Telemetry::Accumulate(probe, value); Telemetry::Accumulate(probe, value);
} }
#endif
void HandshakeCallback(PRFileDesc* fd, void* client_data) { void HandshakeCallback(PRFileDesc* fd, void* client_data) {
nsNSSShutDownPreventionLock locker; nsNSSShutDownPreventionLock locker;
@ -1146,6 +1151,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)); rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
MOZ_ASSERT(rv == SECSuccess); MOZ_ASSERT(rv == SECSuccess);
if (rv == SECSuccess) { if (rv == SECSuccess) {
#if(0) // TenFourFox issue 334
// Get the protocol version for telemetry // Get the protocol version for telemetry
// 1=tls1, 2=tls1.1, 3=tls1.2 // 1=tls1, 2=tls1.1, 3=tls1.2
unsigned int versionEnum = channelInfo.protocolVersion & 0xFF; unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
@ -1155,6 +1161,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
: Telemetry::SSL_CIPHER_SUITE_RESUMED, : Telemetry::SSL_CIPHER_SUITE_RESUMED,
channelInfo); channelInfo);
#endif
SSLCipherSuiteInfo cipherInfo; SSLCipherSuiteInfo cipherInfo;
rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
@ -1163,17 +1170,20 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
if (rv == SECSuccess) { if (rv == SECSuccess) {
usesWeakCipher = cipherInfo.symCipher == ssl_calg_rc4; usesWeakCipher = cipherInfo.symCipher == ssl_calg_rc4;
#if(0)
// keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4 // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
Telemetry::Accumulate( Telemetry::Accumulate(
infoObject->IsFullHandshake() infoObject->IsFullHandshake()
? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
: Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED, : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
cipherInfo.keaType); cipherInfo.keaType);
#endif
DebugOnly<int16_t> KEAUsed; DebugOnly<int16_t> KEAUsed;
MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) && MOZ_ASSERT(NS_SUCCEEDED(infoObject->GetKEAUsed(&KEAUsed)) &&
(KEAUsed == cipherInfo.keaType)); (KEAUsed == cipherInfo.keaType));
#if(0)
if (infoObject->IsFullHandshake()) { if (infoObject->IsFullHandshake()) {
switch (cipherInfo.keaType) { switch (cipherInfo.keaType) {
case ssl_kea_rsa: case ssl_kea_rsa:
@ -1223,6 +1233,7 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
? Telemetry::SSL_SYMMETRIC_CIPHER_FULL ? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
: Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED, : Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
cipherInfo.symCipher); cipherInfo.symCipher);
#endif
} }
} }

View File

@ -623,6 +623,9 @@ static const CipherPref sCipherPrefs[] = {
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, true }, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, true },
{ "security.ssl3.ecdhe_ecdsa_aes_128_sha", { "security.ssl3.ecdhe_ecdsa_aes_128_sha",
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true }, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true },
// stopgap for TenFourFox issue 489 pending ChaCha20/Poly1305 implementation
{ "security.ssl3.ecdhe_rsa_aes_128_sha256",
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, true },
{ "security.ssl3.ecdhe_rsa_aes_256_sha", { "security.ssl3.ecdhe_rsa_aes_256_sha",
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true }, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true },

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ if (versionNum.substr(0,3) == "45.") {
// FPR series // FPR series
var vf = 0 + versionNum.substr(3); var vf = 0 + versionNum.substr(3);
var pl = ""+ (vf - (vf|0)); var pl = ""+ (vf - (vf|0));
pl = 0 + pl.substr(1); pl = ((0 + pl.substr(1) * 10)+0.001)|0; // damn float rounding
vf = vf|0; vf -= 9; vf = vf|0; vf -= 9;
// XXX localize me // XXX localize me
version.textContent = "Feature Parity Release "+vf+ version.textContent = "Feature Parity Release "+vf+

View File

@ -59,6 +59,13 @@ interface nsIDatePicker : nsISupports
*/ */
attribute AString maxDate; attribute AString maxDate;
/**
* The selected date.
*
* @return Returns the date currently selected.
*/
readonly attribute AString selectedDate;
/** /**
* Show date dialog. The dialog is displayed modally. * Show date dialog. The dialog is displayed modally.
* *

View File

@ -12,6 +12,7 @@
#include "mozilla/HashFunctions.h" #include "mozilla/HashFunctions.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "nsAlgorithm.h" #include "nsAlgorithm.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/ChaosMode.h" #include "mozilla/ChaosMode.h"
@ -71,7 +72,7 @@ PLDHashTable::HashStringKey(PLDHashTable* aTable, const void* aKey)
/* static */ PLDHashNumber /* static */ PLDHashNumber
PLDHashTable::HashVoidPtrKeyStub(PLDHashTable* aTable, const void* aKey) PLDHashTable::HashVoidPtrKeyStub(PLDHashTable* aTable, const void* aKey)
{ {
return (PLDHashNumber)(ptrdiff_t)aKey >> 2; return mozilla::HashGeneric(aKey);
} }
/* static */ bool /* static */ bool
@ -256,15 +257,38 @@ PLDHashTable::Hash1(PLDHashNumber aHash0)
return aHash0 >> mHashShift; return aHash0 >> mHashShift;
} }
// Double hashing needs the second hash code to be relatively prime to table
// size, so we simply make hash2 odd.
void void
PLDHashTable::Hash2(PLDHashNumber aHash, PLDHashTable::Hash2(PLDHashNumber aHash0,
uint32_t& aHash2Out, uint32_t& aSizeMaskOut) uint32_t& aHash2Out, uint32_t& aSizeMaskOut)
{ {
uint32_t sizeLog2 = kHashBits - mHashShift; uint32_t sizeLog2 = kHashBits - mHashShift;
aHash2Out = ((aHash << sizeLog2) >> mHashShift) | 1; uint32_t sizeMask = (PLDHashNumber(1) << sizeLog2) - 1;
aSizeMaskOut = (PLDHashNumber(1) << sizeLog2) - 1; aSizeMaskOut = sizeMask;
// The incoming aHash0 always has the low bit unset (since we leave it
// free for the collision flag), and should have reasonably random
// data in the other 31 bits. We used the high bits of aHash0 for
// Hash1, so we use the low bits here. If the table size is large,
// the bits we use may overlap, but that's still more random than
// filling with 0s.
//
// Since the result of Hash2 controls how far we jump around the table
// to build a chain after starting at a location determined by Hash1,
// we'd like to keep it small, to improve cache behavior.
// Keep the jumps from the second hash small, to improve cache behavior.
const uint32_t kHash2MaskMaxBits = 6;
uint32_t hash2Mask;
if (sizeLog2 >= kHash2MaskMaxBits) {
hash2Mask = (PLDHashNumber(1) << kHash2MaskMaxBits) - 1;
} else {
hash2Mask = sizeMask;
}
// Double hashing needs the second hash code to be relatively prime to table
// size, so we simply make hash2 odd.
//
// This also conveniently covers up the fact that we have the low bit
// unset since aHash0 has the low bit unset.
aHash2Out = (aHash0 & hash2Mask) | 1;
} }
// Reserve mKeyHash 0 for free entries and 1 for removed-entry sentinels. Note // Reserve mKeyHash 0 for free entries and 1 for removed-entry sentinels. Note

View File

@ -1026,6 +1026,17 @@ CountCharInReadable(const nsACString& aStr, char aChar)
return count; return count;
} }
bool
StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring)
{
nsAString::size_type src_len = aSource.Length(),
sub_len = aSubstring.Length();
if (sub_len > src_len) {
return false;
}
return Substring(aSource, 0, sub_len).Equals(aSubstring);
}
bool bool
StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring, StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
const nsStringComparator& aComparator) const nsStringComparator& aComparator)
@ -1038,6 +1049,17 @@ StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
} }
bool
StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring)
{
nsACString::size_type src_len = aSource.Length(),
sub_len = aSubstring.Length();
if (sub_len > src_len) {
return false;
}
return Substring(aSource, 0, sub_len).Equals(aSubstring);
}
bool bool
StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring, StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
const nsCStringComparator& aComparator) const nsCStringComparator& aComparator)
@ -1050,6 +1072,17 @@ StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
} }
bool
StringEndsWith(const nsAString& aSource, const nsAString& aSubstring)
{
nsAString::size_type src_len = aSource.Length(),
sub_len = aSubstring.Length();
if (sub_len > src_len) {
return false;
}
return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
}
bool bool
StringEndsWith(const nsAString& aSource, const nsAString& aSubstring, StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
const nsStringComparator& aComparator) const nsStringComparator& aComparator)
@ -1063,6 +1096,17 @@ StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
aComparator); aComparator);
} }
bool
StringEndsWith(const nsACString& aSource, const nsACString& aSubstring)
{
nsACString::size_type src_len = aSource.Length(),
sub_len = aSubstring.Length();
if (sub_len > src_len) {
return false;
}
return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
}
bool bool
StringEndsWith(const nsACString& aSource, const nsACString& aSubstring, StringEndsWith(const nsACString& aSource, const nsACString& aSubstring,
const nsCStringComparator& aComparator) const nsCStringComparator& aComparator)

View File

@ -386,18 +386,18 @@ uint32_t CountCharInReadable(const nsAString& aStr,
uint32_t CountCharInReadable(const nsACString& aStr, uint32_t CountCharInReadable(const nsACString& aStr,
char aChar); char aChar);
bool StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring);
bool StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring, bool StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
const nsStringComparator& aComparator = const nsStringComparator& aComparator);
nsDefaultStringComparator()); bool StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring);
bool StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring, bool StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
const nsCStringComparator& aComparator = const nsCStringComparator& aComparator);
nsDefaultCStringComparator()); bool StringEndsWith(const nsAString& aSource, const nsAString& aSubstring);
bool StringEndsWith(const nsAString& aSource, const nsAString& aSubstring, bool StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
const nsStringComparator& aComparator = const nsStringComparator& aComparator);
nsDefaultStringComparator()); bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring);
bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring, bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring,
const nsCStringComparator& aComparator = const nsCStringComparator& aComparator);
nsDefaultCStringComparator());
const nsAFlatString& EmptyString(); const nsAFlatString& EmptyString();
const nsAFlatCString& EmptyCString(); const nsAFlatCString& EmptyCString();