merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-11-20 11:38:15 +01:00
Родитель 72dbf27b21 397b1a3520
Коммит 16d197f520
79 изменённых файлов: 1203 добавлений и 634 удалений

Просмотреть файл

@ -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)

Просмотреть файл

@ -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]);