+
diff --git a/devtools/client/themes/boxmodel.css b/devtools/client/themes/boxmodel.css
index e44ee536cfad..3765c60fb233 100644
--- a/devtools/client/themes/boxmodel.css
+++ b/devtools/client/themes/boxmodel.css
@@ -7,10 +7,6 @@
*/
.boxmodel-container {
- /* The view will grow bigger as the window gets resized, until 400px */
- max-width: 400px;
- margin: 0px auto;
- padding: 0;
overflow: auto;
}
@@ -33,9 +29,11 @@
position: relative;
color: var(--theme-selection-color);
/* Make sure there is some space between the window's edges and the regions */
- margin: 14px 14px 4px 14px;
+ margin: 14px auto;
width: calc(100% - 2 * 14px);
min-width: 240px;
+ /* The view will grow bigger as the window gets resized, until 400px */
+ max-width: 400px;
}
.boxmodel-box {
diff --git a/devtools/shared/gcli/source/lib/gcli/commands/commands.js b/devtools/shared/gcli/source/lib/gcli/commands/commands.js
index 67793b2dc8f2..0af4be620a9b 100644
--- a/devtools/shared/gcli/source/lib/gcli/commands/commands.js
+++ b/devtools/shared/gcli/source/lib/gcli/commands/commands.js
@@ -335,10 +335,10 @@ Parameter.prototype.toJson = function() {
};
// Values do not need to be serializable, so we don't try. For the client
- // side (which doesn't do any executing) we don't actually care what the
- // default value is, just that it exists
+ // side (which doesn't do any executing) we only care whether default value is
+ // undefined, null, or something else.
if (this.paramSpec.defaultValue !== undefined) {
- json.defaultValue = {};
+ json.defaultValue = (this.paramSpec.defaultValue === null) ? null : {};
}
if (this.paramSpec.description != null) {
json.description = this.paramSpec.description;
diff --git a/devtools/shared/gcli/source/lib/gcli/commands/help.js b/devtools/shared/gcli/source/lib/gcli/commands/help.js
index 317f80240c75..7d1cc9087716 100644
--- a/devtools/shared/gcli/source/lib/gcli/commands/help.js
+++ b/devtools/shared/gcli/source/lib/gcli/commands/help.js
@@ -69,7 +69,7 @@ function getHelpManData(commandData, context) {
}
else {
// We need defaultText to work the text version of defaultValue
- input = l10n.lookupFormat('helpManOptional');
+ input = l10n.lookup('helpManOptional');
/*
var val = param.type.stringify(param.defaultValue);
input = Promise.resolve(val).then(function(defaultValue) {
diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
index cf5ad855f601..62f1bc3cfad8 100644
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -47,6 +47,11 @@ DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
DocGroup::~DocGroup()
{
MOZ_ASSERT(mDocuments.IsEmpty());
+ if (!NS_IsMainThread()) {
+ nsIEventTarget* target = EventTargetFor(TaskCategory::Other);
+ NS_ProxyRelease(target, mReactionsStack.forget());
+ }
+
mTabGroup->mDocGroups.RemoveEntry(mKey);
}
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 3e9d6480c734..0f0ecce8ea68 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5331,7 +5331,7 @@ static bool sRemovingScriptBlockers = false;
void
nsContentUtils::RemoveScriptBlocker()
{
- MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sRemovingScriptBlockers);
NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
--sScriptBlockerCount;
diff --git a/dom/base/test/intersectionobserver_iframe.html b/dom/base/test/intersectionobserver_iframe.html
index 8a4098e74353..d882ed7e4f39 100644
--- a/dom/base/test/intersectionobserver_iframe.html
+++ b/dom/base/test/intersectionobserver_iframe.html
@@ -16,6 +16,7 @@
diff --git a/dom/base/test/intersectionobserver_window.html b/dom/base/test/intersectionobserver_window.html
index c2b1b023ab6a..86fa66682d37 100644
--- a/dom/base/test/intersectionobserver_window.html
+++ b/dom/base/test/intersectionobserver_window.html
@@ -27,6 +27,7 @@
records[0].rootBounds.bottom === viewportHeight &&
records[0].rootBounds.height === viewportHeight;
window.opener.postMessage(passed, '*');
+ io.disconnect();
});
io.observe(document.getElementById("target"));
diff --git a/gfx/thebes/gfxMatrix.h b/gfx/thebes/gfxMatrix.h
index 9282a22dbb33..4f92262cc1e8 100644
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -112,6 +112,18 @@ public:
_31 == 0.0 && _32 == 0.0;
}
+ /* Returns true if the matrix is a rectilinear transformation (i.e.
+ * grid-aligned rectangles are transformed to grid-aligned rectangles)
+ */
+ bool IsRectilinear() const {
+ if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
+ return true;
+ } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Inverts this matrix, if possible. Otherwise, the matrix is left
* unchanged.
diff --git a/image/FrameAnimator.cpp b/image/FrameAnimator.cpp
index 4b360b00230e..4602782af990 100644
--- a/image/FrameAnimator.cpp
+++ b/image/FrameAnimator.cpp
@@ -25,7 +25,7 @@ namespace image {
// AnimationState implementation.
///////////////////////////////////////////////////////////////////////////////
-void
+const gfx::IntRect
AnimationState::UpdateState(bool aAnimationFinished,
RasterImage *aImage,
const gfx::IntSize& aSize)
@@ -36,12 +36,13 @@ AnimationState::UpdateState(bool aAnimationFinished,
DefaultSurfaceFlags(),
PlaybackType::eAnimated));
- UpdateStateInternal(result, aAnimationFinished);
+ return UpdateStateInternal(result, aAnimationFinished, aSize);
}
-void
+const gfx::IntRect
AnimationState::UpdateStateInternal(LookupResult& aResult,
- bool aAnimationFinished)
+ bool aAnimationFinished,
+ const gfx::IntSize& aSize)
{
// Update mDiscarded and mIsCurrentlyDecoded.
if (aResult.Type() == MatchType::NOT_FOUND) {
@@ -73,6 +74,8 @@ AnimationState::UpdateStateInternal(LookupResult& aResult,
}
}
+ gfx::IntRect ret;
+
// Update the value of mCompositedFrameInvalid.
if (mIsCurrentlyDecoded || aAnimationFinished) {
// Animated images that have finished their animation (ie because it is a
@@ -84,6 +87,10 @@ AnimationState::UpdateStateInternal(LookupResult& aResult,
// to do for images that aren't finished animating because before we paint
// the refresh driver will call into us to advance to the correct frame,
// and that will succeed because we have all the frames.
+ if (mCompositedFrameInvalid) {
+ // Invalidate if we are marking the composited frame valid.
+ ret.SizeTo(aSize);
+ }
mCompositedFrameInvalid = false;
} else if (aResult.Type() == MatchType::NOT_FOUND ||
aResult.Type() == MatchType::PENDING) {
@@ -94,6 +101,8 @@ AnimationState::UpdateStateInternal(LookupResult& aResult,
}
// Otherwise don't change the value of mCompositedFrameInvalid, it will be
// updated by RequestRefresh.
+
+ return ret;
}
void
@@ -372,8 +381,11 @@ FrameAnimator::RequestRefresh(AnimationState& aState,
DefaultSurfaceFlags(),
PlaybackType::eAnimated));
- aState.UpdateStateInternal(result, aAnimationFinished);
+ ret.mDirtyRect = aState.UpdateStateInternal(result, aAnimationFinished, mSize);
if (aState.IsDiscarded() || !result) {
+ if (!ret.mDirtyRect.IsEmpty()) {
+ ret.mFrameAdvanced = true;
+ }
return ret;
}
diff --git a/image/FrameAnimator.h b/image/FrameAnimator.h
index 44b5a52e7cac..bebfbe36b739 100644
--- a/image/FrameAnimator.h
+++ b/image/FrameAnimator.h
@@ -42,14 +42,16 @@ public:
/**
* Call this whenever a decode completes, a decode starts, or the image is
* discarded. It will update the internal state. Specifically mDiscarded,
- * mCompositedFrameInvalid, and mIsCurrentlyDecoded.
+ * mCompositedFrameInvalid, and mIsCurrentlyDecoded. Returns a rect to
+ * invalidate.
*/
- void UpdateState(bool aAnimationFinished,
- RasterImage *aImage,
- const gfx::IntSize& aSize);
+ const gfx::IntRect UpdateState(bool aAnimationFinished,
+ RasterImage *aImage,
+ const gfx::IntSize& aSize);
private:
- void UpdateStateInternal(LookupResult& aResult,
- bool aAnimationFinished);
+ const gfx::IntRect UpdateStateInternal(LookupResult& aResult,
+ bool aAnimationFinished,
+ const gfx::IntSize& aSize);
public:
/**
diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp
index b07c7a1c146b..f5d62d6259d1 100644
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -415,9 +415,16 @@ RasterImage::WillDrawOpaqueNow()
return false;
}
- if (mAnimationState && !gfxPrefs::ImageMemAnimatedDiscardable()) {
- // We never discard frames of animated images.
- return true;
+ if (mAnimationState) {
+ if (!gfxPrefs::ImageMemAnimatedDiscardable()) {
+ // We never discard frames of animated images.
+ return true;
+ } else {
+ if (mAnimationState->GetCompositedFrameInvalid()) {
+ // We're not going to draw anything at all.
+ return false;
+ }
+ }
}
// If we are not locked our decoded data could get discard at any time (ie
@@ -464,7 +471,9 @@ RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded)
if (aAnimatedFramesDiscarded && mAnimationState) {
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
- mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ gfx::IntRect rect =
+ mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ NotifyProgress(NoProgress, rect);
}
if (mProgressTracker) {
@@ -1077,7 +1086,9 @@ RasterImage::Discard()
SurfaceCache::RemoveImage(ImageKey(this));
if (mAnimationState) {
- mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ gfx::IntRect rect =
+ mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ NotifyProgress(NoProgress, rect);
}
// Notify that we discarded.
@@ -1250,6 +1261,11 @@ RasterImage::Decode(const IntSize& aSize,
task = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this),
mSourceBuffer, mSize,
decoderFlags, surfaceFlags);
+ // We may not be able to send an invalidation right here because of async
+ // notifications but that's not a problem because the first frame
+ // invalidation (when it comes) will invalidate for us. So we can ignore
+ // the return value of UpdateState. This also handles the invalidation
+ // from setting the composited frame as valid below.
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
// If the animation is finished we can draw right away because we just draw
// the final frame all the time from now on. See comment in
@@ -1714,7 +1730,10 @@ RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus,
// We've finished a full decode of all animation frames and our AnimationState
// has been notified about them all, so let it know not to expect anymore.
mAnimationState->NotifyDecodeComplete();
- mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ gfx::IntRect rect = mAnimationState->UpdateState(mAnimationFinished, this, mSize);
+ if (!rect.IsEmpty()) {
+ NotifyProgress(NoProgress, rect);
+ }
}
// Do some telemetry if this isn't a metadata decode.
diff --git a/image/test/mochitest/test_discardAnimatedImage.html b/image/test/mochitest/test_discardAnimatedImage.html
index ad5df04978dd..d4c25d850c05 100644
--- a/image/test/mochitest/test_discardAnimatedImage.html
+++ b/image/test/mochitest/test_discardAnimatedImage.html
@@ -129,23 +129,30 @@ function addCallbacks(anImage, arrayIndex) {
if (!gCountingFrameUpdates) {
return;
}
- gNumFrameUpdates[arrayIndex]++;
- var r = document.getElementById(gImgs[arrayIndex]).getBoundingClientRect();
- var snapshot = snapshotRect(window, r, "rgba(0,0,0,0)");
- if (gLastSnapShot[arrayIndex] != null) {
- if (snapshot.toDataURL() != gLastSnapShot[arrayIndex].toDataURL()) {
- gNumSnapShotChanges[arrayIndex]++;
+ // Do this off a setTimeout since nsImageLoadingContent uses a scriptblocker
+ // when it notifies us and calling drawWindow can call will paint observers
+ // which can dispatch a scrollport event, and events assert if dispatched
+ // when there is a scriptblocker.
+ setTimeout(function () {
+ gNumFrameUpdates[arrayIndex]++;
+
+ var r = document.getElementById(gImgs[arrayIndex]).getBoundingClientRect();
+ var snapshot = snapshotRect(window, r, "rgba(0,0,0,0)");
+ if (gLastSnapShot[arrayIndex] != null) {
+ if (snapshot.toDataURL() != gLastSnapShot[arrayIndex].toDataURL()) {
+ gNumSnapShotChanges[arrayIndex]++;
+ }
}
- }
- gLastSnapShot[arrayIndex] = snapshot;
+ gLastSnapShot[arrayIndex] = snapshot;
- if (gNumFrameUpdates[arrayIndex] >= kNumFrameUpdatesToExpect &&
- gNumSnapShotChanges[arrayIndex] >= kNumFrameUpdatesToExpect) {
- imgLoadingContent.removeObserver(scriptedObserver);
- }
- ok(true, "got frame update");
- checkIfFinished();
+ if (gNumFrameUpdates[arrayIndex] >= kNumFrameUpdatesToExpect &&
+ gNumSnapShotChanges[arrayIndex] >= kNumFrameUpdatesToExpect) {
+ imgLoadingContent.removeObserver(scriptedObserver);
+ }
+ ok(true, "got frame update");
+ checkIfFinished();
+ }, 0);
};
observer = SpecialPowers.wrapCallbackObject(observer);
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index 8b775f1ed00c..36181b04ce41 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -516,17 +516,22 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
// Non-standard (bug 1277801): Use ClassName as a fallback in the interim
if (!builtinTag) {
const char* className = GetObjectClassName(cx, obj);
+ // "[object Object]" is by far the most common case at this point,
+ // so we optimize it here.
+ if (strcmp(className, "Object") == 0) {
+ builtinTag = cx->names().objectObject;
+ } else {
+ StringBuffer sb(cx);
+ if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
+ !sb.append("]"))
+ {
+ return false;
+ }
- StringBuffer sb(cx);
- if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
- !sb.append("]"))
- {
- return false;
+ builtinTag = sb.finishAtom();
+ if (!builtinTag)
+ return false;
}
-
- builtinTag = sb.finishString();
- if (!builtinTag)
- return false;
}
args.rval().setString(builtinTag);
@@ -538,7 +543,7 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
if (!sb.append("[object ") || !sb.append(tag.toString()) || !sb.append("]"))
return false;
- RootedString str(cx, sb.finishString());
+ JSString* str = sb.finishAtom();
if (!str)
return false;
diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
index 46555c31e19c..2092a2e701bb 100644
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -1013,7 +1013,7 @@ BaselineScript::toggleTraceLoggerScripts(JSRuntime* runtime, JSScript* script, b
// Patch the logging script textId to be correct.
// When logging log the specific textId else the global Scripts textId.
- if (enable && !traceLoggerScriptEvent_.hasPayload())
+ if (enable && !traceLoggerScriptEvent_.hasTextId())
traceLoggerScriptEvent_ = TraceLoggerEvent(TraceLogger_Scripts, script);
AutoWritableJitCode awjc(method());
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index b0866b2b558c..12a7596d5306 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7976,13 +7976,13 @@ JitRuntime::generateTLEventVM(JSContext* cx, MacroAssembler& masm, const VMFunct
}
if (vmSpecificEventEnabled) {
TraceLoggerEvent event(f.name());
- if (!event.hasPayload())
+ if (!event.hasTextId())
return false;
if (enter)
- masm.tracelogStartId(loggerReg, event.payload()->textId(), /* force = */ true);
+ masm.tracelogStartId(loggerReg, event.textId(), /* force = */ true);
else
- masm.tracelogStopId(loggerReg, event.payload()->textId(), /* force = */ true);
+ masm.tracelogStopId(loggerReg, event.textId(), /* force = */ true);
}
masm.Pop(loggerReg);
@@ -9942,22 +9942,22 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
for (uint32_t i = 0; i < patchableTLEvents_.length(); i++) {
TraceLoggerEvent event(patchableTLEvents_[i].event);
- if (!event.hasPayload() || !ionScript->addTraceLoggerEvent(event)) {
+ if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event)) {
TLFailed = true;
break;
}
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLEvents_[i].offset),
- ImmPtr((void*) uintptr_t(event.payload()->textId())),
+ ImmPtr((void*) uintptr_t(event.textId())),
ImmPtr((void*)0));
}
if (!TLFailed && patchableTLScripts_.length() > 0) {
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
TraceLoggerEvent event(TraceLogger_Scripts, script);
- if (!event.hasPayload() || !ionScript->addTraceLoggerEvent(event))
+ if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event))
TLFailed = true;
if (!TLFailed) {
- uint32_t textId = event.payload()->textId();
+ uint32_t textId = event.textId();
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
ImmPtr((void*) uintptr_t(textId)),
diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h
index a0a374ea7eaf..41c118668680 100644
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -447,7 +447,7 @@ struct IonScript
return hasProfilingInstrumentation_;
}
MOZ_MUST_USE bool addTraceLoggerEvent(TraceLoggerEvent& event) {
- MOZ_ASSERT(event.hasPayload());
+ MOZ_ASSERT(event.hasTextId());
return traceLoggerEvents_.append(Move(event));
}
const uint8_t* snapshots() const {
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index 758ccb3276a1..8471175ff1a7 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -258,6 +258,7 @@
macro(objectFunction, objectFunction, "[object Function]") \
macro(objectNull, objectNull, "[object Null]") \
macro(objectNumber, objectNumber, "[object Number]") \
+ macro(objectObject, objectObject, "[object Object]") \
macro(objectRegExp, objectRegExp, "[object RegExp]") \
macro(objects, objects, "objects") \
macro(objectString, objectString, "[object String]") \
diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp
index 77cee0e09cc1..52f680c3acbe 100644
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -357,29 +357,6 @@ TraceLoggerThread::extractScriptDetails(uint32_t textId, const char** filename,
*colno_len = strlen(*colno);
}
-TraceLoggerEventPayload*
-TraceLoggerThreadState::getOrCreateEventPayload(TraceLoggerTextId textId)
-{
- LockGuard guard(lock);
-
- TextIdHashMap::AddPtr p = textIdPayloads.lookupForAdd(textId);
- if (p) {
- MOZ_ASSERT(p->value()->textId() == textId); // Sanity check.
- p->value()->use();
- return p->value();
- }
-
- TraceLoggerEventPayload* payload = js_new(textId, (char*)nullptr);
- if (!payload)
- return nullptr;
-
- if (!textIdPayloads.add(p, textId, payload))
- return nullptr;
-
- payload->use();
- return payload;
-}
-
TraceLoggerEventPayload*
TraceLoggerThreadState::getOrCreateEventPayload(const char* text)
{
@@ -423,20 +400,12 @@ TraceLoggerThreadState::getOrCreateEventPayload(const char* text)
}
TraceLoggerEventPayload*
-TraceLoggerThreadState::getOrCreateEventPayload(TraceLoggerTextId type, const char* filename,
+TraceLoggerThreadState::getOrCreateEventPayload(const char* filename,
size_t lineno, size_t colno, const void* ptr)
{
- MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
- type == TraceLogger_InlinedScripts || type == TraceLogger_Frontend);
-
if (!filename)
filename = "";
- // Only log scripts when enabled otherwise return the global Scripts textId,
- // which will get filtered out.
- if (!isTextIdEnabled(type))
- return getOrCreateEventPayload(type);
-
LockGuard guard(lock);
PointerHashMap::AddPtr p;
@@ -494,10 +463,9 @@ TraceLoggerThreadState::getOrCreateEventPayload(TraceLoggerTextId type, const ch
}
TraceLoggerEventPayload*
-TraceLoggerThreadState::getOrCreateEventPayload(TraceLoggerTextId type, JSScript* script)
+TraceLoggerThreadState::getOrCreateEventPayload(JSScript* script)
{
- return getOrCreateEventPayload(type, script->filename(), script->lineno(), script->column(),
- nullptr);
+ return getOrCreateEventPayload(script->filename(), script->lineno(), script->column(), nullptr);
}
void
@@ -533,7 +501,7 @@ TraceLoggerThread::startEvent(TraceLoggerTextId id) {
void
TraceLoggerThread::startEvent(const TraceLoggerEvent& event) {
- if (!event.hasPayload()) {
+ if (!event.hasTextId()) {
if (!enabled())
return;
startEvent(TraceLogger_Error);
@@ -542,7 +510,7 @@ TraceLoggerThread::startEvent(const TraceLoggerEvent& event) {
"this event. Disabling TraceLogger.");
return;
}
- startEvent(event.payload()->textId());
+ startEvent(event.textId());
}
void
@@ -576,11 +544,11 @@ TraceLoggerThread::stopEvent(TraceLoggerTextId id) {
void
TraceLoggerThread::stopEvent(const TraceLoggerEvent& event) {
- if (!event.hasPayload()) {
+ if (!event.hasTextId()) {
stopEvent(TraceLogger_Error);
return;
}
- stopEvent(event.payload()->textId());
+ stopEvent(event.textId());
}
void
@@ -1009,43 +977,60 @@ js::TraceLogDisableTextId(JSContext* cx, uint32_t textId)
traceLoggerState->disableTextId(cx, textId);
}
-TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId textId)
-{
- payload_ = traceLoggerState ? traceLoggerState->getOrCreateEventPayload(textId) : nullptr;
-}
-
TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId type, JSScript* script)
-{
- payload_ = traceLoggerState ? traceLoggerState->getOrCreateEventPayload(type, script) : nullptr;
-}
+ : TraceLoggerEvent(type, script->filename(), script->lineno(), script->column())
+{ }
TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId type, const char* filename, size_t line,
size_t column)
-
+ : payload_()
{
- payload_ = traceLoggerState
- ? traceLoggerState->getOrCreateEventPayload(type, filename, line, column, nullptr)
- : nullptr;
+ MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
+ type == TraceLogger_InlinedScripts || type == TraceLogger_Frontend);
+
+ if (!traceLoggerState)
+ return;
+
+ // Only log scripts when enabled, otherwise use the more generic type
+ // (which will get filtered out).
+ if (!traceLoggerState->isTextIdEnabled(type)) {
+ payload_.setTextId(type);
+ return;
+ }
+
+ payload_.setEventPayload(
+ traceLoggerState->getOrCreateEventPayload(filename, line, column, nullptr));
}
TraceLoggerEvent::TraceLoggerEvent(const char* text)
+ : payload_()
{
- payload_ = traceLoggerState ? traceLoggerState->getOrCreateEventPayload(text) : nullptr;
+ if (traceLoggerState)
+ payload_.setEventPayload(traceLoggerState->getOrCreateEventPayload(text));
}
TraceLoggerEvent::~TraceLoggerEvent()
{
- if (payload_)
- payload_->release();
+ if (hasExtPayload())
+ extPayload()->release();
+}
+
+uint32_t
+TraceLoggerEvent::textId() const
+{
+ MOZ_ASSERT(hasTextId());
+ if (hasExtPayload())
+ return extPayload()->textId();
+ return payload_.textId();
}
TraceLoggerEvent&
TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
{
- if (other.hasPayload())
- other.payload()->use();
- if (hasPayload())
- payload()->release();
+ if (other.hasExtPayload())
+ other.extPayload()->use();
+ if (hasExtPayload())
+ extPayload()->release();
payload_ = other.payload_;
@@ -1053,8 +1038,8 @@ TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
}
TraceLoggerEvent::TraceLoggerEvent(const TraceLoggerEvent& other)
+ : payload_(other.payload_)
{
- payload_ = other.payload_;
- if (hasPayload())
- payload()->use();
+ if (hasExtPayload())
+ extPayload()->use();
}
diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h
index 7d3388d92326..0b9c05391e9d 100644
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -80,12 +80,56 @@ class TraceLoggerThread;
* this payload, so it cannot get removed.
*/
class TraceLoggerEvent {
+#ifdef JS_TRACE_LOGGING
private:
- TraceLoggerEventPayload* payload_;
+ class EventPayloadOrTextId {
+
+ /**
+ * Payload can be a pointer to a TraceLoggerEventPayload* or a
+ * TraceLoggerTextId. The last bit decides how to read the payload.
+ *
+ * payload_ = [ | 0 ]
+ * ------------------------ = TraceLoggerEventPayload* (incl. last bit)
+ * payload_ = [ | 1 ]
+ * ------------------- = TraceLoggerTextId (excl. last bit)
+ */
+ uintptr_t payload_;
+
+ public:
+ EventPayloadOrTextId()
+ : payload_(0)
+ { }
+
+ bool isEventPayload() const {
+ return (payload_ & 1) == 0;
+ }
+ TraceLoggerEventPayload* eventPayload() const {
+ MOZ_ASSERT(isEventPayload());
+ return (TraceLoggerEventPayload*) payload_;
+ }
+ void setEventPayload(TraceLoggerEventPayload* payload) {
+ payload_ = (uintptr_t)payload;
+ MOZ_ASSERT((payload_ & 1) == 0);
+ }
+ bool isTextId() const {
+ return (payload_ & 1) == 1;
+ }
+ uint32_t textId() const {
+ MOZ_ASSERT(isTextId());
+ return payload_ >> 1;
+ }
+ void setTextId(TraceLoggerTextId textId) {
+ static_assert(TraceLogger_Last < (UINT32_MAX >> 1), "Too many predefined text ids.");
+ payload_ = (((uint32_t)textId) << 1) | 1;
+ }
+ };
+
+ EventPayloadOrTextId payload_;
public:
- TraceLoggerEvent() { payload_ = nullptr; };
-#ifdef JS_TRACE_LOGGING
+ TraceLoggerEvent()
+ : payload_()
+ {}
explicit TraceLoggerEvent(TraceLoggerTextId textId);
TraceLoggerEvent(TraceLoggerTextId type, JSScript* script);
TraceLoggerEvent(TraceLoggerTextId type, const char* filename, size_t line, size_t column);
@@ -93,7 +137,22 @@ class TraceLoggerEvent {
TraceLoggerEvent(const TraceLoggerEvent& event);
TraceLoggerEvent& operator=(const TraceLoggerEvent& other);
~TraceLoggerEvent();
+ uint32_t textId() const;
+ bool hasTextId() const {
+ return hasExtPayload() || payload_.isTextId();
+ }
+
+ private:
+ TraceLoggerEventPayload* extPayload() const {
+ MOZ_ASSERT(hasExtPayload());
+ return payload_.eventPayload();
+ }
+ bool hasExtPayload() const {
+ return payload_.isEventPayload() && !!payload_.eventPayload();
+ }
#else
+ public:
+ TraceLoggerEvent() {}
explicit TraceLoggerEvent(TraceLoggerTextId textId) {}
TraceLoggerEvent(TraceLoggerTextId type, JSScript* script) {}
TraceLoggerEvent(TraceLoggerTextId type, const char* filename, size_t line, size_t column) {}
@@ -101,15 +160,10 @@ class TraceLoggerEvent {
TraceLoggerEvent(const TraceLoggerEvent& event) {}
TraceLoggerEvent& operator=(const TraceLoggerEvent& other) { return *this; };
~TraceLoggerEvent() {}
+ uint32_t textId() const { return 0; }
+ bool hasTextId() const { return false; }
#endif
- TraceLoggerEventPayload* payload() const {
- MOZ_ASSERT(hasPayload());
- return payload_;
- }
- bool hasPayload() const {
- return !!payload_;
- }
};
#ifdef DEBUG
@@ -378,11 +432,10 @@ class TraceLoggerThreadState
// This can be used to give start and stop events. Calls to these functions should be
// limited if possible, because of the overhead.
// Note: it is not allowed to use them in logTimestamp.
- TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId textId);
TraceLoggerEventPayload* getOrCreateEventPayload(const char* text);
- TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId type, JSScript* script);
- TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId type, const char* filename,
- size_t lineno, size_t colno, const void* p);
+ TraceLoggerEventPayload* getOrCreateEventPayload(JSScript* script);
+ TraceLoggerEventPayload* getOrCreateEventPayload(const char* filename, size_t lineno,
+ size_t colno, const void* p);
#endif
};
diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp
index f0065d39ead4..a89e3dccb2a3 100644
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -1021,21 +1021,47 @@ nsSVGOuterSVGAnonChildFrame::GetType() const
}
bool
-nsSVGOuterSVGAnonChildFrame::HasChildrenOnlyTransform(gfx::Matrix *aTransform) const
+nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform,
+ Matrix* aFromParentTransform) const
{
- // We must claim our nsSVGOuterSVGFrame's children-only transforms as our own
- // so that the children we are used to wrap are transformed properly.
+ // Our elements 'transform' attribute is applied to our nsSVGOuterSVGFrame
+ // parent, and the element's children-only transforms are applied to us, the
+ // anonymous child frame. Since we are the child frame, we apply the
+ // children-only transforms as if they are our own transform.
- SVGSVGElement *content = static_cast(mContent);
+ SVGSVGElement* content = static_cast(mContent);
- bool hasTransform = content->HasChildrenOnlyTransform();
-
- if (hasTransform && aTransform) {
- // Outer-