зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge
MozReview-Commit-ID: 2k4filK9zyX
This commit is contained in:
Коммит
39066d6984
|
@ -231,9 +231,9 @@ var TabsInTitlebar = {
|
|||
}
|
||||
|
||||
// Then add a negative margin to the titlebar, so that the following elements
|
||||
// will overlap it by the lesser of the titlebar height or the tabstrip+menu.
|
||||
let minTitlebarOrTabsHeight = Math.min(titlebarContentHeight, tabAndMenuHeight);
|
||||
titlebar.style.marginBottom = "-" + minTitlebarOrTabsHeight + "px";
|
||||
// will overlap it by the greater of the titlebar height or the tabstrip+menu.
|
||||
let maxTitlebarOrTabsHeight = Math.max(titlebarContentHeight, tabAndMenuHeight);
|
||||
titlebar.style.marginBottom = "-" + maxTitlebarOrTabsHeight + "px";
|
||||
|
||||
// Finally, size the placeholders:
|
||||
if (AppConstants.platform == "macosx") {
|
||||
|
|
|
@ -47,20 +47,42 @@ const startupPhases = {
|
|||
// For the following phases of startup we have only a black list for now
|
||||
|
||||
// We are at this phase after creating the first browser window (ie. after final-ui-startup).
|
||||
"before opening first browser window": {},
|
||||
"before opening first browser window": {blacklist: {
|
||||
components: new Set([
|
||||
"nsAsyncShutdown.js",
|
||||
]),
|
||||
modules: new Set([
|
||||
"resource://gre/modules/PlacesBackups.jsm",
|
||||
"resource://gre/modules/PlacesUtils.jsm",
|
||||
])
|
||||
}},
|
||||
|
||||
// We reach this phase right after showing the first browser window.
|
||||
// This means that anything already loaded at this point has been loaded
|
||||
// before first paint and delayed it.
|
||||
"before first paint": {blacklist: {
|
||||
components: new Set([
|
||||
"nsSearchService.js",
|
||||
"PageIconProtocolHandler.js",
|
||||
"PlacesCategoriesStarter.js",
|
||||
"UnifiedComplete.js",
|
||||
"nsPlacesExpiration.js",
|
||||
"nsSearchService.js",
|
||||
]),
|
||||
modules: new Set([
|
||||
"resource://gre/modules/ContextualIdentityService.jsm"
|
||||
"resource:///modules/AboutNewTab.jsm",
|
||||
"resource:///modules/DirectoryLinksProvider.jsm",
|
||||
"resource://gre/modules/BookmarkHTMLUtils.jsm",
|
||||
"resource://gre/modules/Bookmarks.jsm",
|
||||
"resource://gre/modules/ContextualIdentityService.jsm",
|
||||
"resource://gre/modules/NewTabUtils.jsm",
|
||||
"resource://gre/modules/PageThumbs.jsm",
|
||||
"resource://gre/modules/PlacesSyncUtils.jsm",
|
||||
"resource://gre/modules/Sqlite.jsm",
|
||||
]),
|
||||
services: new Set([
|
||||
"@mozilla.org/browser/annotation-service;1",
|
||||
"@mozilla.org/browser/favicon-service;1",
|
||||
"@mozilla.org/browser/nav-bookmarks-service;1",
|
||||
"@mozilla.org/browser/search-service;1",
|
||||
])
|
||||
}},
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-typing"] {
|
||||
overflow: hidden;
|
||||
max-width: 8ch;
|
||||
max-width: 12ch;
|
||||
width: 0;
|
||||
animation-name: search-suggestions-hint-typing;
|
||||
animation-duration: 500ms;
|
||||
|
@ -137,7 +137,7 @@
|
|||
|
||||
@keyframes search-suggestions-hint-typing {
|
||||
from { width: 0; }
|
||||
to { width: 8ch; }
|
||||
to { width: 12ch; }
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-box"] {
|
||||
|
|
|
@ -127,7 +127,7 @@ def using_ccache(ccache, ccache_is_sccache):
|
|||
|
||||
@depends_if(ccache, ccache_is_sccache)
|
||||
def using_sccache(ccache, ccache_is_sccache):
|
||||
return True
|
||||
return ccache and ccache_is_sccache
|
||||
|
||||
set_config('MOZ_USING_CCACHE', using_ccache)
|
||||
set_config('MOZ_USING_SCCACHE', using_sccache)
|
||||
|
|
|
@ -677,6 +677,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
|
|||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
|
||||
cb.NoteXPCOMChild(mClassList.get());
|
||||
|
||||
|
@ -711,6 +714,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
|
|||
mShadowRoot = nullptr;
|
||||
mContainingShadow = nullptr;
|
||||
mChildrenList = nullptr;
|
||||
mLabelsList = nullptr;
|
||||
mCustomElementData = nullptr;
|
||||
mClassList = nullptr;
|
||||
mRegisteredIntersectionObservers.Clear();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
class ContentUnbinder;
|
||||
class nsContentList;
|
||||
class nsLabelsNodeList;
|
||||
class nsDOMAttributeMap;
|
||||
class nsDOMTokenList;
|
||||
class nsIControllers;
|
||||
|
@ -313,6 +314,11 @@ public:
|
|||
*/
|
||||
RefPtr<nsDOMTokenList> mClassList;
|
||||
|
||||
/*
|
||||
* An object implementing the .labels property for this element.
|
||||
*/
|
||||
RefPtr<nsLabelsNodeList> mLabelsList;
|
||||
|
||||
/**
|
||||
* ShadowRoot bound to the element.
|
||||
*/
|
||||
|
|
|
@ -253,19 +253,6 @@ const nsCacheableFuncStringContentList::ContentListType
|
|||
nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection;
|
||||
#endif
|
||||
|
||||
JSObject*
|
||||
nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
|
||||
JSObject*
|
||||
nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// Hashtable for storing nsCacheableFuncStringContentList
|
||||
static PLDHashTable* gFuncStringContentListHashTable;
|
||||
|
||||
|
@ -378,6 +365,7 @@ NS_GetFuncStringHTMLCollection(nsINode* aRootNode,
|
|||
aString);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// nsContentList implementation
|
||||
|
||||
nsContentList::nsContentList(nsINode* aRootNode,
|
||||
|
@ -659,7 +647,7 @@ nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
|
|||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_PRECONDITION(aElement, "Must have a content node to work with");
|
||||
|
||||
|
||||
if (!mFunc || !mFuncMayDependOnAttr || mState == LIST_DIRTY ||
|
||||
!MayContainRelevantNodes(aElement->GetParentNode()) ||
|
||||
!nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
|
||||
|
@ -805,7 +793,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
|
|||
|
||||
ASSERT_IN_SYNC;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsContentList::ContentRemoved(nsIDocument *aDocument,
|
||||
nsIContent* aContainer,
|
||||
|
@ -1074,3 +1062,126 @@ nsContentList::AssertInSync()
|
|||
NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------
|
||||
// nsCacheableFuncStringNodeList
|
||||
|
||||
JSObject*
|
||||
nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// nsCacheableFuncStringHTMLCollection
|
||||
|
||||
JSObject*
|
||||
nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// nsLabelsNodeList
|
||||
|
||||
JSObject*
|
||||
nsLabelsNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
|
||||
int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
MOZ_ASSERT(aElement, "Must have a content node to work with");
|
||||
if (mState == LIST_DIRTY ||
|
||||
!nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to handle input type changes to or from "hidden".
|
||||
if (aElement->IsHTMLElement(nsGkAtoms::input) &&
|
||||
aAttribute == nsGkAtoms::type && aNameSpaceID == kNameSpaceID_None) {
|
||||
SetDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
// If a labelable element is moved to outside or inside of
|
||||
// nested associated labels, we're gonna have to modify
|
||||
// the content list.
|
||||
if (mState != LIST_DIRTY ||
|
||||
nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer)) {
|
||||
SetDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
// If a labelable element is moved to outside or inside of
|
||||
// nested associated labels, we're gonna have to modify
|
||||
// the content list.
|
||||
if (mState != LIST_DIRTY ||
|
||||
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
|
||||
SetDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
// If a labelable element is removed, we're gonna have to clean
|
||||
// the content list.
|
||||
if (mState != LIST_DIRTY ||
|
||||
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
|
||||
SetDirty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode)
|
||||
{
|
||||
MOZ_ASSERT(aRootNode, "Must have root");
|
||||
if (mRootNode == aRootNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRootNode->RemoveMutationObserver(this);
|
||||
mRootNode = aRootNode;
|
||||
mRootNode->AddMutationObserver(this);
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
|
||||
{
|
||||
MOZ_ASSERT(mRootNode, "Must have root");
|
||||
|
||||
// Start searching at the root.
|
||||
nsINode* cur = mRootNode;
|
||||
if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) {
|
||||
mElements.AppendElement(cur->AsElement());
|
||||
}
|
||||
|
||||
nsContentList::PopulateSelf(aNeededLength);
|
||||
}
|
||||
|
|
|
@ -376,9 +376,9 @@ protected:
|
|||
* traversed the whole document (or both).
|
||||
*
|
||||
* @param aNeededLength the length the list should have when we are
|
||||
* done (unless it exhausts the document)
|
||||
* done (unless it exhausts the document)
|
||||
*/
|
||||
void PopulateSelf(uint32_t aNeededLength);
|
||||
virtual void PopulateSelf(uint32_t aNeededLength);
|
||||
|
||||
/**
|
||||
* @param aContainer a content node which must be a descendant of
|
||||
|
@ -589,4 +589,40 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
class nsLabelsNodeList final : public nsContentList
|
||||
{
|
||||
public:
|
||||
nsLabelsNodeList(nsINode* aRootNode,
|
||||
nsContentListMatchFunc aFunc,
|
||||
nsContentListDestroyFunc aDestroyFunc,
|
||||
void* aData)
|
||||
: nsContentList(aRootNode, aFunc, aDestroyFunc, aData)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
* Reset root, mutation observer, and clear content list
|
||||
* if the root has been changed.
|
||||
*
|
||||
* @param aRootNode The node under which to limit our search.
|
||||
*/
|
||||
void MaybeResetRoot(nsINode* aRootNode);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Start searching at the last one if we already have nodes, otherwise
|
||||
* start searching at the root.
|
||||
*
|
||||
* @param aNeededLength The list of length should have when we are
|
||||
* done (unless it exhausts the document).
|
||||
*/
|
||||
void PopulateSelf(uint32_t aNeededLength) override;
|
||||
};
|
||||
#endif // nsContentList_h___
|
||||
|
|
|
@ -339,17 +339,6 @@ nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
|
|||
return rv;
|
||||
}
|
||||
}
|
||||
else if (aHeader == nsGkAtoms::msthemecompatible) {
|
||||
// Disable theming for the presshell if the value is no.
|
||||
// XXXbz don't we want to support this as an HTTP header too?
|
||||
nsAutoString value(aValue);
|
||||
if (value.LowerCaseEqualsLiteral("no")) {
|
||||
nsIPresShell* shell = mDocument->GetShell();
|
||||
if (shell) {
|
||||
shell->DisableThemeSupport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -598,6 +598,7 @@ GK_ATOM(keytext, "keytext")
|
|||
GK_ATOM(keyup, "keyup")
|
||||
GK_ATOM(kind, "kind")
|
||||
GK_ATOM(label, "label")
|
||||
GK_ATOM(labels, "labels")
|
||||
GK_ATOM(lang, "lang")
|
||||
GK_ATOM(language, "language")
|
||||
GK_ATOM(last, "last")
|
||||
|
@ -709,7 +710,6 @@ GK_ATOM(mozprivatebrowsing, "mozprivatebrowsing")
|
|||
GK_ATOM(moz_opaque, "moz-opaque")
|
||||
GK_ATOM(moz_action_hint, "mozactionhint")
|
||||
GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
|
||||
GK_ATOM(msthemecompatible, "msthemecompatible")
|
||||
GK_ATOM(multicol, "multicol")
|
||||
GK_ATOM(multiple, "multiple")
|
||||
GK_ATOM(muted, "muted")
|
||||
|
|
|
@ -1995,7 +1995,7 @@ InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData)
|
|||
}
|
||||
|
||||
TimeStamp startTimeStamp = TimeStamp::Now();
|
||||
|
||||
TimeDuration duration = sGCUnnotifiedTotalTime;
|
||||
uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
|
||||
nsJSContext::GarbageCollectNow(aData ?
|
||||
static_cast<JS::gcreason::Reason>(reason) :
|
||||
|
@ -2004,20 +2004,20 @@ InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData)
|
|||
nsJSContext::NonShrinkingGC,
|
||||
budget);
|
||||
|
||||
TimeDuration duration = sGCUnnotifiedTotalTime;
|
||||
sGCUnnotifiedTotalTime = TimeDuration();
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration sliceDuration = now - startTimeStamp;
|
||||
duration += sliceDuration;
|
||||
if (duration.ToSeconds()) {
|
||||
TimeDuration idleDuration;
|
||||
if (!aDeadline.IsNull()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
if (aDeadline < now) {
|
||||
// This slice overflowed the idle period.
|
||||
idleDuration = aDeadline - startTimeStamp;
|
||||
} else {
|
||||
// Note, we don't want to use duration here, since it may contain
|
||||
// data also from JS engine triggered GC slices.
|
||||
idleDuration = now - startTimeStamp;
|
||||
idleDuration = sliceDuration;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8157,6 +8157,16 @@ HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence)
|
|||
aSequence.AppendElements(mFileData->mEntries);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINodeList>
|
||||
HTMLInputElement::GetLabels()
|
||||
{
|
||||
if (!IsLabelable()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::Labels();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -735,6 +735,8 @@ public:
|
|||
|
||||
// XPCOM GetCustomVisibility() is OK
|
||||
|
||||
already_AddRefed<nsINodeList> GetLabels();
|
||||
|
||||
// XPCOM Select() is OK
|
||||
|
||||
Nullable<uint32_t> GetSelectionStart(ErrorResult& aRv);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsFocusManager.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
|
||||
// construction, destruction
|
||||
|
||||
|
@ -268,17 +269,23 @@ HTMLLabelElement::GetLabeledElement() const
|
|||
return GetFirstLabelableDescendant();
|
||||
}
|
||||
|
||||
// We have a @for. The id has to be linked to an element in the same document
|
||||
// We have a @for. The id has to be linked to an element in the same tree
|
||||
// and this element should be a labelable form control.
|
||||
//XXXsmaug It is unclear how this should work in case the element is in
|
||||
// Shadow DOM.
|
||||
// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365.
|
||||
nsIDocument* doc = GetUncomposedDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
nsINode* root = SubtreeRoot();
|
||||
ShadowRoot* shadow = ShadowRoot::FromNode(root);
|
||||
Element* element = nullptr;
|
||||
|
||||
if (shadow) {
|
||||
element = shadow->GetElementById(elementId);
|
||||
} else {
|
||||
nsIDocument* doc = GetUncomposedDoc();
|
||||
if (doc) {
|
||||
element = doc->GetElementById(elementId);
|
||||
} else {
|
||||
element = nsContentUtils::MatchElementId(root->AsContent(), elementId);
|
||||
}
|
||||
}
|
||||
|
||||
Element* element = doc->GetElementById(elementId);
|
||||
if (element && element->IsLabelable()) {
|
||||
return static_cast<nsGenericHTMLElement*>(element);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "ReferrerPolicy.h"
|
||||
#include "mozilla/dom/HTMLLabelElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -511,6 +512,14 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
}
|
||||
}
|
||||
|
||||
// We need to consider a labels element is moved to another subtree
|
||||
// with different root, it needs to update labels list and its root
|
||||
// as well.
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
if (slots && slots->mLabelsList) {
|
||||
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -531,6 +540,13 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
}
|
||||
}
|
||||
|
||||
// We need to consider a labels element is removed from tree,
|
||||
// it needs to update labels list and its root as well.
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
if (slots && slots->mLabelsList) {
|
||||
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
||||
}
|
||||
|
||||
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
|
@ -1679,6 +1695,30 @@ nsGenericHTMLElement::IsLabelable() const
|
|||
return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsGenericHTMLElement::MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData)
|
||||
{
|
||||
HTMLLabelElement* element = HTMLLabelElement::FromContent(aElement);
|
||||
return element && element->GetControl() == aData;
|
||||
}
|
||||
|
||||
already_AddRefed<nsINodeList>
|
||||
nsGenericHTMLElement::Labels()
|
||||
{
|
||||
MOZ_ASSERT(IsLabelable(),
|
||||
"Labels() only allow labelable elements to use it.");
|
||||
nsDOMSlots* slots = DOMSlots();
|
||||
|
||||
if (!slots->mLabelsList) {
|
||||
slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement,
|
||||
nullptr, this);
|
||||
}
|
||||
|
||||
RefPtr<nsLabelsNodeList> labels = slots->mLabelsList;
|
||||
return labels.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
|
||||
{
|
||||
|
|
|
@ -851,6 +851,12 @@ public:
|
|||
}
|
||||
|
||||
virtual bool IsLabelable() const override;
|
||||
|
||||
static bool MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
|
||||
already_AddRefed<nsINodeList> Labels();
|
||||
|
||||
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
|
||||
|
||||
static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */);
|
||||
|
|
|
@ -128,9 +128,12 @@ is(typeof(document.createElement("button").setCustomValidity), "function",
|
|||
"button.setCustomValidity should be a function");
|
||||
|
||||
// .labels
|
||||
todo("labels" in document.createElement("button"),
|
||||
"button.labels isn't implemented yet");
|
||||
|
||||
ok("labels" in document.createElement("button"),
|
||||
"button.labels should be an IDL attribute of the button element");
|
||||
is(typeof(document.createElement("button").labels), "object",
|
||||
"button.labels should be an object");
|
||||
ok(document.createElement("button").labels instanceof NodeList,
|
||||
"button.labels sohuld be an instance of NodeList");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -43,6 +43,5 @@ interface HTMLButtonElement : HTMLElement {
|
|||
boolean reportValidity();
|
||||
void setCustomValidity(DOMString error);
|
||||
|
||||
// Not yet implemented:
|
||||
// readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -112,7 +112,7 @@ interface HTMLInputElement : HTMLElement {
|
|||
boolean reportValidity();
|
||||
void setCustomValidity(DOMString error);
|
||||
|
||||
// Bug 850365 readonly attribute NodeList labels;
|
||||
readonly attribute NodeList? labels;
|
||||
|
||||
void select();
|
||||
|
||||
|
|
|
@ -26,9 +26,5 @@ interface HTMLMeterElement : HTMLElement {
|
|||
attribute double high;
|
||||
[SetterThrows]
|
||||
attribute double optimum;
|
||||
|
||||
/**
|
||||
* The labels attribute will be done with bug 556743.
|
||||
*/
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -34,6 +34,5 @@ interface HTMLOutputElement : HTMLElement {
|
|||
boolean reportValidity();
|
||||
void setCustomValidity(DOMString error);
|
||||
|
||||
// Not yet implemented (bug 556743).
|
||||
// readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -18,9 +18,5 @@ interface HTMLProgressElement : HTMLElement {
|
|||
[SetterThrows]
|
||||
attribute double max;
|
||||
readonly attribute double position;
|
||||
|
||||
/**
|
||||
* The labels attribute will be done with bug 567740.
|
||||
*/
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -54,7 +54,7 @@ interface HTMLSelectElement : HTMLElement {
|
|||
boolean reportValidity();
|
||||
void setCustomValidity(DOMString error);
|
||||
|
||||
// NYI: readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
|
||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=20720
|
||||
void remove();
|
||||
|
|
|
@ -58,7 +58,7 @@ interface HTMLTextAreaElement : HTMLElement {
|
|||
boolean reportValidity();
|
||||
void setCustomValidity(DOMString error);
|
||||
|
||||
// readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
|
||||
void select();
|
||||
[Throws]
|
||||
|
|
|
@ -201,7 +201,8 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
|
|||
mResultJSON(JS::UndefinedValue()),
|
||||
mResultArrayBuffer(nullptr),
|
||||
mIsMappedArrayBuffer(false),
|
||||
mXPCOMifier(nullptr)
|
||||
mXPCOMifier(nullptr),
|
||||
mEventDispatchingSuspended(false)
|
||||
{
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
@ -1368,7 +1369,7 @@ XMLHttpRequestMainThread::FireReadystatechangeEvent()
|
|||
event->InitEvent(kLiteralString_readystatechange, false, false);
|
||||
// We assume anyone who managed to call CreateReadystatechangeEvent is trusted
|
||||
event->SetTrusted(true);
|
||||
DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
DispatchOrStoreEvent(this, event);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1411,7 +1412,7 @@ XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
|
|||
ProgressEvent::Constructor(aTarget, typeString, init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
DispatchOrStoreEvent(aTarget, event);
|
||||
|
||||
if (aType == ProgressEventType::progress) {
|
||||
mInLoadProgressEvent = false;
|
||||
|
@ -1434,6 +1435,45 @@ XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::DispatchOrStoreEvent(DOMEventTargetHelper* aTarget,
|
||||
Event* aEvent)
|
||||
{
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(aEvent);
|
||||
|
||||
if (mEventDispatchingSuspended) {
|
||||
PendingEvent* event = mPendingEvents.AppendElement();
|
||||
event->mTarget = aTarget;
|
||||
event->mEvent = aEvent;
|
||||
return;
|
||||
}
|
||||
|
||||
aTarget->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::SuspendEventDispatching()
|
||||
{
|
||||
MOZ_ASSERT(!mEventDispatchingSuspended);
|
||||
mEventDispatchingSuspended = true;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::ResumeEventDispatching()
|
||||
{
|
||||
MOZ_ASSERT(mEventDispatchingSuspended);
|
||||
mEventDispatchingSuspended = false;
|
||||
|
||||
nsTArray<PendingEvent> pendingEvents;
|
||||
pendingEvents.SwapElements(mPendingEvents);
|
||||
|
||||
for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
|
||||
pendingEvents[i].mTarget->
|
||||
DispatchDOMEvent(nullptr, pendingEvents[i].mEvent, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIHttpChannel>
|
||||
XMLHttpRequestMainThread::GetCurrentHttpChannel()
|
||||
{
|
||||
|
@ -2409,10 +2449,6 @@ XMLHttpRequestMainThread::ChangeStateToDone()
|
|||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
|
||||
if (mFlagSynchronous) {
|
||||
UnsuppressEventHandlingAndResume();
|
||||
}
|
||||
|
||||
// Per spec, fire the last download progress event, if any,
|
||||
// before readystatechange=4/done. (Note that 0-sized responses
|
||||
// will have not sent a progress event yet, so one must be sent here).
|
||||
|
@ -3033,6 +3069,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
|||
}
|
||||
}
|
||||
|
||||
SuspendEventDispatching();
|
||||
StopProgressEventTimer();
|
||||
|
||||
SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
|
||||
|
@ -3056,6 +3093,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
|||
}
|
||||
|
||||
UnsuppressEventHandlingAndResume();
|
||||
ResumeEventDispatching();
|
||||
} else {
|
||||
// Now that we've successfully opened the channel, we can change state. Note
|
||||
// that this needs to come after the AsyncOpen() and rv check, because this
|
||||
|
|
|
@ -401,7 +401,8 @@ public:
|
|||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Abort() {
|
||||
Abort()
|
||||
{
|
||||
ErrorResult rv;
|
||||
Abort(rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
|
@ -607,8 +608,21 @@ protected:
|
|||
|
||||
nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
void DispatchOrStoreEvent(DOMEventTargetHelper* aTarget, Event* aEvent);
|
||||
|
||||
already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier();
|
||||
|
||||
void SuspendEventDispatching();
|
||||
void ResumeEventDispatching();
|
||||
|
||||
struct PendingEvent
|
||||
{
|
||||
RefPtr<DOMEventTargetHelper> mTarget;
|
||||
RefPtr<Event> mEvent;
|
||||
};
|
||||
|
||||
nsTArray<PendingEvent> mPendingEvents;
|
||||
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
@ -837,6 +851,10 @@ protected:
|
|||
// Helper object to manage our XPCOM scriptability bits
|
||||
nsXMLHttpRequestXPCOMifier* mXPCOMifier;
|
||||
|
||||
// When this is set to true, the event dispatching is suspended. This is
|
||||
// useful to change the correct state when XHR is working sync.
|
||||
bool mEventDispatchingSuspended;
|
||||
|
||||
static bool sDontWarnAboutSyncXHR;
|
||||
};
|
||||
|
||||
|
|
|
@ -195,7 +195,10 @@ WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
|
|||
return IPC_OK();
|
||||
}
|
||||
MOZ_ASSERT(mApi);
|
||||
MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end());
|
||||
|
||||
wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
|
||||
mActiveImageKeys.insert(wr::AsUint64(aImageKey));
|
||||
mApi->AddImage(aImageKey, descriptor,
|
||||
aBuffer.AsSlice());
|
||||
|
||||
|
@ -213,7 +216,10 @@ WebRenderBridgeParent::RecvAddBlobImage(const wr::ImageKey& aImageKey,
|
|||
return IPC_OK();
|
||||
}
|
||||
MOZ_ASSERT(mApi);
|
||||
MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(aImageKey)) == mActiveImageKeys.end());
|
||||
|
||||
wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
|
||||
mActiveImageKeys.insert(wr::AsUint64(aImageKey));
|
||||
mApi->AddBlobImage(aImageKey, descriptor,
|
||||
aBuffer.AsSlice());
|
||||
|
||||
|
@ -229,7 +235,10 @@ WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
|
|||
return IPC_OK();
|
||||
}
|
||||
MOZ_ASSERT(mApi);
|
||||
MOZ_ASSERT(mFontKeys.find(wr::AsUint64(aFontKey)) == mFontKeys.end());
|
||||
|
||||
auto slice = aBuffer.AsSlice();
|
||||
mFontKeys.insert(wr::AsUint64(aFontKey));
|
||||
mApi->AddRawFont(aFontKey, slice, aFontIndex);
|
||||
|
||||
return IPC_OK();
|
||||
|
@ -242,7 +251,14 @@ WebRenderBridgeParent::RecvDeleteFont(const wr::FontKey& aFontKey)
|
|||
return IPC_OK();
|
||||
}
|
||||
MOZ_ASSERT(mApi);
|
||||
mApi->DeleteFont(aFontKey);
|
||||
|
||||
if (mFontKeys.find(wr::AsUint64(aFontKey)) != mFontKeys.end()) {
|
||||
mFontKeys.erase(wr::AsUint64(aFontKey));
|
||||
mApi->DeleteFont(aFontKey);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("invalid FontKey");
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -269,10 +285,12 @@ WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey)
|
|||
return IPC_OK();
|
||||
}
|
||||
MOZ_ASSERT(mApi);
|
||||
if (mActiveKeys.Get(wr::AsUint64(aImageKey), nullptr)) {
|
||||
mActiveKeys.Remove(wr::AsUint64(aImageKey));
|
||||
if (mActiveImageKeys.find(wr::AsUint64(aImageKey)) != mActiveImageKeys.end()) {
|
||||
mActiveImageKeys.erase(wr::AsUint64(aImageKey));
|
||||
mKeysToDelete.push_back(aImageKey);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("invalid ImageKey");
|
||||
}
|
||||
mKeysToDelete.push_back(aImageKey);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -465,8 +483,8 @@ WebRenderBridgeParent::ProcessWebRenderParentCommands(InfallibleTArray<WebRender
|
|||
const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
|
||||
Range<const wr::ImageKey> keys(&op.key(), 1);
|
||||
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
|
||||
MOZ_ASSERT(!mActiveKeys.Get(wr::AsUint64(keys[0]), nullptr));
|
||||
mActiveKeys.Put(wr::AsUint64(keys[0]), keys[0]);
|
||||
MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(keys[0])) == mActiveImageKeys.end());
|
||||
mActiveImageKeys.insert(wr::AsUint64(keys[0]));
|
||||
|
||||
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
|
||||
if (!host) {
|
||||
|
@ -1029,10 +1047,14 @@ WebRenderBridgeParent::ClearResources()
|
|||
mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId);
|
||||
// Schedule composition to clean up Pipeline
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
for (auto iter = mActiveKeys.Iter(); !iter.Done(); iter.Next()) {
|
||||
mKeysToDelete.push_back(iter.Data());
|
||||
iter.Remove();
|
||||
for (std::unordered_set<uint64_t>::iterator iter = mFontKeys.begin(); iter != mFontKeys.end(); iter++) {
|
||||
mApi->DeleteFont(wr::AsFontKey(*iter));
|
||||
}
|
||||
mFontKeys.clear();
|
||||
for (std::unordered_set<uint64_t>::iterator iter = mActiveImageKeys.begin(); iter != mActiveImageKeys.end(); iter++) {
|
||||
mKeysToDelete.push_back(wr::AsImageKey(*iter));
|
||||
}
|
||||
mActiveImageKeys.clear();
|
||||
DeleteOldImages();
|
||||
for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->ClearWrBridge();
|
||||
|
|
|
@ -247,8 +247,10 @@ private:
|
|||
RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
|
||||
RefPtr<CompositorAnimationStorage> mAnimStorage;
|
||||
std::vector<wr::ImageKey> mKeysToDelete;
|
||||
// XXX How to handle active keys of non-ExternalImages?
|
||||
nsDataHashtable<nsUint64HashKey, wr::ImageKey> mActiveKeys;
|
||||
// mActiveImageKeys and mFontKeys are used to avoid leaking animations when
|
||||
// WebRenderBridgeParent is destroyed abnormally and Tab move between different windows.
|
||||
std::unordered_set<uint64_t> mActiveImageKeys;
|
||||
std::unordered_set<uint64_t> mFontKeys;
|
||||
// mActiveAnimations is used to avoid leaking animations when WebRenderBridgeParent is
|
||||
// destroyed abnormally and Tab move between different windows.
|
||||
std::unordered_set<uint64_t> mActiveAnimations;
|
||||
|
|
|
@ -115,6 +115,26 @@ inline uint64_t AsUint64(const ImageKey& aId) {
|
|||
+ static_cast<uint64_t>(aId.mHandle);
|
||||
}
|
||||
|
||||
inline ImageKey AsImageKey(const uint64_t& aId) {
|
||||
ImageKey imageKey;
|
||||
imageKey.mNamespace = aId >> 32;
|
||||
imageKey.mHandle = aId;
|
||||
return imageKey;
|
||||
}
|
||||
|
||||
// Whenever possible, use wr::FontKey instead of manipulating uint64_t.
|
||||
inline uint64_t AsUint64(const FontKey& aId) {
|
||||
return (static_cast<uint64_t>(aId.mNamespace) << 32)
|
||||
+ static_cast<uint64_t>(aId.mHandle);
|
||||
}
|
||||
|
||||
inline FontKey AsFontKey(const uint64_t& aId) {
|
||||
FontKey fontKey;
|
||||
fontKey.mNamespace = aId >> 32;
|
||||
fontKey.mHandle = aId;
|
||||
return fontKey;
|
||||
}
|
||||
|
||||
// Whenever possible, use wr::PipelineId instead of manipulating uint64_t.
|
||||
inline uint64_t AsUint64(const PipelineId& aId) {
|
||||
return (static_cast<uint64_t>(aId.mNamespace) << 32)
|
||||
|
|
|
@ -553,20 +553,6 @@ class JS_PUBLIC_API(AutoAssertNoAlloc)
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert if a GC barrier is invoked while this class is live. This class does
|
||||
* not disable the static rooting hazard analysis.
|
||||
*/
|
||||
class JS_PUBLIC_API(AutoAssertOnBarrier)
|
||||
{
|
||||
JSContext* context;
|
||||
bool prev;
|
||||
|
||||
public:
|
||||
explicit AutoAssertOnBarrier(JSContext* cx);
|
||||
~AutoAssertOnBarrier();
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable the static rooting hazard analysis in the live region and assert if
|
||||
* any allocation that could potentially trigger a GC occurs while this guard
|
||||
|
@ -645,9 +631,6 @@ UnmarkGrayGCThingRecursively(GCCellPtr thing);
|
|||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
BarriersAreAllowedOnCurrentThread();
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeGCThingToActiveJS(JS::GCCellPtr thing)
|
||||
{
|
||||
|
@ -662,8 +645,6 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing)
|
|||
if (thing.mayBeOwnedByOtherRuntime())
|
||||
return;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(BarriersAreAllowedOnCurrentThread());
|
||||
|
||||
if (IsIncrementalBarrierNeededOnTenuredGCThing(thing))
|
||||
JS::IncrementalReadBarrier(thing);
|
||||
else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell()))
|
||||
|
|
|
@ -69,6 +69,10 @@ class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy>
|
|||
}
|
||||
}
|
||||
|
||||
bool needsSweep() const {
|
||||
return this->initialized() && !this->empty();
|
||||
}
|
||||
|
||||
void sweep() {
|
||||
if (!this->initialized())
|
||||
return;
|
||||
|
@ -246,6 +250,10 @@ class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
|
|||
GCPolicy<T>::trace(trc, &e.mutableFront(), "hashset element");
|
||||
}
|
||||
|
||||
bool needsSweep() const {
|
||||
return this->initialized() && !this->empty();
|
||||
}
|
||||
|
||||
void sweep() {
|
||||
if (!this->initialized())
|
||||
return;
|
||||
|
|
|
@ -135,6 +135,10 @@ class GCVector
|
|||
GCPolicy<T>::trace(trc, &elem, "vector element");
|
||||
}
|
||||
|
||||
bool needsSweep() const {
|
||||
return !this->empty();
|
||||
}
|
||||
|
||||
void sweep() {
|
||||
uint32_t src, dst = 0;
|
||||
for (src = 0; src < length(); src++) {
|
||||
|
|
|
@ -1613,6 +1613,7 @@ class HashTable : private AllocPolicy
|
|||
{
|
||||
METER(stats.rehashes++);
|
||||
removedCount = 0;
|
||||
gen++;
|
||||
for (size_t i = 0; i < capacity(); ++i)
|
||||
table[i].unsetCollision();
|
||||
|
||||
|
@ -1797,6 +1798,9 @@ class HashTable : private AllocPolicy
|
|||
if (!p.isValid())
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(p.generation == generation());
|
||||
MOZ_ASSERT(p.mutationCount == mutationCount);
|
||||
|
||||
// Changing an entry from removed to live does not affect whether we
|
||||
// are overloaded and can be handled separately.
|
||||
if (p.entry_->isRemoved()) {
|
||||
|
@ -1880,6 +1884,7 @@ class HashTable : private AllocPolicy
|
|||
MOZ_ASSERT(table);
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
MOZ_ASSERT(p.found());
|
||||
MOZ_ASSERT(p.generation == generation());
|
||||
remove(*p.entry_);
|
||||
checkUnderloaded();
|
||||
}
|
||||
|
@ -1889,6 +1894,7 @@ class HashTable : private AllocPolicy
|
|||
MOZ_ASSERT(table);
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
MOZ_ASSERT(p.found());
|
||||
MOZ_ASSERT(p.generation == generation());
|
||||
typename HashTableEntry<T>::NonConstT t(mozilla::Move(*p));
|
||||
HashPolicy::setKey(t, const_cast<Key&>(k));
|
||||
remove(*p.entry_);
|
||||
|
|
|
@ -168,6 +168,7 @@ struct Zone
|
|||
bool isGCSweeping() const { return gcState_ == Sweep; }
|
||||
bool isGCFinished() const { return gcState_ == Finished; }
|
||||
bool isGCCompacting() const { return gcState_ == Compact; }
|
||||
bool isGCMarking() const { return gcState_ == Mark || gcState_ == MarkGray; }
|
||||
bool isGCSweepingOrCompacting() const { return gcState_ == Sweep || gcState_ == Compact; }
|
||||
|
||||
static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
|
||||
|
|
|
@ -38,6 +38,7 @@ class WeakCacheBase : public mozilla::LinkedListElement<WeakCacheBase>
|
|||
virtual ~WeakCacheBase() {}
|
||||
|
||||
virtual void sweep() = 0;
|
||||
virtual bool needsSweep() = 0;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
@ -69,6 +70,10 @@ class WeakCache : protected detail::WeakCacheBase,
|
|||
void sweep() override {
|
||||
GCPolicy<T>::sweep(&cache);
|
||||
}
|
||||
|
||||
bool needsSweep() override {
|
||||
return cache.needsSweep();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
|
|
@ -712,13 +712,6 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
|||
if (!NameFunctions(cx, pn))
|
||||
return false;
|
||||
|
||||
// XDR the newly delazified function.
|
||||
if (script->scriptSource()->hasEncoder() &&
|
||||
!script->scriptSource()->xdrEncodeFunction(cx, fun, sourceObject))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -685,7 +685,7 @@ class HeapSlot : public WriteBarrieredBase<Value>
|
|||
const Value& target) const;
|
||||
#endif
|
||||
|
||||
void set(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
|
||||
MOZ_ALWAYS_INLINE void set(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
|
||||
MOZ_ASSERT(preconditionForSet(owner, kind, slot));
|
||||
pre();
|
||||
value = v;
|
||||
|
|
|
@ -340,26 +340,26 @@ ShouldTraceCrossCompartment(JSTracer* trc, JSObject* src, const Value& val)
|
|||
}
|
||||
|
||||
static void
|
||||
AssertZoneIsMarking(Cell* thing)
|
||||
AssertShouldMarkInZone(Cell* thing)
|
||||
{
|
||||
MOZ_ASSERT(TenuredCell::fromPointer(thing)->zone()->isGCMarking());
|
||||
MOZ_ASSERT(thing->asTenured().zone()->shouldMarkInZone());
|
||||
}
|
||||
|
||||
static void
|
||||
AssertZoneIsMarking(JSString* str)
|
||||
AssertShouldMarkInZone(JSString* str)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Zone* zone = TenuredCell::fromPointer(str)->zone();
|
||||
MOZ_ASSERT(zone->isGCMarking() || zone->isAtomsZone());
|
||||
Zone* zone = str->asTenured().zone();
|
||||
MOZ_ASSERT(zone->shouldMarkInZone() || zone->isAtomsZone());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
AssertZoneIsMarking(JS::Symbol* sym)
|
||||
AssertShouldMarkInZone(JS::Symbol* sym)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Zone* zone = TenuredCell::fromPointer(sym)->zone();
|
||||
MOZ_ASSERT(zone->isGCMarking() || zone->isAtomsZone());
|
||||
Zone* zone = sym->asTenured().zone();
|
||||
MOZ_ASSERT(zone->shouldMarkInZone() || zone->isAtomsZone());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -771,35 +771,35 @@ GCMarker::markImplicitEdges(T* thing)
|
|||
|
||||
template <typename T>
|
||||
static inline bool
|
||||
MustSkipMarking(GCMarker* gcmarker, T thing)
|
||||
ShouldMark(GCMarker* gcmarker, T thing)
|
||||
{
|
||||
// Don't trace things that are owned by another runtime.
|
||||
if (IsOwnedByOtherRuntime(gcmarker->runtime(), thing))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// Don't mark things outside a zone if we are in a per-zone GC.
|
||||
return !thing->zone()->isGCMarking();
|
||||
return thing->zone()->shouldMarkInZone();
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
MustSkipMarking<JSObject*>(GCMarker* gcmarker, JSObject* obj)
|
||||
ShouldMark<JSObject*>(GCMarker* gcmarker, JSObject* obj)
|
||||
{
|
||||
// Don't trace things that are owned by another runtime.
|
||||
if (IsOwnedByOtherRuntime(gcmarker->runtime(), obj))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// We may mark a Nursery thing outside the context of the
|
||||
// MinorCollectionTracer because of a pre-barrier. The pre-barrier is not
|
||||
// needed in this case because we perform a minor collection before each
|
||||
// incremental slice.
|
||||
if (IsInsideNursery(obj))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// Don't mark things outside a zone if we are in a per-zone GC. It is
|
||||
// faster to check our own arena, which we can do since we know that
|
||||
// the object is tenured.
|
||||
return !TenuredCell::fromPointer(obj)->zone()->isGCMarking();
|
||||
return obj->asTenured().zone()->shouldMarkInZone();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -807,7 +807,7 @@ void
|
|||
DoMarking(GCMarker* gcmarker, T* thing)
|
||||
{
|
||||
// Do per-type marking precondition checks.
|
||||
if (MustSkipMarking(gcmarker, thing))
|
||||
if (!ShouldMark(gcmarker, thing))
|
||||
return;
|
||||
|
||||
CheckTracedThing(gcmarker, thing);
|
||||
|
@ -834,7 +834,7 @@ void
|
|||
NoteWeakEdge(GCMarker* gcmarker, T** thingp)
|
||||
{
|
||||
// Do per-type marking precondition checks.
|
||||
if (MustSkipMarking(gcmarker, *thingp))
|
||||
if (!ShouldMark(gcmarker, *thingp))
|
||||
return;
|
||||
|
||||
CheckTracedThing(gcmarker, *thingp);
|
||||
|
@ -990,7 +990,7 @@ template <typename T>
|
|||
bool
|
||||
js::GCMarker::mark(T* thing)
|
||||
{
|
||||
AssertZoneIsMarking(thing);
|
||||
AssertShouldMarkInZone(thing);
|
||||
MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing)));
|
||||
return gc::ParticipatesInCC<T>::value
|
||||
? gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor())
|
||||
|
@ -1125,7 +1125,7 @@ JSString::traceBase(JSTracer* trc)
|
|||
inline void
|
||||
js::GCMarker::eagerlyMarkChildren(JSLinearString* linearStr)
|
||||
{
|
||||
AssertZoneIsMarking(linearStr);
|
||||
AssertShouldMarkInZone(linearStr);
|
||||
MOZ_ASSERT(linearStr->isMarked());
|
||||
MOZ_ASSERT(linearStr->JSString::isLinear());
|
||||
|
||||
|
@ -1135,7 +1135,7 @@ js::GCMarker::eagerlyMarkChildren(JSLinearString* linearStr)
|
|||
MOZ_ASSERT(linearStr->JSString::isLinear());
|
||||
if (linearStr->isPermanentAtom())
|
||||
break;
|
||||
AssertZoneIsMarking(linearStr);
|
||||
AssertShouldMarkInZone(linearStr);
|
||||
if (!mark(static_cast<JSString*>(linearStr)))
|
||||
break;
|
||||
}
|
||||
|
@ -1188,7 +1188,7 @@ js::GCMarker::eagerlyMarkChildren(JSRope* rope)
|
|||
|
||||
JS_DIAGNOSTICS_ASSERT(rope->getTraceKind() == JS::TraceKind::String);
|
||||
JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
|
||||
AssertZoneIsMarking(rope);
|
||||
AssertShouldMarkInZone(rope);
|
||||
MOZ_ASSERT(rope->isMarked());
|
||||
JSRope* next = nullptr;
|
||||
|
||||
|
@ -1674,7 +1674,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
|
||||
case MarkStack::ObjectTag: {
|
||||
obj = stack.popPtr().as<JSObject>();
|
||||
AssertZoneIsMarking(obj);
|
||||
AssertShouldMarkInZone(obj);
|
||||
goto scan_obj;
|
||||
}
|
||||
|
||||
|
@ -1738,7 +1738,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
|
||||
scan_obj:
|
||||
{
|
||||
AssertZoneIsMarking(obj);
|
||||
AssertShouldMarkInZone(obj);
|
||||
|
||||
budget.step();
|
||||
if (budget.isOverBudget()) {
|
||||
|
|
|
@ -251,8 +251,8 @@ Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode)
|
|||
void
|
||||
JS::Zone::checkUniqueIdTableAfterMovingGC()
|
||||
{
|
||||
for (UniqueIdMap::Enum e(uniqueIds()); !e.empty(); e.popFront())
|
||||
js::gc::CheckGCThingAfterMovingGC(e.front().key());
|
||||
for (auto r = uniqueIds().all(); !r.empty(); r.popFront())
|
||||
js::gc::CheckGCThingAfterMovingGC(r.front().key());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -242,11 +242,8 @@ struct Zone : public JS::shadow::Zone,
|
|||
return CurrentThreadIsHeapMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
|
||||
}
|
||||
|
||||
bool isGCMarking() {
|
||||
if (CurrentThreadIsHeapCollecting())
|
||||
return gcState_ == Mark || gcState_ == MarkGray;
|
||||
else
|
||||
return needsIncrementalBarrier();
|
||||
bool shouldMarkInZone() const {
|
||||
return needsIncrementalBarrier() || isGCMarking();
|
||||
}
|
||||
|
||||
// Get a number that is incremented whenever this zone is collected, and
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
class C { }
|
||||
class D extends C { }
|
||||
|
||||
function f()
|
||||
{
|
||||
for (var i = 0; i < 2000; ++i)
|
||||
new D();
|
||||
}
|
||||
|
||||
f();
|
|
@ -0,0 +1,29 @@
|
|||
load(libdir + 'bytecode-cache.js');
|
||||
var test = "";
|
||||
gczeal(0);
|
||||
|
||||
// Check that a GC can relazify decoded functions.
|
||||
//
|
||||
// Generations 0 and 3 are executed from the source, thus f is not executed yet.
|
||||
// Generations 1 and 2 are decoded, thus we recorded the delazified f function.
|
||||
test = `
|
||||
function f() { return 1; };
|
||||
assertEq(isLazyFunction(f), generation == 0 || generation == 3);
|
||||
f();
|
||||
expect = isRelazifiableFunction(f);
|
||||
assertEq(isLazyFunction(f), false);
|
||||
`;
|
||||
evalWithCache(test, {
|
||||
checkAfter: function (ctx) {
|
||||
gc(ctx.global.f, "shrinking"); // relazify f, if possible.
|
||||
evaluate("assertEq(isLazyFunction(f), expect);", ctx);
|
||||
}
|
||||
});
|
||||
|
||||
evalWithCache(test, {
|
||||
incremental: true,
|
||||
checkAfter: function (ctx) {
|
||||
gc(ctx.global.f, "shrinking"); // relazify f, if possible.
|
||||
evaluate("assertEq(isLazyFunction(f), expect);", ctx);
|
||||
}
|
||||
});
|
|
@ -1414,6 +1414,11 @@ static const VMFunction ThrowUninitializedThisInfo =
|
|||
FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis,
|
||||
"BaselineThrowUninitializedThis");
|
||||
|
||||
typedef bool (*ThrowInitializedThisFn)(JSContext*, BaselineFrame* frame);
|
||||
static const VMFunction ThrowInitializedThisInfo =
|
||||
FunctionInfo<ThrowInitializedThisFn>(BaselineThrowInitializedThis,
|
||||
"BaselineThrowInitializedThis");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_CHECKTHIS()
|
||||
{
|
||||
|
@ -1424,18 +1429,35 @@ BaselineCompiler::emit_JSOP_CHECKTHIS()
|
|||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitCheckThis(ValueOperand val)
|
||||
BaselineCompiler::emit_JSOP_CHECKTHISREINIT()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
|
||||
|
||||
return emitCheckThis(R0, /* reinit = */true);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitCheckThis(ValueOperand val, bool reinit)
|
||||
{
|
||||
Label thisOK;
|
||||
masm.branchTestMagic(Assembler::NotEqual, val, &thisOK);
|
||||
if (reinit)
|
||||
masm.branchTestMagic(Assembler::Equal, val, &thisOK);
|
||||
else
|
||||
masm.branchTestMagic(Assembler::NotEqual, val, &thisOK);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, val.scratchReg());
|
||||
pushArg(val.scratchReg());
|
||||
|
||||
if (!callVM(ThrowUninitializedThisInfo))
|
||||
return false;
|
||||
if (reinit) {
|
||||
if (!callVM(ThrowInitializedThisInfo))
|
||||
return false;
|
||||
} else {
|
||||
if (!callVM(ThrowUninitializedThisInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
masm.bind(&thisOK);
|
||||
return true;
|
||||
|
@ -4224,6 +4246,56 @@ BaselineCompiler::emit_JSOP_SUPERBASE()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*SuperFunOperationFn)(JSContext*, HandleObject);
|
||||
static const VMFunction SuperFunOperationInfo =
|
||||
FunctionInfo<SuperFunOperationFn>(SuperFunOperation, "SuperFunOperation");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SUPERFUN()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
Register callee = R0.scratchReg();
|
||||
Register proto = R1.scratchReg();
|
||||
Register scratch = R2.scratchReg();
|
||||
|
||||
// Lookup callee object of environment containing [[ThisValue]]
|
||||
getThisEnvironmentCallee(callee);
|
||||
|
||||
// Load prototype of callee
|
||||
masm.loadObjProto(callee, proto);
|
||||
|
||||
// Use VMCall for missing or lazy proto
|
||||
Label needVMCall;
|
||||
MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
|
||||
masm.branchPtr(Assembler::BelowOrEqual, proto, ImmWord(1), &needVMCall);
|
||||
|
||||
// Use VMCall for non-JSFunction objects (eg. Proxy)
|
||||
masm.branchTestObjClass(Assembler::NotEqual, proto, scratch, &JSFunction::class_, &needVMCall);
|
||||
|
||||
// Use VMCall if not constructor
|
||||
masm.load16ZeroExtend(Address(proto, JSFunction::offsetOfFlags()), scratch);
|
||||
masm.branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::CONSTRUCTOR), &needVMCall);
|
||||
|
||||
// Valid constructor
|
||||
Label hasSuperFun;
|
||||
masm.jump(&hasSuperFun);
|
||||
|
||||
// Slow path VM Call
|
||||
masm.bind(&needVMCall);
|
||||
prepareVMCall();
|
||||
pushArg(callee);
|
||||
if (!callVM(SuperFunOperationInfo))
|
||||
return false;
|
||||
masm.movePtr(ReturnReg, proto);
|
||||
|
||||
// Box prototype and return
|
||||
masm.bind(&hasSuperFun);
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
|
||||
frame.push(R1);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*NewArgumentsObjectFn)(JSContext*, BaselineFrame*, MutableHandleValue);
|
||||
static const VMFunction NewArgumentsObjectInfo =
|
||||
FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject, "NewArgumentsObject");
|
||||
|
|
|
@ -217,6 +217,7 @@ namespace jit {
|
|||
_(JSOP_RESUME) \
|
||||
_(JSOP_CALLEE) \
|
||||
_(JSOP_SUPERBASE) \
|
||||
_(JSOP_SUPERFUN) \
|
||||
_(JSOP_GETRVAL) \
|
||||
_(JSOP_SETRVAL) \
|
||||
_(JSOP_RETRVAL) \
|
||||
|
@ -226,6 +227,7 @@ namespace jit {
|
|||
_(JSOP_CHECKISOBJ) \
|
||||
_(JSOP_CHECKISCALLABLE) \
|
||||
_(JSOP_CHECKTHIS) \
|
||||
_(JSOP_CHECKTHISREINIT) \
|
||||
_(JSOP_CHECKRETURN) \
|
||||
_(JSOP_NEWTARGET) \
|
||||
_(JSOP_SUPERCALL) \
|
||||
|
@ -295,7 +297,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
private:
|
||||
MethodStatus emitBody();
|
||||
|
||||
MOZ_MUST_USE bool emitCheckThis(ValueOperand val);
|
||||
MOZ_MUST_USE bool emitCheckThis(ValueOperand val, bool reinit=false);
|
||||
void emitLoadReturnValue(ValueOperand val);
|
||||
|
||||
void emitInitializeLocals();
|
||||
|
|
|
@ -2397,7 +2397,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
|||
FallbackICSpew(cx, stub, "Call(%s)", CodeName[op]);
|
||||
|
||||
MOZ_ASSERT(argc == GET_ARGC(pc));
|
||||
bool constructing = (op == JSOP_NEW);
|
||||
bool constructing = (op == JSOP_NEW || op == JSOP_SUPERCALL);
|
||||
bool ignoresReturnValue = (op == JSOP_CALL_IGNORES_RV);
|
||||
|
||||
// Ensure vp array is rooted - we may GC in here.
|
||||
|
@ -2432,7 +2432,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
|||
}
|
||||
}
|
||||
|
||||
if (op == JSOP_NEW) {
|
||||
if (constructing) {
|
||||
if (!ConstructFromStack(cx, callArgs))
|
||||
return false;
|
||||
res.set(callArgs.rval());
|
||||
|
@ -2506,7 +2506,7 @@ DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_
|
|||
RootedScript script(cx, frame->script());
|
||||
jsbytecode* pc = stub->icEntry()->pc(script);
|
||||
JSOp op = JSOp(*pc);
|
||||
bool constructing = (op == JSOP_SPREADNEW);
|
||||
bool constructing = (op == JSOP_SPREADNEW || op == JSOP_SPREADSUPERCALL);
|
||||
FallbackICSpew(cx, stub, "SpreadCall(%s)", CodeName[op]);
|
||||
|
||||
// Ensure vp array is rooted - we may GC in here.
|
||||
|
|
|
@ -4860,6 +4860,9 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
|||
if (!target || !target->hasScript())
|
||||
return nullptr;
|
||||
|
||||
if (target->isBoundFunction() || target->isDerivedClassConstructor())
|
||||
return nullptr;
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObject(pc);
|
||||
if (!templateObject)
|
||||
return nullptr;
|
||||
|
|
|
@ -1037,6 +1037,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void branchPtr(Condition cond, const Address& lhs, ImmGCPtr rhs, Label* label) PER_SHARED_ARCH;
|
||||
inline void branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label* label) PER_SHARED_ARCH;
|
||||
|
||||
inline void branchPtr(Condition cond, const BaseIndex& lhs, ImmWord rhs, Label* label) PER_SHARED_ARCH;
|
||||
|
||||
inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
|
||||
inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs, Label* label)
|
||||
|
@ -1654,6 +1656,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
if (type == MIRType::Value)
|
||||
branchTestGCThing(Assembler::NotEqual, address, &done);
|
||||
else if (type == MIRType::Object || type == MIRType::String)
|
||||
branchPtr(Assembler::Equal, address, ImmWord(0), &done);
|
||||
|
||||
Push(PreBarrierReg);
|
||||
computeEffectiveAddress(address, PreBarrierReg);
|
||||
|
|
|
@ -2386,6 +2386,7 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
|
|||
MOZ_ASSERT(frame->isFunctionFrame() || frame->isEvalFrame());
|
||||
MOZ_ASSERT(stub->monitorsThis() ||
|
||||
*GetNextPc(pc) == JSOP_CHECKTHIS ||
|
||||
*GetNextPc(pc) == JSOP_CHECKTHISREINIT ||
|
||||
*GetNextPc(pc) == JSOP_CHECKRETURN);
|
||||
if (stub->monitorsThis())
|
||||
TypeScript::SetThis(cx, script, TypeSet::UnknownType());
|
||||
|
|
|
@ -1433,15 +1433,15 @@ MarkValueFromIon(JSRuntime* rt, Value* vp)
|
|||
void
|
||||
MarkStringFromIon(JSRuntime* rt, JSString** stringp)
|
||||
{
|
||||
if (*stringp)
|
||||
TraceManuallyBarrieredEdge(&rt->gc.marker, stringp, "write barrier");
|
||||
MOZ_ASSERT(*stringp);
|
||||
TraceManuallyBarrieredEdge(&rt->gc.marker, stringp, "write barrier");
|
||||
}
|
||||
|
||||
void
|
||||
MarkObjectFromIon(JSRuntime* rt, JSObject** objp)
|
||||
{
|
||||
if (*objp)
|
||||
TraceManuallyBarrieredEdge(&rt->gc.marker, objp, "write barrier");
|
||||
MOZ_ASSERT(*objp);
|
||||
TraceManuallyBarrieredEdge(&rt->gc.marker, objp, "write barrier");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1497,6 +1497,12 @@ BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
|
|||
return ThrowUninitializedThis(cx, frame);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineThrowInitializedThis(JSContext* cx, BaselineFrame* frame)
|
||||
{
|
||||
return ThrowInitializedThis(cx, frame);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ThrowObjectCoercible(JSContext* cx, HandleValue v)
|
||||
|
|
|
@ -831,6 +831,9 @@ ThrowReadOnlyError(JSContext* cx, HandleObject obj, int32_t index);
|
|||
MOZ_MUST_USE bool
|
||||
BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
BaselineThrowInitializedThis(JSContext* cx, BaselineFrame* frame);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
|
||||
|
||||
|
|
|
@ -1457,6 +1457,12 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh
|
|||
branchPtr(cond, scratch2, rhs, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs, ImmWord rhs, Label* label)
|
||||
{
|
||||
branch32(cond, lhs, Imm32(rhs.value), label);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline CodeOffsetJump
|
||||
MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label)
|
||||
|
|
|
@ -1032,6 +1032,17 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh
|
|||
branchPtr(cond, scratch, rhs, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs, ImmWord rhs, Label* label)
|
||||
{
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
const Register scratch = temps.AcquireX().asUnsized();
|
||||
MOZ_ASSERT(scratch != lhs.base);
|
||||
MOZ_ASSERT(scratch != lhs.index);
|
||||
loadPtr(lhs, scratch);
|
||||
branchPtr(cond, scratch, rhs, label);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
CodeOffsetJump
|
||||
MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label)
|
||||
|
|
|
@ -571,6 +571,13 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh
|
|||
branchPtr(cond, SecondScratchReg, rhs, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs, ImmWord rhs, Label* label)
|
||||
{
|
||||
loadPtr(lhs, SecondScratchReg);
|
||||
branchPtr(cond, SecondScratchReg, rhs, label);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
CodeOffsetJump
|
||||
MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label)
|
||||
|
|
|
@ -871,6 +871,9 @@ class Assembler : public AssemblerX86Shared
|
|||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpq_im(rhs.value, lhs.disp(), lhs.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpq_im(rhs.value, lhs.disp(), lhs.base(), lhs.index(), lhs.scale());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.cmpq_im(rhs.value, lhs.address());
|
||||
break;
|
||||
|
|
|
@ -582,6 +582,12 @@ MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label
|
|||
branchPtrImpl(cond, lhs, rhs, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs, ImmWord rhs, Label* label)
|
||||
{
|
||||
branchPtrImpl(cond, lhs, rhs, label);
|
||||
}
|
||||
|
||||
template <typename T, typename S, typename L>
|
||||
void
|
||||
MacroAssembler::branchPtrImpl(Condition cond, const T& lhs, const S& rhs, L label)
|
||||
|
|
|
@ -1347,7 +1347,6 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
|||
dtoaState(nullptr),
|
||||
heapState(JS::HeapState::Idle),
|
||||
suppressGC(0),
|
||||
allowGCBarriers(true),
|
||||
#ifdef DEBUG
|
||||
ionCompiling(false),
|
||||
ionCompilingSafeForMinorGC(false),
|
||||
|
|
|
@ -474,10 +474,6 @@ struct JSContext : public JS::RootingContext,
|
|||
*/
|
||||
js::ThreadLocalData<int32_t> suppressGC;
|
||||
|
||||
// In some cases, invoking GC barriers (incremental or otherwise) will break
|
||||
// things. These barriers assert if this flag is set.
|
||||
js::ThreadLocalData<bool> allowGCBarriers;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Whether this thread is actively Ion compiling.
|
||||
js::ThreadLocalData<bool> ionCompiling;
|
||||
|
|
|
@ -1567,6 +1567,14 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
|
|||
// Only functions without inner functions are re-lazified.
|
||||
script->setLazyScript(lazy);
|
||||
}
|
||||
|
||||
// XDR the newly delazified function.
|
||||
if (script->scriptSource()->hasEncoder()) {
|
||||
RootedScriptSource sourceObject(cx, lazy->sourceObject());
|
||||
if (!script->scriptSource()->xdrEncodeFunction(cx, fun, sourceObject))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5233,6 +5233,9 @@ PrepareWeakCacheTasks(JSRuntime* rt)
|
|||
// Build a vector of sweep tasks to run on a helper thread.
|
||||
WeakCacheTaskVector tasks;
|
||||
bool ok = IterateWeakCaches(rt, [&] (JS::detail::WeakCacheBase* cache) {
|
||||
if (!cache->needsSweep())
|
||||
return true;
|
||||
|
||||
return tasks.emplaceBack(rt, *cache);
|
||||
});
|
||||
|
||||
|
@ -6009,7 +6012,6 @@ GCRuntime::canChangeActiveContext(JSContext* cx)
|
|||
// scheduling.
|
||||
return cx->heapState == JS::HeapState::Idle
|
||||
&& !cx->suppressGC
|
||||
&& cx->allowGCBarriers
|
||||
&& !cx->inUnsafeRegion
|
||||
&& !cx->generationalDisabled
|
||||
&& !cx->compactingDisabledCount
|
||||
|
@ -7494,25 +7496,6 @@ JS::AutoAssertNoGC::~AutoAssertNoGC()
|
|||
cx_->inUnsafeRegion--;
|
||||
}
|
||||
|
||||
JS::AutoAssertOnBarrier::AutoAssertOnBarrier(JSContext* cx)
|
||||
: context(cx),
|
||||
prev(cx->allowGCBarriers)
|
||||
{
|
||||
context->allowGCBarriers = false;
|
||||
}
|
||||
|
||||
JS::AutoAssertOnBarrier::~AutoAssertOnBarrier()
|
||||
{
|
||||
MOZ_ASSERT(!context->allowGCBarriers);
|
||||
context->allowGCBarriers = prev;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::gc::BarriersAreAllowedOnCurrentThread()
|
||||
{
|
||||
return TlsContext.get()->allowGCBarriers;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JS::AutoAssertNoAlloc::AutoAssertNoAlloc(JSContext* cx)
|
||||
: gc(nullptr)
|
||||
|
|
|
@ -3554,6 +3554,12 @@ JSObject::uninlinedIsProxy() const
|
|||
return is<ProxyObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::uninlinedNonProxyIsExtensible() const
|
||||
{
|
||||
return nonProxyIsExtensible();
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::dump(FILE* fp) const
|
||||
{
|
||||
|
|
|
@ -504,6 +504,7 @@ class JSObject : public js::gc::Cell
|
|||
// places that want it (JITs and the like), and it'd be a pain to mark them
|
||||
// all as friends.
|
||||
inline bool nonProxyIsExtensible() const;
|
||||
bool uninlinedNonProxyIsExtensible() const;
|
||||
|
||||
public:
|
||||
/*
|
||||
|
|
|
@ -599,6 +599,10 @@ class InnerViewTable
|
|||
void sweep();
|
||||
void sweepAfterMinorGC();
|
||||
|
||||
bool needsSweep() const {
|
||||
return map.needsSweep();
|
||||
}
|
||||
|
||||
bool needsSweepAfterMinorGC() const {
|
||||
return !nurseryKeys.empty() || !nurseryKeysValid;
|
||||
}
|
||||
|
|
|
@ -2757,7 +2757,7 @@ END_CASE(JSOP_CHECKTHIS)
|
|||
CASE(JSOP_CHECKTHISREINIT)
|
||||
{
|
||||
if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
|
||||
MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx, REGS.fp()));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -4226,24 +4226,10 @@ END_CASE(JSOP_NEWTARGET)
|
|||
CASE(JSOP_SUPERFUN)
|
||||
{
|
||||
ReservedRooted<JSObject*> superEnvFunc(&rootObject0, &GetSuperEnvFunction(cx, REGS));
|
||||
MOZ_ASSERT(superEnvFunc->as<JSFunction>().isClassConstructor());
|
||||
MOZ_ASSERT(superEnvFunc->as<JSFunction>().nonLazyScript()->isDerivedClassConstructor());
|
||||
|
||||
ReservedRooted<JSObject*> superFun(&rootObject1);
|
||||
|
||||
if (!GetPrototype(cx, superEnvFunc, &superFun))
|
||||
goto error;
|
||||
|
||||
ReservedRooted<Value> superFunVal(&rootValue0, UndefinedValue());
|
||||
superFun = SuperFunOperation(cx, superEnvFunc);
|
||||
if (!superFun)
|
||||
superFunVal = NullValue();
|
||||
else if (!superFun->isConstructor())
|
||||
superFunVal = ObjectValue(*superFun);
|
||||
|
||||
if (superFunVal.isObjectOrNull()) {
|
||||
ReportIsNotFunction(cx, superFunVal, JSDVG_IGNORE_STACK, CONSTRUCT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PUSH_OBJECT(*superFun);
|
||||
}
|
||||
|
@ -5241,3 +5227,35 @@ js::HomeObjectSuperBase(JSContext* cx, HandleObject homeObj)
|
|||
|
||||
return superBase;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::SuperFunOperation(JSContext* cx, HandleObject callee)
|
||||
{
|
||||
MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
|
||||
MOZ_ASSERT(callee->as<JSFunction>().nonLazyScript()->isDerivedClassConstructor());
|
||||
|
||||
RootedObject superFun(cx);
|
||||
|
||||
if (!GetPrototype(cx, callee, &superFun))
|
||||
return nullptr;
|
||||
|
||||
RootedValue superFunVal(cx, UndefinedValue());
|
||||
if (!superFun)
|
||||
superFunVal = NullValue();
|
||||
else if (!superFun->isConstructor())
|
||||
superFunVal = ObjectValue(*superFun);
|
||||
|
||||
if (superFunVal.isObjectOrNull()) {
|
||||
ReportIsNotFunction(cx, superFunVal, JSDVG_IGNORE_STACK, CONSTRUCT);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return superFun;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ThrowInitializedThis(JSContext* cx, AbstractFramePtr frame)
|
||||
{
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -571,6 +571,9 @@ ThrowCheckIsCallable(JSContext* cx, CheckIsCallableKind kind);
|
|||
bool
|
||||
ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
|
||||
|
||||
bool
|
||||
ThrowInitializedThis(JSContext* cx, AbstractFramePtr frame);
|
||||
|
||||
bool
|
||||
DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
|
@ -592,6 +595,9 @@ MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, Handl
|
|||
JSObject*
|
||||
HomeObjectSuperBase(JSContext* cx, HandleObject homeObj);
|
||||
|
||||
JSObject*
|
||||
SuperFunOperation(JSContext* cx, HandleObject callee);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Interpreter_h */
|
||||
|
|
|
@ -420,7 +420,7 @@ NativeObject::copy(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
|
|||
return obj;
|
||||
}
|
||||
|
||||
inline void
|
||||
MOZ_ALWAYS_INLINE void
|
||||
NativeObject::setSlotWithType(JSContext* cx, Shape* shape,
|
||||
const Value& value, bool overwriting)
|
||||
{
|
||||
|
@ -739,8 +739,9 @@ LookupOwnPropertyInline(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
// Check for a native property.
|
||||
if (Shape* shape = obj->lookup(cx, id)) {
|
||||
// Check for a native property. Call Shape::search directly (instead of
|
||||
// NativeObject::lookup) because it's inlined.
|
||||
if (Shape* shape = obj->lastProperty()->search(cx, id)) {
|
||||
propp.setNativeProperty(shape);
|
||||
*donep = true;
|
||||
return true;
|
||||
|
|
|
@ -795,15 +795,16 @@ class NativeObject : public ShapedObject
|
|||
void freeSlot(JSContext* cx, uint32_t slot);
|
||||
|
||||
private:
|
||||
static Shape* getChildProperty(JSContext* cx, HandleNativeObject obj,
|
||||
HandleShape parent, MutableHandle<StackShape> child);
|
||||
static MOZ_ALWAYS_INLINE Shape* getChildProperty(JSContext* cx, HandleNativeObject obj,
|
||||
HandleShape parent,
|
||||
MutableHandle<StackShape> child);
|
||||
|
||||
public:
|
||||
/* Add a property whose id is not yet in this scope. */
|
||||
static Shape* addProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
JSGetterOp getter, JSSetterOp setter,
|
||||
uint32_t slot, unsigned attrs, unsigned flags,
|
||||
bool allowDictionary = true);
|
||||
static MOZ_ALWAYS_INLINE Shape* addProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
JSGetterOp getter, JSSetterOp setter,
|
||||
uint32_t slot, unsigned attrs, unsigned flags,
|
||||
bool allowDictionary = true);
|
||||
|
||||
/* Add a data property whose id is not yet in this scope. */
|
||||
static Shape* addDataProperty(JSContext* cx, HandleNativeObject obj,
|
||||
|
@ -901,36 +902,36 @@ class NativeObject : public ShapedObject
|
|||
return getSlotAddressUnchecked(slot);
|
||||
}
|
||||
|
||||
HeapSlot& getSlotRef(uint32_t slot) {
|
||||
MOZ_ALWAYS_INLINE HeapSlot& getSlotRef(uint32_t slot) {
|
||||
MOZ_ASSERT(slotInRange(slot));
|
||||
return *getSlotAddress(slot);
|
||||
}
|
||||
|
||||
const HeapSlot& getSlotRef(uint32_t slot) const {
|
||||
MOZ_ALWAYS_INLINE const HeapSlot& getSlotRef(uint32_t slot) const {
|
||||
MOZ_ASSERT(slotInRange(slot));
|
||||
return *getSlotAddress(slot);
|
||||
}
|
||||
|
||||
// Check requirements on values stored to this object.
|
||||
inline void checkStoredValue(const Value& v) {
|
||||
MOZ_ALWAYS_INLINE void checkStoredValue(const Value& v) {
|
||||
MOZ_ASSERT(IsObjectValueInCompartment(v, compartment()));
|
||||
MOZ_ASSERT(AtomIsMarked(zoneFromAnyThread(), v));
|
||||
}
|
||||
|
||||
void setSlot(uint32_t slot, const Value& value) {
|
||||
MOZ_ALWAYS_INLINE void setSlot(uint32_t slot, const Value& value) {
|
||||
MOZ_ASSERT(slotInRange(slot));
|
||||
checkStoredValue(value);
|
||||
getSlotRef(slot).set(this, HeapSlot::Slot, slot, value);
|
||||
}
|
||||
|
||||
void initSlot(uint32_t slot, const Value& value) {
|
||||
MOZ_ALWAYS_INLINE void initSlot(uint32_t slot, const Value& value) {
|
||||
MOZ_ASSERT(getSlot(slot).isUndefined());
|
||||
MOZ_ASSERT(slotInRange(slot));
|
||||
checkStoredValue(value);
|
||||
initSlotUnchecked(slot, value);
|
||||
}
|
||||
|
||||
void initSlotUnchecked(uint32_t slot, const Value& value) {
|
||||
MOZ_ALWAYS_INLINE void initSlotUnchecked(uint32_t slot, const Value& value) {
|
||||
getSlotAddressUnchecked(slot)->init(this, HeapSlot::Slot, slot, value);
|
||||
}
|
||||
|
||||
|
@ -964,30 +965,30 @@ class NativeObject : public ShapedObject
|
|||
static bool rollbackProperties(JSContext* cx, HandleNativeObject obj,
|
||||
uint32_t slotSpan);
|
||||
|
||||
inline void setSlotWithType(JSContext* cx, Shape* shape,
|
||||
const Value& value, bool overwriting = true);
|
||||
MOZ_ALWAYS_INLINE void setSlotWithType(JSContext* cx, Shape* shape,
|
||||
const Value& value, bool overwriting = true);
|
||||
|
||||
inline const Value& getReservedSlot(uint32_t index) const {
|
||||
MOZ_ALWAYS_INLINE const Value& getReservedSlot(uint32_t index) const {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
return getSlot(index);
|
||||
}
|
||||
|
||||
const HeapSlot& getReservedSlotRef(uint32_t index) const {
|
||||
MOZ_ALWAYS_INLINE const HeapSlot& getReservedSlotRef(uint32_t index) const {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
return getSlotRef(index);
|
||||
}
|
||||
|
||||
HeapSlot& getReservedSlotRef(uint32_t index) {
|
||||
MOZ_ALWAYS_INLINE HeapSlot& getReservedSlotRef(uint32_t index) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
return getSlotRef(index);
|
||||
}
|
||||
|
||||
void initReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ALWAYS_INLINE void initReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
initSlot(index, v);
|
||||
}
|
||||
|
||||
void setReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ALWAYS_INLINE void setReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
setSlot(index, v);
|
||||
}
|
||||
|
|
|
@ -1907,8 +1907,8 @@ ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
|
|||
if (!table || !table->initialized())
|
||||
return;
|
||||
|
||||
for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
|
||||
NewEntry entry = e.front();
|
||||
for (auto r = table->all(); !r.empty(); r.popFront()) {
|
||||
NewEntry entry = r.front();
|
||||
CheckGCThingAfterMovingGC(entry.group.unbarrieredGet());
|
||||
TaggedProto proto = entry.group.unbarrieredGet()->proto();
|
||||
if (proto.isObject())
|
||||
|
@ -1921,7 +1921,7 @@ ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
|
|||
|
||||
NewEntry::Lookup lookup(clasp, proto, entry.associated);
|
||||
auto ptr = table->lookup(lookup);
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@ class ObjectGroup : public gc::TenuredCell
|
|||
inline HeapTypeSet* getProperty(JSContext* cx, JSObject* obj, jsid id);
|
||||
|
||||
/* Get a property only if it already exists. */
|
||||
inline HeapTypeSet* maybeGetProperty(jsid id);
|
||||
MOZ_ALWAYS_INLINE HeapTypeSet* maybeGetProperty(jsid id);
|
||||
|
||||
/*
|
||||
* Iterate through the group's properties. getPropertyCount overapproximates
|
||||
|
|
|
@ -333,6 +333,30 @@ Shape::searchNoHashify(Shape* start, jsid id)
|
|||
return start->searchLinear(id);
|
||||
}
|
||||
|
||||
/* static */ MOZ_ALWAYS_INLINE Shape*
|
||||
NativeObject::addProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
GetterOp getter, SetterOp setter, uint32_t slot, unsigned attrs,
|
||||
unsigned flags, bool allowDictionary)
|
||||
{
|
||||
MOZ_ASSERT(!JSID_IS_VOID(id));
|
||||
MOZ_ASSERT(getter != JS_PropertyStub);
|
||||
MOZ_ASSERT(setter != JS_StrictPropertyStub);
|
||||
MOZ_ASSERT(obj->uninlinedNonProxyIsExtensible());
|
||||
MOZ_ASSERT(!obj->containsPure(id));
|
||||
|
||||
AutoKeepShapeTables keep(cx);
|
||||
ShapeTable::Entry* entry = nullptr;
|
||||
if (obj->inDictionaryMode()) {
|
||||
ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, keep);
|
||||
if (!table)
|
||||
return nullptr;
|
||||
entry = &table->search<MaybeAdding::Adding>(id, keep);
|
||||
}
|
||||
|
||||
return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, entry,
|
||||
allowDictionary, keep);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Shape_inl_h */
|
||||
|
|
|
@ -290,7 +290,7 @@ Shape::replaceLastProperty(JSContext* cx, StackBaseShape& base,
|
|||
* which must be lastProperty() if inDictionaryMode(), else parent must be
|
||||
* one of lastProperty() or lastProperty()->parent.
|
||||
*/
|
||||
/* static */ Shape*
|
||||
/* static */ MOZ_ALWAYS_INLINE Shape*
|
||||
NativeObject::getChildProperty(JSContext* cx,
|
||||
HandleNativeObject obj, HandleShape parent,
|
||||
MutableHandle<StackShape> child)
|
||||
|
@ -418,30 +418,6 @@ js::NativeObject::toDictionaryMode(JSContext* cx, HandleNativeObject obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ Shape*
|
||||
NativeObject::addProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
GetterOp getter, SetterOp setter, uint32_t slot, unsigned attrs,
|
||||
unsigned flags, bool allowDictionary)
|
||||
{
|
||||
MOZ_ASSERT(!JSID_IS_VOID(id));
|
||||
MOZ_ASSERT(getter != JS_PropertyStub);
|
||||
MOZ_ASSERT(setter != JS_StrictPropertyStub);
|
||||
MOZ_ASSERT(obj->nonProxyIsExtensible());
|
||||
MOZ_ASSERT(!obj->containsPure(id));
|
||||
|
||||
AutoKeepShapeTables keep(cx);
|
||||
ShapeTable::Entry* entry = nullptr;
|
||||
if (obj->inDictionaryMode()) {
|
||||
ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, keep);
|
||||
if (!table)
|
||||
return nullptr;
|
||||
entry = &table->search<MaybeAdding::Adding>(id, keep);
|
||||
}
|
||||
|
||||
return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, entry,
|
||||
allowDictionary, keep);
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldConvertToDictionary(NativeObject* obj)
|
||||
{
|
||||
|
@ -1288,12 +1264,12 @@ Zone::checkBaseShapeTableAfterMovingGC()
|
|||
if (!baseShapes().initialized())
|
||||
return;
|
||||
|
||||
for (BaseShapeSet::Enum e(baseShapes()); !e.empty(); e.popFront()) {
|
||||
UnownedBaseShape* base = e.front().unbarrieredGet();
|
||||
for (auto r = baseShapes().all(); !r.empty(); r.popFront()) {
|
||||
UnownedBaseShape* base = r.front().unbarrieredGet();
|
||||
CheckGCThingAfterMovingGC(base);
|
||||
|
||||
BaseShapeSet::Ptr ptr = baseShapes().lookup(base);
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1349,8 +1325,8 @@ Zone::checkInitialShapesTableAfterMovingGC()
|
|||
* initialShapes that points into the nursery, and that the hash table
|
||||
* entries are discoverable.
|
||||
*/
|
||||
for (InitialShapeSet::Enum e(initialShapes()); !e.empty(); e.popFront()) {
|
||||
InitialShapeEntry entry = e.front();
|
||||
for (auto r = initialShapes().all(); !r.empty(); r.popFront()) {
|
||||
InitialShapeEntry entry = r.front();
|
||||
JSProtoKey protoKey = entry.proto.key();
|
||||
TaggedProto proto = entry.proto.proto().unbarrieredGet();
|
||||
Shape* shape = entry.shape.unbarrieredGet();
|
||||
|
@ -1365,7 +1341,7 @@ Zone::checkInitialShapesTableAfterMovingGC()
|
|||
shape->numFixedSlots(),
|
||||
shape->getObjectFlags());
|
||||
InitialShapeSet::Ptr ptr = initialShapes().lookup(lookup);
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -405,11 +405,10 @@ PropertyHasBeenMarkedNonConstant(JSObject* obj, jsid id)
|
|||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
HasTypePropertyId(JSObject* obj, jsid id, TypeSet::Type type)
|
||||
HasTrackedPropertyType(JSObject* obj, jsid id, TypeSet::Type type)
|
||||
{
|
||||
id = IdToTypeId(id);
|
||||
if (!TrackPropertyTypes(obj, id))
|
||||
return true;
|
||||
MOZ_ASSERT(id == IdToTypeId(id));
|
||||
MOZ_ASSERT(TrackPropertyTypes(obj, id));
|
||||
|
||||
if (HeapTypeSet* types = obj->group()->maybeGetProperty(id)) {
|
||||
if (!types->hasType(type))
|
||||
|
@ -423,6 +422,16 @@ HasTypePropertyId(JSObject* obj, jsid id, TypeSet::Type type)
|
|||
return false;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
HasTypePropertyId(JSObject* obj, jsid id, TypeSet::Type type)
|
||||
{
|
||||
id = IdToTypeId(id);
|
||||
if (!TrackPropertyTypes(obj, id))
|
||||
return true;
|
||||
|
||||
return HasTrackedPropertyType(obj, id, type);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
HasTypePropertyId(JSObject* obj, jsid id, const Value& value)
|
||||
{
|
||||
|
@ -433,20 +442,18 @@ void AddTypePropertyId(JSContext* cx, ObjectGroup* group, JSObject* obj, jsid id
|
|||
void AddTypePropertyId(JSContext* cx, ObjectGroup* group, JSObject* obj, jsid id, const Value& value);
|
||||
|
||||
/* Add a possible type for a property of obj. */
|
||||
inline void
|
||||
MOZ_ALWAYS_INLINE void
|
||||
AddTypePropertyId(JSContext* cx, JSObject* obj, jsid id, TypeSet::Type type)
|
||||
{
|
||||
id = IdToTypeId(id);
|
||||
if (TrackPropertyTypes(obj, id))
|
||||
if (TrackPropertyTypes(obj, id) && !HasTrackedPropertyType(obj, id, type))
|
||||
AddTypePropertyId(cx, obj->group(), obj, id, type);
|
||||
}
|
||||
|
||||
inline void
|
||||
MOZ_ALWAYS_INLINE void
|
||||
AddTypePropertyId(JSContext* cx, JSObject* obj, jsid id, const Value& value)
|
||||
{
|
||||
id = IdToTypeId(id);
|
||||
if (TrackPropertyTypes(obj, id))
|
||||
AddTypePropertyId(cx, obj->group(), obj, id, value);
|
||||
return AddTypePropertyId(cx, obj, id, TypeSet::GetValueType(value));
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -830,7 +837,7 @@ struct TypeHashSet
|
|||
|
||||
// Lookup an entry in a hash set, return nullptr if it does not exist.
|
||||
template <class T, class U, class KEY>
|
||||
static inline U*
|
||||
static MOZ_ALWAYS_INLINE U*
|
||||
Lookup(U** values, unsigned count, T key)
|
||||
{
|
||||
if (count == 0)
|
||||
|
@ -1126,7 +1133,7 @@ ObjectGroup::getProperty(JSContext* cx, JSObject* obj, jsid id)
|
|||
return &base->types;
|
||||
}
|
||||
|
||||
inline HeapTypeSet*
|
||||
MOZ_ALWAYS_INLINE HeapTypeSet*
|
||||
ObjectGroup::maybeGetProperty(jsid id)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
|
||||
|
|
|
@ -786,7 +786,6 @@ nsIPresShell::nsIPresShell()
|
|||
, mIsDestroying(false)
|
||||
, mIsReflowing(false)
|
||||
, mPaintingSuppressed(false)
|
||||
, mIsThemeSupportDisabled(false)
|
||||
, mIsActive(false)
|
||||
, mFrozen(false)
|
||||
, mIsFirstPaint(false)
|
||||
|
@ -853,7 +852,6 @@ PresShell::PresShell()
|
|||
mLastOSWake = mLoadBegin = TimeStamp::Now();
|
||||
|
||||
mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
|
||||
mIsThemeSupportDisabled = false;
|
||||
mIsActive = true;
|
||||
// FIXME/bug 735029: find a better solution to this problem
|
||||
mIsFirstPaint = true;
|
||||
|
|
|
@ -954,20 +954,6 @@ public:
|
|||
*/
|
||||
virtual void UnsuppressPainting() = 0;
|
||||
|
||||
/**
|
||||
* Called to disable nsITheme support in a specific presshell.
|
||||
*/
|
||||
void DisableThemeSupport()
|
||||
{
|
||||
// Doesn't have to be dynamic. Just set the bool.
|
||||
mIsThemeSupportDisabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether theme support is enabled.
|
||||
*/
|
||||
bool IsThemeSupportEnabled() const { return !mIsThemeSupportDisabled; }
|
||||
|
||||
/**
|
||||
* Get the set of agent style sheets for this presentation
|
||||
*/
|
||||
|
@ -1862,9 +1848,6 @@ protected:
|
|||
// For all documents we initially lock down painting.
|
||||
bool mPaintingSuppressed : 1;
|
||||
|
||||
// Whether or not form controls should use nsITheme in this shell.
|
||||
bool mIsThemeSupportDisabled : 1;
|
||||
|
||||
bool mIsActive : 1;
|
||||
bool mFrozen : 1;
|
||||
bool mIsFirstPaint : 1;
|
||||
|
|
|
@ -1108,6 +1108,7 @@ inDOMUtils::SetContentState(nsIDOMElement* aElement,
|
|||
NS_IMETHODIMP
|
||||
inDOMUtils::RemoveContentState(nsIDOMElement* aElement,
|
||||
EventStates::InternalType aState,
|
||||
bool aClearActiveDocument,
|
||||
bool* aRetVal)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
|
@ -1117,6 +1118,15 @@ inDOMUtils::RemoveContentState(nsIDOMElement* aElement,
|
|||
NS_ENSURE_TRUE(esm, NS_ERROR_INVALID_ARG);
|
||||
|
||||
*aRetVal = esm->SetContentState(nullptr, EventStates(aState));
|
||||
|
||||
if (aClearActiveDocument && EventStates(aState) == NS_EVENT_STATE_ACTIVE) {
|
||||
EventStateManager* activeESM = static_cast<EventStateManager*>(
|
||||
EventStateManager::GetActiveEventStateManager());
|
||||
if (activeESM == esm) {
|
||||
EventStateManager::ClearGlobalActiveContent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ interface inIDOMUtils : nsISupports
|
|||
in boolean aShowingAnonymousContent);
|
||||
nsIDOMNodeList getChildrenForNode(in nsIDOMNode aNode,
|
||||
in boolean aShowingAnonymousContent);
|
||||
|
||||
|
||||
// XBL utilities
|
||||
nsIArray getBindingURLs(in nsIDOMElement aElement);
|
||||
|
||||
|
@ -164,11 +164,15 @@ interface inIDOMUtils : nsISupports
|
|||
* that for the remove case we simply pass in nullptr for the element.
|
||||
* Use them accordingly.
|
||||
*
|
||||
* When removing the active state, you may optionally also clear the active
|
||||
* document as well by setting aClearActiveDocument
|
||||
*
|
||||
* @return Returns true if the state was set successfully. See more details
|
||||
* in EventStateManager.h SetContentState.
|
||||
*/
|
||||
bool setContentState(in nsIDOMElement aElement, in unsigned long long aState);
|
||||
bool removeContentState(in nsIDOMElement aElement, in unsigned long long aState);
|
||||
bool removeContentState(in nsIDOMElement aElement, in unsigned long long aState,
|
||||
[optional] in bool aClearActiveDocument);
|
||||
|
||||
nsIDOMFontFaceList getUsedFontFaces(in nsIDOMRange aRange);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<meta http-equiv="msthemecompatible" content="no">
|
||||
<div style="width: 200px; height: 200px; overflow: scroll;">
|
||||
<div style="width: 200px; height: 200px; overflow: scroll; -moz-appearance:none">
|
||||
<div style="width: 100000px; height: 1000000px"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<meta http-equiv="msthemecompatible" content="no">
|
||||
<div style="width: 200px; height: 200px; overflow: scroll;">
|
||||
<div style="width: 200px; height: 200px; overflow: scroll;; -moz-appearance:none">
|
||||
<div style="width: 3725px; height: 3725px"></div>
|
||||
</div>
|
||||
<!--
|
||||
|
|
|
@ -80,7 +80,7 @@ ListInterfaceAddresses(int aFd, const char* aInterface, AddrMapType& aAddrMap)
|
|||
switch(family=ifreq.ifr_addr.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), 0, 0, NI_NUMERICHOST);
|
||||
getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), nullptr, 0, NI_NUMERICHOST);
|
||||
break;
|
||||
case AF_UNSPEC:
|
||||
return NS_OK;
|
||||
|
|
|
@ -186,7 +186,7 @@ class Continuation {
|
|||
}
|
||||
Continuation() {
|
||||
// empty constructor needed for nsTArray
|
||||
value = 0L;
|
||||
value = nullptr;
|
||||
length = 0;
|
||||
needsPercentDecoding = false;
|
||||
wasQuotedString = false;
|
||||
|
@ -971,7 +971,7 @@ nsMIMEHeaderParamImpl::DecodeParameter(const nsACString& aParamValue,
|
|||
// static
|
||||
char *DecodeQ(const char *in, uint32_t length)
|
||||
{
|
||||
char *out, *dest = 0;
|
||||
char *out, *dest = nullptr;
|
||||
|
||||
out = dest = (char *)PR_Calloc(length + 1, sizeof(char));
|
||||
if (dest == nullptr)
|
||||
|
@ -1186,7 +1186,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
|
|||
// safe because we don't use a raw *char any more.
|
||||
aResult.SetCapacity(3 * strlen(aHeader));
|
||||
|
||||
while ((p = PL_strstr(begin, "=?")) != 0) {
|
||||
while ((p = PL_strstr(begin, "=?")) != nullptr) {
|
||||
if (isLastEncodedWord) {
|
||||
// See if it's all whitespace.
|
||||
for (q = begin; q < p; ++q) {
|
||||
|
@ -1214,7 +1214,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
|
|||
|
||||
// Get charset info
|
||||
charsetStart = p;
|
||||
charsetEnd = 0;
|
||||
charsetEnd = nullptr;
|
||||
for (q = p; *q != '?'; q++) {
|
||||
if (*q <= ' ' || PL_strchr(especials, *q)) {
|
||||
goto badsyntax;
|
||||
|
|
|
@ -1337,7 +1337,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
getter_Copies(sval));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (sval.IsEmpty())
|
||||
mDefaultSocketType.Adopt(0);
|
||||
mDefaultSocketType.Adopt(nullptr);
|
||||
else {
|
||||
// verify that this socket type is actually valid
|
||||
nsCOMPtr<nsISocketProviderService> sps(
|
||||
|
@ -1899,13 +1899,13 @@ PrepareAcceptLanguages(const char *i_AcceptLanguages, nsACString &o_AcceptLangua
|
|||
count_n = 0;
|
||||
p2 = q_Accept;
|
||||
for (token = nsCRT::strtok(o_Accept, ",", &p);
|
||||
token != (char *) 0;
|
||||
token != nullptr;
|
||||
token = nsCRT::strtok(p, ",", &p))
|
||||
{
|
||||
token = net_FindCharNotInSet(token, HTTP_LWS);
|
||||
char* trim;
|
||||
trim = net_FindCharInSet(token, ";" HTTP_LWS);
|
||||
if (trim != (char*)0) // remove "; q=..." if present
|
||||
if (trim != nullptr) // remove "; q=..." if present
|
||||
*trim = '\0';
|
||||
|
||||
if (*token != '\0') {
|
||||
|
|
|
@ -196,7 +196,7 @@ public:
|
|||
void* operator()(void* anObject) override {
|
||||
nsCString *string = (nsCString*)anObject;
|
||||
delete string;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -215,9 +215,9 @@ void nsNotifyAddrListener::checkLink(void)
|
|||
// Walk through the linked list, maintaining head pointer so we can free
|
||||
// list later
|
||||
|
||||
for (ifa = list; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
for (ifa = list; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
int family;
|
||||
if (ifa->ifa_addr == NULL)
|
||||
if (ifa->ifa_addr == nullptr)
|
||||
continue;
|
||||
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
|
|
|
@ -202,6 +202,12 @@ macosx64/opt:
|
|||
- macosx64-tests-talos
|
||||
- macosx64-tests-debug
|
||||
|
||||
macosx64-devedition/opt:
|
||||
build-platform: macosx64-devedition/opt
|
||||
test-sets:
|
||||
- macosx64-tests-talos
|
||||
- macosx64-tests-debug
|
||||
|
||||
##
|
||||
# Android platforms (matching /android.*/)
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ BUILDER_NAME_PREFIX = {
|
|||
'linux64-jsdcov': 'Ubuntu Code Coverage VM 12.04 x64',
|
||||
'linux64-stylo': 'Ubuntu VM 12.04 x64',
|
||||
'macosx64': 'Rev7 MacOSX Yosemite 10.10.5',
|
||||
'macosx64-devedition': 'Rev7 MacOSX Yosemite 10.10.5 DevEdition',
|
||||
'android-4.3-arm7-api-15': 'Android 4.3 armv7 API 15+',
|
||||
'android-4.2-x86': 'Android 4.2 x86 Emulator',
|
||||
'android-4.3-arm7-api-15-gradle': 'Android 4.3 armv7 API 15+',
|
||||
|
@ -46,7 +47,7 @@ def test_packages_url(taskdesc):
|
|||
build_platform = taskdesc['attributes']['build_platform']
|
||||
build_type = taskdesc['attributes']['build_type']
|
||||
|
||||
if build_platform == 'macosx64' and build_type == 'opt':
|
||||
if build_platform.startswith('macosx64') and build_type == 'opt':
|
||||
target = 'firefox-{}.en-US.{}'.format(get_firefox_version(), 'mac')
|
||||
else:
|
||||
target = 'target'
|
||||
|
|
|
@ -56658,6 +56658,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/forms/the-label-element/iframe-label-attributes.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/forms/the-legend-element/.gitkeep": [
|
||||
[
|
||||
{}
|
||||
|
@ -189030,12 +189035,16 @@
|
|||
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/forms/the-label-element/iframe-label-attributes.html": [
|
||||
"5110391fe9ee5f04c2175bdaa1f38eeba0c40803",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/forms/the-label-element/label-attributes.html": [
|
||||
"bb00ee78b9fa2343d85dcaa13376a832d376617a",
|
||||
"4ce7bb05fecd15b76e40959bb9ab1e0b0adcd8da",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/forms/the-label-element/labelable-elements.html": [
|
||||
"421328f898fb2487152f6fd8df315fc22ddea61a",
|
||||
"80275984254360d8b713b5b330c18ae34138b670",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/forms/the-label-element/proxy-click-to-associated-element.html": [
|
||||
|
|
|
@ -1060,9 +1060,6 @@
|
|||
[HTMLInputElement interface: attribute valueHigh]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: document.createElement("input") must inherit property "dirName" with the proper type (6)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1078,9 +1075,6 @@
|
|||
[HTMLButtonElement interface: attribute menu]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: document.createElement("button") must inherit property "menu" with the proper type (11)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1090,15 +1084,9 @@
|
|||
[HTMLSelectElement interface: attribute autocomplete]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: document.createElement("select") must inherit property "autocomplete" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: document.createElement("select") must inherit property "labels" with the proper type (26)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: attribute autocomplete]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1108,9 +1096,6 @@
|
|||
[HTMLTextAreaElement interface: attribute inputMode]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "autocomplete" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1120,9 +1105,6 @@
|
|||
[HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "inputMode" with the proper type (6)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "labels" with the proper type (25)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLKeygenElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1228,24 +1210,6 @@
|
|||
[HTMLKeygenElement interface: document.createElement("keygen") must inherit property "labels" with the proper type (13)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLOutputElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLOutputElement interface: document.createElement("output") must inherit property "labels" with the proper type (12)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: document.createElement("progress") must inherit property "labels" with the proper type (3)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: document.createElement("meter") must inherit property "labels" with the proper type (6)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMenuItemElement interface: attribute default]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -2755,75 +2719,6 @@
|
|||
[HTMLMediaElement interface: new Audio() must inherit property "videoTracks" with the proper type (39)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: document.createElement("input") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("text") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("hidden") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("search") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("tel") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("url") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("email") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("password") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("date") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("month") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("week") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("time") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("datetime-local") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("number") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("range") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("color") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("checkbox") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("radio") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("file") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("submit") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("image") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("reset") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: createInput("button") must inherit property "labels" with the proper type (46)]
|
||||
expected: FAIL
|
||||
|
||||
[CanvasRenderingContext2D interface: operation getTransform()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -3379,9 +3274,6 @@
|
|||
[Document interface: document.implementation.createDocument(null, "", null) must inherit property "onmousewheel" with the proper type (126)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: document.createElement("button") must inherit property "labels" with the proper type (17)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLScriptElement interface: attribute noModule]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[label-attributes.html]
|
||||
type: testharness
|
||||
[A non-control follows by a control with same ID.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has multiple labels.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has no label 1.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has no label 2.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has an implicit label.]
|
||||
expected: FAIL
|
||||
|
|
@ -1,32 +1,6 @@
|
|||
[labelable-elements.html]
|
||||
type: testharness
|
||||
[Check if the output element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the progress element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the select element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the textarea element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the button element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the hidden input element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the input element in radio state can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the meter element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the hidden input element has null 'labels']
|
||||
expected: FAIL
|
||||
|
||||
[Check if the keygen element is not a labelable element]
|
||||
expected: FAIL
|
||||
|
||||
[Check if the keygen element can access 'labels']
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[button_labels.html]
|
||||
type: testharness
|
||||
[Forms]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[input_labels.html]
|
||||
type: testharness
|
||||
[Forms]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
<label>
|
||||
<div id="div1"></div>
|
||||
</label>
|
||||
<label for="test13"></label>
|
||||
</body>
|
||||
</html>
|
|
@ -32,10 +32,53 @@
|
|||
|
||||
<label id="lbl5" for="test7"></label>
|
||||
<input id="test7">
|
||||
|
||||
<label id="lbl7">
|
||||
<label id="lbl8">
|
||||
<div id="div1">
|
||||
<input id="test8">
|
||||
</div>
|
||||
</label>
|
||||
</label>
|
||||
<div id="div2"></div>
|
||||
|
||||
<label id="lbl9">
|
||||
<label id="lbl10" for="test10">
|
||||
<div id="div3">
|
||||
<input id="test9">
|
||||
</div>
|
||||
</label>
|
||||
</label>
|
||||
<div id="div4"><input id="test10"></div>
|
||||
|
||||
<label id="lbl11">
|
||||
<object id="obj">
|
||||
<input id="test11">
|
||||
<input id="test12">
|
||||
</object>
|
||||
</label>
|
||||
<label id="lbl12" for="test12"><div id="div5"></div></label>
|
||||
|
||||
<label id="lbl13">
|
||||
<p id="p1">
|
||||
<input id="test13">
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<div id="div6">
|
||||
<div id="div7">
|
||||
<label id="lbl14">
|
||||
<label id="lbl15" for="test15">
|
||||
<input id="test14">
|
||||
</label>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<input id="test15">
|
||||
</form>
|
||||
|
||||
<label id="lbl6" for="test7"></label>
|
||||
|
||||
<div id="content" style="display: none">
|
||||
<script>
|
||||
|
||||
//control attribute
|
||||
|
@ -57,6 +100,7 @@
|
|||
}, "A label element not in a document can not label any element in the document.");
|
||||
|
||||
test(function () {
|
||||
var labels = document.getElementById("test3").labels;
|
||||
assert_equals(document.getElementById("lbl1").control, document.getElementById("test3"),
|
||||
"The first labelable descendant of a label element should be its labeled control.");
|
||||
|
||||
|
@ -64,6 +108,10 @@
|
|||
document.getElementById("lbl1").insertBefore(input, document.getElementById("test2"));
|
||||
assert_equals(document.getElementById("lbl1").control, input,
|
||||
"The first labelable descendant of a label element in tree order should be its labeled control.");
|
||||
assert_equals(input.labels.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
|
||||
assert_equals(labels.length, 0,
|
||||
"The number of labels should be 0 if it's not the first labelable descendant of a label element.");
|
||||
input.remove();
|
||||
}, "The labeled control for a label element that has no 'for' attribute is the first labelable element which is a descendant of that label element.");
|
||||
|
||||
|
@ -100,6 +148,168 @@
|
|||
newLabel.remove();
|
||||
}, "A form control has multiple labels.");
|
||||
|
||||
test(function () {
|
||||
var labels = document.getElementById("test8").labels;
|
||||
assert_true(labels instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels.length, 2,
|
||||
"The form control has two ancestors with no explicit associated label, and is the first labelable descendant.");
|
||||
assert_array_equals(labels, [document.getElementById("lbl7"), document.getElementById("lbl8")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
|
||||
document.getElementById('div2').insertBefore(document.getElementById('div1'), document.getElementById('div2').firstChild);
|
||||
assert_equals(labels.length, 0,
|
||||
"The number of labels should be 0 after the labelable element is moved to outside of nested associated labels.");
|
||||
}, "A labelable element is moved to outside of nested associated labels.");
|
||||
|
||||
test(function () {
|
||||
var labels1 = document.getElementById("test9").labels;
|
||||
var labels2 = document.getElementById("test10").labels;
|
||||
assert_true(labels1 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_true(labels2 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels1.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
|
||||
assert_equals(labels2.length, 1,
|
||||
"The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
|
||||
assert_array_equals(labels1, [document.getElementById("lbl9")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
assert_array_equals(labels2, [document.getElementById("lbl10")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
document.getElementById('div3').insertBefore(document.getElementById('div4'), document.getElementById('div3').firstChild);
|
||||
assert_equals(labels1.length, 0,
|
||||
"The number of labels should be 0 if it's not the first labelable descendant of a label element.");
|
||||
assert_equals(labels2.length, 2,
|
||||
"The form control has an ancestor with an explicit associated label, and is the first labelable descendant.");
|
||||
}, "A labelable element is moved to inside of nested associated labels.");
|
||||
|
||||
test(function () {
|
||||
var labels1 = document.getElementById("test11").labels;
|
||||
var labels2 = document.getElementById("test12").labels;
|
||||
assert_true(labels1 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_true(labels2 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels1.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
|
||||
assert_equals(labels2.length, 1,
|
||||
"The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
|
||||
assert_array_equals(labels1, [document.getElementById("lbl11")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
assert_array_equals(labels2, [document.getElementById("lbl12")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
document.getElementById('div5').appendChild(document.getElementById('obj'));
|
||||
assert_equals(labels1.length, 0,
|
||||
"The number of labels should be 0 after the labelable element is moved to outside of associated label.");
|
||||
assert_equals(labels2.length, 1,
|
||||
"The number of labels should be 1 after the labelable element is moved to outside of associated label.");
|
||||
}, "A labelable element which is a descendant of non-labelable element is moved to outside of associated label.");
|
||||
|
||||
async_test(function () {
|
||||
var labels = document.getElementById("test13").labels;
|
||||
assert_true(labels instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
|
||||
assert_array_equals(labels, [document.getElementById("lbl13")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
let iframe = document.createElement('iframe');
|
||||
|
||||
iframe.onload = this.step_func_done(() => {
|
||||
iframe.contentWindow.document.getElementById("div1").appendChild(document.getElementById("p1"));
|
||||
assert_equals(labels.length, 2,
|
||||
"The number of labels should be 2 after the labelable element is moved to iframe.");
|
||||
});
|
||||
|
||||
iframe.setAttribute('src', 'http://web-platform.test:8000/html/semantics/forms/the-label-element/iframe-label-attributes.html');
|
||||
document.body.appendChild(iframe);
|
||||
}, "A labelable element is moved to iframe.");
|
||||
|
||||
test(function () {
|
||||
var labels1 = document.getElementById("test14").labels;
|
||||
var labels2 = document.getElementById("test15").labels;
|
||||
assert_true(labels1 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels1.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
|
||||
assert_equals(labels2.length, 1,
|
||||
"The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
|
||||
assert_array_equals(labels1, [document.getElementById("lbl14")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
|
||||
document.getElementById('div6').removeChild(document.getElementById('div7'));
|
||||
assert_equals(labels1.length, 0,
|
||||
"The number of labels should be 0 after the labelable element is removed.");
|
||||
assert_equals(labels2.length, 0,
|
||||
"The number of labels should be 0 since there is no label with a 'for' attribute associated with this labelable element.");
|
||||
}, "A div element which contains labelable element is removed.");
|
||||
|
||||
test(function () {
|
||||
// <label><input id="test16"><label for="test16"></label></label>
|
||||
var label1 = document.createElement('label');
|
||||
label1.innerHTML = "<input id='test16'>";
|
||||
var label2 = document.createElement('label');
|
||||
label2.htmlFor = "test16";
|
||||
label1.appendChild(label2);
|
||||
|
||||
var input = label1.firstChild;
|
||||
var labels = input.labels;
|
||||
|
||||
assert_equals(labels.length, 2,
|
||||
"The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
|
||||
assert_true(labels instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(label1.control, input, "The first labelable descendant of a label element should be its labeled control.");
|
||||
assert_equals(label2.control, input, "The labeled cotrol should be associated with the control whose ID is equal to the value of the 'for' attribute.");
|
||||
}, "A labelable element not in a document can label element in the same tree.");
|
||||
|
||||
test(function () {
|
||||
var isShadowDOMV0;
|
||||
if ("createShadowRoot" in document.getElementById('content')) {
|
||||
isShadowDOMV0 = true;
|
||||
}
|
||||
var root1;
|
||||
if (isShadowDOMV0) {
|
||||
root1 = document.getElementById('content').createShadowRoot();
|
||||
} else {
|
||||
root1 = document.getElementById('content').attachShadow({mode: 'open'});
|
||||
}
|
||||
assert_true(root1 instanceof DocumentFragment,
|
||||
"ShadowRoot should be an instance of DocumentFragment.");
|
||||
// <label><input id="shadow1"/></label><div id="div1"></div>
|
||||
var label1 = document.createElement('label');
|
||||
var input1 = document.createElement('input');
|
||||
input1.setAttribute("id", "shadow1");
|
||||
label1.appendChild(input1);
|
||||
root1.appendChild(label1);
|
||||
|
||||
var div1 = document.createElement('div');
|
||||
label1.appendChild(div1);
|
||||
// <label for="shadow2"></label><input id="shadow2"/>
|
||||
var root2;
|
||||
if (isShadowDOMV0) {
|
||||
root2 = div1.createShadowRoot();
|
||||
} else {
|
||||
root2 = div1.attachShadow({mode: 'open'});
|
||||
}
|
||||
|
||||
assert_true(root2 instanceof DocumentFragment,
|
||||
"ShadowRoot should be an instance of DocumentFragment.");
|
||||
var label2 = document.createElement('label');
|
||||
label2.setAttribute("for", "shadow2");
|
||||
|
||||
var input2 = document.createElement('input');
|
||||
input2.setAttribute("id", "shadow2");
|
||||
root2.appendChild(label2);
|
||||
root2.appendChild(input2);
|
||||
|
||||
assert_equals(root1.getElementById("shadow1").labels.length, 1,
|
||||
"The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
|
||||
assert_equals(root2.getElementById("shadow2").labels.length, 1,
|
||||
"The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
|
||||
}, "A labelable element inside the shadow DOM.");
|
||||
|
||||
test(function () {
|
||||
var labels = document.getElementById("test3").labels;
|
||||
assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
|
||||
|
|
|
@ -104,6 +104,7 @@ test(function() {
|
|||
|
||||
hiddenInput.type = "hidden";
|
||||
assert_equals(labels.length, 0, "Retained .labels NodeList should be empty after input type changed to hidden");
|
||||
assert_equals(hiddenInput.labels, null, ".labels NodeList should be null after input type changed to hidden");
|
||||
|
||||
hiddenInput.type = "checkbox";
|
||||
assert_true(labels === hiddenInput.labels, ".labels property must return the [SameObject] after input type is toggled back from 'hidden'");
|
||||
|
|
|
@ -190,6 +190,7 @@ var listener = {
|
|||
onWindowLoaded() {
|
||||
let browser = this.win.document.createElementNS(XUL_NS, "browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
|
||||
let remoteBrowser = Services.appinfo.browserTabsRemoteAutostart;
|
||||
browser.setAttribute("remote", remoteBrowser);
|
||||
|
|
|
@ -259,7 +259,12 @@ this.SelectContentHelper.prototype = {
|
|||
|
||||
case "Forms:DismissedDropDown":
|
||||
let selectedOption = this.element.item(this.element.selectedIndex);
|
||||
if (this.initialSelection != selectedOption) {
|
||||
if (this.initialSelection === selectedOption) {
|
||||
// Clear active document
|
||||
DOMUtils.removeContentState(this.element,
|
||||
kStateActive,
|
||||
/* aClearActiveDocument */ true);
|
||||
} else {
|
||||
let win = this.element.ownerGlobal;
|
||||
// For ordering of events, we're using non-e10s as our guide here,
|
||||
// since the spec isn't exactly clear. In non-e10s, we fire:
|
||||
|
@ -270,8 +275,12 @@ this.SelectContentHelper.prototype = {
|
|||
if (!this.closedWithEnter) {
|
||||
this.dispatchMouseEvent(win, selectedOption, "mousedown");
|
||||
this.dispatchMouseEvent(win, selectedOption, "mouseup");
|
||||
DOMUtils.removeContentState(this.element, kStateActive);
|
||||
}
|
||||
// Clear active document no matter user selects
|
||||
// via keyboard or mouse
|
||||
DOMUtils.removeContentState(this.element,
|
||||
kStateActive,
|
||||
/* aClearActiveDocument */ true);
|
||||
|
||||
let inputEvent = new win.UIEvent("input", {
|
||||
bubbles: true,
|
||||
|
|
|
@ -3574,12 +3574,6 @@ bool
|
|||
nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
|
||||
uint8_t aWidgetType)
|
||||
{
|
||||
// We don't have CSS set up to render non-native scrollbars on Mac OS X so we
|
||||
// render natively even if native theme support is disabled.
|
||||
if (aWidgetType != NS_THEME_SCROLLBAR &&
|
||||
aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
|
||||
return false;
|
||||
|
||||
// if this is a dropdown button in a combobox the answer is always no
|
||||
if (aWidgetType == NS_THEME_MENULIST_BUTTON) {
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
|
|
|
@ -2441,9 +2441,6 @@ nsNativeThemeWin::ThemeSupportsWidget(nsPresContext* aPresContext,
|
|||
// XXXdwh We can go even further and call the API to ask if support exists for
|
||||
// specific widgets.
|
||||
|
||||
if (aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
|
||||
return false;
|
||||
|
||||
if (aWidgetType == NS_THEME_FOCUS_OUTLINE) {
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче