import changes from tenfourfox-history:

- #374, #446: M1354080 (2d2a85336)
- make it only a warning on non-intel (c236974a3)
- factor code constants to a tag and make it endianness dependent (9539a6422)
- closes #374: asynchronous SVG through <img> (a87df728a)
- closes #391: M1342721 with some ideas from M1342439 (dd4ffb4f1)
- #425: M1385478 IsRequired() (07b90443f)
- closes #425: faster ToLowerCase() with ideas from M1383647 (5963b7a79)
- #432: M1390402 partial (without semantic changes) plus other partial cleanup (e2a616378)
This commit is contained in:
2018-05-31 15:23:51 +08:00
parent c940fb1d4d
commit aadb31cb88
32 changed files with 407 additions and 204 deletions
+11
View File
@@ -94,6 +94,17 @@ public:
*/
virtual void NotifyAnimationUpdated(Animation& aAnimation);
/**
* Returns true if any CSS animations, CSS transitions or Web animations are
* currently associated with this timeline. As soon as an animation is
* applied to an element it is associated with the timeline even if it has a
* delayed start, so this includes animations that may not be active for some
* time.
*/
bool HasAnimations() const {
return !mAnimations.IsEmpty();
}
void RemoveAnimation(Animation* aAnimation);
protected:
+10 -2
View File
@@ -8382,7 +8382,11 @@ nsDocument::AddToRadioGroup(const nsAString& aName,
nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
NS_ASSERTION(element, "radio controls have to be content elements");
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
HTMLInputElement* input = HTMLInputElement::FromContent(element);
NS_ASSERTION(input, "radio controls have to be input elements!");
if (input->IsRequired()) {
radioGroup->mRequiredRadioCount++;
}
}
@@ -8396,7 +8400,11 @@ nsDocument::RemoveFromRadioGroup(const nsAString& aName,
nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
NS_ASSERTION(element, "radio controls have to be content elements");
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
HTMLInputElement* input = HTMLInputElement::FromContent(element);
NS_ASSERTION(input, "radio controls have to be input elements!");
if (input->IsRequired()) {
NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
"mRequiredRadioCount about to wrap below 0!");
radioGroup->mRequiredRadioCount--;
+1 -1
View File
@@ -979,7 +979,7 @@ nsGenericDOMDataNode::GetText()
uint32_t
nsGenericDOMDataNode::TextLength() const
{
return mText.GetLength();
return TextDataLength();
}
nsresult
+5
View File
@@ -219,6 +219,11 @@ public:
rv = ReplaceData(aOffset, aCount, aData);
}
uint32_t TextDataLength() const
{
return mText.GetLength();
}
//----------------------------------------
#ifdef DEBUG
+1 -3
View File
@@ -2396,9 +2396,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
bool overrecursed = false;
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, overrecursed = true);
if (overrecursed) {
if (MOZ_UNLIKELY(!js::CheckRecursionConservativeDontReport(cx))) {
NS_WARNING("Overrecursion in SetNewDocument");
return NS_ERROR_FAILURE;
}
+3 -1
View File
@@ -1891,7 +1891,9 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
JS_CHECK_RECURSION_CONSERVATIVE(aCx, return NS_ERROR_FAILURE);
if (MOZ_UNLIKELY(!js::CheckRecursionConservative(aCx))) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JSObject*> aObj(aCx, aObjArg);
const DOMJSClass* domClass = GetDOMClass(aObj);
+3 -1
View File
@@ -278,11 +278,13 @@ private:
#define DISABLED_STATES (NS_EVENT_STATE_DISABLED | NS_EVENT_STATE_ENABLED)
#define REQUIRED_STATES (NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL)
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FULL_SCREEN_ANCESTOR | \
DISABLED_STATES | \
DISABLED_STATES | REQUIRED_STATES | \
NS_EVENT_STATE_UNRESOLVED)
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
+9 -3
View File
@@ -2296,7 +2296,10 @@ HTMLFormElement::AddToRadioGroup(const nsAString& aName,
nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
NS_ASSERTION(element, "radio controls have to be content elements!");
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
HTMLInputElement* input = HTMLInputElement::FromContent(element);
NS_ASSERTION(input, "radio controls have to be input elements!");
if (input->IsRequired()) {
mRequiredRadioButtonCounts.Put(aName,
mRequiredRadioButtonCounts.Get(aName)+1);
}
@@ -2307,9 +2310,12 @@ HTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
nsIFormControl* aRadio)
{
nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
NS_ASSERTION(element, "radio controls have to be content elements!");
NS_ASSERTION(element, "radio controls have to be content elements");
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
HTMLInputElement* input = HTMLInputElement::FromContent(element);
NS_ASSERTION(input, "radio controls have to be input elements!");
if (input->IsRequired()) {
uint32_t requiredNb = mRequiredRadioButtonCounts.Get(aName);
NS_ASSERTION(requiredNb >= 1,
"At least one radio button has to be required!");
+19 -10
View File
@@ -1149,6 +1149,13 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
UpdateDisabledState(aNotify);
}
if (aName == nsGkAtoms::required && DoesRequiredApply()) {
// This *has* to be called *before* UpdateValueMissingValidityState
// because UpdateValueMissingValidityState depends on our required
// state.
UpdateRequiredState(!!aValue, aNotify);
}
UpdateValueMissingValidityState();
// This *has* to be called *after* validity has changed.
@@ -4371,6 +4378,15 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType)
mFocusedValue.Truncate();
}
// Update or clear our required states since we may have changed from a
// required input type to a non-required input type or viceversa.
if (DoesRequiredApply()) {
bool isRequired = HasAttr(kNameSpaceID_None, nsGkAtoms::required);
UpdateRequiredState(isRequired, false); // See below for why this is OK.
} else {
RemoveStatesSilently(REQUIRED_STATES);
}
UpdateHasRange();
// Do not notify, it will be done after if needed.
@@ -5757,12 +5773,6 @@ HTMLInputElement::IntrinsicState() const
state |= nsImageLoadingContent::ImageState();
}
if (DoesRequiredApply() && HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
state |= NS_EVENT_STATE_REQUIRED;
} else {
state |= NS_EVENT_STATE_OPTIONAL;
}
if (IsCandidateForConstraintValidation()) {
if (IsValid()) {
state |= NS_EVENT_STATE_VALID;
@@ -6369,8 +6379,7 @@ HTMLInputElement::IsValueMissing() const
// Should use UpdateValueMissingValidityStateForRadio() for type radio.
MOZ_ASSERT(mType != NS_FORM_INPUT_RADIO);
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required) ||
!DoesRequiredApply()) {
if (!IsRequired() || !DoesRequiredApply()) {
return false;
}
@@ -6635,7 +6644,7 @@ HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
// If there is no selection, that might mean the radio is not in a group.
// In that case, we can look for the checked state of the radio.
bool selected = selection || (!aIgnoreSelf && mChecked);
bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
bool required = !aIgnoreSelf && IsRequired();
bool valueMissing = false;
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
@@ -6652,7 +6661,7 @@ HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
// If the current radio is required and not ignored, we can assume the entire
// group is required.
if (!required) {
required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required))
required = (aIgnoreSelf && IsRequired())
? container->GetRequiredRadioCount(name) - 1
: container->GetRequiredRadioCount(name);
}
+16 -5
View File
@@ -774,6 +774,22 @@ public:
*/
static Decimal StringToDecimal(const nsAString& aValue);
/**
* Returns if the required attribute applies for the current type.
*/
bool DoesRequiredApply() const;
/**
* Returns the current required state of the element. This function differs
* from Required() in that this function only returns true for input types
* that @required attribute applies and the attribute is set; in contrast,
* Required() returns true whenever @required attribute is set.
*/
bool IsRequired() const
{
return State().HasState(NS_EVENT_STATE_REQUIRED);
}
protected:
virtual ~HTMLInputElement();
@@ -964,11 +980,6 @@ protected:
*/
bool DoesReadOnlyApply() const;
/**
* Returns if the required attribute applies for the current type.
*/
bool DoesRequiredApply() const;
/**
* Returns if the pattern attribute applies for the current type.
*/
+7 -8
View File
@@ -1070,7 +1070,7 @@ HTMLSelectElement::IsOptionDisabled(int32_t aIndex, bool* aIsDisabled)
}
bool
HTMLSelectElement::IsOptionDisabled(HTMLOptionElement* aOption)
HTMLSelectElement::IsOptionDisabled(HTMLOptionElement* aOption) const
{
MOZ_ASSERT(aOption);
if (aOption->Disabled()) {
@@ -1301,6 +1301,11 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
UpdateValueMissingValidityState();
UpdateBarredFromConstraintValidation();
} else if (aName == nsGkAtoms::required) {
// This *has* to be called *before* UpdateValueMissingValidityState
// because UpdateValueMissingValidityState depends on our required
// state.
UpdateRequiredState(!!aValue, aNotify);
UpdateValueMissingValidityState();
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state
@@ -1523,12 +1528,6 @@ HTMLSelectElement::IntrinsicState() const
}
}
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
state |= NS_EVENT_STATE_REQUIRED;
} else {
state |= NS_EVENT_STATE_OPTIONAL;
}
return state;
}
@@ -1771,7 +1770,7 @@ HTMLSelectElement::RebuildOptionsArray(bool aNotify)
}
bool
HTMLSelectElement::IsValueMissing()
HTMLSelectElement::IsValueMissing() const
{
if (!Required()) {
return false;
+3 -3
View File
@@ -198,7 +198,7 @@ public:
}
bool Required() const
{
return GetBoolAttr(nsGkAtoms::required);
return State().HasState(NS_EVENT_STATE_REQUIRED);
}
void SetRequired(bool aVal, ErrorResult& aRv)
{
@@ -332,7 +332,7 @@ public:
*/
NS_IMETHOD IsOptionDisabled(int32_t aIndex,
bool* aIsDisabled);
bool IsOptionDisabled(HTMLOptionElement* aOption);
bool IsOptionDisabled(HTMLOptionElement* aOption) const;
/**
* Sets multiple options (or just sets startIndex if select is single)
@@ -505,7 +505,7 @@ protected:
// nsIConstraintValidation
void UpdateBarredFromConstraintValidation();
bool IsValueMissing();
bool IsValueMissing() const;
/**
* Get the index of the first option at, under or following the content in
+8 -7
View File
@@ -1136,12 +1136,6 @@ HTMLTextAreaElement::IntrinsicState() const
{
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
state |= NS_EVENT_STATE_REQUIRED;
} else {
state |= NS_EVENT_STATE_OPTIONAL;
}
if (IsCandidateForConstraintValidation()) {
if (IsValid()) {
state |= NS_EVENT_STATE_VALID;
@@ -1286,6 +1280,13 @@ HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
UpdateDisabledState(aNotify);
}
if (aName == nsGkAtoms::required) {
// This *has* to be called *before* UpdateValueMissingValidityState
// because UpdateValueMissingValidityState depends on our required
// state.
UpdateRequiredState(!!aValue, aNotify);
}
UpdateValueMissingValidityState();
// This *has* to be called *after* validity has changed.
@@ -1368,7 +1369,7 @@ HTMLTextAreaElement::IsTooLong()
bool
HTMLTextAreaElement::IsValueMissing() const
{
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required) || !IsMutable()) {
if (!Required() || !IsMutable()) {
return false;
}
+2 -2
View File
@@ -222,9 +222,9 @@ public:
{
SetHTMLBoolAttr(nsGkAtoms::readonly, aReadOnly, aError);
}
bool Required()
bool Required() const
{
return GetBoolAttr(nsGkAtoms::required);
return State().HasState(NS_EVENT_STATE_REQUIRED);
}
void SetRangeText(const nsAString& aReplacement, ErrorResult& aRv);
+19
View File
@@ -107,6 +107,7 @@
#include "mozilla/dom/HTMLBodyElement.h"
#include "imgIContainer.h"
#include "nsComputedDOMStyle.h"
#include "mozilla/dom/HTMLInputElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -2640,6 +2641,24 @@ void nsGenericHTMLFormElement::UpdateDisabledState(bool aNotify)
}
}
void
nsGenericHTMLFormElement::UpdateRequiredState(bool aIsRequired, bool aNotify)
{
EventStates requiredStates;
if (aIsRequired) {
requiredStates |= NS_EVENT_STATE_REQUIRED;
} else {
requiredStates |= NS_EVENT_STATE_OPTIONAL;
}
EventStates oldRequiredStates = State() & REQUIRED_STATES;
EventStates changedStates = requiredStates ^ oldRequiredStates;
if (!changedStates.IsEmpty()) {
ToggleStates(changedStates, aNotify);
}
}
void
nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
{
+5
View File
@@ -1351,6 +1351,11 @@ public:
*/
void UpdateDisabledState(bool aNotify);
/**
* Update our required/optional flags to match the given aIsRequired boolean.
*/
void UpdateRequiredState(bool aIsRequired, bool aNotify);
void FieldSetFirstLegendChanged(bool aNotify) {
UpdateFieldSet(aNotify);
}
-16
View File
@@ -383,10 +383,6 @@ TabParent::AddWindowListeners()
this, false, false);
}
}
if (nsIPresShell* shell = mFrameElement->OwnerDoc()->GetShell()) {
mPresShellWithRefreshListener = shell;
shell->AddPostRefreshObserver(this);
}
}
}
@@ -401,18 +397,6 @@ TabParent::RemoveWindowListeners()
this, false);
}
}
if (mPresShellWithRefreshListener) {
mPresShellWithRefreshListener->RemovePostRefreshObserver(this);
mPresShellWithRefreshListener = nullptr;
}
}
void
TabParent::DidRefresh()
{
if (mChromeOffset != -GetChildProcessOffset()) {
UpdatePosition();
}
}
void
-4
View File
@@ -85,7 +85,6 @@ class TabParent final : public PBrowserParent
, public nsISecureBrowserUI
, public nsSupportsWeakReference
, public TabContext
, public nsAPostRefreshObserver
, public nsIWebBrowserPersistable
{
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@@ -145,7 +144,6 @@ public:
void RemoveWindowListeners();
void AddWindowListeners();
void DidRefresh() override;
virtual bool RecvMoveFocus(const bool& aForward,
const bool& aForDocumentNavigation) override;
@@ -628,8 +626,6 @@ private:
// cursor. This happens whenever the cursor is in the tab's region.
bool mTabSetsCursor;
RefPtr<nsIPresShell> mPresShellWithRefreshListener;
bool mHasContentOpener;
DebugOnly<int32_t> mActiveSupressDisplayportCount;
-29
View File
@@ -3473,15 +3473,6 @@ nsEditor::IsEditable(nsINode* aNode)
}
}
bool
nsEditor::IsMozEditorBogusNode(nsINode* element)
{
return element && element->IsElement() &&
element->AsElement()->AttrValueIs(kNameSpaceID_None,
kMOZEditorBogusNodeAttrAtom, kMOZEditorBogusNodeValue,
eCaseMatters);
}
uint32_t
nsEditor::CountEditableChildren(nsINode* aNode)
{
@@ -3625,12 +3616,6 @@ nsEditor::IsTextNode(nsIDOMNode *aNode)
return (nodeType == nsIDOMNode::TEXT_NODE);
}
bool
nsEditor::IsTextNode(nsINode *aNode)
{
return aNode->NodeType() == nsIDOMNode::TEXT_NODE;
}
///////////////////////////////////////////////////////////////////////////
// GetChildAt: returns the node at this position index in the parent
//
@@ -4844,20 +4829,6 @@ nsEditor::FinalizeSelection()
return NS_OK;
}
dom::Element *
nsEditor::GetRoot()
{
if (!mRootElement)
{
nsCOMPtr<nsIDOMElement> root;
// Let GetRootElement() do the work
GetRootElement(getter_AddRefs(root));
}
return mRootElement;
}
dom::Element*
nsEditor::GetEditorRoot()
{
+21 -3
View File
@@ -569,7 +569,13 @@ public:
virtual bool IsEditable(nsINode* aNode);
/** returns true if aNode is a MozEditorBogus node */
bool IsMozEditorBogusNode(nsINode* aNode);
bool IsMozEditorBogusNode(nsINode* aNode)
{
return aNode && aNode->IsElement() &&
aNode->AsElement()->AttrValueIs(kNameSpaceID_None,
kMOZEditorBogusNodeAttrAtom, kMOZEditorBogusNodeValue,
eCaseMatters);
}
/** counts number of editable child nodes */
uint32_t CountEditableChildren(nsINode* aNode);
@@ -598,7 +604,10 @@ public:
virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2);
static bool IsTextNode(nsIDOMNode *aNode);
static bool IsTextNode(nsINode *aNode);
static bool IsTextNode(nsINode* aNode)
{
return aNode->NodeType() == nsIDOMNode::TEXT_NODE;
}
static nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset);
static nsCOMPtr<nsIDOMNode> GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset);
@@ -664,7 +673,16 @@ public:
virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget() = 0;
// Fast non-refcounting editor root element accessor
mozilla::dom::Element *GetRoot();
mozilla::dom::Element *GetRoot()
{
if (!mRootElement) {
// Let GetRootElement() do the work
nsCOMPtr<nsIDOMElement> root;
GetRootElement(getter_AddRefs(root));
}
return mRootElement;
}
// Likewise, but gets the editor's root instead, which is different for HTML
// editors
+3 -2
View File
@@ -1176,11 +1176,12 @@ nsTextEditRules::CreateBogusNodeIfNeeded(Selection* aSelection)
// Now we've got the body element. Iterate over the body element's children,
// looking for editable content. If no editable content is found, insert the
// bogus node.
for (nsCOMPtr<nsIContent> bodyChild = body->GetFirstChild();
bool bodyEditable = mEditor->IsEditable(body);
for (nsIContent* bodyChild = body->GetFirstChild();
bodyChild;
bodyChild = bodyChild->GetNextSibling()) {
if (mEditor->IsMozEditorBogusNode(bodyChild) ||
!mEditor->IsEditable(body) || // XXX hoist out of the loop?
!bodyEditable ||
mEditor->IsEditable(bodyChild) || mEditor->IsBlockNode(bodyChild)) {
return NS_OK;
}
+7 -1
View File
@@ -209,6 +209,12 @@ struct writeBuf
int offset;
};
#ifdef __ppc__
#define TAG_CFF 0x43464620
#else
#define TAG_CFF 0x20464643
#endif
bool
ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
{
@@ -223,7 +229,7 @@ ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
bool CFF = false;
for (CFIndex i = 0; i<count; i++) {
uint32_t tag = (uint32_t)(uintptr_t)CFArrayGetValueAtIndex(tags, i);
if (tag == 0x43464620) // 'CFF '
if (tag == TAG_CFF) // 'CFF '
CFF = true;
CFDataRef data = CGFontCopyTableForTag(mFont, tag);
records[i].tag = tag;
+31 -2
View File
@@ -5,7 +5,9 @@
#include "SVGDocumentWrapper.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Element.h"
#include "nsDOMNavigationTiming.h"
#include "nsICategoryManager.h"
#include "nsIChannel.h"
#include "nsIContentViewer.h"
@@ -115,8 +117,21 @@ bool
SVGDocumentWrapper::IsAnimated()
{
nsIDocument* doc = mViewer->GetDocument();
return doc && doc->HasAnimationController() &&
doc->GetAnimationController()->HasRegisteredAnimations();
if (!doc) {
return false;
}
if (doc->Timeline()->HasAnimations()) {
// CSS animations (technically HasAnimations() also checks for CSS
// transitions and Web animations but since SVG-as-an-image doesn't run
// script they will never run in the document that we wrap).
return true;
}
if (doc->HasAnimationController() &&
doc->GetAnimationController()->HasRegisteredAnimations()) {
// SMIL animations
return true;
}
return false;
}
void
@@ -330,6 +345,20 @@ SVGDocumentWrapper::SetupViewer(nsIRequest* aRequest,
NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
// Create a navigation time object and pass it to the SVG document through
// the viewer.
// The timeline(DocumentTimeline, used in CSS animation) of this SVG
// document needs this navigation timing object for time computation, such
// as to calculate current time stamp based on the start time of navigation
// time object.
//
// For a root document, DocShell would do these sort of things
// automatically. Since there is no DocShell for this wrapped SVG document,
// we must set it up manually.
RefPtr<nsDOMNavigationTiming> timing = new nsDOMNavigationTiming();
timing->NotifyNavigationStart();
viewer->SetNavigationTiming(timing);
nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
+6
View File
@@ -524,6 +524,12 @@ VectorImage::RequestRefresh(const TimeStamp& aTime)
return;
}
PendingAnimationTracker* tracker =
mSVGDocumentWrapper->GetDocument()->GetPendingAnimationTracker();
if (tracker && ShouldAnimate()) {
tracker->TriggerPendingAnimationsOnNextTick(aTime);
}
EvaluateAnimation();
mSVGDocumentWrapper->TickRefreshDriver();
+2
View File
@@ -28,6 +28,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "jscntxtinlines.h"
#include "irregexp/RegExpEngine.h"
#include "irregexp/NativeRegExpMacroAssembler.h"
+2
View File
@@ -149,6 +149,8 @@ class ExclusiveContext : public ContextFriendFields,
return isJSContext();
}
JSRuntime* ecRuntime() const { return runtime_; } // TenFourFox issue 391
bool runtimeMatches(JSRuntime* rt) const {
return runtime_ == rt;
}
+122 -6
View File
@@ -19,8 +19,130 @@
#include "vm/ProxyObject.h"
#include "vm/Symbol.h"
MOZ_ALWAYS_INLINE bool
JSContext::runningWithTrustedPrincipals() const
{
return !compartment() || compartment()->principals() == runtime()->trustedPrincipals();
}
namespace js {
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(GetRuntime(cx));
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
// Needed for issue 391 -- see below
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(ExclusiveContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(cx->ecRuntime());
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, int extraAllowance = 0)
{
StackKind kind = cx->runningWithTrustedPrincipals() ? StackForTrustedScript
: StackForUntrustedScript;
return GetNativeStackLimit(cx, kind, extraAllowance);
}
/*
* These macros report a stack overflow and run |onerror| if we are close to
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a
* little extra space so that we can ensure that crucial code is able to run.
* JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check,
* including a safety buffer (as in, it uses the untrusted limit and subtracts
* a little more from it).
*/
// Implement a fast path a la bug 1342439, but without all that churn.
// Leave the old limit versions here just in case.
// TenFourFox issue 391
#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION(cx, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx, js::StackForUntrustedScript), &stackDummy_))) { \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_))) {\
js::ReportOverRecursed(cx); \
onerror; \
} \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx, js::StackForUntrustedScript), &stackDummy_))) { \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_))) {\
onerror; \
} \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
class CompartmentChecker
{
JSCompartment* compartment;
@@ -382,12 +504,6 @@ JSContext::setPendingException(js::Value v)
MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
}
inline bool
JSContext::runningWithTrustedPrincipals() const
{
return !compartment() || compartment()->principals() == runtime()->trustedPrincipals();
}
inline void
js::ExclusiveContext::enterCompartment(JSCompartment* c)
{
+17 -2
View File
@@ -385,9 +385,24 @@ js::IsObjectInContextCompartment(JSObject* obj, const JSContext* cx)
}
JS_FRIEND_API(bool)
js::RunningWithTrustedPrincipals(JSContext* cx)
js::CheckRecursion(JSContext* cx)
{
return cx->runningWithTrustedPrincipals();
JS_CHECK_RECURSION(cx, return false);
return true;
}
JS_FRIEND_API(bool)
js::CheckRecursionConservative(JSContext* cx)
{
JS_CHECK_RECURSION_CONSERVATIVE(cx, return false);
return true;
}
JS_FRIEND_API(bool)
js::CheckRecursionConservativeDontReport(JSContext* cx)
{
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, return false);
return true;
}
JS_FRIEND_API(JSFunction*)
+5 -81
View File
@@ -967,89 +967,13 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
JS_FRIEND_API(bool)
RunningWithTrustedPrincipals(JSContext* cx);
CheckRecursion(JSContext* cx);
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(GetRuntime(cx));
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
JS_FRIEND_API(bool)
CheckRecursionConservative(JSContext* cx);
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, int extraAllowance = 0)
{
StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript
: StackForUntrustedScript;
return GetNativeStackLimit(cx, kind, extraAllowance);
}
/*
* These macros report a stack overflow and run |onerror| if we are close to
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a
* little extra space so that we can ensure that crucial code is able to run.
* JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check,
* including a safety buffer (as in, it uses the untrusted limit and subtracts
* a little more from it).
*/
#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror)
#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror)
#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
JS_FRIEND_API(bool)
CheckRecursionConservativeDontReport(JSContext* cx);
JS_FRIEND_API(void)
StartPCCountProfiling(JSContext* cx);
+64 -6
View File
@@ -603,6 +603,64 @@ js::SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t l
return NewDependentString(cx, str, begin, len);
}
// Adapted from bug 1383647
static inline bool
FastLatin1LowerCase(Latin1Char ch)
{
if (MOZ_LIKELY(ch < 128))
return ch >= 'A' && ch <= 'Z';
// U+00C0 to U+00DE, except U+00D7, have a lowercase form.
bool canLower = ((ch & ~0x1F) == /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */ 0xc0) &&
((ch & /* MULTIPLICATION_SIGN */ 0xd7) != 0xd7);
MOZ_ASSERT(canLower == CanLowerCase(char16_t(ch)));
return canLower;
}
static JSString*
ToLowerCaseLatin1(JSContext* cx, JSLinearString* str)
{
// Unlike toUpperCase, toLowerCase has the nice invariant that if the input
// is a Latin1 string, the output is also a Latin1 string.
UniquePtr<Latin1Char[], JS::FreePolicy> newChars;
size_t length = str->length();
{
AutoCheckCannotGC nogc;
const Latin1Char* chars = str->chars<Latin1Char>(nogc);
// Look for the first upper case character.
size_t i = 0;
for (; i < length; i++) {
if (FastLatin1LowerCase(chars[i]))
break;
}
// If all characters are lower case, return the input string.
if (i == length)
return str;
newChars = cx->make_pod_array<Latin1Char>(length + 1);
if (MOZ_UNLIKELY(!newChars))
return nullptr;
PodCopy(newChars.get(), chars, i);
for (; i < length; i++) {
char16_t c = unicode::ToLowerCase(chars[i]);
MOZ_ASSERT_IF((IsSame<Latin1Char, Latin1Char>::value), c <= JSString::MAX_LATIN1_CHAR);
newChars[i] = c;
}
newChars[length] = 0;
}
JSString* res = NewStringDontDeflate<CanGC>(cx, newChars.get(), length);
if (MOZ_UNLIKELY(!res))
return nullptr;
newChars.release();
return res;
}
template <typename CharT>
static JSString*
ToLowerCase(JSContext* cx, JSLinearString* str)
@@ -628,7 +686,7 @@ ToLowerCase(JSContext* cx, JSLinearString* str)
return str;
newChars = cx->make_pod_array<CharT>(length + 1);
if (!newChars)
if (MOZ_UNLIKELY(!newChars))
return nullptr;
PodCopy(newChars.get(), chars, i);
@@ -643,7 +701,7 @@ ToLowerCase(JSContext* cx, JSLinearString* str)
}
JSString* res = NewStringDontDeflate<CanGC>(cx, newChars.get(), length);
if (!res)
if (MOZ_UNLIKELY(!res))
return nullptr;
newChars.release();
@@ -654,18 +712,18 @@ static inline bool
ToLowerCaseHelper(JSContext* cx, CallReceiver call)
{
RootedString str(cx, ThisToStringForStringProto(cx, call));
if (!str)
if (MOZ_UNLIKELY(!str))
return false;
JSLinearString* linear = str->ensureLinear(cx);
if (!linear)
if (MOZ_UNLIKELY(!linear))
return false;
if (linear->hasLatin1Chars())
str = ToLowerCase<Latin1Char>(cx, linear);
str = ToLowerCaseLatin1(cx, linear);
else
str = ToLowerCase<char16_t>(cx, linear);
if (!str)
if (MOZ_UNLIKELY(!str))
return false;
call.rval().setString(str);
+3 -1
View File
@@ -258,7 +258,9 @@ XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
bool XPCVariant::InitializeData(JSContext* cx)
{
JS_CHECK_RECURSION(cx, return false);
if (MOZ_UNLIKELY(!js::CheckRecursion(cx))) {
return false;
}
RootedValue val(cx, GetJSVal());
+2 -5
View File
@@ -1619,7 +1619,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
nsIFrame* frame = aBuilder->RootReferenceFrame();
nsPresContext* presContext = frame->PresContext();
nsIPresShell* presShell = presContext->GetPresShell();
nsIPresShell* presShell = presContext->PresShell();
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
NotifySubDocInvalidationFunc computeInvalidFunc =
@@ -1646,10 +1646,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
containerParameters, nullptr);
nsIDocument* document = nullptr;
if (presShell) {
document = presShell->GetDocument();
}
nsIDocument* document = presShell->GetDocument();
if (!root) {
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);