зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
16d197f520
|
@ -76,7 +76,10 @@ function runTests1(aTab) {
|
|||
|
||||
gDevTools.unregisterTool(toolId1);
|
||||
|
||||
runTests2();
|
||||
// Wait for unregisterTool to select the next tool before calling runTests2,
|
||||
// otherwise we will receive the wrong select event when waiting for
|
||||
// unregisterTool to select the next tool in continueTests below.
|
||||
toolbox.once("select", runTests2);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -550,59 +550,6 @@ ConvertActorsToBlobs(IDBDatabase* aDatabase,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
nsIDOMEvent* aEvent = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aResultHelper);
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"DispatchSuccessEvent",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
nsRefPtr<IDBRequest> request = aResultHelper->Request();
|
||||
MOZ_ASSERT(request);
|
||||
request->AssertIsOnOwningThread();
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction = aResultHelper->Transaction();
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> successEvent;
|
||||
if (!aEvent) {
|
||||
successEvent = CreateGenericEvent(request,
|
||||
nsDependentString(kSuccessEventType),
|
||||
eDoesNotBubble,
|
||||
eNotCancelable);
|
||||
if (NS_WARN_IF(!successEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEvent = successEvent;
|
||||
}
|
||||
|
||||
request->SetResultCallback(aResultHelper);
|
||||
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT_IF(transaction, transaction->IsOpen());
|
||||
|
||||
bool dummy;
|
||||
nsresult rv = request->DispatchEvent(aEvent, &dummy);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(transaction,
|
||||
transaction->IsOpen() || transaction->IsAborted());
|
||||
|
||||
WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
|
||||
MOZ_ASSERT(internalEvent);
|
||||
|
||||
if (transaction &&
|
||||
transaction->IsOpen() &&
|
||||
internalEvent->mFlags.mExceptionHasBeenRisen) {
|
||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DispatchErrorEvent(IDBRequest* aRequest,
|
||||
nsresult aErrorCode,
|
||||
|
@ -662,6 +609,64 @@ DispatchErrorEvent(IDBRequest* aRequest,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
nsIDOMEvent* aEvent = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aResultHelper);
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"DispatchSuccessEvent",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
nsRefPtr<IDBRequest> request = aResultHelper->Request();
|
||||
MOZ_ASSERT(request);
|
||||
request->AssertIsOnOwningThread();
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction = aResultHelper->Transaction();
|
||||
|
||||
if (transaction && transaction->IsAborted()) {
|
||||
DispatchErrorEvent(request, transaction->AbortCode(), transaction);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> successEvent;
|
||||
if (!aEvent) {
|
||||
successEvent = CreateGenericEvent(request,
|
||||
nsDependentString(kSuccessEventType),
|
||||
eDoesNotBubble,
|
||||
eNotCancelable);
|
||||
if (NS_WARN_IF(!successEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEvent = successEvent;
|
||||
}
|
||||
|
||||
request->SetResultCallback(aResultHelper);
|
||||
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT_IF(transaction, transaction->IsOpen());
|
||||
|
||||
bool dummy;
|
||||
nsresult rv = request->DispatchEvent(aEvent, &dummy);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(transaction,
|
||||
transaction->IsOpen() || transaction->IsAborted());
|
||||
|
||||
WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
|
||||
MOZ_ASSERT(internalEvent);
|
||||
|
||||
if (transaction &&
|
||||
transaction->IsOpen() &&
|
||||
internalEvent->mFlags.mExceptionHasBeenRisen) {
|
||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -189,6 +189,13 @@ public:
|
|||
return NS_FAILED(mAbortCode);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AbortCode() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mAbortCode;
|
||||
}
|
||||
|
||||
void
|
||||
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
|
||||
|
||||
|
|
|
@ -1669,6 +1669,7 @@ MediaCache::NoteSeek(MediaCacheStream* aStream, int64_t aOldOffset)
|
|||
std::min<int64_t>((aOldOffset + BLOCK_SIZE - 1)/BLOCK_SIZE,
|
||||
aStream->mBlocks.Length());
|
||||
while (blockIndex < endIndex) {
|
||||
MOZ_ASSERT(endIndex > 0);
|
||||
int32_t cacheBlockIndex = aStream->mBlocks[endIndex - 1];
|
||||
if (cacheBlockIndex >= 0) {
|
||||
BlockOwner* bo = GetBlockOwner(cacheBlockIndex, aStream);
|
||||
|
|
|
@ -418,14 +418,10 @@ void
|
|||
MediaSource::DurationChange(double aOldDuration, double aNewDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("MediaSource(%p)::DurationChange(aNewDuration=%f)", this, aNewDuration);
|
||||
MSE_DEBUG("MediaSource(%p)::DurationChange(aOldDuration=%f, aNewDuration=%f)", this, aOldDuration, aNewDuration);
|
||||
|
||||
if (aNewDuration < aOldDuration) {
|
||||
ErrorResult rv;
|
||||
mSourceBuffers->Remove(aNewDuration, aOldDuration, rv);
|
||||
if (rv.Failed()) {
|
||||
return;
|
||||
}
|
||||
mSourceBuffers->RangeRemoval(aNewDuration, aOldDuration);
|
||||
}
|
||||
// TODO: If partial audio frames/text cues exist, clamp duration based on mSourceBuffers.
|
||||
}
|
||||
|
|
|
@ -188,10 +188,19 @@ SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
|||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
if (mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
|
||||
if (mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
|
||||
mMediaSource->SetReadyState(MediaSourceReadyState::Open);
|
||||
}
|
||||
RangeRemoval(aStart, aEnd);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::RangeRemoval(double aStart, double aEnd)
|
||||
{
|
||||
StartUpdating();
|
||||
/// TODO: Run coded frame removal algorithm.
|
||||
|
||||
|
|
|
@ -108,6 +108,9 @@ public:
|
|||
double GetBufferedStart();
|
||||
double GetBufferedEnd();
|
||||
|
||||
// Runs the range removal algorithm as defined by the MSE spec.
|
||||
void RangeRemoval(double aStart, double aEnd);
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
|
|
@ -108,15 +108,12 @@ SourceBufferList::AnyUpdating()
|
|||
}
|
||||
|
||||
void
|
||||
SourceBufferList::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
||||
SourceBufferList::RangeRemoval(double aStart, double aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("SourceBufferList(%p)::Remove(aStart=%f, aEnd=%f", this, aStart, aEnd);
|
||||
MSE_DEBUG("SourceBufferList(%p)::RangeRemoval(aStart=%f, aEnd=%f", this, aStart, aEnd);
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
|
||||
mSourceBuffers[i]->Remove(aStart, aEnd, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
mSourceBuffers[i]->RangeRemoval(aStart, aEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,8 @@ public:
|
|||
// Returns true if updating is true on any SourceBuffers in the list.
|
||||
bool AnyUpdating();
|
||||
|
||||
// Calls Remove(aStart, aEnd) on each SourceBuffer in the list. Aborts on
|
||||
// first error, with result returned in aRv.
|
||||
void Remove(double aStart, double aEnd, ErrorResult& aRv);
|
||||
// Runs the range removal steps from the MSE specification on each SourceBuffer.
|
||||
void RangeRemoval(double aStart, double aEnd);
|
||||
|
||||
// Mark all SourceBuffers input buffers as ended.
|
||||
void Ended();
|
||||
|
|
|
@ -9,6 +9,8 @@ support-files =
|
|||
[test_MediaSource_disabled.html]
|
||||
[test_BufferedSeek.html]
|
||||
[test_BufferingWait.html]
|
||||
[test_EndOfStream.html]
|
||||
skip-if = (toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187
|
||||
[test_FrameSelection.html]
|
||||
[test_HaveMetadataUnbufferedSeek.html]
|
||||
[test_LoadedMetadataFired.html]
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var updateCount = 0;
|
||||
|
||||
runWithMSE(function (ms, v) {
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
@ -19,7 +21,13 @@ runWithMSE(function (ms, v) {
|
|||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer));
|
||||
sb.addEventListener("updateend", function () {
|
||||
ms.endOfStream()
|
||||
updateCount++;
|
||||
/* Ensure that we endOfStream on the first update event only as endOfStream can
|
||||
raise more if the duration of the last buffered range and the intial duration
|
||||
differ. See bug 1065207 */
|
||||
if (updateCount == 1) {
|
||||
ms.endOfStream();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>MSE: endOfStream call after an appendBuffer</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
runWithMSE(function () {
|
||||
var ms = new MediaSource();
|
||||
|
||||
var v = document.createElement("video");
|
||||
v.src = URL.createObjectURL(ms);
|
||||
document.body.appendChild(v);
|
||||
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 88966));
|
||||
var count = 0;
|
||||
sb.addEventListener("updateend", function () {
|
||||
++count;
|
||||
if (count == 1) {
|
||||
setTimeout(function() {
|
||||
var fail = false;
|
||||
try {
|
||||
ms.endOfStream();
|
||||
} catch (e) {
|
||||
fail = true;
|
||||
}
|
||||
ok(!fail, "MediaSource.endOfStream succeeded");
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var updateCount = 0;
|
||||
|
||||
runWithMSE(function (ms, v) {
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
@ -34,13 +36,13 @@ runWithMSE(function (ms, v) {
|
|||
fetchWithXHR("seek_lowres.webm", function (arrayBuffer) {
|
||||
// Append initialization segment.
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438));
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
updateCount++;
|
||||
if (updateCount == 1) {
|
||||
// Append media segment covering range [2, 4].
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 51003));
|
||||
first = false;
|
||||
} else {
|
||||
}
|
||||
else if (updateCount == 2) {
|
||||
ms.endOfStream();
|
||||
target = targets.shift();
|
||||
v.currentTime = target.currentTime;
|
||||
|
|
|
@ -57,7 +57,12 @@ runWithMSE(function () {
|
|||
sb.addEventListener("update", function () {
|
||||
is(sb.updating, false, "SourceBuffer.updating is expected value in update event");
|
||||
updateCount++;
|
||||
ms.endOfStream();
|
||||
/* Ensure that we endOfStream on the first update event only as endOfStream can
|
||||
raise more if the duration of the last buffered range and the intial duration
|
||||
differ. See bug 1065207 */
|
||||
if (updateCount == 1) {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
|
||||
sb.addEventListener("updatestart", function () {
|
||||
|
@ -84,9 +89,10 @@ runWithMSE(function () {
|
|||
// XXX: Duration should be exactly 4.0, see bug 1065207.
|
||||
ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
|
||||
ok(Math.abs(v.currentTime - 4) <= 0.002, "Video has played to end");
|
||||
is(updateCount, 1, "update event received");
|
||||
is(updateendCount, 1, "updateend event received");
|
||||
is(updatestartCount, 1, "updatestart event received");
|
||||
// XXX: 2 update events can be received dueto duration differences, see bug 1065207.
|
||||
ok(updateCount == 1 || updateCount == 2, "update event received");
|
||||
ok(updateendCount == 1 || updateendCount == 2, "updateend event received");
|
||||
ok(updatestartCount == 1 || updatestartCount == 2, "updatestart event received");
|
||||
is(loadedmetadataCount, 1, "loadedmetadata event received");
|
||||
v.parentNode.removeChild(v);
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var updateCount = 0;
|
||||
|
||||
runWithMSE(function (ms, v) {
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
@ -19,7 +21,13 @@ runWithMSE(function (ms, v) {
|
|||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer));
|
||||
sb.addEventListener("updateend", function () {
|
||||
ms.endOfStream()
|
||||
updateCount++;
|
||||
/* Ensure that we endOfStream on the first update event only as endOfStream can
|
||||
raise more if the duration of the last buffered range and the intial duration
|
||||
differ. See bug 1065207 */
|
||||
if (updateCount == 1) {
|
||||
ms.endOfStream();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ runWithMSE(function (ms, v) {
|
|||
if (updateCount == 1) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 25223));
|
||||
}
|
||||
else {
|
||||
else if (updateCount == 2) {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -12,18 +12,20 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var updateCount = 0;
|
||||
|
||||
runWithMSE(function (ms, v) {
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
updateCount++;
|
||||
if (updateCount == 1) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
first = false;
|
||||
} else {
|
||||
}
|
||||
else if (updateCount == 2) {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -12,20 +12,22 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var updateCount = 0;
|
||||
|
||||
runWithMSE(function (ms, v) {
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
updateCount++;
|
||||
if (updateCount == 1) {
|
||||
window.setTimeout(function () {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
first = false;
|
||||
}, 1000);
|
||||
} else {
|
||||
}
|
||||
else if (updateCount == 2) {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -121,6 +121,15 @@ function PlayFragmented(test, elem, token)
|
|||
var curFragment = 0;
|
||||
|
||||
function addNextFragment() {
|
||||
/* We can get another updateevent as a result of calling ms.endOfStream() if
|
||||
the highest end time of our source buffers is different from that of the
|
||||
media source duration. Due to bug 1065207 this can happen because of
|
||||
inaccuracies in the frame duration calculations. Check if we are already
|
||||
"ended" and ignore the update event */
|
||||
if (ms.readyState == "ended") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (curFragment >= test.fragments.length) {
|
||||
Log(token, "addNextFragment() end of stream");
|
||||
ms.endOfStream();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PluginHelperQt.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QEventLoop>
|
||||
|
||||
static const int kMaxtimeToProcessEvents = 30;
|
||||
|
||||
bool
|
||||
PluginHelperQt::AnswerProcessSomeEvents()
|
||||
{
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef PluginHelperQt_h_
|
||||
#define PluginHelperQt_h_
|
||||
|
||||
class PluginHelperQt
|
||||
{
|
||||
public:
|
||||
static bool AnswerProcessSomeEvents();
|
||||
};
|
||||
|
||||
#endif // PluginHelperQt_h_
|
|
@ -5,10 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
// Must be included first to avoid conflicts.
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QEventLoop>
|
||||
#include "NestedLoopTimer.h"
|
||||
#include "PluginHelperQt.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
|
@ -1646,13 +1643,11 @@ PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsSca
|
|||
#endif // #if defined(XP_MACOSX)
|
||||
|
||||
#if defined(MOZ_WIDGET_QT)
|
||||
static const int kMaxtimeToProcessEvents = 30;
|
||||
bool
|
||||
PluginModuleParent::AnswerProcessSomeEvents()
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents);
|
||||
|
||||
PluginHelperQt::AnswerProcessSomeEvents();
|
||||
PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
|
||||
|
||||
return true;
|
||||
|
|
|
@ -70,8 +70,9 @@ if CONFIG['MOZ_ENABLE_QT']:
|
|||
GENERATED_SOURCES += [
|
||||
'moc_NestedLoopTimer.cpp',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'NestedLoopTimer.cpp',
|
||||
'PluginHelperQt.cpp',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
@ -1764,7 +1764,7 @@ public:
|
|||
// Note that we don't need to check mDispatchInputEvent here. We need
|
||||
// to check it only when the editor requests to dispatch the input event.
|
||||
|
||||
if (!mTarget->IsInDoc()) {
|
||||
if (!mTarget->IsInComposedDoc()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -850,6 +850,16 @@ DrawTargetD2D1::factory()
|
|||
return mFactory;
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::CleanupD2D()
|
||||
{
|
||||
if (mFactory) {
|
||||
RadialGradientEffectD2D1::Unregister(mFactory);
|
||||
mFactory->Release();
|
||||
mFactory = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::MarkChanged()
|
||||
{
|
||||
|
|
|
@ -609,6 +609,11 @@ Factory::SetDirect3D11Device(ID3D11Device *aDevice)
|
|||
{
|
||||
mD3D11Device = aDevice;
|
||||
|
||||
if (mD2D1Device) {
|
||||
mD2D1Device->Release();
|
||||
mD2D1Device = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ID2D1Factory1> factory = D2DFactory1();
|
||||
|
||||
RefPtr<IDXGIDevice> device;
|
||||
|
@ -656,7 +661,12 @@ Factory::GetD2DVRAMUsageSourceSurface()
|
|||
void
|
||||
Factory::D2DCleanup()
|
||||
{
|
||||
if (mD2D1Device) {
|
||||
mD2D1Device->Release();
|
||||
mD2D1Device = nullptr;
|
||||
}
|
||||
DrawTargetD2D::CleanupD2D();
|
||||
DrawTargetD2D1::CleanupD2D();
|
||||
}
|
||||
|
||||
#endif // XP_WIN
|
||||
|
|
|
@ -284,6 +284,12 @@ RadialGradientEffectD2D1::Register(ID2D1Factory1 *aFactory)
|
|||
return hr;
|
||||
}
|
||||
|
||||
void
|
||||
RadialGradientEffectD2D1::Unregister(ID2D1Factory1 *aFactory)
|
||||
{
|
||||
aFactory->UnregisterEffect(CLSID_RadialGradientEffect);
|
||||
}
|
||||
|
||||
HRESULT __stdcall
|
||||
RadialGradientEffectD2D1::CreateEffect(IUnknown **aEffectImpl)
|
||||
{
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDrawInfo);
|
||||
|
||||
static HRESULT Register(ID2D1Factory1* aFactory);
|
||||
static void Unregister(ID2D1Factory1* aFactory);
|
||||
static HRESULT __stdcall CreateEffect(IUnknown** aEffectImpl);
|
||||
|
||||
HRESULT SetStopCollection(IUnknown *aStopCollection);
|
||||
|
|
|
@ -89,17 +89,21 @@ if CONFIG['INTEL_ARCHITECTURE']:
|
|||
if CONFIG['_MSC_VER'] != '1400':
|
||||
SOURCES += [
|
||||
'BlurSSE2.cpp',
|
||||
'convolverSSE2.cpp',
|
||||
'FilterProcessingSSE2.cpp',
|
||||
'ImageScalingSSE2.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_SKIA']:
|
||||
SOURCES += [
|
||||
'convolverSSE2.cpp',
|
||||
]
|
||||
DEFINES['USE_SSE2'] = True
|
||||
# The file uses SSE2 intrinsics, so it needs special compile flags on some
|
||||
# compilers.
|
||||
SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
if CONFIG['MOZ_ENABLE_SKIA']:
|
||||
SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Blur.cpp',
|
||||
|
|
|
@ -402,19 +402,6 @@ APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
|
|||
return apzc;
|
||||
}
|
||||
|
||||
static EventRegions
|
||||
EventRegionsFor(const LayerMetricsWrapper& aLayer)
|
||||
{
|
||||
// This is a workaround for bug 1082594. We should be able to replace this
|
||||
// with just a call to aLayer.GetEventRegions() once that bug is fixed.
|
||||
if (aLayer.IsScrollInfoLayer()) {
|
||||
EventRegions regions(ParentLayerIntRect::ToUntyped(RoundedIn(aLayer.Metrics().mCompositionBounds)));
|
||||
regions.mDispatchToContentHitRegion = regions.mHitRegion;
|
||||
return regions;
|
||||
}
|
||||
return aLayer.GetEventRegions();
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
||||
const LayerMetricsWrapper& aLayer,
|
||||
|
@ -497,7 +484,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
|||
// region as we loop backwards through the children.
|
||||
nsIntRegion childRegion;
|
||||
if (gfxPrefs::LayoutEventRegionsEnabled()) {
|
||||
childRegion = EventRegionsFor(child).mHitRegion;
|
||||
childRegion = child.GetEventRegions().mHitRegion;
|
||||
} else {
|
||||
childRegion = child.GetVisibleRegion();
|
||||
}
|
||||
|
@ -531,7 +518,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
|||
// we count the children as obscuring the parent or not.
|
||||
|
||||
EventRegions unobscured;
|
||||
unobscured.Sub(EventRegionsFor(aLayer), obscured);
|
||||
unobscured.Sub(aLayer.GetEventRegions(), obscured);
|
||||
APZCTM_LOG("Picking up unobscured hit region %s from layer %p\n", Stringify(unobscured).c_str(), aLayer.GetLayer());
|
||||
|
||||
// Take the hit region of the |aLayer|'s subtree (which has already been
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <QWindow>
|
||||
#ifdef MOZ_X11
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#endif
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/platform_thread.h"
|
||||
|
||||
|
|
|
@ -52,23 +52,35 @@ class ChunkPool
|
|||
|
||||
size_t count() const { return count_; }
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline Chunk *get(JSRuntime *rt);
|
||||
Chunk *head() { MOZ_ASSERT(head_); return head_; }
|
||||
Chunk *pop();
|
||||
void push(Chunk *chunk);
|
||||
Chunk *remove(Chunk *chunk);
|
||||
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
inline void put(Chunk *chunk);
|
||||
#ifdef DEBUG
|
||||
bool contains(Chunk *chunk) const;
|
||||
bool verify() const;
|
||||
#endif
|
||||
|
||||
class Enum {
|
||||
// Pool mutation does not invalidate an Iter unless the mutation
|
||||
// is of the Chunk currently being visited by the Iter.
|
||||
class Iter {
|
||||
public:
|
||||
explicit Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.head_) {}
|
||||
bool empty() { return !*chunkp; }
|
||||
Chunk *front();
|
||||
inline void popFront();
|
||||
inline void removeAndPopFront();
|
||||
explicit Iter(ChunkPool &pool) : current_(pool.head_) {}
|
||||
bool done() const { return !current_; }
|
||||
void next();
|
||||
Chunk *get() const { return current_; }
|
||||
operator Chunk *() const { return get(); }
|
||||
Chunk *operator->() const { return get(); }
|
||||
private:
|
||||
ChunkPool &pool;
|
||||
Chunk **chunkp;
|
||||
Chunk *current_;
|
||||
};
|
||||
|
||||
private:
|
||||
// ChunkPool controls external resources with interdependencies on the
|
||||
// JSRuntime and related structs, so must not be copied.
|
||||
ChunkPool(const ChunkPool &) MOZ_DELETE;
|
||||
ChunkPool operator=(const ChunkPool &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// Performs extra allocation off the main thread so that when memory is
|
||||
|
@ -463,10 +475,11 @@ class GCRuntime
|
|||
inline void updateOnArenaFree(const ChunkInfo &info);
|
||||
|
||||
GCChunkSet::Range allChunks() { return chunkSet.all(); }
|
||||
Chunk **getAvailableChunkList();
|
||||
void moveChunkToFreePool(Chunk *chunk, const AutoLockGC &lock);
|
||||
bool hasChunk(Chunk *chunk) { return chunkSet.has(chunk); }
|
||||
ChunkPool &availableChunks(const AutoLockGC &lock) { return availableChunks_; }
|
||||
ChunkPool &emptyChunks(const AutoLockGC &lock) { return emptyChunks_; }
|
||||
const ChunkPool &availableChunks(const AutoLockGC &lock) const { return availableChunks_; }
|
||||
const ChunkPool &emptyChunks(const AutoLockGC &lock) const { return emptyChunks_; }
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
|
@ -629,8 +642,8 @@ class GCRuntime
|
|||
* During the GC when all arenas in a chunk become free, that chunk is
|
||||
* removed from the list and scheduled for release.
|
||||
*/
|
||||
js::gc::Chunk *availableChunkListHead;
|
||||
js::gc::ChunkPool emptyChunks_;
|
||||
ChunkPool availableChunks_;
|
||||
ChunkPool emptyChunks_;
|
||||
|
||||
js::RootedValueMap rootsHash;
|
||||
|
||||
|
|
|
@ -746,7 +746,7 @@ static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t) + sizeof(uint64_t),
|
|||
struct ChunkInfo
|
||||
{
|
||||
Chunk *next;
|
||||
Chunk **prevp;
|
||||
Chunk *prev;
|
||||
|
||||
/* Free arenas are linked together with aheader.next. */
|
||||
ArenaHeader *freeArenasHead;
|
||||
|
@ -945,10 +945,6 @@ struct Chunk
|
|||
return info.numArenasFree != 0;
|
||||
}
|
||||
|
||||
inline void addToAvailableList(JSRuntime *rt);
|
||||
inline void insertToAvailableList(Chunk **insertPoint);
|
||||
inline void removeFromAvailableList();
|
||||
|
||||
ArenaHeader *allocateArena(JSRuntime *rt, JS::Zone *zone, AllocKind kind,
|
||||
const AutoLockGC &lock);
|
||||
|
||||
|
@ -962,22 +958,6 @@ struct Chunk
|
|||
|
||||
void decommitAllArenas(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Assuming that the info.prevp points to the next field of the previous
|
||||
* chunk in a doubly-linked list, get that chunk.
|
||||
*/
|
||||
Chunk *getPrevious() {
|
||||
MOZ_ASSERT(info.prevp);
|
||||
return fromPointerToNext(info.prevp);
|
||||
}
|
||||
|
||||
/* Get the chunk from a pointer to its info.next field. */
|
||||
static Chunk *fromPointerToNext(Chunk **nextFieldPtr) {
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(nextFieldPtr);
|
||||
MOZ_ASSERT((addr & ChunkMask) == offsetof(Chunk, info.next));
|
||||
return reinterpret_cast<Chunk *>(addr - offsetof(Chunk, info.next));
|
||||
}
|
||||
|
||||
private:
|
||||
inline void init(JSRuntime *rt);
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// Random chosen test: js/src/jit-test/tests/ion/bug928423.js
|
||||
o = {
|
||||
a: 1,
|
||||
b: 1
|
||||
}
|
||||
print(1);
|
||||
for (var x = 0; x < 2; x++) {
|
||||
print(2);
|
||||
o["a1".substr(0, 1)]
|
||||
o["b1".substr(0, 1)]
|
||||
}
|
||||
print(3);
|
||||
// jsfunfuzz
|
||||
"a" + "b"
|
|
@ -6058,6 +6058,8 @@ bool CodeGenerator::visitSubstr(LSubstr *lir)
|
|||
Register length = ToRegister(lir->length());
|
||||
Register output = ToRegister(lir->output());
|
||||
Register temp = ToRegister(lir->temp());
|
||||
Register temp2 = ToRegister(lir->temp2());
|
||||
Register temp3 = ToRegister(lir->temp3());
|
||||
Address stringFlags(string, JSString::offsetOfFlags());
|
||||
|
||||
Label isLatin1, notInline, nonZero, isInlinedLatin1;
|
||||
|
@ -6102,9 +6104,10 @@ bool CodeGenerator::visitSubstr(LSubstr *lir)
|
|||
Address(output, JSString::offsetOfFlags()));
|
||||
masm.computeEffectiveAddress(stringStorage, temp);
|
||||
BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
|
||||
masm.computeEffectiveAddress(chars, begin);
|
||||
masm.computeEffectiveAddress(chars, temp2);
|
||||
masm.computeEffectiveAddress(outputStorage, temp);
|
||||
CopyStringChars(masm, temp, begin, length, string, sizeof(char16_t), sizeof(char16_t));
|
||||
CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char16_t), sizeof(char16_t));
|
||||
masm.load32(Address(output, JSString::offsetOfLength()), length);
|
||||
masm.store16(Imm32(0), Address(temp, 0));
|
||||
masm.jump(done);
|
||||
}
|
||||
|
@ -6112,11 +6115,12 @@ bool CodeGenerator::visitSubstr(LSubstr *lir)
|
|||
{
|
||||
masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS | JSString::LATIN1_CHARS_BIT),
|
||||
Address(output, JSString::offsetOfFlags()));
|
||||
masm.computeEffectiveAddress(stringStorage, temp);
|
||||
masm.computeEffectiveAddress(stringStorage, temp2);
|
||||
static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
|
||||
masm.addPtr(temp, begin);
|
||||
masm.addPtr(begin, temp2);
|
||||
masm.computeEffectiveAddress(outputStorage, temp);
|
||||
CopyStringChars(masm, temp, begin, length, string, sizeof(char), sizeof(char));
|
||||
CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char), sizeof(char));
|
||||
masm.load32(Address(output, JSString::offsetOfLength()), length);
|
||||
masm.store8(Imm32(0), Address(temp, 0));
|
||||
masm.jump(done);
|
||||
}
|
||||
|
|
|
@ -3450,18 +3450,20 @@ class LStringSplit : public LCallInstructionHelper<1, 2, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LSubstr : public LInstructionHelper<1, 3, 1>
|
||||
class LSubstr : public LInstructionHelper<1, 3, 3>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(Substr)
|
||||
|
||||
LSubstr(const LAllocation &string, const LAllocation &begin, const LAllocation &length,
|
||||
const LDefinition &temp)
|
||||
const LDefinition &temp, const LDefinition &temp2, const LDefinition &temp3)
|
||||
{
|
||||
setOperand(0, string);
|
||||
setOperand(1, begin);
|
||||
setOperand(2, length);
|
||||
setTemp(0, temp);
|
||||
setTemp(1, temp2);
|
||||
setTemp(2, temp3);
|
||||
}
|
||||
const LAllocation *string() {
|
||||
return getOperand(0);
|
||||
|
@ -3475,6 +3477,12 @@ class LSubstr : public LInstructionHelper<1, 3, 1>
|
|||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition *temp2() {
|
||||
return getTemp(1);
|
||||
}
|
||||
const LDefinition *temp3() {
|
||||
return getTemp(2);
|
||||
}
|
||||
const MStringSplit *mir() const {
|
||||
return mir_->toStringSplit();
|
||||
}
|
||||
|
|
|
@ -2184,10 +2184,15 @@ LIRGenerator::visitStringReplace(MStringReplace *ins)
|
|||
bool
|
||||
LIRGenerator::visitSubstr(MSubstr *ins)
|
||||
{
|
||||
LSubstr *lir = new (alloc()) LSubstr(useFixed(ins->string(), CallTempReg1),
|
||||
// The last temporary need to be a register that can handle 8bit moves, but
|
||||
// there is no way to signal that to register allocator, except to give a
|
||||
// fixed temporary that is able to do this.
|
||||
LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()),
|
||||
useRegister(ins->begin()),
|
||||
useRegister(ins->length()),
|
||||
temp());
|
||||
temp(),
|
||||
temp(),
|
||||
tempFixed(CallTempReg1));
|
||||
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ UNIFIED_SOURCES += [
|
|||
'testFuncCallback.cpp',
|
||||
'testFunctionProperties.cpp',
|
||||
'testGCAllocator.cpp',
|
||||
'testGCChunkPool.cpp',
|
||||
'testGCExactRooting.cpp',
|
||||
'testGCFinalizeCallback.cpp',
|
||||
'testGCHeapPostBarriers.cpp',
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "gc/GCRuntime.h"
|
||||
#include "gc/Heap.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
BEGIN_TEST(testGCChunkPool)
|
||||
{
|
||||
const int N = 10;
|
||||
js::gc::ChunkPool pool;
|
||||
|
||||
// Create.
|
||||
for (int i = 0; i < N; ++i) {
|
||||
js::gc::Chunk *chunk = js::gc::Chunk::allocate(rt);
|
||||
CHECK(chunk);
|
||||
pool.push(chunk);
|
||||
}
|
||||
MOZ_ASSERT(pool.verify());
|
||||
|
||||
// Iterate.
|
||||
uint32_t i = 0;
|
||||
for (js::gc::ChunkPool::Iter iter(pool); !iter.done(); iter.next(), ++i)
|
||||
CHECK(iter.get());
|
||||
CHECK(i == pool.count());
|
||||
MOZ_ASSERT(pool.verify());
|
||||
|
||||
// Push/Pop.
|
||||
for (int i = 0; i < N; ++i) {
|
||||
js::gc::Chunk *chunkA = pool.pop();
|
||||
js::gc::Chunk *chunkB = pool.pop();
|
||||
js::gc::Chunk *chunkC = pool.pop();
|
||||
pool.push(chunkA);
|
||||
pool.push(chunkB);
|
||||
pool.push(chunkC);
|
||||
}
|
||||
MOZ_ASSERT(pool.verify());
|
||||
|
||||
// Remove.
|
||||
js::gc::Chunk *chunk = nullptr;
|
||||
int offset = N / 2;
|
||||
for (js::gc::ChunkPool::Iter iter(pool); !iter.done(); iter.next(), --offset) {
|
||||
if (offset == 0) {
|
||||
chunk = pool.remove(iter.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(chunk);
|
||||
MOZ_ASSERT(!pool.contains(chunk));
|
||||
MOZ_ASSERT(pool.verify());
|
||||
pool.push(chunk);
|
||||
|
||||
// Destruct.
|
||||
js::AutoLockGC lock(rt);
|
||||
for (js::gc::ChunkPool::Iter iter(pool); !iter.done();) {
|
||||
js::gc::Chunk *chunk = iter.get();
|
||||
iter.next();
|
||||
pool.remove(chunk);
|
||||
js::gc::UnmapPages(chunk, js::gc::ChunkSize);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testGCChunkPool)
|
195
js/src/jsgc.cpp
195
js/src/jsgc.cpp
|
@ -663,53 +663,81 @@ FreeChunk(JSRuntime *rt, Chunk *p)
|
|||
UnmapPages(static_cast<void *>(p), ChunkSize);
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline Chunk *
|
||||
ChunkPool::get(JSRuntime *rt)
|
||||
Chunk *
|
||||
ChunkPool::pop()
|
||||
{
|
||||
Chunk *chunk = head_;
|
||||
if (!chunk) {
|
||||
MOZ_ASSERT(!count_);
|
||||
MOZ_ASSERT(bool(head_) == bool(count_));
|
||||
if (!count_)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(count_);
|
||||
head_ = chunk->info.next;
|
||||
--count_;
|
||||
return chunk;
|
||||
return remove(head_);
|
||||
}
|
||||
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
inline void
|
||||
ChunkPool::put(Chunk *chunk)
|
||||
void
|
||||
ChunkPool::push(Chunk *chunk)
|
||||
{
|
||||
MOZ_ASSERT(!chunk->info.next);
|
||||
MOZ_ASSERT(!chunk->info.prev);
|
||||
|
||||
chunk->info.age = 0;
|
||||
chunk->info.next = head_;
|
||||
if (head_)
|
||||
head_->info.prev = chunk;
|
||||
head_ = chunk;
|
||||
count_++;
|
||||
++count_;
|
||||
|
||||
MOZ_ASSERT(verify());
|
||||
}
|
||||
|
||||
inline Chunk *
|
||||
ChunkPool::Enum::front()
|
||||
Chunk *
|
||||
ChunkPool::remove(Chunk *chunk)
|
||||
{
|
||||
Chunk *chunk = *chunkp;
|
||||
MOZ_ASSERT_IF(chunk, pool.count() != 0);
|
||||
MOZ_ASSERT(count_ > 0);
|
||||
MOZ_ASSERT(contains(chunk));
|
||||
|
||||
if (head_ == chunk)
|
||||
head_ = chunk->info.next;
|
||||
if (chunk->info.prev)
|
||||
chunk->info.prev->info.next = chunk->info.next;
|
||||
if (chunk->info.next)
|
||||
chunk->info.next->info.prev = chunk->info.prev;
|
||||
chunk->info.next = chunk->info.prev = nullptr;
|
||||
--count_;
|
||||
|
||||
MOZ_ASSERT(verify());
|
||||
return chunk;
|
||||
}
|
||||
|
||||
inline void
|
||||
ChunkPool::Enum::popFront()
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
ChunkPool::contains(Chunk *chunk) const
|
||||
{
|
||||
MOZ_ASSERT(!empty());
|
||||
chunkp = &front()->info.next;
|
||||
verify();
|
||||
for (Chunk *cursor = head_; cursor; cursor = cursor->info.next) {
|
||||
if (cursor == chunk)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void
|
||||
ChunkPool::Enum::removeAndPopFront()
|
||||
bool
|
||||
ChunkPool::verify() const
|
||||
{
|
||||
MOZ_ASSERT(!empty());
|
||||
*chunkp = front()->info.next;
|
||||
--pool.count_;
|
||||
MOZ_ASSERT(bool(head_) == bool(count_));
|
||||
uint32_t count = 0;
|
||||
for (Chunk *cursor = head_; cursor; cursor = cursor->info.next, ++count) {
|
||||
MOZ_ASSERT_IF(cursor->info.prev, cursor->info.prev->info.next == cursor);
|
||||
MOZ_ASSERT_IF(cursor->info.next, cursor->info.next->info.prev == cursor);
|
||||
}
|
||||
MOZ_ASSERT(count_ == count);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ChunkPool::Iter::next()
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
current_ = current_->info.next;
|
||||
}
|
||||
|
||||
Chunk *
|
||||
|
@ -723,15 +751,17 @@ GCRuntime::expireEmptyChunkPool(bool shrinkBuffers, const AutoLockGC &lock)
|
|||
*/
|
||||
Chunk *freeList = nullptr;
|
||||
unsigned freeChunkCount = 0;
|
||||
for (ChunkPool::Enum e(emptyChunks(lock)); !e.empty(); ) {
|
||||
Chunk *chunk = e.front();
|
||||
for (ChunkPool::Iter iter(emptyChunks(lock)); !iter.done();) {
|
||||
Chunk *chunk = iter.get();
|
||||
iter.next();
|
||||
|
||||
MOZ_ASSERT(chunk->unused());
|
||||
MOZ_ASSERT(!chunkSet.has(chunk));
|
||||
if (freeChunkCount >= tunables.maxEmptyChunkCount() ||
|
||||
(freeChunkCount >= tunables.minEmptyChunkCount() &&
|
||||
(shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE)))
|
||||
{
|
||||
e.removeAndPopFront();
|
||||
emptyChunks(lock).remove(chunk);
|
||||
prepareToFreeChunk(chunk->info);
|
||||
chunk->info.next = freeList;
|
||||
freeList = chunk;
|
||||
|
@ -739,7 +769,6 @@ GCRuntime::expireEmptyChunkPool(bool shrinkBuffers, const AutoLockGC &lock)
|
|||
/* Keep the chunk but increase its age. */
|
||||
++freeChunkCount;
|
||||
++chunk->info.age;
|
||||
e.popFront();
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(emptyChunks(lock).count() <= tunables.maxEmptyChunkCount());
|
||||
|
@ -750,9 +779,10 @@ GCRuntime::expireEmptyChunkPool(bool shrinkBuffers, const AutoLockGC &lock)
|
|||
static void
|
||||
FreeChunkPool(JSRuntime *rt, ChunkPool &pool)
|
||||
{
|
||||
for (ChunkPool::Enum e(pool); !e.empty();) {
|
||||
Chunk *chunk = e.front();
|
||||
e.removeAndPopFront();
|
||||
for (ChunkPool::Iter iter(pool); !iter.done();) {
|
||||
Chunk *chunk = iter.get();
|
||||
iter.next();
|
||||
pool.remove(chunk);
|
||||
MOZ_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
FreeChunk(rt, chunk);
|
||||
}
|
||||
|
@ -787,7 +817,7 @@ Chunk::allocate(JSRuntime *rt)
|
|||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void
|
||||
void
|
||||
GCRuntime::releaseChunk(Chunk *chunk)
|
||||
{
|
||||
MOZ_ASSERT(chunk);
|
||||
|
@ -840,6 +870,8 @@ Chunk::init(JSRuntime *rt)
|
|||
|
||||
/* Initialize the chunk info. */
|
||||
info.age = 0;
|
||||
info.next = nullptr;
|
||||
info.prev = nullptr;
|
||||
info.trailer.storeBuffer = nullptr;
|
||||
info.trailer.location = ChunkLocationBitTenuredHeap;
|
||||
info.trailer.runtime = rt;
|
||||
|
@ -847,47 +879,6 @@ Chunk::init(JSRuntime *rt)
|
|||
/* The rest of info fields are initialized in pickChunk. */
|
||||
}
|
||||
|
||||
inline Chunk **
|
||||
GCRuntime::getAvailableChunkList()
|
||||
{
|
||||
return &availableChunkListHead;
|
||||
}
|
||||
|
||||
inline void
|
||||
Chunk::addToAvailableList(JSRuntime *rt)
|
||||
{
|
||||
insertToAvailableList(rt->gc.getAvailableChunkList());
|
||||
}
|
||||
|
||||
inline void
|
||||
Chunk::insertToAvailableList(Chunk **insertPoint)
|
||||
{
|
||||
MOZ_ASSERT(hasAvailableArenas());
|
||||
MOZ_ASSERT(!info.prevp);
|
||||
MOZ_ASSERT(!info.next);
|
||||
info.prevp = insertPoint;
|
||||
Chunk *insertBefore = *insertPoint;
|
||||
if (insertBefore) {
|
||||
MOZ_ASSERT(insertBefore->info.prevp == insertPoint);
|
||||
insertBefore->info.prevp = &info.next;
|
||||
}
|
||||
info.next = insertBefore;
|
||||
*insertPoint = this;
|
||||
}
|
||||
|
||||
inline void
|
||||
Chunk::removeFromAvailableList()
|
||||
{
|
||||
MOZ_ASSERT(info.prevp);
|
||||
*info.prevp = info.next;
|
||||
if (info.next) {
|
||||
MOZ_ASSERT(info.next->info.prevp == &info.next);
|
||||
info.next->info.prevp = info.prevp;
|
||||
}
|
||||
info.prevp = nullptr;
|
||||
info.next = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for and return the next decommitted Arena. Our goal is to keep
|
||||
* lastDecommittedArenaOffset "close" to a free arena. We do this by setting
|
||||
|
@ -955,7 +946,7 @@ Chunk::allocateArena(JSRuntime *rt, Zone *zone, AllocKind thingKind, const AutoL
|
|||
: fetchNextDecommittedArena();
|
||||
aheader->init(zone, thingKind);
|
||||
if (MOZ_UNLIKELY(!hasAvailableArenas()))
|
||||
removeFromAvailableList();
|
||||
rt->gc.availableChunks(lock).remove(this);
|
||||
return aheader;
|
||||
}
|
||||
|
||||
|
@ -1006,14 +997,14 @@ Chunk::releaseArena(JSRuntime *rt, ArenaHeader *aheader, const AutoLockGC &lock,
|
|||
}
|
||||
|
||||
if (info.numArenasFree == 1) {
|
||||
MOZ_ASSERT(!info.prevp);
|
||||
MOZ_ASSERT(!info.prev);
|
||||
MOZ_ASSERT(!info.next);
|
||||
addToAvailableList(rt);
|
||||
rt->gc.availableChunks(lock).push(this);
|
||||
} else if (!unused()) {
|
||||
MOZ_ASSERT(info.prevp);
|
||||
MOZ_ASSERT(rt->gc.availableChunks(lock).contains(this));
|
||||
} else {
|
||||
MOZ_ASSERT(unused());
|
||||
removeFromAvailableList();
|
||||
rt->gc.availableChunks(lock).remove(this);
|
||||
decommitAllArenas(rt);
|
||||
rt->gc.moveChunkToFreePool(this, lock);
|
||||
}
|
||||
|
@ -1025,7 +1016,7 @@ GCRuntime::moveChunkToFreePool(Chunk *chunk, const AutoLockGC &lock)
|
|||
MOZ_ASSERT(chunk->unused());
|
||||
MOZ_ASSERT(chunkSet.has(chunk));
|
||||
chunkSet.remove(chunk);
|
||||
emptyChunks(lock).put(chunk);
|
||||
emptyChunks(lock).push(chunk);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -1079,12 +1070,10 @@ Chunk *
|
|||
GCRuntime::pickChunk(const AutoLockGC &lock,
|
||||
AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
|
||||
{
|
||||
Chunk **listHeadp = getAvailableChunkList();
|
||||
Chunk *chunk = *listHeadp;
|
||||
if (chunk)
|
||||
return chunk;
|
||||
if (availableChunks(lock).count())
|
||||
return availableChunks(lock).head();
|
||||
|
||||
chunk = emptyChunks(lock).get(rt);
|
||||
Chunk *chunk = emptyChunks(lock).pop();
|
||||
if (!chunk) {
|
||||
chunk = Chunk::allocate(rt);
|
||||
if (!chunk)
|
||||
|
@ -1111,9 +1100,7 @@ GCRuntime::pickChunk(const AutoLockGC &lock,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
chunk->info.prevp = nullptr;
|
||||
chunk->info.next = nullptr;
|
||||
chunk->addToAvailableList(rt);
|
||||
availableChunks(lock).push(chunk);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
@ -1168,7 +1155,6 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
|||
stats(rt),
|
||||
marker(rt),
|
||||
usage(nullptr),
|
||||
availableChunkListHead(nullptr),
|
||||
maxMallocBytes(0),
|
||||
numArenasFreeCommitted(0),
|
||||
verifyPreData(nullptr),
|
||||
|
@ -1412,7 +1398,13 @@ GCRuntime::finish()
|
|||
|
||||
zones.clear();
|
||||
|
||||
availableChunkListHead = nullptr;
|
||||
for (ChunkPool::Iter iter(availableChunks_); !iter.done();) {
|
||||
Chunk *chunk = iter.get();
|
||||
iter.next();
|
||||
MOZ_ASSERT(chunkSet.has(chunk));
|
||||
availableChunks_.remove(chunk);
|
||||
}
|
||||
|
||||
if (chunkSet.initialized()) {
|
||||
for (GCChunkSet::Range r(chunkSet.all()); !r.empty(); r.popFront())
|
||||
releaseChunk(r.front());
|
||||
|
@ -3407,7 +3399,7 @@ void
|
|||
GCRuntime::decommitAllWithoutUnlocking(const AutoLockGC &lock)
|
||||
{
|
||||
MOZ_ASSERT(emptyChunks(lock).count() == 0);
|
||||
for (Chunk *chunk = *getAvailableChunkList(); chunk; chunk = chunk->info.next) {
|
||||
for (ChunkPool::Iter chunk(availableChunks(lock)); !chunk.done(); chunk.next()) {
|
||||
for (size_t i = 0; i < ArenasPerChunk; ++i) {
|
||||
if (chunk->decommittedArenas.get(i) || chunk->arenas[i].aheader.allocated())
|
||||
continue;
|
||||
|
@ -3418,21 +3410,23 @@ GCRuntime::decommitAllWithoutUnlocking(const AutoLockGC &lock)
|
|||
}
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(availableChunks(lock).verify());
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::decommitArenas(const AutoLockGC &lock)
|
||||
{
|
||||
// Verify that all entries in the empty chunks pool are decommitted.
|
||||
for (ChunkPool::Enum e(emptyChunks(lock)); !e.empty(); e.popFront())
|
||||
MOZ_ASSERT(e.front()->info.numArenasFreeCommitted == 0);
|
||||
for (ChunkPool::Iter chunk(emptyChunks(lock)); !chunk.done(); chunk.next())
|
||||
MOZ_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
|
||||
// Build a Vector of all current available Chunks. Since we release the
|
||||
// gc lock while doing the decommit syscall, it is dangerous to iterate
|
||||
// the available list directly, as concurrent operations can modify it.
|
||||
mozilla::Vector<Chunk *> toDecommit;
|
||||
for (Chunk *chunk = availableChunkListHead; chunk; chunk = chunk->info.next) {
|
||||
if (!toDecommit.append(chunk)) {
|
||||
MOZ_ASSERT(availableChunks(lock).verify());
|
||||
for (ChunkPool::Iter iter(availableChunks(lock)); !iter.done(); iter.next()) {
|
||||
if (!toDecommit.append(iter.get())) {
|
||||
// The OOM handler does a full, immediate decommit, so there is
|
||||
// nothing more to do here in any case.
|
||||
return onOutOfMallocMemory(lock);
|
||||
|
@ -3462,6 +3456,7 @@ GCRuntime::decommitArenas(const AutoLockGC &lock)
|
|||
return;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(availableChunks(lock).verify());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3654,7 +3649,7 @@ BackgroundAllocTask::run()
|
|||
if (!chunk)
|
||||
break;
|
||||
}
|
||||
chunkPool_.put(chunk);
|
||||
chunkPool_.push(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -369,12 +369,17 @@ class DebugScript
|
|||
*/
|
||||
uint32_t stepMode;
|
||||
|
||||
/* Number of breakpoint sites at opcodes in the script. */
|
||||
/*
|
||||
* Number of breakpoint sites at opcodes in the script. This is the number
|
||||
* of populated entries in DebugScript::breakpoints, below.
|
||||
*/
|
||||
uint32_t numSites;
|
||||
|
||||
/*
|
||||
* Array with all breakpoints installed at opcodes in the script, indexed
|
||||
* by the offset of the opcode into the script.
|
||||
* Breakpoints set in our script. For speed and simplicity, this array is
|
||||
* parallel to script->code(): the BreakpointSite for the opcode at
|
||||
* script->code()[offset] is debugScript->breakpoints[offset]. Naturally,
|
||||
* this array's true length is script->length().
|
||||
*/
|
||||
BreakpointSite *breakpoints[1];
|
||||
};
|
||||
|
|
|
@ -241,6 +241,7 @@ class Debugger::FrameRange
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/*** Breakpoints *********************************************************************************/
|
||||
|
||||
BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc)
|
||||
|
@ -343,6 +344,7 @@ Breakpoint::nextInSite()
|
|||
return (link == &site->breakpoints) ? nullptr : fromSiteLinks(link);
|
||||
}
|
||||
|
||||
|
||||
/*** Debugger hook dispatch **********************************************************************/
|
||||
|
||||
Debugger::Debugger(JSContext *cx, NativeObject *dbg)
|
||||
|
@ -2968,8 +2970,11 @@ Debugger::addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> global)
|
|||
}
|
||||
|
||||
/*
|
||||
* Each debugger-debuggee relation must be stored in up to three places.
|
||||
* JSCompartment::addDebuggee enables debug mode if needed.
|
||||
* For global to become this js::Debugger's debuggee:
|
||||
* - global must be in this->debuggees,
|
||||
* - this js::Debugger must be in global->getDebuggers(), and
|
||||
* - JSCompartment::isDebuggee()'s bit must be set.
|
||||
* All three indications must be kept consistent.
|
||||
*/
|
||||
AutoCompartment ac(cx, global);
|
||||
GlobalObject::DebuggerVector *v = GlobalObject::getOrCreateDebuggers(cx, global);
|
||||
|
@ -5814,6 +5819,7 @@ static const JSFunctionSpec DebuggerFrame_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
|
||||
/*** Debugger.Object *****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
@ -878,8 +878,7 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
|||
#ifdef DEBUG
|
||||
// reget frame from content since it may have been regenerated...
|
||||
if (changeData->mContent) {
|
||||
if (!nsAnimationManager::ContentOrAncestorHasAnimation(changeData->mContent) &&
|
||||
!nsTransitionManager::ContentOrAncestorHasTransition(changeData->mContent)) {
|
||||
if (!css::CommonAnimationManager::ContentOrAncestorHasAnimation(changeData->mContent)) {
|
||||
nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
DebugVerifyStyleTree(frame);
|
||||
|
|
|
@ -2890,6 +2890,12 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect& aRect)
|
||||
{
|
||||
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aRect);
|
||||
}
|
||||
|
||||
nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aCaretFrame)
|
||||
: nsDisplayItem(aBuilder, aCaretFrame)
|
||||
|
|
|
@ -2583,6 +2583,11 @@ public:
|
|||
// this layer. aFrame must have the same reference frame as mFrame.
|
||||
void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
|
||||
|
||||
// Indicate that an inactive scrollframe's scrollport should be added to the
|
||||
// dispatch-to-content region, to ensure that APZ lets content create a
|
||||
// displayport.
|
||||
void AddInactiveScrollPort(const nsRect& aRect);
|
||||
|
||||
const nsRegion& HitRegion() { return mHitRegion; }
|
||||
const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; }
|
||||
const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; }
|
||||
|
|
|
@ -2952,6 +2952,17 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
(!mIsRoot || aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext());
|
||||
}
|
||||
|
||||
if (aBuilder->IsPaintingToWindow() &&
|
||||
!mShouldBuildScrollableLayer &&
|
||||
shouldBuildLayer)
|
||||
{
|
||||
if (nsDisplayLayerEventRegions *eventRegions = aBuilder->GetLayerEventRegions()) {
|
||||
// Make sure that APZ will dispatch events back to content so we can
|
||||
// create a displayport for this frame.
|
||||
eventRegions->AddInactiveScrollPort(mScrollPort + aBuilder->ToReferenceFrame(mOuter));
|
||||
}
|
||||
}
|
||||
|
||||
mScrollParentID = aBuilder->GetCurrentScrollParentId();
|
||||
|
||||
nsDisplayListCollection scrolledContent;
|
||||
|
|
|
@ -1447,6 +1447,39 @@ nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||
return LAYER_ACTIVE;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ nsRegion
|
||||
nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap)
|
||||
{
|
||||
*aSnap = true;
|
||||
bool animated;
|
||||
if (mImage && mImage->GetAnimated(&animated) == NS_OK && !animated &&
|
||||
mImage->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
|
||||
// OK, the entire region painted by the image is opaque. But what is that
|
||||
// region? It's the image's "dest rect" (the rect where a full copy of
|
||||
// the image is mapped), clipped to the container's content box (which is
|
||||
// what GetBounds() returns). So, we grab those rects and intersect them.
|
||||
const nsRect frameContentBox = GetBounds(aSnap);
|
||||
|
||||
// Note: To get the "dest rect", we have to provide the "constraint rect"
|
||||
// (which is the content-box, with the effects of fragmentation undone).
|
||||
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
|
||||
nsRect constraintRect(frameContentBox.TopLeft(),
|
||||
imageFrame->mComputedSize);
|
||||
constraintRect.y -= imageFrame->GetContinuationOffset();
|
||||
|
||||
const nsRect destRect =
|
||||
nsLayoutUtils::ComputeObjectDestRect(constraintRect,
|
||||
imageFrame->mIntrinsicSize,
|
||||
imageFrame->mIntrinsicRatio,
|
||||
imageFrame->StylePosition());
|
||||
|
||||
return nsRegion(destRect.Intersect(frameContentBox));
|
||||
}
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
|
|
@ -399,20 +399,14 @@ public:
|
|||
return imageFrame->GetInnerArea() + ToReferenceFrame();
|
||||
}
|
||||
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) MOZ_OVERRIDE
|
||||
{
|
||||
return GetBounds(aSnap);
|
||||
}
|
||||
|
||||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
||||
{
|
||||
*aSnap = true;
|
||||
bool animated;
|
||||
if (mImage && mImage->GetAnimated(&animated) == NS_OK && !animated && mImage->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
|
||||
return nsRegion(GetBounds(aSnap));
|
||||
}
|
||||
return nsRegion();
|
||||
}
|
||||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) MOZ_OVERRIDE;
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
.test {
|
||||
background: salmon;
|
||||
padding: 4px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
<embed class="test" src="blue-32x32.png">
|
||||
<object class="test" data="blue-32x32.png"></object>
|
||||
<video class="test" poster="blue-32x32.png"></video>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!--
|
||||
This testcase ensures that we paint the background around an opaque image,
|
||||
when the image is kept from filling the container via 'object-fit'. This
|
||||
is an interesting case because, by default, images fill their container,
|
||||
which means we can often optimize away the background completely. BUT, if
|
||||
"object-fit" prevents the image from filling its container, we can't
|
||||
optimize away the background; it need to be painted in the uncovered area.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
.test {
|
||||
background: salmon;
|
||||
object-fit: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
<embed class="test" src="blue-32x32.png">
|
||||
<object class="test" data="blue-32x32.png"></object>
|
||||
<video class="test" poster="blue-32x32.png"></video>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
.fakeBackground {
|
||||
background: salmon;
|
||||
height: 3in;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
img.test {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: block; /* Required for fragmentation */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="fakeBackground"></div>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
<div class="fakeBackground"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!--
|
||||
This testcase ensures that we paint the background around an opaque image,
|
||||
when the image is kept from filling the container via 'object-fit' (and
|
||||
the img element is fragmented). This is an interesting case because, by
|
||||
default, images fill their container, which means we can often optimize
|
||||
away the background completely. BUT, if "object-fit" prevents the image
|
||||
from filling its container, we can't optimize away the background; it need
|
||||
to be painted in the uncovered area.
|
||||
-->
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
img.test {
|
||||
background: salmon;
|
||||
object-fit: none;
|
||||
width: 32px;
|
||||
/* We make the height 6in larger than the image's intrinsic height,
|
||||
* which gives us the following happy results:
|
||||
* (1) the <img> will split over several 3in tall reftest-print cards
|
||||
* (so, we get to test fragmentation).
|
||||
* (2) the image pixels end up on the second fragment (not the first),
|
||||
* so we get to test image-data painting on later fragments.
|
||||
* (3) the reference case can easily match us using a simple img
|
||||
* with 3in-tall divs before & after it.
|
||||
*/
|
||||
height: calc(32px + 6in);
|
||||
display: block; /* Required for fragmentation */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
.test {
|
||||
background: salmon;
|
||||
padding-top: 5px;
|
||||
padding-left: 5px;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
<embed class="test" src="blue-32x32.png">
|
||||
<object class="test" data="blue-32x32.png"></object>
|
||||
<video class="test" poster="blue-32x32.png"></video>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!--
|
||||
This testcase ensures that we paint the background around an opaque image,
|
||||
when the image is offset from the container via 'object-position'. This is
|
||||
an interesting case because, by default, images fill their container,
|
||||
which means we can often optimize away the background completely. BUT, if
|
||||
"object-position" offsets the image from its container's content-box, we
|
||||
can't optimize away the background; it need to be painted in the uncovered
|
||||
area.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
.test {
|
||||
background: salmon;
|
||||
object-position: 5px 5px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
<embed class="test" src="blue-32x32.png">
|
||||
<object class="test" data="blue-32x32.png"></object>
|
||||
<video class="test" poster="blue-32x32.png"></video>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
img.test {
|
||||
background: salmon;
|
||||
padding-left: 10px;
|
||||
padding-top: 20px;
|
||||
width: 22px;
|
||||
height: calc(5in - 20px);
|
||||
display: block; /* Required for fragmentation */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!--
|
||||
This testcase ensures that we paint the background around an opaque image,
|
||||
when the image is offset from the container via 'object-position' (and
|
||||
the img element is fragmented). This is an interesting case because, by
|
||||
default, images fill their container, which means we can often optimize
|
||||
away the background completely. BUT, if "object-position" offsets the
|
||||
image from its container's content-box, we can't optimize away the
|
||||
background; it need to be painted in the uncovered area.
|
||||
-->
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
img.test {
|
||||
background: salmon;
|
||||
object-position: 10px 20px;
|
||||
width: 32px;
|
||||
height: 5in;
|
||||
display: block; /* Required for fragmentation */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="test" src="blue-32x32.png">
|
||||
</body>
|
||||
</html>
|
|
@ -11,6 +11,12 @@ random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1b.htm
|
|||
random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1c.html sync-image-switch-1-ref.html # bug 855050 for WinXP
|
||||
random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1d.html sync-image-switch-1-ref.html # bug 855050 for WinXP
|
||||
|
||||
# Tests for "object-fit" & "object-position"
|
||||
test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-1.html image-object-fit-with-background-1-ref.html
|
||||
test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-2.html image-object-fit-with-background-2-ref.html
|
||||
test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-1.html image-object-position-with-background-1-ref.html
|
||||
test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html
|
||||
|
||||
# Tests for image-orientation used with 'from-image' (note that all
|
||||
# image-orientation tests are fuzzy because the JPEG images do not perfectly
|
||||
# reproduce blocks of solid color, even at maximum quality):
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "nsDisplayList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "RestyleManager.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
|
@ -186,6 +187,50 @@ CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
CommonAnimationManager::RulesMatching(ElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
nsIStyleRule *rule =
|
||||
GetAnimationRule(aData->mElement,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
CommonAnimationManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
if (aData->mPseudoType != nsCSSPseudoElements::ePseudo_before &&
|
||||
aData->mPseudoType != nsCSSPseudoElements::ePseudo_after) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Do we really want to be the only thing keeping a
|
||||
// pseudo-element alive? I *think* the non-animation restyle should
|
||||
// handle that, but should add a test.
|
||||
nsIStyleRule *rule = GetAnimationRule(aData->mElement, aData->mPseudoType);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
CommonAnimationManager::RulesMatching(AnonBoxRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/* virtual */ void
|
||||
CommonAnimationManager::RulesMatching(XULTreeRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* virtual */ size_t
|
||||
CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
|
@ -257,6 +302,106 @@ CommonAnimationManager::ExtractComputedValueForTransition(
|
|||
return result;
|
||||
}
|
||||
|
||||
AnimationPlayerCollection*
|
||||
CommonAnimationManager::GetAnimationPlayers(dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded)
|
||||
{
|
||||
if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
||||
// Early return for the most common case.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIAtom *propName;
|
||||
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
propName = GetAnimationsAtom();
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
|
||||
propName = GetAnimationsBeforeAtom();
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
propName = GetAnimationsAfterAtom();
|
||||
} else {
|
||||
NS_ASSERTION(!aCreateIfNeeded,
|
||||
"should never try to create transitions for pseudo "
|
||||
"other than :before or :after");
|
||||
return nullptr;
|
||||
}
|
||||
AnimationPlayerCollection* collection =
|
||||
static_cast<AnimationPlayerCollection*>(aElement->GetProperty(propName));
|
||||
if (!collection && aCreateIfNeeded) {
|
||||
// FIXME: Consider arena-allocating?
|
||||
collection =
|
||||
new AnimationPlayerCollection(aElement, propName, this);
|
||||
nsresult rv =
|
||||
aElement->SetProperty(propName, collection,
|
||||
&AnimationPlayerCollection::PropertyDtor, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
delete collection;
|
||||
return nullptr;
|
||||
}
|
||||
if (propName == nsGkAtoms::animationsProperty ||
|
||||
propName == nsGkAtoms::transitionsProperty) {
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
AddElementCollection(collection);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
nsIStyleRule*
|
||||
CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_after,
|
||||
"forbidden pseudo type");
|
||||
|
||||
if (!mPresContext->IsDynamic()) {
|
||||
// For print or print preview, ignore animations.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnimationPlayerCollection* collection =
|
||||
GetAnimationPlayers(aElement, aPseudoType, false);
|
||||
if (!collection) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RestyleManager* restyleManager = mPresContext->RestyleManager();
|
||||
if (restyleManager->SkipAnimationRules()) {
|
||||
// During the non-animation part of processing restyles, we don't
|
||||
// add the animation rule.
|
||||
|
||||
if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) {
|
||||
collection->PostRestyleForAnimation(mPresContext);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Animations should already be refreshed, but transitions may not be.
|
||||
// Note that this is temporary, we would like both animations and transitions
|
||||
// to both be refreshed by this point.
|
||||
if (IsAnimationManager()) {
|
||||
NS_WARN_IF_FALSE(!collection->mNeedsRefreshes ||
|
||||
collection->mStyleRuleRefreshTime ==
|
||||
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
||||
"should already have refreshed style rule");
|
||||
} else {
|
||||
// FIXME: Remove this assignment. See bug 1061364.
|
||||
collection->mNeedsRefreshes = true;
|
||||
collection->EnsureStyleRuleFor(
|
||||
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
||||
EnsureStyleRule_IsNotThrottled);
|
||||
}
|
||||
|
||||
return collection->mStyleRule;
|
||||
}
|
||||
|
||||
/* static */ const CommonAnimationManager::LayerAnimationRecord
|
||||
CommonAnimationManager::sLayerAnimationInfo[] =
|
||||
{ { eCSSProperty_transform,
|
||||
|
|
|
@ -53,6 +53,12 @@ public:
|
|||
virtual nsRestyleHint
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#ifdef MOZ_XUL
|
||||
virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#endif
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
|
@ -68,10 +74,23 @@ public:
|
|||
// elements.
|
||||
void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
|
||||
|
||||
virtual AnimationPlayerCollection*
|
||||
AnimationPlayerCollection*
|
||||
GetAnimationPlayers(dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded) = 0;
|
||||
bool aCreateIfNeeded);
|
||||
|
||||
// Returns true if aContent or any of its ancestors has an animation
|
||||
// or transition.
|
||||
static bool ContentOrAncestorHasAnimation(nsIContent* aContent) {
|
||||
do {
|
||||
if (aContent->GetProperty(nsGkAtoms::animationsProperty) ||
|
||||
aContent->GetProperty(nsGkAtoms::transitionsProperty)) {
|
||||
return true;
|
||||
}
|
||||
} while ((aContent = aContent->GetParent()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notify this manager that one of its collections of animation players,
|
||||
// has been updated.
|
||||
|
@ -82,6 +101,9 @@ public:
|
|||
Cannot_Throttle
|
||||
};
|
||||
|
||||
nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
static bool ExtractComputedValueForTransition(
|
||||
nsCSSProperty aProperty,
|
||||
nsStyleContext* aStyleContext,
|
||||
|
@ -114,6 +136,14 @@ protected:
|
|||
// Check to see if we should stop or start observing the refresh driver
|
||||
void CheckNeedsRefresh();
|
||||
|
||||
virtual nsIAtom* GetAnimationsAtom() = 0;
|
||||
virtual nsIAtom* GetAnimationsBeforeAtom() = 0;
|
||||
virtual nsIAtom* GetAnimationsAfterAtom() = 0;
|
||||
|
||||
virtual bool IsAnimationManager() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// When this returns a value other than nullptr, it also,
|
||||
// as a side-effect, notifies the ActiveLayerTracker.
|
||||
static AnimationPlayerCollection*
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/StyleAnimationValue.h"
|
||||
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
#include "nsCSSRules.h"
|
||||
|
@ -198,97 +197,6 @@ nsAnimationManager::QueueEvents(AnimationPlayerCollection* aCollection,
|
|||
}
|
||||
}
|
||||
|
||||
AnimationPlayerCollection*
|
||||
nsAnimationManager::GetAnimationPlayers(dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded)
|
||||
{
|
||||
if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
||||
// Early return for the most common case.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIAtom *propName;
|
||||
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
propName = nsGkAtoms::animationsProperty;
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
|
||||
propName = nsGkAtoms::animationsOfBeforeProperty;
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
propName = nsGkAtoms::animationsOfAfterProperty;
|
||||
} else {
|
||||
NS_ASSERTION(!aCreateIfNeeded,
|
||||
"should never try to create transitions for pseudo "
|
||||
"other than :before or :after");
|
||||
return nullptr;
|
||||
}
|
||||
AnimationPlayerCollection* collection =
|
||||
static_cast<AnimationPlayerCollection*>(aElement->GetProperty(propName));
|
||||
if (!collection && aCreateIfNeeded) {
|
||||
// FIXME: Consider arena-allocating?
|
||||
collection =
|
||||
new AnimationPlayerCollection(aElement, propName, this);
|
||||
nsresult rv =
|
||||
aElement->SetProperty(propName, collection,
|
||||
&AnimationPlayerCollection::PropertyDtor, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
delete collection;
|
||||
return nullptr;
|
||||
}
|
||||
if (propName == nsGkAtoms::animationsProperty) {
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
AddElementCollection(collection);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsAnimationManager::RulesMatching(ElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
nsIStyleRule *rule =
|
||||
GetAnimationRule(aData->mElement,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsAnimationManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
if (aData->mPseudoType != nsCSSPseudoElements::ePseudo_before &&
|
||||
aData->mPseudoType != nsCSSPseudoElements::ePseudo_after) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Do we really want to be the only thing keeping a
|
||||
// pseudo-element alive? I *think* the non-animation restyle should
|
||||
// handle that, but should add a test.
|
||||
nsIStyleRule *rule = GetAnimationRule(aData->mElement, aData->mPseudoType);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsAnimationManager::RulesMatching(AnonBoxRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/* virtual */ void
|
||||
nsAnimationManager::RulesMatching(XULTreeRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* virtual */ size_t
|
||||
nsAnimationManager::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
|
@ -729,47 +637,6 @@ nsAnimationManager::BuildSegment(InfallibleTArray<AnimationPropertySegment>&
|
|||
return true;
|
||||
}
|
||||
|
||||
nsIStyleRule*
|
||||
nsAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_after,
|
||||
"forbidden pseudo type");
|
||||
|
||||
if (!mPresContext->IsDynamic()) {
|
||||
// For print or print preview, ignore animations.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnimationPlayerCollection* collection =
|
||||
GetAnimationPlayers(aElement, aPseudoType, false);
|
||||
if (!collection) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RestyleManager* restyleManager = mPresContext->RestyleManager();
|
||||
if (restyleManager->SkipAnimationRules()) {
|
||||
// During the non-animation part of processing restyles, we don't
|
||||
// add the animation rule.
|
||||
|
||||
if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) {
|
||||
collection->PostRestyleForAnimation(mPresContext);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(!collection->mNeedsRefreshes ||
|
||||
collection->mStyleRuleRefreshTime ==
|
||||
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
||||
"should already have refreshed style rule");
|
||||
|
||||
return collection->mStyleRule;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
|
|
|
@ -161,17 +161,6 @@ public:
|
|||
aContent, nsGkAtoms::animationsProperty, aProperty);
|
||||
}
|
||||
|
||||
// Returns true if aContent or any of its ancestors has an animation.
|
||||
static bool ContentOrAncestorHasAnimation(nsIContent* aContent) {
|
||||
do {
|
||||
if (aContent->GetProperty(nsGkAtoms::animationsProperty)) {
|
||||
return true;
|
||||
}
|
||||
} while ((aContent = aContent->GetParent()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateStyleAndEvents(mozilla::AnimationPlayerCollection* aEA,
|
||||
mozilla::TimeStamp aRefreshTime,
|
||||
mozilla::EnsureStyleRuleFlags aFlags);
|
||||
|
@ -179,12 +168,6 @@ public:
|
|||
mozilla::EventArray &aEventsToDispatch);
|
||||
|
||||
// nsIStyleRuleProcessor (parts)
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#ifdef MOZ_XUL
|
||||
virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#endif
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
|
@ -223,12 +206,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual mozilla::AnimationPlayerCollection*
|
||||
GetAnimationPlayers(mozilla::dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded) MOZ_OVERRIDE;
|
||||
nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
protected:
|
||||
virtual nsIAtom* GetAnimationsAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::animationsProperty;
|
||||
}
|
||||
virtual nsIAtom* GetAnimationsBeforeAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::animationsOfBeforeProperty;
|
||||
}
|
||||
virtual nsIAtom* GetAnimationsAfterAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::animationsOfAfterProperty;
|
||||
}
|
||||
virtual bool IsAnimationManager() MOZ_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void BuildAnimations(nsStyleContext* aStyleContext,
|
||||
|
|
|
@ -1450,8 +1450,11 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
|
|||
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_before ||
|
||||
aPseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
PresContext()->TransitionManager()->
|
||||
WalkTransitionRule(aElement, aPseudoType, &ruleWalker);
|
||||
nsIStyleRule* rule = PresContext()->TransitionManager()->
|
||||
GetAnimationRule(aElement, aPseudoType);
|
||||
if (rule) {
|
||||
ruleWalker.ForwardOnPossiblyCSSRule(rule);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -436,7 +436,7 @@ nsTransitionManager::ConsiderStartingTransition(
|
|||
"Should have one animation property segment for a transition");
|
||||
if (haveCurrentTransition && haveValues &&
|
||||
oldPT->Properties()[0].mSegments[0].mToValue == endValue) {
|
||||
// WalkTransitionRule already called RestyleForAnimation.
|
||||
// GetAnimationRule already called RestyleForAnimation.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -460,7 +460,7 @@ nsTransitionManager::ConsiderStartingTransition(
|
|||
// |aElementTransitions| is now a dangling pointer!
|
||||
aElementTransitions = nullptr;
|
||||
}
|
||||
// WalkTransitionRule already called RestyleForAnimation.
|
||||
// GetAnimationRule already called RestyleForAnimation.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -579,133 +579,10 @@ nsTransitionManager::ConsiderStartingTransition(
|
|||
aWhichStarted->AddProperty(aProperty);
|
||||
}
|
||||
|
||||
AnimationPlayerCollection*
|
||||
nsTransitionManager::GetAnimationPlayers(
|
||||
dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded)
|
||||
{
|
||||
if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
||||
// Early return for the most common case.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIAtom *propName;
|
||||
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
propName = nsGkAtoms::transitionsProperty;
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
|
||||
propName = nsGkAtoms::transitionsOfBeforeProperty;
|
||||
} else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
propName = nsGkAtoms::transitionsOfAfterProperty;
|
||||
} else {
|
||||
NS_ASSERTION(!aCreateIfNeeded,
|
||||
"should never try to create transitions for pseudo "
|
||||
"other than :before or :after");
|
||||
return nullptr;
|
||||
}
|
||||
AnimationPlayerCollection* collection =
|
||||
static_cast<AnimationPlayerCollection*>(aElement->GetProperty(propName));
|
||||
if (!collection && aCreateIfNeeded) {
|
||||
// FIXME: Consider arena-allocating?
|
||||
collection = new AnimationPlayerCollection(aElement, propName, this);
|
||||
nsresult rv =
|
||||
aElement->SetProperty(propName, collection,
|
||||
&AnimationPlayerCollection::PropertyDtor, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
delete collection;
|
||||
return nullptr;
|
||||
}
|
||||
if (propName == nsGkAtoms::transitionsProperty) {
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
AddElementCollection(collection);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
/*
|
||||
* nsIStyleRuleProcessor implementation
|
||||
*/
|
||||
|
||||
void
|
||||
nsTransitionManager::WalkTransitionRule(dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
nsRuleWalker* aRuleWalker)
|
||||
{
|
||||
AnimationPlayerCollection* collection =
|
||||
GetAnimationPlayers(aElement, aPseudoType, false);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPresContext->IsDynamic()) {
|
||||
// For print or print preview, ignore animations.
|
||||
return;
|
||||
}
|
||||
|
||||
RestyleManager* restyleManager = mPresContext->RestyleManager();
|
||||
if (restyleManager->SkipAnimationRules()) {
|
||||
// If we're processing a normal style change rather than one from
|
||||
// animation, don't add the transition rule. This allows us to
|
||||
// compute the new style value rather than having the transition
|
||||
// override it, so that we can start transitioning differently.
|
||||
|
||||
if (restyleManager->PostAnimationRestyles()) {
|
||||
// We need to immediately restyle with animation
|
||||
// after doing this.
|
||||
collection->PostRestyleForAnimation(mPresContext);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
collection->mNeedsRefreshes = true;
|
||||
collection->EnsureStyleRuleFor(
|
||||
mPresContext->RefreshDriver()->MostRecentRefresh(),
|
||||
EnsureStyleRule_IsNotThrottled);
|
||||
|
||||
if (collection->mStyleRule) {
|
||||
aRuleWalker->Forward(collection->mStyleRule);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsTransitionManager::RulesMatching(ElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
WalkTransitionRule(aData->mElement,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement,
|
||||
aData->mRuleWalker);
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsTransitionManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aData->mPresContext == mPresContext,
|
||||
"pres context mismatch");
|
||||
|
||||
// Note: If we're the only thing keeping a pseudo-element frame alive
|
||||
// (per ProbePseudoStyleContext), we still want to keep it alive, so
|
||||
// this is ok.
|
||||
WalkTransitionRule(aData->mElement, aData->mPseudoType,
|
||||
aData->mRuleWalker);
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsTransitionManager::RulesMatching(AnonBoxRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/* virtual */ void
|
||||
nsTransitionManager::RulesMatching(XULTreeRuleProcessorData* aData)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* virtual */ size_t
|
||||
nsTransitionManager::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
|
|
|
@ -99,23 +99,6 @@ public:
|
|||
|
||||
typedef mozilla::AnimationPlayerCollection AnimationPlayerCollection;
|
||||
|
||||
static AnimationPlayerCollection*
|
||||
GetTransitions(nsIContent* aContent) {
|
||||
return static_cast<AnimationPlayerCollection*>
|
||||
(aContent->GetProperty(nsGkAtoms::transitionsProperty));
|
||||
}
|
||||
|
||||
// Returns true if aContent or any of its ancestors has a transition.
|
||||
static bool ContentOrAncestorHasTransition(nsIContent* aContent) {
|
||||
do {
|
||||
if (GetTransitions(aContent)) {
|
||||
return true;
|
||||
}
|
||||
} while ((aContent = aContent->GetParent()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static AnimationPlayerCollection*
|
||||
GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
|
||||
{
|
||||
|
@ -148,13 +131,6 @@ public:
|
|||
mInAnimationOnlyStyleUpdate = aInAnimationOnlyUpdate;
|
||||
}
|
||||
|
||||
// nsIStyleRuleProcessor (parts)
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#ifdef MOZ_XUL
|
||||
virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
#endif
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
|
@ -165,13 +141,16 @@ public:
|
|||
|
||||
void FlushTransitions(FlushFlags aFlags);
|
||||
|
||||
virtual AnimationPlayerCollection*
|
||||
GetAnimationPlayers(mozilla::dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded) MOZ_OVERRIDE;
|
||||
void WalkTransitionRule(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
nsRuleWalker* aRuleWalker);
|
||||
protected:
|
||||
virtual nsIAtom* GetAnimationsAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::transitionsProperty;
|
||||
}
|
||||
virtual nsIAtom* GetAnimationsBeforeAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::transitionsOfBeforeProperty;
|
||||
}
|
||||
virtual nsIAtom* GetAnimationsAfterAtom() MOZ_OVERRIDE {
|
||||
return nsGkAtoms::transitionsOfAfterProperty;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
|
|
|
@ -464,6 +464,14 @@ status_t MPEG4Extractor::readMetaData() {
|
|||
status_t err;
|
||||
while (!mFirstTrack) {
|
||||
err = parseChunk(&offset, 0);
|
||||
// The parseChunk function returns UNKNOWN_ERROR to skip
|
||||
// some boxes we don't want to handle. Filter that error
|
||||
// code but return others so e.g. I/O errors propagate.
|
||||
if (err != OK && err != (status_t) UNKNOWN_ERROR) {
|
||||
ALOGW("Error %d parsing chuck at offset %lld looking for first track",
|
||||
err, (long long)offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mInitCheck == OK) {
|
||||
|
|
|
@ -42,18 +42,6 @@ static uint8_t kStunMessage[] = {
|
|||
};
|
||||
static size_t kStunMessageLen = sizeof(kStunMessage);
|
||||
|
||||
class DummySocket;
|
||||
|
||||
// Temporary whitelist for refcounted class dangerously exposing its destructor.
|
||||
// Filed bug 1028140 to address this class.
|
||||
namespace mozilla {
|
||||
template<>
|
||||
struct HasDangerousPublicDestructor<DummySocket>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
}
|
||||
|
||||
class DummySocket : public NrSocketBase {
|
||||
public:
|
||||
DummySocket()
|
||||
|
@ -207,6 +195,8 @@ class DummySocket : public NrSocketBase {
|
|||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DummySocket);
|
||||
|
||||
private:
|
||||
~DummySocket() {}
|
||||
|
||||
DISALLOW_COPY_ASSIGN(DummySocket);
|
||||
|
||||
size_t writable_; // Amount we allow someone to write.
|
||||
|
@ -230,7 +220,7 @@ class BufferedStunSocketTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
void SetUp() {
|
||||
ScopedDeletePtr<DummySocket> dummy(new DummySocket());
|
||||
nsRefPtr<DummySocket> dummy(new DummySocket());
|
||||
|
||||
int r = nr_socket_buffered_stun_create(
|
||||
dummy->get_nr_socket(),
|
||||
|
@ -251,7 +241,7 @@ class BufferedStunSocketTest : public ::testing::Test {
|
|||
nr_socket *socket() { return test_socket_; }
|
||||
|
||||
protected:
|
||||
DummySocket *dummy_;
|
||||
nsRefPtr<DummySocket> dummy_;
|
||||
nr_socket *test_socket_;
|
||||
nr_transport_addr remote_addr_;
|
||||
};
|
||||
|
|
|
@ -6,17 +6,51 @@ config = {
|
|||
"suite_definitions": {
|
||||
"mochitest": {
|
||||
"run_filename": "runtestsremote.py",
|
||||
"testsdir": "mochitest",
|
||||
"options": ["--autorun", "--close-when-done", "--dm_trans=sut",
|
||||
"--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
|
||||
"--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
|
||||
"--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
|
||||
"--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
|
||||
"--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
|
||||
"--quiet", "--log-raw=%(raw_log_file)s"
|
||||
"--quiet", "--log-raw=%(raw_log_file)s",
|
||||
"--total-chunks=16",
|
||||
"--run-only-tests=android23.json"
|
||||
],
|
||||
},
|
||||
"mochitest-gl": {
|
||||
"run_filename": "runtestsremote.py",
|
||||
"testsdir": "mochitest",
|
||||
"options": ["--autorun", "--close-when-done", "--dm_trans=sut",
|
||||
"--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
|
||||
"--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
|
||||
"--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
|
||||
"--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
|
||||
"--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
|
||||
"--quiet", "--log-raw=%(raw_log_file)s",
|
||||
"--total-chunks=2",
|
||||
"--test-manifest=gl.json"
|
||||
],
|
||||
},
|
||||
"robocop": {
|
||||
"run_filename": "runtestsremote.py",
|
||||
"testsdir": "mochitest",
|
||||
"options": ["--autorun", "--close-when-done", "--dm_trans=sut",
|
||||
"--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
|
||||
"--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
|
||||
"--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
|
||||
"--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
|
||||
"--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
|
||||
"--quiet", "--log-raw=%(raw_log_file)s",
|
||||
"--total-chunks=4",
|
||||
"--robocop-path=../..",
|
||||
"--robocop-ids=fennec_ids.txt",
|
||||
"--robocop=robocop.ini",
|
||||
],
|
||||
},
|
||||
"reftest": {
|
||||
"run_filename": "remotereftest.py",
|
||||
"testsdir": "reftest",
|
||||
"options": [ "--app=%(app)s", "--ignore-window-size",
|
||||
"--bootstrap",
|
||||
"--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
|
||||
|
@ -24,16 +58,49 @@ config = {
|
|||
"--devicePort=%(device_port)s", "--http-port=%(http_port)s",
|
||||
"--ssl-port=%(ssl_port)s", "--httpd-path", "reftest/components",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--total-chunks=16",
|
||||
"tests/layout/reftests/reftest.list",
|
||||
],
|
||||
},
|
||||
"crashtest": {
|
||||
"run_filename": "remotereftest.py",
|
||||
"testsdir": "reftest",
|
||||
"options": [ "--app=%(app)s", "--ignore-window-size",
|
||||
"--bootstrap",
|
||||
"--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
|
||||
"--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s",
|
||||
"--devicePort=%(device_port)s", "--http-port=%(http_port)s",
|
||||
"--ssl-port=%(ssl_port)s", "--httpd-path", "reftest/components",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--total-chunks=2",
|
||||
"tests/testing/crashtest/crashtests.list"
|
||||
],
|
||||
},
|
||||
"jsreftest": {
|
||||
"run_filename": "remotereftest.py",
|
||||
"testsdir": "reftest",
|
||||
"options": [ "--app=%(app)s", "--ignore-window-size",
|
||||
"--bootstrap",
|
||||
"--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
|
||||
"--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s",
|
||||
"--devicePort=%(device_port)s", "--http-port=%(http_port)s",
|
||||
"--ssl-port=%(ssl_port)s", "--httpd-path", "reftest/components",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"../jsreftest/tests/jstests.list",
|
||||
"--total-chunks=6",
|
||||
"--extra-profile-file=jsreftest/tests/user.js",
|
||||
],
|
||||
},
|
||||
"xpcshell": {
|
||||
"run_filename": "remotexpcshelltests.py",
|
||||
"testsdir": "xpcshell",
|
||||
"options": ["--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
|
||||
"--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s",
|
||||
"--apk=%(installer_path)s", "--no-logfiles",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--manifest=tests/xpcshell.ini",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--total-chunks=3",
|
||||
],
|
||||
},
|
||||
}, # end suite_definitions
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
from marionette_test import MarionetteTestCase
|
||||
from marionette import HTMLElement
|
||||
from by import By
|
||||
from errors import NoSuchElementException
|
||||
from errors import NoSuchElementException, InvalidSelectorException
|
||||
|
||||
|
||||
class TestElements(MarionetteTestCase):
|
||||
|
@ -154,3 +154,8 @@ class TestElements(MarionetteTestCase):
|
|||
fbody = self.marionette.find_element(By.TAG_NAME, 'body')
|
||||
abody = self.marionette.get_active_element()
|
||||
self.assertEqual(fbody, abody)
|
||||
|
||||
def test_throws_error_when_trying_to_use_invalid_selector_type(self):
|
||||
test_html = self.marionette.absolute_url("test.html")
|
||||
self.marionette.navigate(test_html)
|
||||
self.assertRaises(InvalidSelectorException, self.marionette.find_element, "Brie Search Type", "doesn't matter")
|
||||
|
|
|
@ -293,7 +293,7 @@ ElementManager.prototype = {
|
|||
let startNode = (values.element != undefined) ?
|
||||
this.getKnownElement(values.element, win) : win.document;
|
||||
if (this.elementStrategies.indexOf(values.using) < 0) {
|
||||
throw new ElementException("No such strategy.", 17, null);
|
||||
throw new ElementException("No such strategy.", 32, null);
|
||||
}
|
||||
let found = all ? this.findElements(values.using, values.value, win.document, startNode) :
|
||||
this.findElement(values.using, values.value, win.document, startNode);
|
||||
|
|
|
@ -17,9 +17,20 @@
|
|||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
function redirectToHarness()
|
||||
{
|
||||
redirect("chrome://mochikit/content/harness.xul");
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
// Wait for MozAfterPaint, since the listener in browser-test.js is not
|
||||
// added until then.
|
||||
window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
|
||||
window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
|
||||
setTimeout(redirectToHarness, 0);
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
[mediasource-remove.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Test remove transitioning readyState from \'ended\' to \'open\'.]
|
||||
expected: FAIL
|
||||
|
||||
[Test removing all appended data.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ const STRING_TYPE_NAME = "type.%ID%.name";
|
|||
const SEC_IN_A_DAY = 24 * 60 * 60;
|
||||
|
||||
const EME_PREF_ENABLED = "media.eme.enabled";
|
||||
const NS_GRE_BIN_DIR = "GreBinD";
|
||||
const CLEARKEY_PLUGIN_ID = "gmp-clearkey";
|
||||
const CLEARKEY_VERSION = "0.1";
|
||||
|
||||
|
@ -283,7 +284,8 @@ let OpenH264Provider = {
|
|||
|
||||
if (Preferences.get(EME_PREF_ENABLED, false)) {
|
||||
try {
|
||||
gmpService.addPluginDirectory(OS.Path.join(OS.Constants.Path.libDir,
|
||||
let greBinDir = Services.dirsvc.get(NS_GRE_BIN_DIR, Ci.nsILocalFile);
|
||||
gmpService.addPluginDirectory(OS.Path.join(greBinDir.path,
|
||||
CLEARKEY_PLUGIN_ID,
|
||||
CLEARKEY_VERSION));
|
||||
} catch (e) {
|
||||
|
|
|
@ -84,6 +84,9 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|||
'android/nsMIMEInfoAndroid.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
|
||||
SOURCES += [
|
||||
'unix/nsMIMEInfoQt.cpp',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'unix/nsGNOMERegistry.cpp',
|
||||
'unix/nsMIMEInfoUnix.cpp',
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#endif
|
||||
|
||||
#include "nsMIMEInfoQt.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoQt::LoadUriInternal(nsIURI * aURI)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
nsAutoCString spec;
|
||||
aURI->GetAsciiSpec(spec);
|
||||
if (QDesktopServices::openUrl(QUrl(spec.get()))) {
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsMIMEInfoQt_h_
|
||||
#define nsMIMEInfoQt_h_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
class nsMIMEInfoQt
|
||||
{
|
||||
public:
|
||||
static nsresult LoadUriInternal(nsIURI * aURI);
|
||||
};
|
||||
|
||||
#endif // nsMIMEInfoQt_h_
|
|
@ -5,9 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
#if (MOZ_ENABLE_CONTENTACTION)
|
||||
#include <contentaction/contentaction.h>
|
||||
#include "nsContentHandlerApp.h"
|
||||
|
@ -24,6 +21,9 @@
|
|||
#ifdef MOZ_ENABLE_DBUS
|
||||
#include "nsDBusHandlerApp.h"
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include "nsMIMEInfoQt.h"
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoUnix::LoadUriInternal(nsIURI * aURI)
|
||||
|
@ -32,11 +32,7 @@ nsMIMEInfoUnix::LoadUriInternal(nsIURI * aURI)
|
|||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
if (NS_FAILED(rv)) {
|
||||
nsAutoCString spec;
|
||||
aURI->GetAsciiSpec(spec);
|
||||
if (QDesktopServices::openUrl(QUrl(spec.get()))) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
rv = nsMIMEInfoQt::LoadUriInternal(aURI);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ LOCAL_INCLUDES += [
|
|||
|
||||
if CONFIG['MOZ_X11']:
|
||||
LOCAL_INCLUDES += [
|
||||
'../shared/x11',
|
||||
'../x11',
|
||||
]
|
||||
|
||||
#DEFINES['DEBUG_WIDGETS'] = True
|
||||
|
|
|
@ -291,15 +291,9 @@ static const QPrinter::PageSize indexToQtPaperEnum[] =
|
|||
NS_IMETHODIMP
|
||||
nsPrintSettingsQt::GetPaperName(char16_t** aPaperName)
|
||||
{
|
||||
PR_STATIC_ASSERT(sizeof(indexToPaperName)/
|
||||
sizeof(char*) == QPrinter::NPageSize);
|
||||
PR_STATIC_ASSERT(sizeof(indexToQtPaperEnum)/
|
||||
sizeof(QPrinter::PageSize) == QPrinter::NPageSize);
|
||||
|
||||
QPrinter::PaperSize size = mQPrinter->paperSize();
|
||||
QString name(indexToPaperName[size]);
|
||||
*aPaperName = ToNewUnicode(nsDependentString
|
||||
((const char16_t*)name.constData()));
|
||||
*aPaperName = ToNewUnicode(nsDependentString((const char16_t*)name.constData()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -307,7 +301,7 @@ NS_IMETHODIMP
|
|||
nsPrintSettingsQt::SetPaperName(const char16_t* aPaperName)
|
||||
{
|
||||
QString ref((QChar*)aPaperName, NS_strlen(aPaperName));
|
||||
for (uint32_t i = 0; i < QPrinter::NPageSize; i++)
|
||||
for (uint32_t i = 0; i < sizeof(indexToPaperName)/sizeof(char*); i++)
|
||||
{
|
||||
if (ref == QString(indexToPaperName[i])) {
|
||||
mQPrinter->setPageSize(indexToQtPaperEnum[i]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче