From b5d6a6e431351d3a99bfc3ef4a2a88ef1ac06ada Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Mon, 14 Jul 2014 01:59:30 -0700 Subject: [PATCH 01/38] Bug 1037903: convert from frame's writing mode to block's writing mode in GetBEndMarginClone. r=jfkthame --- layout/generic/crashtests/1037903.html | 6 ++++++ layout/generic/crashtests/crashtests.list | 1 + layout/generic/nsBlockReflowState.cpp | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 layout/generic/crashtests/1037903.html diff --git a/layout/generic/crashtests/1037903.html b/layout/generic/crashtests/1037903.html new file mode 100644 index 000000000000..3905967ecf70 --- /dev/null +++ b/layout/generic/crashtests/1037903.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 98d816d82481..1199c54b32b1 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -535,3 +535,4 @@ asserts(1-2) load 1015563-1.html asserts(1-2) load 1015563-2.html load outline-on-frameset.xhtml pref(font.size.inflation.minTwips,200) load 1032450.html +load 1037903.html diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 60345ab399fb..f1d0d5597577 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -176,7 +176,9 @@ GetBEndMarginClone(nsIFrame* aFrame, if (aFrame->StyleBorder()->mBoxDecorationBreak == NS_STYLE_BOX_DECORATION_BREAK_CLONE) { nsCSSOffsetState os(aFrame, aRenderingContext, aContentArea.Width(aWritingMode)); - return os.ComputedLogicalMargin().BEnd(aWritingMode); + return os.ComputedLogicalMargin(). + ConvertTo(aWritingMode, + aFrame->GetWritingMode()).BEnd(aWritingMode); } return 0; } From b59461402ab3fb4f0ac8e297fba9088909c231b5 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 14 Jul 2014 10:05:17 +0100 Subject: [PATCH 02/38] Bug 941804 - Reduce chunk size to 256K for B2G r=terrence --- js/public/HeapAPI.h | 13 +++++++++++++ js/src/gc/Heap.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 402ae0f2c489..e16d9f5f93de 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -13,6 +13,10 @@ #include "js/Utility.h" +#ifdef MOZ_B2G +#define JS_GC_CHUNK_SIZE_SMALL +#endif + /* These values are private to the JS engine. */ namespace js { @@ -32,7 +36,11 @@ const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; +#ifdef JS_GC_CHUNK_SIZE_SMALL +const size_t ChunkShift = 18; +#else const size_t ChunkShift = 20; +#endif const size_t ChunkSize = size_t(1) << ChunkShift; const size_t ChunkMask = ChunkSize - 1; @@ -41,8 +49,13 @@ const size_t CellSize = size_t(1) << CellShift; const size_t CellMask = CellSize - 1; /* These are magic constants derived from actual offsets in gc/Heap.h. */ +#ifdef JS_GC_CHUNK_SIZE_SMALL +const size_t ChunkMarkBitmapOffset = 258104; +const size_t ChunkMarkBitmapBits = 31744; +#else const size_t ChunkMarkBitmapOffset = 1032352; const size_t ChunkMarkBitmapBits = 129024; +#endif const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t); diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index b6e664f0da6e..97d8469581b8 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -700,7 +700,12 @@ const size_t BytesPerArenaWithHeader = ArenaSize + ArenaBitmapBytes; const size_t ChunkDecommitBitmapBytes = ChunkSize / ArenaSize / JS_BITS_PER_BYTE; const size_t ChunkBytesAvailable = ChunkSize - sizeof(ChunkInfo) - ChunkDecommitBitmapBytes; const size_t ArenasPerChunk = ChunkBytesAvailable / BytesPerArenaWithHeader; + +#ifdef JS_GC_CHUNK_SIZE_SMALL +static_assert(ArenasPerChunk == 62, "Do not accidentally change our heap's density."); +#else static_assert(ArenasPerChunk == 252, "Do not accidentally change our heap's density."); +#endif /* A chunk bitmap contains enough mark bits for all the cells in a chunk. */ struct ChunkBitmap From 81b32d0f450cb93e7e468fc12627898b25cb5647 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 14 Jul 2014 10:05:17 +0100 Subject: [PATCH 03/38] Bug 999158 - Keep a spare chunk around to mitigate GGC OOM crashes on tenuring r=terrence --- js/src/gc/GCRuntime.h | 5 +---- js/src/jsgc.cpp | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index cbd001dc723b..c05f79fee585 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -55,9 +55,6 @@ class ChunkPool /* Must be called either during the GC or with the GC lock taken. */ inline void put(Chunk *chunk); - /* Must be called with the GC lock taken. */ - void expireAndFree(JSRuntime *rt, bool releaseAll); - class Enum { public: Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.emptyChunkListHead) {} @@ -358,7 +355,7 @@ class GCRuntime * Return the list of chunks that can be released outside the GC lock. * Must be called either during the GC or with the GC lock taken. */ - Chunk *expireChunkPool(bool releaseAll); + Chunk *expireChunkPool(bool shrinkBuffers, bool releaseAll); void expireAndFreeChunkPool(bool releaseAll); void freeChunkList(Chunk *chunkListHead); void prepareToFreeChunk(ChunkInfo &info); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 804b8a168ee8..ff1310e34095 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -239,10 +239,16 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */ static const int IGC_MARK_SLICE_MULTIPLIER = 2; -#if defined(ANDROID) || defined(MOZ_B2G) -static const int MAX_EMPTY_CHUNK_COUNT = 2; +#ifdef JSGC_GENERATIONAL +static const unsigned MIN_EMPTY_CHUNK_COUNT = 1; #else -static const int MAX_EMPTY_CHUNK_COUNT = 30; +static const unsigned MIN_EMPTY_CHUNK_COUNT = 0; +#endif + +#if defined(ANDROID) || defined(MOZ_B2G) +static const unsigned MAX_EMPTY_CHUNK_COUNT = 2; +#else +static const unsigned MAX_EMPTY_CHUNK_COUNT = 30; #endif const AllocKind gc::slotsToThingKind[] = { @@ -712,7 +718,7 @@ ChunkPool::Enum::removeAndPopFront() /* Must be called either during the GC or with the GC lock taken. */ Chunk * -GCRuntime::expireChunkPool(bool releaseAll) +GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) { /* * Return old empty chunks to the system while preserving the order of @@ -721,14 +727,14 @@ GCRuntime::expireChunkPool(bool releaseAll) * and are more likely to reach the max age. */ Chunk *freeList = nullptr; - int freeChunkCount = 0; + unsigned freeChunkCount = 0; for (ChunkPool::Enum e(chunkPool); !e.empty(); ) { Chunk *chunk = e.front(); JS_ASSERT(chunk->unused()); JS_ASSERT(!chunkSet.has(chunk)); - JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); - if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE || - freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT) + if (releaseAll || freeChunkCount >= MAX_EMPTY_CHUNK_COUNT || + (freeChunkCount >= MIN_EMPTY_CHUNK_COUNT && + (shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE))) { e.removeAndPopFront(); prepareToFreeChunk(chunk->info); @@ -736,10 +742,12 @@ GCRuntime::expireChunkPool(bool releaseAll) freeList = chunk; } else { /* Keep the chunk but increase its age. */ + ++freeChunkCount; ++chunk->info.age; e.popFront(); } } + JS_ASSERT_IF(shrinkBuffers, chunkPool.getEmptyCount() <= MIN_EMPTY_CHUNK_COUNT); JS_ASSERT_IF(releaseAll, chunkPool.getEmptyCount() == 0); return freeList; } @@ -757,7 +765,7 @@ GCRuntime::freeChunkList(Chunk *chunkListHead) void GCRuntime::expireAndFreeChunkPool(bool releaseAll) { - freeChunkList(expireChunkPool(releaseAll)); + freeChunkList(expireChunkPool(true, releaseAll)); } /* static */ Chunk * @@ -1056,7 +1064,7 @@ GCRuntime::wantBackgroundAllocation() const * of them. */ return helperState.canBackgroundAllocate() && - chunkPool.getEmptyCount() == 0 && + chunkPool.getEmptyCount() < MIN_EMPTY_CHUNK_COUNT && chunkSet.count() >= 4; } @@ -2609,7 +2617,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink) rt->threadPool.pruneChunkCache(); #endif - if (Chunk *toFree = expireChunkPool(shouldShrink)) { + if (Chunk *toFree = expireChunkPool(shouldShrink, false)) { AutoUnlockGC unlock(rt); freeChunkList(toFree); } From 574c86f3cfd21a64af81aab752a72df9a270a703 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 14 Jul 2014 12:33:49 +0200 Subject: [PATCH 04/38] Backed out changeset 62725e1af7fc (bug 999158) for b2g test bustage on a CLOSED TREE --- js/src/gc/GCRuntime.h | 5 ++++- js/src/jsgc.cpp | 28 ++++++++++------------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index c05f79fee585..cbd001dc723b 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -55,6 +55,9 @@ class ChunkPool /* Must be called either during the GC or with the GC lock taken. */ inline void put(Chunk *chunk); + /* Must be called with the GC lock taken. */ + void expireAndFree(JSRuntime *rt, bool releaseAll); + class Enum { public: Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.emptyChunkListHead) {} @@ -355,7 +358,7 @@ class GCRuntime * Return the list of chunks that can be released outside the GC lock. * Must be called either during the GC or with the GC lock taken. */ - Chunk *expireChunkPool(bool shrinkBuffers, bool releaseAll); + Chunk *expireChunkPool(bool releaseAll); void expireAndFreeChunkPool(bool releaseAll); void freeChunkList(Chunk *chunkListHead); void prepareToFreeChunk(ChunkInfo &info); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index ff1310e34095..804b8a168ee8 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -239,16 +239,10 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */ static const int IGC_MARK_SLICE_MULTIPLIER = 2; -#ifdef JSGC_GENERATIONAL -static const unsigned MIN_EMPTY_CHUNK_COUNT = 1; -#else -static const unsigned MIN_EMPTY_CHUNK_COUNT = 0; -#endif - #if defined(ANDROID) || defined(MOZ_B2G) -static const unsigned MAX_EMPTY_CHUNK_COUNT = 2; +static const int MAX_EMPTY_CHUNK_COUNT = 2; #else -static const unsigned MAX_EMPTY_CHUNK_COUNT = 30; +static const int MAX_EMPTY_CHUNK_COUNT = 30; #endif const AllocKind gc::slotsToThingKind[] = { @@ -718,7 +712,7 @@ ChunkPool::Enum::removeAndPopFront() /* Must be called either during the GC or with the GC lock taken. */ Chunk * -GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) +GCRuntime::expireChunkPool(bool releaseAll) { /* * Return old empty chunks to the system while preserving the order of @@ -727,14 +721,14 @@ GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) * and are more likely to reach the max age. */ Chunk *freeList = nullptr; - unsigned freeChunkCount = 0; + int freeChunkCount = 0; for (ChunkPool::Enum e(chunkPool); !e.empty(); ) { Chunk *chunk = e.front(); JS_ASSERT(chunk->unused()); JS_ASSERT(!chunkSet.has(chunk)); - if (releaseAll || freeChunkCount >= MAX_EMPTY_CHUNK_COUNT || - (freeChunkCount >= MIN_EMPTY_CHUNK_COUNT && - (shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE))) + JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); + if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE || + freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT) { e.removeAndPopFront(); prepareToFreeChunk(chunk->info); @@ -742,12 +736,10 @@ GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) freeList = chunk; } else { /* Keep the chunk but increase its age. */ - ++freeChunkCount; ++chunk->info.age; e.popFront(); } } - JS_ASSERT_IF(shrinkBuffers, chunkPool.getEmptyCount() <= MIN_EMPTY_CHUNK_COUNT); JS_ASSERT_IF(releaseAll, chunkPool.getEmptyCount() == 0); return freeList; } @@ -765,7 +757,7 @@ GCRuntime::freeChunkList(Chunk *chunkListHead) void GCRuntime::expireAndFreeChunkPool(bool releaseAll) { - freeChunkList(expireChunkPool(true, releaseAll)); + freeChunkList(expireChunkPool(releaseAll)); } /* static */ Chunk * @@ -1064,7 +1056,7 @@ GCRuntime::wantBackgroundAllocation() const * of them. */ return helperState.canBackgroundAllocate() && - chunkPool.getEmptyCount() < MIN_EMPTY_CHUNK_COUNT && + chunkPool.getEmptyCount() == 0 && chunkSet.count() >= 4; } @@ -2617,7 +2609,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink) rt->threadPool.pruneChunkCache(); #endif - if (Chunk *toFree = expireChunkPool(shouldShrink, false)) { + if (Chunk *toFree = expireChunkPool(shouldShrink)) { AutoUnlockGC unlock(rt); freeChunkList(toFree); } From 783f4386db371a3af395e7a2c7bb8a85059fc88a Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 14 Jul 2014 12:34:33 +0200 Subject: [PATCH 05/38] Backed out changeset a1feed3cd303 (bug 941804) for b2g bustage on a CLOSED TREE --- js/public/HeapAPI.h | 13 ------------- js/src/gc/Heap.h | 5 ----- 2 files changed, 18 deletions(-) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index e16d9f5f93de..402ae0f2c489 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -13,10 +13,6 @@ #include "js/Utility.h" -#ifdef MOZ_B2G -#define JS_GC_CHUNK_SIZE_SMALL -#endif - /* These values are private to the JS engine. */ namespace js { @@ -36,11 +32,7 @@ const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; -#ifdef JS_GC_CHUNK_SIZE_SMALL -const size_t ChunkShift = 18; -#else const size_t ChunkShift = 20; -#endif const size_t ChunkSize = size_t(1) << ChunkShift; const size_t ChunkMask = ChunkSize - 1; @@ -49,13 +41,8 @@ const size_t CellSize = size_t(1) << CellShift; const size_t CellMask = CellSize - 1; /* These are magic constants derived from actual offsets in gc/Heap.h. */ -#ifdef JS_GC_CHUNK_SIZE_SMALL -const size_t ChunkMarkBitmapOffset = 258104; -const size_t ChunkMarkBitmapBits = 31744; -#else const size_t ChunkMarkBitmapOffset = 1032352; const size_t ChunkMarkBitmapBits = 129024; -#endif const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t); diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 97d8469581b8..b6e664f0da6e 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -700,12 +700,7 @@ const size_t BytesPerArenaWithHeader = ArenaSize + ArenaBitmapBytes; const size_t ChunkDecommitBitmapBytes = ChunkSize / ArenaSize / JS_BITS_PER_BYTE; const size_t ChunkBytesAvailable = ChunkSize - sizeof(ChunkInfo) - ChunkDecommitBitmapBytes; const size_t ArenasPerChunk = ChunkBytesAvailable / BytesPerArenaWithHeader; - -#ifdef JS_GC_CHUNK_SIZE_SMALL -static_assert(ArenasPerChunk == 62, "Do not accidentally change our heap's density."); -#else static_assert(ArenasPerChunk == 252, "Do not accidentally change our heap's density."); -#endif /* A chunk bitmap contains enough mark bits for all the cells in a chunk. */ struct ChunkBitmap From ca29747d5e9ee6aa20c23baec71b91c963ee8241 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 14 Jul 2014 13:45:34 +0100 Subject: [PATCH 06/38] Bug 999158 - Keep a spare chunk around to mitigate GGC OOM crashes on tenuring r=terrence --- js/src/gc/GCRuntime.h | 5 +---- js/src/jsgc.cpp | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index cbd001dc723b..c05f79fee585 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -55,9 +55,6 @@ class ChunkPool /* Must be called either during the GC or with the GC lock taken. */ inline void put(Chunk *chunk); - /* Must be called with the GC lock taken. */ - void expireAndFree(JSRuntime *rt, bool releaseAll); - class Enum { public: Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.emptyChunkListHead) {} @@ -358,7 +355,7 @@ class GCRuntime * Return the list of chunks that can be released outside the GC lock. * Must be called either during the GC or with the GC lock taken. */ - Chunk *expireChunkPool(bool releaseAll); + Chunk *expireChunkPool(bool shrinkBuffers, bool releaseAll); void expireAndFreeChunkPool(bool releaseAll); void freeChunkList(Chunk *chunkListHead); void prepareToFreeChunk(ChunkInfo &info); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 804b8a168ee8..ff1310e34095 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -239,10 +239,16 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */ static const int IGC_MARK_SLICE_MULTIPLIER = 2; -#if defined(ANDROID) || defined(MOZ_B2G) -static const int MAX_EMPTY_CHUNK_COUNT = 2; +#ifdef JSGC_GENERATIONAL +static const unsigned MIN_EMPTY_CHUNK_COUNT = 1; #else -static const int MAX_EMPTY_CHUNK_COUNT = 30; +static const unsigned MIN_EMPTY_CHUNK_COUNT = 0; +#endif + +#if defined(ANDROID) || defined(MOZ_B2G) +static const unsigned MAX_EMPTY_CHUNK_COUNT = 2; +#else +static const unsigned MAX_EMPTY_CHUNK_COUNT = 30; #endif const AllocKind gc::slotsToThingKind[] = { @@ -712,7 +718,7 @@ ChunkPool::Enum::removeAndPopFront() /* Must be called either during the GC or with the GC lock taken. */ Chunk * -GCRuntime::expireChunkPool(bool releaseAll) +GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) { /* * Return old empty chunks to the system while preserving the order of @@ -721,14 +727,14 @@ GCRuntime::expireChunkPool(bool releaseAll) * and are more likely to reach the max age. */ Chunk *freeList = nullptr; - int freeChunkCount = 0; + unsigned freeChunkCount = 0; for (ChunkPool::Enum e(chunkPool); !e.empty(); ) { Chunk *chunk = e.front(); JS_ASSERT(chunk->unused()); JS_ASSERT(!chunkSet.has(chunk)); - JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); - if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE || - freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT) + if (releaseAll || freeChunkCount >= MAX_EMPTY_CHUNK_COUNT || + (freeChunkCount >= MIN_EMPTY_CHUNK_COUNT && + (shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE))) { e.removeAndPopFront(); prepareToFreeChunk(chunk->info); @@ -736,10 +742,12 @@ GCRuntime::expireChunkPool(bool releaseAll) freeList = chunk; } else { /* Keep the chunk but increase its age. */ + ++freeChunkCount; ++chunk->info.age; e.popFront(); } } + JS_ASSERT_IF(shrinkBuffers, chunkPool.getEmptyCount() <= MIN_EMPTY_CHUNK_COUNT); JS_ASSERT_IF(releaseAll, chunkPool.getEmptyCount() == 0); return freeList; } @@ -757,7 +765,7 @@ GCRuntime::freeChunkList(Chunk *chunkListHead) void GCRuntime::expireAndFreeChunkPool(bool releaseAll) { - freeChunkList(expireChunkPool(releaseAll)); + freeChunkList(expireChunkPool(true, releaseAll)); } /* static */ Chunk * @@ -1056,7 +1064,7 @@ GCRuntime::wantBackgroundAllocation() const * of them. */ return helperState.canBackgroundAllocate() && - chunkPool.getEmptyCount() == 0 && + chunkPool.getEmptyCount() < MIN_EMPTY_CHUNK_COUNT && chunkSet.count() >= 4; } @@ -2609,7 +2617,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink) rt->threadPool.pruneChunkCache(); #endif - if (Chunk *toFree = expireChunkPool(shouldShrink)) { + if (Chunk *toFree = expireChunkPool(shouldShrink, false)) { AutoUnlockGC unlock(rt); freeChunkList(toFree); } From 2cd40ad8a54fd4917205ecc8d970c9fade5b787f Mon Sep 17 00:00:00 2001 From: Dragana Damjanovic Date: Thu, 10 Jul 2014 10:13:00 -0400 Subject: [PATCH 07/38] Bug 915024 - Add ForcePending for HttpChannel. r=jduell --- netwerk/base/public/moz.build | 1 + .../base/public/nsIForcePendingChannel.idl | 22 +++++ netwerk/protocol/ftp/FTPChannelParent.cpp | 84 ++++++++++++++----- netwerk/protocol/ftp/FTPChannelParent.h | 5 +- netwerk/protocol/ftp/nsFTPChannel.cpp | 7 +- netwerk/protocol/ftp/nsFTPChannel.h | 8 +- netwerk/protocol/http/HttpBaseChannel.cpp | 13 +++ netwerk/protocol/http/HttpBaseChannel.h | 3 + .../protocol/http/nsIHttpChannelInternal.idl | 7 +- .../converters/nsUnknownDecoder.cpp | 12 +-- 10 files changed, 124 insertions(+), 38 deletions(-) create mode 100644 netwerk/base/public/nsIForcePendingChannel.idl diff --git a/netwerk/base/public/moz.build b/netwerk/base/public/moz.build index 0dde4a862bc0..21f0c6be9914 100644 --- a/netwerk/base/public/moz.build +++ b/netwerk/base/public/moz.build @@ -43,6 +43,7 @@ XPIDL_SOURCES += [ 'nsIExternalProtocolHandler.idl', 'nsIFileStreams.idl', 'nsIFileURL.idl', + 'nsIForcePendingChannel.idl', 'nsIIncrementalDownload.idl', 'nsIInputStreamChannel.idl', 'nsIInputStreamPump.idl', diff --git a/netwerk/base/public/nsIForcePendingChannel.idl b/netwerk/base/public/nsIForcePendingChannel.idl new file mode 100644 index 000000000000..bb428bda8782 --- /dev/null +++ b/netwerk/base/public/nsIForcePendingChannel.idl @@ -0,0 +1,22 @@ +/* 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 "nsISupports.idl" + +/** + * nsIForcePending interface exposes a function that enables overwriting of the normal + * behavior for the channel's IsPending(), forcing 'true' to be returned. + */ + +[scriptable, uuid(225ab092-1554-423a-9492-606f6db3b4fb)] +interface nsIForcePendingChannel : nsISupports +{ + +/** + * forcePending(true) overrides the normal behavior for the + * channel's IsPending(), forcing 'true' to be returned. A call to + * forcePending(false) reverts IsPending() back to normal behavior. + */ + void forcePending(in boolean aForcePending); +}; diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 773a91bca4fb..c4a8ce67642d 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -9,6 +9,9 @@ #include "nsFTPChannel.h" #include "nsNetUtil.h" #include "nsFtpProtocolHandler.h" +#include "nsIEncodedChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsIForcePendingChannel.h" #include "mozilla/ipc/InputStreamUtils.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/unused.h" @@ -57,7 +60,8 @@ NS_IMPL_ISUPPORTS(FTPChannelParent, nsIStreamListener, nsIParentChannel, nsIInterfaceRequestor, - nsIRequestObserver) + nsIRequestObserver, + nsIChannelEventSink) //----------------------------------------------------------------------------- // FTPChannelParent::PFTPChannelParent @@ -114,13 +118,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI, if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); - mChannel = static_cast(chan.get()); + mChannel = chan; + + // later on mChannel may become an HTTP channel (we'll be redirected to one + // if we're using a proxy), but for now this is safe + nsFtpChannel* ftpChan = static_cast(mChannel.get()); if (mPBOverride != kPBOverride_Unset) { - mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); + ftpChan->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); } - - rv = mChannel->SetNotificationCallbacks(this); + rv = ftpChan->SetNotificationCallbacks(this); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); @@ -128,16 +135,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI, nsCOMPtr upload = DeserializeInputStream(aUploadStream, fds); if (upload) { // contentType and contentLength are ignored - rv = mChannel->SetUploadStream(upload, EmptyCString(), 0); + rv = ftpChan->SetUploadStream(upload, EmptyCString(), 0); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); } - rv = mChannel->ResumeAt(aStartPos, aEntityID); + rv = ftpChan->ResumeAt(aStartPos, aEntityID); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); - rv = mChannel->AsyncOpen(this, nullptr); + rv = ftpChan->AsyncOpen(this, nullptr); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); @@ -154,7 +161,7 @@ FTPChannelParent::ConnectChannel(const uint32_t& channelId) nsCOMPtr channel; rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)); if (NS_SUCCEEDED(rv)) - mChannel = static_cast(channel.get()); + mChannel = channel; LOG((" found channel %p, rv=%08x", mChannel.get(), rv)); @@ -240,7 +247,10 @@ FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode) // Reset fake pending status in case OnStopRequest has already been called. if (mChannel) { - mChannel->ForcePending(false); + nsCOMPtr forcePendingIChan = do_QueryInterface(mChannel); + if (forcePendingIChan) { + forcePendingIChan->ForcePending(false); + } } OnStopRequest(mChannel, nullptr, status); @@ -297,14 +307,14 @@ FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) resChan->GetEntityID(entityID); } - nsCOMPtr ftpChan = do_QueryInterface(aRequest); PRTime lastModified = 0; + nsCOMPtr ftpChan = do_QueryInterface(aRequest); if (ftpChan) { ftpChan->GetLastModifiedTime(&lastModified); - } else { - // Temporary hack: if we were redirected to use an HTTP channel (ie FTP is - // using an HTTP proxy), cancel, as we don't support those redirects yet. - aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED); + } + nsCOMPtr httpChan = do_QueryInterface(aRequest); + if (httpChan) { + httpChan->GetLastModifiedTime(&lastModified); } URIParams uriparam; @@ -499,7 +509,10 @@ FTPChannelParent::StartDiversion() // Fake pending status in case OnStopRequest has already been called. if (mChannel) { - mChannel->ForcePending(true); + nsCOMPtr forcePendingIChan = do_QueryInterface(mChannel); + if (forcePendingIChan) { + forcePendingIChan->ForcePending(true); + } } // Call OnStartRequest for the "DivertTo" listener. @@ -567,8 +580,10 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode, MOZ_RELEASE_ASSERT(mChannel); mChannel->Cancel(aErrorCode); - - mChannel->ForcePending(false); + nsCOMPtr forcePendingIChan = do_QueryInterface(mChannel); + if (forcePendingIChan) { + forcePendingIChan->ForcePending(false); + } bool isPending = false; nsresult rv = mChannel->IsPending(&isPending); @@ -581,9 +596,15 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode, // Channel has already sent OnStartRequest to the child, so ensure that we // call it here if it hasn't already been called. if (!mDivertedOnStartRequest) { - mChannel->ForcePending(true); + nsCOMPtr forcePendingIChan = do_QueryInterface(mChannel); + if (forcePendingIChan) { + forcePendingIChan->ForcePending(true); + } mDivertToListener->OnStartRequest(mChannel, nullptr); - mChannel->ForcePending(false); + + if (forcePendingIChan) { + forcePendingIChan->ForcePending(false); + } } // If the channel is pending, it will call OnStopRequest itself; otherwise, do // it here. @@ -598,6 +619,29 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode, } } +//----------------------------------------------------------------------------- +// FTPChannelParent::nsIChannelEventSink +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +FTPChannelParent::AsyncOnChannelRedirect( + nsIChannel *oldChannel, + nsIChannel *newChannel, + uint32_t redirectFlags, + nsIAsyncVerifyRedirectCallback* callback) +{ + nsCOMPtr ftpChan = do_QueryInterface(newChannel); + if (!ftpChan) { + // when FTP is set to use HTTP proxying, we wind up getting redirected to an HTTP channel. + nsCOMPtr httpChan = do_QueryInterface(newChannel); + if (!httpChan) + return NS_ERROR_UNEXPECTED; + } + mChannel = newChannel; + callback->OnRedirectVerifyCallback(NS_OK); + return NS_OK; +} + //--------------------- } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/ftp/FTPChannelParent.h b/netwerk/protocol/ftp/FTPChannelParent.h index c1623302a5c4..f52c3c605bc5 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.h +++ b/netwerk/protocol/ftp/FTPChannelParent.h @@ -24,6 +24,7 @@ class FTPChannelParent : public PFTPChannelParent , public nsIParentChannel , public nsIInterfaceRequestor , public ADivertableParentChannel + , public nsIChannelEventSink { public: NS_DECL_ISUPPORTS @@ -31,6 +32,7 @@ public: NS_DECL_NSISTREAMLISTENER NS_DECL_NSIPARENTCHANNEL NS_DECL_NSIINTERFACEREQUESTOR + NS_DECL_NSICHANNELEVENTSINK FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus); @@ -77,7 +79,8 @@ protected: virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; - nsRefPtr mChannel; + // if configured to use HTTP proxy for FTP, this can an an HTTP channel. + nsCOMPtr mChannel; bool mIPCClosed; diff --git a/netwerk/protocol/ftp/nsFTPChannel.cpp b/netwerk/protocol/ftp/nsFTPChannel.cpp index 53320952e290..d4cafa2860c3 100644 --- a/netwerk/protocol/ftp/nsFTPChannel.cpp +++ b/netwerk/protocol/ftp/nsFTPChannel.cpp @@ -29,7 +29,8 @@ NS_IMPL_ISUPPORTS_INHERITED(nsFtpChannel, nsIUploadChannel, nsIResumableChannel, nsIFTPChannel, - nsIProxiedChannel) + nsIProxiedChannel, + nsIForcePendingChannel) //----------------------------------------------------------------------------- @@ -199,7 +200,7 @@ nsFtpChannel::GetFTPEventSink(nsCOMPtr &aResult) aResult = mFTPEventSink; } -void +NS_IMETHODIMP nsFtpChannel::ForcePending(bool aForcePending) { // Set true here so IsPending will return true. @@ -207,6 +208,8 @@ nsFtpChannel::ForcePending(bool aForcePending) // OnStopRequest can be called in the parent before callbacks are diverted // back from the child to the listener in the parent. mForcePending = aForcePending; + + return NS_OK; } NS_IMETHODIMP diff --git a/netwerk/protocol/ftp/nsFTPChannel.h b/netwerk/protocol/ftp/nsFTPChannel.h index b9f4a1b0e357..e2763a47b2b3 100644 --- a/netwerk/protocol/ftp/nsFTPChannel.h +++ b/netwerk/protocol/ftp/nsFTPChannel.h @@ -12,6 +12,7 @@ #include "nsString.h" #include "nsCOMPtr.h" #include "nsIFTPChannel.h" +#include "nsIForcePendingChannel.h" #include "nsIUploadChannel.h" #include "nsIProxyInfo.h" #include "nsIProxiedChannel.h" @@ -23,7 +24,8 @@ class nsFtpChannel : public nsBaseChannel, public nsIFTPChannel, public nsIUploadChannel, public nsIResumableChannel, - public nsIProxiedChannel + public nsIProxiedChannel, + public nsIForcePendingChannel { public: NS_DECL_ISUPPORTS_INHERITED @@ -88,8 +90,8 @@ public: // Helper function for getting the nsIFTPEventSink. void GetFTPEventSink(nsCOMPtr &aResult); -public: /* Internal Necko use only. */ - void ForcePending(bool aForcePending); +public: + NS_IMETHOD ForcePending(bool aForcePending); protected: virtual ~nsFtpChannel() {} diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 3c391a26ca67..dc4cdd348132 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -164,6 +164,7 @@ NS_INTERFACE_MAP_BEGIN(HttpBaseChannel) NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel) NS_INTERFACE_MAP_ENTRY(nsIHttpChannel) NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal) + NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel) NS_INTERFACE_MAP_ENTRY(nsIRedirectHistory) NS_INTERFACE_MAP_ENTRY(nsIUploadChannel) NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2) @@ -1638,6 +1639,18 @@ HttpBaseChannel::ForcePending(bool aForcePending) return NS_OK; } +NS_IMETHODIMP +HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime) +{ + if (!mResponseHead) + return NS_ERROR_NOT_AVAILABLE; + uint32_t lastMod; + mResponseHead->GetLastModifiedValue(&lastMod); + *lastModifiedTime = lastMod; + return NS_OK; +} + + //----------------------------------------------------------------------------- // HttpBaseChannel::nsISupportsPriority //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 79ce6780feda..0e1d6b683850 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -19,6 +19,7 @@ #include "nsIHttpChannel.h" #include "nsHttpHandler.h" #include "nsIHttpChannelInternal.h" +#include "nsIForcePendingChannel.h" #include "nsIRedirectHistory.h" #include "nsIUploadChannel.h" #include "nsIUploadChannel2.h" @@ -63,6 +64,7 @@ class HttpBaseChannel : public nsHashPropertyBag , public nsITraceableChannel , public PrivateBrowsingChannel , public nsITimedChannel + , public nsIForcePendingChannel { protected: virtual ~HttpBaseChannel(); @@ -173,6 +175,7 @@ public: NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable); NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect); NS_IMETHOD ForcePending(bool aForcePending); + NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime); inline void CleanRedirectCacheChainIfNecessary() { diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index ed0e658b8e68..b9c80cc82160 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -200,10 +200,5 @@ interface nsIHttpChannelInternal : nsISupports */ void addRedirect(in nsIPrincipal aPrincipal); - /** - * ForcePending(true) overrides the normal behavior for the - * channel's IsPending(), forcing 'true' to be returned. A call to - * ForcePending(false) reverts IsPending() back to normal behavior. - */ - void ForcePending(in boolean aForcePending); + readonly attribute PRTime lastModifiedTime; }; diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index 937a9f27db84..e2bb90401b6b 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -17,7 +17,7 @@ #include "nsIViewSourceChannel.h" #include "nsIHttpChannel.h" -#include "nsIHttpChannelInternal.h" +#include "nsIForcePendingChannel.h" #include "nsNetCID.h" #include "nsNetUtil.h" @@ -204,9 +204,9 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt, // Make sure channel listeners see channel as pending while we call // OnStartRequest/OnDataAvailable, even though the underlying channel // has already hit OnStopRequest. - nsCOMPtr httpChannel = do_QueryInterface(request); - if (httpChannel) { - httpChannel->ForcePending(true); + nsCOMPtr forcePendingChannel = do_QueryInterface(request); + if (forcePendingChannel) { + forcePendingChannel->ForcePending(true); } rv = FireListenerNotifications(request, aCtxt); @@ -216,8 +216,8 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt, } // now we need to set pending state to false before calling OnStopRequest - if (httpChannel) { - httpChannel->ForcePending(false); + if (forcePendingChannel) { + forcePendingChannel->ForcePending(false); } } From 9687f0176010825eb964bb2ce8cc184f62e7a77c Mon Sep 17 00:00:00 2001 From: Jed Parsons Date: Fri, 20 Jun 2014 16:59:37 -0700 Subject: [PATCH 08/38] Bug 1026072 - this.getContextForMM(...).RP is undefined. r=MattN --- dom/identity/DOMIdentity.jsm | 88 +++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/dom/identity/DOMIdentity.jsm b/dom/identity/DOMIdentity.jsm index e6c6e4a2b029..b9ddf6d8a733 100644 --- a/dom/identity/DOMIdentity.jsm +++ b/dom/identity/DOMIdentity.jsm @@ -4,7 +4,10 @@ "use strict"; -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, + interfaces: Ci, + utils: Cu, + results: Cr} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -18,12 +21,14 @@ this.EXPORTED_SYMBOLS = ["DOMIdentity"]; XPCOMUtils.defineLazyModuleGetter(this, "objectCopy", "resource://gre/modules/identity/IdentityUtils.jsm"); +/* jshint ignore:start */ XPCOMUtils.defineLazyModuleGetter(this, "IdentityService", #ifdef MOZ_B2G_VERSION "resource://gre/modules/identity/MinimalIdentity.jsm"); #else "resource://gre/modules/identity/Identity.jsm"); #endif +/* jshint ignore:end */ XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAccounts", "resource://gre/modules/identity/FirefoxAccounts.jsm"); @@ -51,6 +56,23 @@ function IDDOMMessage(aOptions) { objectCopy(aOptions, this); } +function _sendAsyncMessage(identifier, message) { + if (this._mm) { + try { + this._mm.sendAsyncMessage(identifier, message); + } catch(err) { + // We may receive a NS_ERROR_NOT_INITIALIZED if the target window has + // been closed. This can legitimately happen if an app has been killed + // while we are in the midst of a sign-in flow. + if (err.result == Cr.NS_ERROR_NOT_INITIALIZED) { + log("Cannot sendAsyncMessage because the recipient frame has closed"); + return; + } + log("ERROR: sendAsyncMessage: " + err); + } + } +}; + function IDPProvisioningContext(aID, aOrigin, aTargetMM) { this._id = aID; this._origin = aOrigin; @@ -61,19 +83,21 @@ IDPProvisioningContext.prototype = { get id() this._id, get origin() this._origin, + sendAsyncMessage: _sendAsyncMessage, + doBeginProvisioningCallback: function IDPPC_doBeginProvCB(aID, aCertDuration) { let message = new IDDOMMessage({id: this.id}); message.identity = aID; message.certDuration = aCertDuration; - this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback", - message); + this.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback", + message); }, doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) { log("doGenKeyPairCallback"); let message = new IDDOMMessage({id: this.id}); message.publicKey = aPublicKey; - this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message); + this.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message); }, doError: function(msg) { @@ -91,11 +115,13 @@ IDPAuthenticationContext.prototype = { get id() this._id, get origin() this._origin, + sendAsyncMessage: _sendAsyncMessage, + doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) { let message = new IDDOMMessage({id: this.id}); message.identity = aIdentity; - this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback", - message); + this.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback", + message); }, doError: function IDPAC_doError(msg) { @@ -123,37 +149,39 @@ function RPWatchContext(aOptions, aTargetMM, aPrincipal) { } RPWatchContext.prototype = { + sendAsyncMessage: _sendAsyncMessage, + doLogin: function RPWatchContext_onlogin(aAssertion, aMaybeInternalParams) { log("doLogin: " + this.id); let message = new IDDOMMessage({id: this.id, assertion: aAssertion}); if (aMaybeInternalParams) { message._internalParams = aMaybeInternalParams; } - this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message); + this.sendAsyncMessage("Identity:RP:Watch:OnLogin", message); }, doLogout: function RPWatchContext_onlogout() { log("doLogout: " + this.id); let message = new IDDOMMessage({id: this.id}); - this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message); + this.sendAsyncMessage("Identity:RP:Watch:OnLogout", message); }, doReady: function RPWatchContext_onready() { log("doReady: " + this.id); let message = new IDDOMMessage({id: this.id}); - this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message); + this.sendAsyncMessage("Identity:RP:Watch:OnReady", message); }, doCancel: function RPWatchContext_oncancel() { log("doCancel: " + this.id); let message = new IDDOMMessage({id: this.id}); - this._mm.sendAsyncMessage("Identity:RP:Watch:OnCancel", message); + this.sendAsyncMessage("Identity:RP:Watch:OnCancel", message); }, doError: function RPWatchContext_onerror(aMessage) { log("doError: " + this.id + ": " + JSON.stringify(aMessage)); let message = new IDDOMMessage({id: this.id, message: aMessage}); - this._mm.sendAsyncMessage("Identity:RP:Watch:OnError", message); + this.sendAsyncMessage("Identity:RP:Watch:OnError", message); } }; @@ -207,7 +235,8 @@ this.DOMIdentity = { */ getService: function(message) { if (!this._serviceContexts.has(message.id)) { - throw new Error("getService called before newContext for " + message.id); + log("ERROR: getService called before newContext for " + message.id); + return null; } let context = this._serviceContexts.get(message.id); @@ -348,7 +377,9 @@ this.DOMIdentity = { }, _subscribeListeners: function DOMIdentity__subscribeListeners() { - if (!ppmm) return; + if (!ppmm) { + return; + } for (let message of this.messages) { ppmm.addMessageListener(message, this); } @@ -373,20 +404,31 @@ this.DOMIdentity = { // not have the right callbacks, we don't want unwatch to throw, because it // will break the process of releasing the page's resources and leak // memory. - try { - this.getService(message).RP.unwatch(message.id, targetMM); - } catch(ex) { - log("ERROR: can't unwatch " + message.id + ": " + ex); + let service = this.getService(message); + if (service && service.RP) { + service.RP.unwatch(message.id, targetMM); + this.deleteContextForMM(targetMM); + return; } + log("Can't find a service to unwatch() for " + message.id); }, _request: function DOMIdentity__request(message) { - this.getService(message).RP.request(message.id, message); + let service = this.getService(message); + if (service && service.RP) { + service.RP.request(message.id, message); + return; + } + log("No context in which to call request(); Did you call watch() first?"); }, _logout: function DOMIdentity__logout(message) { - log("logout " + message + "\n"); - this.getService(message).RP.logout(message.id, message.origin, message); + let service = this.getService(message); + if (service && service.RP) { + service.RP.logout(message.id, message.origin, message); + return; + } + log("No context in which to call logout(); Did you call watch() first?"); }, _childProcessShutdown: function DOMIdentity__childProcessShutdown(targetMM) { @@ -394,7 +436,11 @@ this.DOMIdentity = { return; } - this.getContextForMM(targetMM).RP.childProcessShutdown(targetMM); + let service = this.getContextForMM(targetMM); + if (service && service.RP) { + service.RP.childProcessShutdown(targetMM); + } + this.deleteContextForMM(targetMM); let options = makeMessageObject({messageManager: targetMM, id: null, origin: null}); From f6d80145b1d3c6d5a9393faa9bcd201cbcbe521f Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Sat, 12 Jul 2014 12:54:00 -0400 Subject: [PATCH 09/38] Bug 1034463 - Ensure that PCLocationMap only ever stores scripts from its own compartment. r=shu --- js/src/jscntxtinlines.h | 1 + js/src/vm/SavedStacks.cpp | 32 +++++++++++++++++++++++++++----- js/src/vm/SavedStacks.h | 4 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 1c2fb204337d..8fe8b146897e 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -135,6 +135,7 @@ class CompartmentChecker void check(InterpreterFrame *fp); void check(AbstractFramePtr frame); + void check(SavedStacks *stacks); }; #endif /* JS_CRASH_DIAGNOSTICS */ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index af405b1ab25d..b92537c408fc 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -16,6 +16,7 @@ #include "vm/GlobalObject.h" #include "vm/StringBuffer.h" +#include "jscntxtinlines.h" #include "jsobjinlines.h" using mozilla::AddToHash; @@ -399,7 +400,7 @@ bool SavedStacks::saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame, unsigned maxFrameCount) { JS_ASSERT(initialized()); - JS_ASSERT(&cx->compartment()->savedStacks() == this); + assertSameCompartment(cx, this); FrameIter iter(cx, FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED); return insertFrames(cx, iter, frame, maxFrameCount); @@ -504,8 +505,11 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram if (iter.hasScript()) { JSScript *script = iter.script(); jsbytecode *pc = iter.pc(); - if (!getLocation(cx, script, pc, &location)) - return false; + { + AutoCompartment ac(cx, iter.compartment()); + if (!cx->compartment()->savedStacks().getLocation(cx, script, pc, &location)) + return false; + } } else { const char *filename = iter.scriptFilename(); if (!filename) @@ -595,13 +599,13 @@ SavedStacks::createFrameFromLookup(JSContext *cx, const SavedFrame::Lookup &look if (!proto) return nullptr; - JS_ASSERT(proto->compartment() == cx->compartment()); + assertSameCompartment(cx, proto); RootedObject global(cx, cx->compartment()->maybeGlobal()); if (!global) return nullptr; - JS_ASSERT(global->compartment() == cx->compartment()); + assertSameCompartment(cx, global); RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global)); if (!frameObj) @@ -635,6 +639,12 @@ bool SavedStacks::getLocation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleLocationValue locationp) { + // We should only ever be caching location values for scripts in this + // compartment. Otherwise, we would get dead cross-compartment scripts in + // the cache because our compartment's sweep method isn't called when their + // compartment gets collected. + assertSameCompartment(cx, this, script); + PCKey key(script, pc); PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key); @@ -666,4 +676,16 @@ SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata) return true; } +#ifdef JS_CRASH_DIAGNOSTICS +void +CompartmentChecker::check(SavedStacks *stacks) +{ + if (&compartment->savedStacks() != stacks) { + printf("*** Compartment SavedStacks mismatch: %p vs. %p\n", + (void *) &compartment->savedStacks(), stacks); + MOZ_CRASH(); + } +} +#endif /* JS_CRASH_DIAGNOSTICS */ + } /* namespace js */ diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index be54359bbb6f..71cdee4c5694 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -113,8 +113,8 @@ class SavedStacks { size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); private: - SavedFrame::Set frames; - JSObject *savedFrameProto; + SavedFrame::Set frames; + JSObject *savedFrameProto; bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0); From 345b6b66a6a296da6be8cb6ecfcf142e2db92ff0 Mon Sep 17 00:00:00 2001 From: Richard Marti Date: Sat, 12 Jul 2014 20:19:06 +0200 Subject: [PATCH 10/38] Bug 1037081 - Remove the -moz-user-select from treecols. r=MattN --- browser/themes/shared/incontentprefs/preferences.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/browser/themes/shared/incontentprefs/preferences.css b/browser/themes/shared/incontentprefs/preferences.css index c96e159169c3..eee0f7486021 100644 --- a/browser/themes/shared/incontentprefs/preferences.css +++ b/browser/themes/shared/incontentprefs/preferences.css @@ -20,6 +20,11 @@ page { -moz-user-select: text; } +treecol { + /* override the * rule to let the treecol be sortable */ + -moz-user-select: none; +} + caption { -moz-appearance: none; margin: 0; From 7cd825c5a36bf92d4e842eed9a8bc712d19aabcd Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Fri, 11 Jul 2014 08:28:00 -0400 Subject: [PATCH 11/38] Bug 1037470 - Fix debug build bustage with Ion disabled. r=jandem --- js/src/vm/Debugger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 95aafed69d17..778636b606f8 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4183,7 +4183,7 @@ static void UpdateFrameIterPc(FrameIter &iter) { if (iter.abstractFramePtr().isRematerializedFrame()) { -#ifdef DEBUG +#if defined(DEBUG) && defined(JS_ION) // Rematerialized frames don't need their pc updated. The reason we // need to update pc is because we might get the same Debugger.Frame // object for multiple re-entries into debugger code from debuggee From 6072b8f9b3c8cfab04bb1862dea93bce7c1dbd9d Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 14 Jul 2014 15:01:32 +0200 Subject: [PATCH 12/38] Bug 1034689 part 1 - Make AndroidBridge JSON parsing work with Latin1 strings. r=Waldo --- js/src/jsapi.cpp | 26 +++++++++++++++++++++++--- js/src/jsapi.h | 7 +++++++ widget/android/AndroidBridge.cpp | 8 +------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3563fd4c115d..5b82cf2b84a2 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5722,13 +5722,17 @@ JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer, } JS_PUBLIC_API(bool) -JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp) +JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, MutableHandleValue vp) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); + return ParseJSONWithReviver(cx, mozilla::Range(chars, len), NullHandleValue, vp); +} - RootedValue reviver(cx, NullValue()); - return ParseJSONWithReviver(cx, mozilla::Range(chars, len), reviver, vp); +JS_PUBLIC_API(bool) +JS_ParseJSON(JSContext *cx, HandleString str, MutableHandleValue vp) +{ + return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp); } JS_PUBLIC_API(bool) @@ -5739,6 +5743,22 @@ JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, Handle return ParseJSONWithReviver(cx, mozilla::Range(chars, len), reviver, vp); } +JS_PUBLIC_API(bool) +JS_ParseJSONWithReviver(JSContext *cx, HandleString str, HandleValue reviver, MutableHandleValue vp) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, str); + + AutoStableStringChars stableChars(cx); + if (!stableChars.init(cx, str)) + return false; + + return stableChars.isLatin1() + ? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp) + : ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver, vp); +} + /************************************************************************/ JS_PUBLIC_API(void) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 386f20c21dac..c08383d36e85 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4483,10 +4483,17 @@ JS_Stringify(JSContext *cx, JS::MutableHandleValue value, JS::HandleObject repla JS_PUBLIC_API(bool) JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp); +JS_PUBLIC_API(bool) +JS_ParseJSON(JSContext *cx, JS::HandleString str, JS::MutableHandleValue vp); + JS_PUBLIC_API(bool) JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, JS::HandleValue reviver, JS::MutableHandleValue vp); +JS_PUBLIC_API(bool) +JS_ParseJSONWithReviver(JSContext *cx, JS::HandleString str, JS::HandleValue reviver, + JS::MutableHandleValue vp); + /************************************************************************/ /* diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index c54f4214d299..ae5feb08517a 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -1588,14 +1588,8 @@ NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val, } JS::RootedString jsonStr(cx, val.toString()); - size_t strLen = 0; - const jschar* strChar = JS_GetStringCharsAndLength(cx, jsonStr, &strLen); - if (!strChar) { - return NS_ERROR_UNEXPECTED; - } - JS::RootedValue jsonVal(cx); - if (!JS_ParseJSON(cx, strChar, strLen, &jsonVal) || !jsonVal.isObject()) { + if (!JS_ParseJSON(cx, jsonStr, &jsonVal) || !jsonVal.isObject()) { return NS_ERROR_INVALID_ARG; } From f84bfd597e4c40ce1f16f32a0008291ed4625b7e Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 14 Jul 2014 06:35:23 -0700 Subject: [PATCH 13/38] Bug 1036419 - Add lock to GrallocReporter::CollectReports() r=nical --- gfx/layers/ipc/SharedBufferManagerParent.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gfx/layers/ipc/SharedBufferManagerParent.cpp b/gfx/layers/ipc/SharedBufferManagerParent.cpp index 059140c3cbe0..243707d4e7cd 100644 --- a/gfx/layers/ipc/SharedBufferManagerParent.cpp +++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp @@ -43,11 +43,15 @@ public: NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) { + if (SharedBufferManagerParent::sManagerMonitor) { + SharedBufferManagerParent::sManagerMonitor->Lock(); + } map::iterator it; for (it = SharedBufferManagerParent::sManagers.begin(); it != SharedBufferManagerParent::sManagers.end(); it++) { base::ProcessId pid = it->first; SharedBufferManagerParent *mgr = it->second; + MutexAutoLock lock(mgr->mBuffersMutex); std::map >::iterator buf_it; for (buf_it = mgr->mBuffers.begin(); buf_it != mgr->mBuffers.end(); buf_it++) { nsresult rv; @@ -72,10 +76,16 @@ public: "conditions."), aData); if (rv != NS_OK) { + if (SharedBufferManagerParent::sManagerMonitor) { + SharedBufferManagerParent::sManagerMonitor->Unlock(); + } return rv; } } } + if (SharedBufferManagerParent::sManagerMonitor) { + SharedBufferManagerParent::sManagerMonitor->Unlock(); + } return NS_OK; } From 4618eb06b9e5b2716c39f8b2d0a4775014e6c04b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:15 -0400 Subject: [PATCH 14/38] Bug 857648 part 1. Remove unnecessary code that tries to filter out non-JS stack frames from a known-JS-only stack. r=khuey --- dom/bindings/Exceptions.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index e9166199763f..9b1072eeaaa6 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -182,16 +182,7 @@ GetCurrentJSStack() return nullptr; } - // peel off native frames... - uint32_t language; - nsCOMPtr caller; - while (stack && - NS_SUCCEEDED(stack->GetLanguage(&language)) && - language != nsIProgrammingLanguage::JAVASCRIPT && - NS_SUCCEEDED(stack->GetCaller(getter_AddRefs(caller))) && - caller) { - stack = caller; - } + // Note that CreateStack only returns JS frames, so we're done here. return stack.forget(); } From deb48d9267067ca3979ac157c746166be686106a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:16 -0400 Subject: [PATCH 15/38] Bug 857648 part 2. Split JSStackFrame into a generic class and a JS-specific class. r=khuey --- dom/bindings/Exceptions.cpp | 224 +++++++++++++++++++++++------------- 1 file changed, 146 insertions(+), 78 deletions(-) diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index 9b1072eeaaa6..a55e4db86a8d 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -251,46 +251,106 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(StackDescriptionOwner) } NS_IMPL_CYCLE_COLLECTION_TRACE_END -class JSStackFrame : public nsIStackFrame +class StackFrame : public nsIStackFrame { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS(JSStackFrame) + NS_DECL_CYCLE_COLLECTION_CLASS(StackFrame) NS_DECL_NSISTACKFRAME - // A null aStackDescription or an aIndex that's out of range for the - // number of frames aStackDescription has will mean that the - // JSStackFrame will never look at the stack description. Instead, - // it is expected to be initialized by the caller as needed. - JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex); + StackFrame(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller); + + StackFrame() + : mLineno(0) + , mLanguage(nsIProgrammingLanguage::UNKNOWN) + { + } - static already_AddRefed - CreateStack(JSContext* aCx, int32_t aMaxDepth = -1); static already_AddRefed CreateStackFrameLocation(uint32_t aLanguage, const char* aFilename, const char* aFunctionName, int32_t aLineNumber, nsIStackFrame* aCaller); +protected: + virtual ~StackFrame(); -private: - virtual ~JSStackFrame(); - - bool IsJSFrame() const { - return mLanguage == nsIProgrammingLanguage::JAVASCRIPT; + virtual bool IsJSFrame() const + { + return false; } - int32_t GetLineno(); + virtual int32_t GetLineno() + { + return mLineno; + } - nsRefPtr mStackDescription; nsCOMPtr mCaller; - - // Cached values nsString mFilename; nsString mFunname; int32_t mLineno; uint32_t mLanguage; +}; +StackFrame::StackFrame(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller) + : mCaller(aCaller) + , mLineno(aLineNumber) + , mLanguage(aLanguage) +{ + CopyUTF8toUTF16(aFilename, mFilename); + CopyUTF8toUTF16(aFunctionName, mFunname); +} + +StackFrame::~StackFrame() +{ +} + +NS_IMPL_CYCLE_COLLECTION(StackFrame, mCaller) +NS_IMPL_CYCLE_COLLECTING_ADDREF(StackFrame) +NS_IMPL_CYCLE_COLLECTING_RELEASE(StackFrame) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StackFrame) + NS_INTERFACE_MAP_ENTRY(nsIStackFrame) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +class JSStackFrame : public StackFrame +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JSStackFrame, StackFrame) + + // aStackDescription must not be null. aIndex must be a valid index + // into aStackDescription. + JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex); + + static already_AddRefed + CreateStack(JSContext* aCx, int32_t aMaxDepth = -1); + + NS_IMETHOD GetLanguageName(nsACString& aLanguageName) MOZ_OVERRIDE; + NS_IMETHOD GetFilename(nsAString& aFilename) MOZ_OVERRIDE; + NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE; + NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE; + +protected: + virtual bool IsJSFrame() const MOZ_OVERRIDE { + return true; + } + + virtual int32_t GetLineno() MOZ_OVERRIDE; + +private: + virtual ~JSStackFrame(); + + nsRefPtr mStackDescription; size_t mIndex; bool mFilenameInitialized; @@ -301,60 +361,48 @@ private: JSStackFrame::JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex) - : mLineno(0) + : mStackDescription(aStackDescription) + , mIndex(aIndex) + , mFilenameInitialized(false) + , mFunnameInitialized(false) + , mLinenoInitialized(false) + , mCallerInitialized(false) { - if (aStackDescription && aIndex < aStackDescription->NumFrames()) { - mStackDescription = aStackDescription; - mIndex = aIndex; - mFilenameInitialized = false; - mFunnameInitialized = false; - mLinenoInitialized = false; - mCallerInitialized = false; - mLanguage = nsIProgrammingLanguage::JAVASCRIPT; - } else { - MOZ_ASSERT(!mStackDescription); - mIndex = 0; - mFilenameInitialized = true; - mFunnameInitialized = true; - mLinenoInitialized = true; - mCallerInitialized = true; - mLanguage = nsIProgrammingLanguage::UNKNOWN; - } + MOZ_ASSERT(aStackDescription && aIndex < aStackDescription->NumFrames()); + + mLineno = 0; + mLanguage = nsIProgrammingLanguage::JAVASCRIPT; } JSStackFrame::~JSStackFrame() { } -NS_IMPL_CYCLE_COLLECTION(JSStackFrame, mStackDescription, mCaller) +NS_IMPL_CYCLE_COLLECTION_INHERITED(JSStackFrame, StackFrame, mStackDescription) -NS_IMPL_CYCLE_COLLECTING_ADDREF(JSStackFrame) -NS_IMPL_CYCLE_COLLECTING_RELEASE(JSStackFrame) +NS_IMPL_ADDREF_INHERITED(JSStackFrame, StackFrame) +NS_IMPL_RELEASE_INHERITED(JSStackFrame, StackFrame) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame) - NS_INTERFACE_MAP_ENTRY(nsIStackFrame) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(JSStackFrame) +NS_INTERFACE_MAP_END_INHERITING(StackFrame) /* readonly attribute uint32_t language; */ -NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage) +NS_IMETHODIMP StackFrame::GetLanguage(uint32_t* aLanguage) { *aLanguage = mLanguage; return NS_OK; } /* readonly attribute string languageName; */ +NS_IMETHODIMP StackFrame::GetLanguageName(nsACString& aLanguageName) +{ + aLanguageName.AssignLiteral("C++"); + return NS_OK; +} + NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName) { - static const char js[] = "JavaScript"; - static const char cpp[] = "C++"; - - if (IsJSFrame()) { - aLanguageName.AssignASCII(js); - } else { - aLanguageName.AssignASCII(cpp); - } - + aLanguageName.AssignLiteral("JavaScript"); return NS_OK; } @@ -369,6 +417,11 @@ NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename) mFilenameInitialized = true; } + return StackFrame::GetFilename(aFilename); +} + +NS_IMETHODIMP StackFrame::GetFilename(nsAString& aFilename) +{ // The filename must be set to null if empty. if (mFilename.IsEmpty()) { aFilename.SetIsVoid(true); @@ -390,6 +443,11 @@ NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction) mFunnameInitialized = true; } + return StackFrame::GetName(aFunction); +} + +NS_IMETHODIMP StackFrame::GetName(nsAString& aFunction) +{ // The function name must be set to null if empty. if (mFunname.IsEmpty()) { aFunction.SetIsVoid(true); @@ -400,6 +458,7 @@ NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction) return NS_OK; } +// virtual int32_t JSStackFrame::GetLineno() { @@ -409,18 +468,18 @@ JSStackFrame::GetLineno() mLinenoInitialized = true; } - return mLineno; + return StackFrame::GetLineno(); } /* readonly attribute int32_t lineNumber; */ -NS_IMETHODIMP JSStackFrame::GetLineNumber(int32_t* aLineNumber) +NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber) { *aLineNumber = GetLineno(); return NS_OK; } /* readonly attribute AUTF8String sourceLine; */ -NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine) +NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine) { aSourceLine.Truncate(); return NS_OK; @@ -430,15 +489,27 @@ NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine) NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller) { if (!mCallerInitialized) { - mCaller = new JSStackFrame(mStackDescription, mIndex+1); + if (mIndex + 1 < mStackDescription->NumFrames()) { + mCaller = new JSStackFrame(mStackDescription, mIndex+1); + } else { + // Do we really need this dummy frame? If so, we should document why... I + // guess for symmetry with the "nothing on the stack" case, which returns + // a single dummy frame? + mCaller = new StackFrame(); + } mCallerInitialized = true; } + return StackFrame::GetCaller(aCaller); +} + +NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller) +{ NS_IF_ADDREF(*aCaller = mCaller); return NS_OK; } /* AUTF8String toString (); */ -NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval) +NS_IMETHODIMP StackFrame::ToString(nsACString& _retval) { _retval.Truncate(); @@ -480,28 +551,25 @@ JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth) return nullptr; } - nsRefPtr descOwner = new StackDescriptionOwner(desc); - - nsRefPtr first = new JSStackFrame(descOwner, 0); + nsCOMPtr first; + if (desc->nframes == 0) { + first = new StackFrame(); + } else { + nsRefPtr descOwner = new StackDescriptionOwner(desc); + first = new JSStackFrame(descOwner, 0); + } return first.forget(); } /* static */ already_AddRefed -JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage, - const char* aFilename, - const char* aFunctionName, - int32_t aLineNumber, - nsIStackFrame* aCaller) +StackFrame::CreateStackFrameLocation(uint32_t aLanguage, + const char* aFilename, + const char* aFunctionName, + int32_t aLineNumber, + nsIStackFrame* aCaller) { - nsRefPtr self = new JSStackFrame(nullptr, 0); - - self->mLanguage = aLanguage; - self->mLineno = aLineNumber; - CopyUTF8toUTF16(aFilename, self->mFilename); - CopyUTF8toUTF16(aFunctionName, self->mFunname); - - self->mCaller = aCaller; - + nsRefPtr self = + new StackFrame(aLanguage, aFilename, aFunctionName, aLineNumber, aCaller); return self.forget(); } @@ -518,9 +586,9 @@ CreateStackFrameLocation(uint32_t aLanguage, int32_t aLineNumber, nsIStackFrame* aCaller) { - return JSStackFrame::CreateStackFrameLocation(aLanguage, aFilename, - aFunctionName, aLineNumber, - aCaller); + return StackFrame::CreateStackFrameLocation(aLanguage, aFilename, + aFunctionName, aLineNumber, + aCaller); } } // namespace exceptions From 616d872d6815005794aedabb9b928dd1ab9905ac Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:16 -0400 Subject: [PATCH 16/38] Bug 857648 part 3. Switch from using JS::DescribeStack to JS::CaptureCurrentStack for producing JSStackFrames. r=khuey --- dom/bindings/Exceptions.cpp | 189 +++++++++++++++++------------------- 1 file changed, 90 insertions(+), 99 deletions(-) diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index a55e4db86a8d..d4f382382d92 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -188,69 +188,6 @@ GetCurrentJSStack() namespace exceptions { -class StackDescriptionOwner { -public: - StackDescriptionOwner(JS::StackDescription* aDescription) - : mDescription(aDescription) - { - mozilla::HoldJSObjects(this); - } - -protected: - ~StackDescriptionOwner() - { - // Make sure to set mDescription to null before calling DropJSObjects, since - // in debug builds DropJSObjects try to trace us and we don't want to trace - // a dead StackDescription. - if (mDescription) { - JS::FreeStackDescription(nullptr, mDescription); - mDescription = nullptr; - } - mozilla::DropJSObjects(this); - } - -public: - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(StackDescriptionOwner) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(StackDescriptionOwner) - - JS::FrameDescription& FrameAt(size_t aIndex) - { - MOZ_ASSERT(aIndex < mDescription->nframes); - return mDescription->frames[aIndex]; - } - - unsigned NumFrames() - { - return mDescription->nframes; - } - -private: - JS::StackDescription* mDescription; -}; - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(StackDescriptionOwner, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(StackDescriptionOwner, Release) - -NS_IMPL_CYCLE_COLLECTION_CLASS(StackDescriptionOwner) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StackDescriptionOwner) - if (tmp->mDescription) { - JS::FreeStackDescription(nullptr, tmp->mDescription); - tmp->mDescription = nullptr; - } -NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StackDescriptionOwner) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(StackDescriptionOwner) - JS::StackDescription* desc = tmp->mDescription; - if (tmp->mDescription) { - for (size_t i = 0; i < desc->nframes; ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].markedLocation1()); - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].markedLocation2()); - } - } -NS_IMPL_CYCLE_COLLECTION_TRACE_END - class StackFrame : public nsIStackFrame { public: @@ -284,9 +221,10 @@ protected: return false; } - virtual int32_t GetLineno() + virtual nsresult GetLineno(int32_t* aLineNo) { - return mLineno; + *aLineNo = mLineno; + return NS_OK; } nsCOMPtr mCaller; @@ -326,11 +264,11 @@ class JSStackFrame : public StackFrame { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JSStackFrame, StackFrame) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSStackFrame, + StackFrame) - // aStackDescription must not be null. aIndex must be a valid index - // into aStackDescription. - JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex); + // aStack must not be null. + JSStackFrame(JS::Handle aStack); static already_AddRefed CreateStack(JSContext* aCx, int32_t aMaxDepth = -1); @@ -345,13 +283,12 @@ protected: return true; } - virtual int32_t GetLineno() MOZ_OVERRIDE; + virtual nsresult GetLineno(int32_t* aLineNo) MOZ_OVERRIDE; private: virtual ~JSStackFrame(); - nsRefPtr mStackDescription; - size_t mIndex; + JS::Heap mStack; bool mFilenameInitialized; bool mFunnameInitialized; @@ -359,26 +296,35 @@ private: bool mCallerInitialized; }; -JSStackFrame::JSStackFrame(StackDescriptionOwner* aStackDescription, - size_t aIndex) - : mStackDescription(aStackDescription) - , mIndex(aIndex) +JSStackFrame::JSStackFrame(JS::Handle aStack) + : mStack(aStack) , mFilenameInitialized(false) , mFunnameInitialized(false) , mLinenoInitialized(false) , mCallerInitialized(false) { - MOZ_ASSERT(aStackDescription && aIndex < aStackDescription->NumFrames()); + MOZ_ASSERT(mStack); + mozilla::HoldJSObjects(this); mLineno = 0; mLanguage = nsIProgrammingLanguage::JAVASCRIPT; } JSStackFrame::~JSStackFrame() { + mozilla::DropJSObjects(this); } -NS_IMPL_CYCLE_COLLECTION_INHERITED(JSStackFrame, StackFrame, mStackDescription) +NS_IMPL_CYCLE_COLLECTION_CLASS(JSStackFrame) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(JSStackFrame, StackFrame) + tmp->mStack = nullptr; +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(JSStackFrame, StackFrame) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSStackFrame, StackFrame) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack) +NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_ADDREF_INHERITED(JSStackFrame, StackFrame) NS_IMPL_RELEASE_INHERITED(JSStackFrame, StackFrame) @@ -410,10 +356,20 @@ NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName) NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename) { if (!mFilenameInitialized) { - JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); - if (const char *filename = desc.filename()) { - CopyUTF8toUTF16(filename, mFilename); + ThreadsafeAutoJSContext cx; + JS::Rooted stack(cx, mStack); + JS::ExposeObjectToActiveJS(mStack); + JSAutoCompartment ac(cx, stack); + JS::Rooted filenameVal(cx); + if (!JS_GetProperty(cx, stack, "source", &filenameVal) || + !filenameVal.isString()) { + return NS_ERROR_UNEXPECTED; } + nsAutoJSString str; + if (!str.init(cx, filenameVal.toString())) { + return NS_ERROR_OUT_OF_MEMORY; + } + mFilename = str; mFilenameInitialized = true; } @@ -436,9 +392,22 @@ NS_IMETHODIMP StackFrame::GetFilename(nsAString& aFilename) NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction) { if (!mFunnameInitialized) { - JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); - if (JSFlatString *name = desc.funDisplayName()) { - AssignJSFlatString(mFunname, name); + ThreadsafeAutoJSContext cx; + JS::Rooted stack(cx, mStack); + JS::ExposeObjectToActiveJS(mStack); + JSAutoCompartment ac(cx, stack); + JS::Rooted nameVal(cx); + // functionDisplayName can be null + if (!JS_GetProperty(cx, stack, "functionDisplayName", &nameVal) || + (!nameVal.isString() && !nameVal.isNull())) { + return NS_ERROR_UNEXPECTED; + } + if (nameVal.isString()) { + nsAutoJSString str; + if (!str.init(cx, nameVal.toString())) { + return NS_ERROR_OUT_OF_MEMORY; + } + mFunname = str; } mFunnameInitialized = true; } @@ -459,23 +428,30 @@ NS_IMETHODIMP StackFrame::GetName(nsAString& aFunction) } // virtual -int32_t -JSStackFrame::GetLineno() +nsresult +JSStackFrame::GetLineno(int32_t* aLineNo) { if (!mLinenoInitialized) { - JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); - mLineno = desc.lineno(); + ThreadsafeAutoJSContext cx; + JS::Rooted stack(cx, mStack); + JS::ExposeObjectToActiveJS(mStack); + JSAutoCompartment ac(cx, stack); + JS::Rooted lineVal(cx); + if (!JS_GetProperty(cx, stack, "line", &lineVal) || + !lineVal.isNumber()) { + return NS_ERROR_UNEXPECTED; + } + mLineno = lineVal.toNumber(); mLinenoInitialized = true; } - return StackFrame::GetLineno(); + return StackFrame::GetLineno(aLineNo); } /* readonly attribute int32_t lineNumber; */ NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber) { - *aLineNumber = GetLineno(); - return NS_OK; + return GetLineno(aLineNumber); } /* readonly attribute AUTF8String sourceLine; */ @@ -489,8 +465,19 @@ NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine) NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller) { if (!mCallerInitialized) { - if (mIndex + 1 < mStackDescription->NumFrames()) { - mCaller = new JSStackFrame(mStackDescription, mIndex+1); + ThreadsafeAutoJSContext cx; + JS::Rooted stack(cx, mStack); + JS::ExposeObjectToActiveJS(mStack); + JSAutoCompartment ac(cx, stack); + JS::Rooted callerVal(cx); + if (!JS_GetProperty(cx, stack, "parent", &callerVal) || + !callerVal.isObjectOrNull()) { + return NS_ERROR_UNEXPECTED; + } + + if (callerVal.isObject()) { + JS::Rooted caller(cx, &callerVal.toObject()); + mCaller = new JSStackFrame(caller); } else { // Do we really need this dummy frame? If so, we should document why... I // guess for symmetry with the "nothing on the stack" case, which returns @@ -530,11 +517,16 @@ NS_IMETHODIMP StackFrame::ToString(nsACString& _retval) if (funname.IsEmpty()) { funname.AssignLiteral(""); } + + int32_t lineno; + rv = GetLineno(&lineno); + NS_ENSURE_SUCCESS(rv, rv); + static const char format[] = "%s frame :: %s :: %s :: line %d"; _retval.AppendPrintf(format, frametype, NS_ConvertUTF16toUTF8(filename).get(), NS_ConvertUTF16toUTF8(funname).get(), - GetLineno()); + lineno); return NS_OK; } @@ -546,17 +538,16 @@ JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth) aMaxDepth = MAX_FRAMES; } - JS::StackDescription* desc = JS::DescribeStack(aCx, aMaxDepth); - if (!desc) { + JS::Rooted stack(aCx); + if (!JS::CaptureCurrentStack(aCx, &stack, aMaxDepth)) { return nullptr; } nsCOMPtr first; - if (desc->nframes == 0) { + if (!stack) { first = new StackFrame(); } else { - nsRefPtr descOwner = new StackDescriptionOwner(desc); - first = new JSStackFrame(descOwner, 0); + first = new JSStackFrame(stack); } return first.forget(); } From a0954ac75c04f74a0fe1af8545f4808689ae67de Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:16 -0400 Subject: [PATCH 17/38] Bug 857648 part 4. Add a formattedStack attribute on nsIStackFrame. r=khuey --- dom/bindings/Exceptions.cpp | 33 +++++++++++++++++++++++++++++++++ xpcom/base/nsIException.idl | 7 ++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index d4f382382d92..9b709b426e22 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -277,6 +277,7 @@ public: NS_IMETHOD GetFilename(nsAString& aFilename) MOZ_OVERRIDE; NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE; NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE; + NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE; protected: virtual bool IsJSFrame() const MOZ_OVERRIDE { @@ -289,11 +290,13 @@ private: virtual ~JSStackFrame(); JS::Heap mStack; + nsString mFormattedStack; bool mFilenameInitialized; bool mFunnameInitialized; bool mLinenoInitialized; bool mCallerInitialized; + bool mFormattedStackInitialized; }; JSStackFrame::JSStackFrame(JS::Handle aStack) @@ -302,6 +305,7 @@ JSStackFrame::JSStackFrame(JS::Handle aStack) , mFunnameInitialized(false) , mLinenoInitialized(false) , mCallerInitialized(false) + , mFormattedStackInitialized(false) { MOZ_ASSERT(mStack); @@ -495,6 +499,35 @@ NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller) return NS_OK; } +NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack) +{ + if (!mFormattedStackInitialized) { + ThreadsafeAutoJSContext cx; + JS::Rooted stack(cx, JS::ObjectValue(*mStack)); + JS::ExposeObjectToActiveJS(mStack); + JSAutoCompartment ac(cx, mStack); + JS::Rooted formattedStack(cx, JS::ToString(cx, stack)); + if (!formattedStack) { + return NS_ERROR_UNEXPECTED; + } + nsAutoJSString str; + if (!str.init(cx, formattedStack)) { + return NS_ERROR_OUT_OF_MEMORY; + } + mFormattedStack = str; + mFormattedStackInitialized = true; + } + + aStack = mFormattedStack; + return NS_OK; +} + +NS_IMETHODIMP StackFrame::GetFormattedStack(nsAString& aStack) +{ + aStack.Truncate(); + return NS_OK; +} + /* AUTF8String toString (); */ NS_IMETHODIMP StackFrame::ToString(nsACString& _retval) { diff --git a/xpcom/base/nsIException.idl b/xpcom/base/nsIException.idl index 897b7f8fb2f5..f6e9952680d3 100644 --- a/xpcom/base/nsIException.idl +++ b/xpcom/base/nsIException.idl @@ -10,7 +10,7 @@ #include "nsISupports.idl" -[scriptable, uuid(3bc4793f-e6be-44d6-b839-d6b9e85e5346)] +[scriptable, uuid(13b75be1-f950-497b-81e4-a0214a14e5ae)] interface nsIStackFrame : nsISupports { // see nsIProgrammingLanguage for list of language consts @@ -23,6 +23,11 @@ interface nsIStackFrame : nsISupports readonly attribute AUTF8String sourceLine; readonly attribute nsIStackFrame caller; + // Returns a formatted stack string that looks like the sort of + // string that would be returned by .stack on JS Error objects. + // Only works on JS-language stack frames. + readonly attribute AString formattedStack; + AUTF8String toString(); }; From 87884f3b8fcbaa08cd7955fa0f86a2747f69dfdd Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:16 -0400 Subject: [PATCH 18/38] Bug 857648 part 5. Expose a .stack property on DOMExceptions. r=khuey --- .../browser_scratchpad_display_non_error_exceptions.js | 6 ++++-- dom/base/DOMException.cpp | 9 +++++++++ dom/base/DOMException.h | 4 ++++ dom/webidl/DOMException.webidl | 4 ++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js b/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js index 5ff735752bf3..9ea4ccabed15 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js @@ -63,7 +63,8 @@ function runTests() method: "display", code: error4, result: error4 + openComment + "Exception: Node cannot be inserted " + - "at the specified point in the hierarchy\n@1" + closeComment, + "at the specified point in the hierarchy\n@" + + scratchpad.uniqueName + ":1:0" + closeComment, label: "Alternative format error display output" }, { @@ -100,7 +101,8 @@ function runTests() method: "run", code: error4, result: error4 + openComment + "Exception: Node cannot be inserted " + - "at the specified point in the hierarchy\n@1" + closeComment, + "at the specified point in the hierarchy\n@" + + scratchpad.uniqueName + ":1:0" + closeComment, label: "Alternative format error run output" }]; diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp index ea2d36959d90..9b6f8e2c9a96 100644 --- a/dom/base/DOMException.cpp +++ b/dom/base/DOMException.cpp @@ -22,6 +22,7 @@ #include "xpcprivate.h" #include "mozilla/dom/DOMExceptionBinding.h" +#include "mozilla/ErrorResult.h" using namespace mozilla; @@ -553,6 +554,14 @@ Exception::GetData() const return data.forget(); } +void +Exception::GetStack(nsAString& aStack, ErrorResult& aRv) const +{ + if (mLocation) { + aRv = mLocation->GetFormattedStack(aStack); + } +} + void Exception::Stringify(nsString& retval) { diff --git a/dom/base/DOMException.h b/dom/base/DOMException.h index 87e614484e56..230bdc46ea5c 100644 --- a/dom/base/DOMException.h +++ b/dom/base/DOMException.h @@ -32,6 +32,8 @@ NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName, uint16_t* aCode = nullptr); namespace mozilla { +class ErrorResult; + namespace dom { #define MOZILLA_EXCEPTION_IID \ @@ -81,6 +83,8 @@ public: already_AddRefed GetData() const; + void GetStack(nsAString& aStack, ErrorResult& aRv) const; + void Stringify(nsString& retval); // XPCOM factory ctor. diff --git a/dom/webidl/DOMException.webidl b/dom/webidl/DOMException.webidl index 58da190a07db..d039cfc1d645 100644 --- a/dom/webidl/DOMException.webidl +++ b/dom/webidl/DOMException.webidl @@ -56,6 +56,10 @@ interface ExceptionMembers // Arbitary data for the implementation. readonly attribute nsISupports? data; + + // Formatted exception stack + [Throws, Replaceable] + readonly attribute DOMString stack; }; [NoInterfaceObject] From 2a55c83f058c282b1543d062d734e587874f3e88 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 4 Jul 2014 01:25:30 -0400 Subject: [PATCH 19/38] Bug 857648 part 6. Remove the now-unused JS::DescribeStack API. r=jimb --- js/public/OldDebugAPI.h | 63 ------------------------------- js/src/vm/OldDebugAPI.cpp | 79 --------------------------------------- 2 files changed, 142 deletions(-) diff --git a/js/public/OldDebugAPI.h b/js/public/OldDebugAPI.h index 9e67bb466ca8..9b604f71078b 100644 --- a/js/public/OldDebugAPI.h +++ b/js/public/OldDebugAPI.h @@ -37,69 +37,6 @@ JS_GetScriptFilename(JSScript *script); namespace JS { -class FrameDescription -{ - public: - explicit FrameDescription(const js::FrameIter& iter); - FrameDescription(const FrameDescription &rhs); - ~FrameDescription(); - - unsigned lineno() { - if (!linenoComputed_) { - lineno_ = JS_PCToLineNumber(nullptr, script_, pc_); - linenoComputed_ = true; - } - return lineno_; - } - - const char *filename() const { - return filename_; - } - - JSFlatString *funDisplayName() const { - return funDisplayName_ ? JS_ASSERT_STRING_IS_FLAT(funDisplayName_) : nullptr; - } - - // Both these locations should be traced during GC but otherwise not used; - // they are implementation details. - Heap &markedLocation1() { - return script_; - } - Heap &markedLocation2() { - return funDisplayName_; - } - - private: - void operator=(const FrameDescription &) MOZ_DELETE; - - // These fields are always initialized: - Heap funDisplayName_; - const char *filename_; - - // One of script_ xor scriptSource_ is non-null. - Heap script_; - js::ScriptSource *scriptSource_; - - // For script_-having frames, lineno_ is lazily computed as an optimization. - bool linenoComputed_; - unsigned lineno_; - - // pc_ is non-null iff script_ is non-null. If !pc_, linenoComputed_ = true. - jsbytecode *pc_; -}; - -struct StackDescription -{ - unsigned nframes; - FrameDescription *frames; -}; - -extern JS_PUBLIC_API(StackDescription *) -DescribeStack(JSContext *cx, unsigned maxFrames); - -extern JS_PUBLIC_API(void) -FreeStackDescription(JSContext *cx, StackDescription *desc); - extern JS_PUBLIC_API(char *) FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps); diff --git a/js/src/vm/OldDebugAPI.cpp b/js/src/vm/OldDebugAPI.cpp index 260b1bb77335..234f4a6a0de4 100644 --- a/js/src/vm/OldDebugAPI.cpp +++ b/js/src/vm/OldDebugAPI.cpp @@ -895,85 +895,6 @@ js_CallContextDebugHandler(JSContext *cx) } } -/* - * A contructor that crates a FrameDescription from a ScriptFrameIter, to avoid - * constructing a FrameDescription on the stack just to append it to a vector. - * FrameDescription contains Heap fields that should not live on the stack. - */ -JS::FrameDescription::FrameDescription(const FrameIter& iter) - : scriptSource_(nullptr), - linenoComputed_(false), - pc_(nullptr) -{ - if (iter.isNonEvalFunctionFrame()) - funDisplayName_ = iter.functionDisplayAtom(); - - if (iter.hasScript()) { - script_ = iter.script(); - pc_ = iter.pc(); - filename_ = script_->filename(); - } else { - scriptSource_ = iter.scriptSource(); - scriptSource_->incref(); - filename_ = scriptSource_->filename(); - lineno_ = iter.computeLine(); - linenoComputed_ = true; - } -} - -JS::FrameDescription::FrameDescription(const FrameDescription &rhs) - : funDisplayName_(rhs.funDisplayName_), - filename_(rhs.filename_), - script_(rhs.script_), - scriptSource_(rhs.scriptSource_), - linenoComputed_(rhs.linenoComputed_), - lineno_(rhs.lineno_), - pc_(rhs.pc_) -{ - if (scriptSource_) - scriptSource_->incref(); -} - - -JS::FrameDescription::~FrameDescription() -{ - if (scriptSource_) - scriptSource_->decref(); -} - -JS_PUBLIC_API(JS::StackDescription *) -JS::DescribeStack(JSContext *cx, unsigned maxFrames) -{ - Vector frames(cx); - - NonBuiltinFrameIter i(cx, FrameIter::ALL_CONTEXTS, - FrameIter::GO_THROUGH_SAVED, - cx->compartment()->principals); - for ( ; !i.done(); ++i) { - if (!frames.append(i)) - return nullptr; - if (frames.length() == maxFrames) - break; - } - - JS::StackDescription *desc = js_new(); - if (!desc) - return nullptr; - - desc->nframes = frames.length(); - desc->frames = frames.extractRawBuffer(); - return desc; -} - -JS_PUBLIC_API(void) -JS::FreeStackDescription(JSContext *cx, JS::StackDescription *desc) -{ - for (size_t i = 0; i < desc->nframes; ++i) - desc->frames[i].~FrameDescription(); - js_free(desc->frames); - js_delete(desc); -} - namespace { class AutoPropertyDescArray From 5a2a8aca751632d5a219544af6148029bce37acf Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 14 Jul 2014 10:44:06 -0400 Subject: [PATCH 20/38] Backed out changeset 28664fb86b3c (bug 1036847) for causing frequent OSX mochitest timeouts. --- dom/apps/tests/file_packaged_app.sjs | 30 +---- dom/apps/tests/test_packaged_app_common.js | 8 +- dom/apps/tests/test_packaged_app_install.html | 108 +++--------------- 3 files changed, 24 insertions(+), 122 deletions(-) diff --git a/dom/apps/tests/file_packaged_app.sjs b/dom/apps/tests/file_packaged_app.sjs index 90ff6cb133cc..9e0e44842ea6 100644 --- a/dom/apps/tests/file_packaged_app.sjs +++ b/dom/apps/tests/file_packaged_app.sjs @@ -20,23 +20,12 @@ var gDevUrl = "http://dev.url"; function handleRequest(request, response) { var query = getQuery(request); + response.setHeader("Access-Control-Allow-Origin", "*", false); + var packageSize = ("packageSize" in query) ? query.packageSize : 0; var appName = ("appName" in query) ? query.appName : gAppName; var devName = ("devName" in query) ? query.devName : gDevName; var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl; - // allowCancel just means deliver the file slowly so we have time to cancel it - var allowCancel = "allowCancel" in query; - var getPackage = "getPackage" in query; - var alreadyDeferred = Number(getState("alreadyDeferred")); - - if (allowCancel && getPackage && !alreadyDeferred) { - // Only do this for the actual package delivery. - response.processAsync(); - // And to avoid timer problems, only do this once. - setState("alreadyDeferred", "1"); - } - - response.setHeader("Access-Control-Allow-Origin", "*", false); // If this is a version update, update state, prepare the manifest, // the application package and return. @@ -47,8 +36,7 @@ function handleRequest(request, response) { var packageName = "test_packaged_app_" + packageVersion + ".zip"; setState("packageName", packageName); - var packagePath = "/" + gBasePath + "file_packaged_app.sjs?" + - (allowCancel?"allowCancel&": "") + "getPackage=" + + var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" + packageName; setState("packagePath", packagePath); @@ -96,19 +84,11 @@ function handleRequest(request, response) { response.setHeader("Etag", etag, false); // Serve the application package corresponding to the requested app version. - if (getPackage) { + if ("getPackage" in query) { var resource = readFile(packageName, true); response.setHeader("Content-Type", "Content-Type: application/java-archive", false); - if (allowCancel && !alreadyDeferred) { - var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.initWithCallback(function (aTimer) { - response.write(resource); - response.finish(); - }, 3000, Ci.nsITimer.TYPE_ONE_SHOT); - } else { - response.write(resource); - } + response.write(resource); return; } diff --git a/dom/apps/tests/test_packaged_app_common.js b/dom/apps/tests/test_packaged_app_common.js index abcdeacf6008..9a0bddbff4c3 100644 --- a/dom/apps/tests/test_packaged_app_common.js +++ b/dom/apps/tests/test_packaged_app_common.js @@ -57,17 +57,13 @@ var PackagedTestHelper = (function PackagedTestHelper() { finish(); } - function setAppVersion(aVersion, aCb, aDontUpdatePackage, aAllowCancel) { + function setAppVersion(aVersion, aCb, aDontUpdatePackage) { var xhr = new XMLHttpRequest(); var dontUpdate = ""; - var allowCancel = ""; if (aDontUpdatePackage) { dontUpdate = "&dontUpdatePackage=1"; } - if (aAllowCancel) { - allowCancel= "&allowCancel=1"; - } - var url = gSJS + "?setVersion=" + aVersion + dontUpdate + allowCancel; + var url = gSJS + "?setVersion=" + aVersion + dontUpdate; xhr.addEventListener("load", function() { is(xhr.responseText, "OK", "setAppVersion OK"); aCb(); diff --git a/dom/apps/tests/test_packaged_app_install.html b/dom/apps/tests/test_packaged_app_install.html index 2b6bc91a7cb8..e3f40b7967f1 100644 --- a/dom/apps/tests/test_packaged_app_install.html +++ b/dom/apps/tests/test_packaged_app_install.html @@ -34,7 +34,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) { req.onerror = function(evt) { var error = evt.target.error.name; if (error == aExpectedError) { - info("Got expected " + aExpectedError); + ok(true, "Got expected " + aExpectedError); PackagedTestHelper.next(); } else { ok(false, "Got unexpected " + error); @@ -46,7 +46,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) { function checkUninstallApp(aApp) { var req = navigator.mozApps.mgmt.uninstall(aApp); req.onsuccess = function() { - info("App uninstalled"); + ok(true, "App uninstalled"); aApp.ondownloadsuccess = null; aApp.ondownloaderror = null; aApp.onprogress = null; @@ -83,11 +83,11 @@ var steps = [ // Set up SpecialPowers.setAllAppsLaunchable(true); SpecialPowers.addPermission("webapps-manage", true, document); - info("Set up"); + ok(true, "Set up"); PackagedTestHelper.next(); }, function() { - info("autoConfirmAppInstall"); + ok(true, "autoConfirmAppInstall"); SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next); }, function() { @@ -96,17 +96,17 @@ var steps = [ function() { // Bug 927699 - navigator.mozApps.install(url) lets NS_ERROR_FAILURE onto // the web. - info("== TEST == INVALID_URL"); + ok(true, "== TEST == INVALID_URL"); checkAppInstallError("", "INVALID_URL"); }, function() { // Test network error. - info("== TEST == Network error"); + ok(true, "== TEST == Network error"); checkAppInstallError("http://notvalidurl", "NETWORK_ERROR"); }, function() { // Test wrong mini-manifest content type. - info("== TEST == Not valid mini-manifest content type"); + ok(true, "== TEST == Not valid mini-manifest content type"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&noManifestContentType=true"; @@ -114,7 +114,7 @@ var steps = [ }, function() { // Test mini-manifest 'size' value is not number. Bug 839435. - info("== TEST == Size value is not a number"); + ok(true, "== TEST == Size value is not a number"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&packageSize=\"NotANumber\""; @@ -122,7 +122,7 @@ var steps = [ }, function() { // Test mini-manifest negative 'size' value. Bug 839435. - info("== TEST == Negative size value"); + ok(true, "== TEST == Negative size value"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&packageSize=-1"; @@ -130,7 +130,7 @@ var steps = [ }, function() { // Test wrong package path - info("== TEST == Installing app with wrong package path"); + ok(true, "== TEST == Installing app with wrong package path"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&wrongPackagePath=true"; @@ -138,7 +138,7 @@ var steps = [ }, function() { // Test no manifest in zip file. - info("== TEST == No manifest in the zip file"); + ok(true, "== TEST == No manifest in the zip file"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true"; PackagedTestHelper.checkAppDownloadError(miniManifestURL, "MISSING_MANIFEST", 0, true, true, @@ -150,7 +150,7 @@ var steps = [ function() { // Test mini-manifest app name is different from the webapp manifest name. // Bug 844243. - info("== TEST == Mini-manifest app name is different from webapp " + + ok(true, "== TEST == Mini-manifest app name is different from webapp " + "manifest name"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + @@ -187,11 +187,11 @@ var steps = [ PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next); }, function() { - info("== TEST == Install packaged app"); + ok(true, "== TEST == Install packaged app"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true"; navigator.mozApps.mgmt.oninstall = function(evt) { - info("Got oninstall event"); + ok(true, "Got oninstall event"); PackagedTestHelper.gApp = evt.application; PackagedTestHelper.gApp.ondownloaderror = function() { ok(false, "Download error " + @@ -199,7 +199,7 @@ var steps = [ PackagedTestHelper.finish(); }; PackagedTestHelper.gApp.ondownloadsuccess = function() { - info("App downloaded"); + ok(true, "App downloaded"); var expected = { name: PackagedTestHelper.gAppName, manifestURL: miniManifestURL, @@ -220,85 +220,11 @@ var steps = [ var request = navigator.mozApps.installPackage(miniManifestURL); request.onerror = PackagedTestHelper.mozAppsError; request.onsuccess = function() { - info("Application installed"); + ok(true, "Application installed"); }; }, function() { - PackagedTestHelper.setAppVersion(3, PackagedTestHelper.next, false, true); - }, - function() { - info("== TEST == Install packaged app with a cancel/resume"); - var miniManifestURL = PackagedTestHelper.gSJS + - "?getManifest=true&allowCancel"; - navigator.mozApps.mgmt.oninstall = function(evt) { - info("Got oninstall event"); - PackagedTestHelper.gApp = evt.application; - - PackagedTestHelper.gApp.onprogress = function() { - // Let's try cancelling and resuming the download later on. - PackagedTestHelper.gApp.cancelDownload(); - // And only do this once. - PackagedTestHelper.gApp.onprogress = null; - }; - - var alreadyCancelled = false; - PackagedTestHelper.gApp.ondownloaderror = function() { - ok(!alreadyCancelled, "The download should be cancelled only once!"); - is(PackagedTestHelper.gApp.downloadError.name, "DOWNLOAD_CANCELED", - "Download error " + PackagedTestHelper.gApp.downloadError.name); - if (!alreadyCancelled) { - PackagedTestHelper.gApp.download(); - alreadyCancelled = true; - } - }; - - PackagedTestHelper.gApp.ondownloadsuccess = function() { - info("App downloaded"); - // We could try also applying the download we just made. - var expected = { - name: PackagedTestHelper.gAppName, - manifestURL: miniManifestURL, - installOrigin: PackagedTestHelper.gInstallOrigin, - progress: 0, - installState: "pending", - downloadAvailable: false, - downloading: false, - downloadSize: 0, - size: 0, - readyToApplyDownload: true - }; - PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected, - true, false, function() {}); - }; - - PackagedTestHelper.gApp.ondownloadapplied = function() { - info("App download applied."); - var expected = { - name: PackagedTestHelper.gAppName, - manifestURL: miniManifestURL, - installOrigin: PackagedTestHelper.gInstallOrigin, - progress: 0, - installState: "installed", - downloadAvailable: false, - downloading: false, - downloadSize: 0, - size: 0, - readyToApplyDownload: false - }; - PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected, - true, false, PackagedTestHelper.next); - } - - }; - - var request = navigator.mozApps.installPackage(miniManifestURL); - request.onerror = PackagedTestHelper.mozAppsError; - request.onsuccess = function() { - info("Application installed"); - }; - }, - function() { - info("all done!\n"); + ok(true, "all done!\n"); PackagedTestHelper.finish(); } ]; From d4944c4aec5e5516e49bea6ddbf99926695bba83 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Mon, 14 Jul 2014 07:59:12 -0700 Subject: [PATCH 21/38] No bug - Remove unnecessary line in browser_uriFixupIntegration.js DONTBUILD --- docshell/test/browser/browser_uriFixupIntegration.js | 1 - 1 file changed, 1 deletion(-) diff --git a/docshell/test/browser/browser_uriFixupIntegration.js b/docshell/test/browser/browser_uriFixupIntegration.js index a9ecc1e6e2ce..765954091dff 100644 --- a/docshell/test/browser/browser_uriFixupIntegration.js +++ b/docshell/test/browser/browser_uriFixupIntegration.js @@ -5,7 +5,6 @@ const Cc = Components.classes; const Ci = Components.interfaces; const kSearchEngineID = "browser_urifixup_search_engine"; -const kTest const kSearchEngineURL = "http://example.com/?search={searchTerms}"; Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get", kSearchEngineURL); From f9be4e4d22f01bbadee52fab3e18bf496f7f528a Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Wed, 9 Jul 2014 18:06:12 -0400 Subject: [PATCH 22/38] bug 1037082 - part 1/3 dont doauthretry with closed persistent connection r=hurley --- netwerk/protocol/http/nsHttpConnection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 1dfc61198b21..18b9a01f68e7 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -123,7 +123,7 @@ public: nsIAsyncInputStream **, nsIAsyncOutputStream **); void GetSecurityInfo(nsISupports **); - bool IsPersistent() { return IsKeepAlive(); } + bool IsPersistent() { return IsKeepAlive() && !mDontReuse; } bool IsReused(); void SetIsReusedAfter(uint32_t afterMilliseconds); nsresult PushBack(const char *data, uint32_t length); From 57387b318afe7f59f44fc693654deaa08f02186d Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Tue, 24 Jun 2014 16:52:48 -0400 Subject: [PATCH 23/38] bug 1037082 - part 2/3 407 proxy auth for http over https r=hurley --- netwerk/protocol/http/nsHttpChannelAuthProvider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.h b/netwerk/protocol/http/nsHttpChannelAuthProvider.h index c402cb08af64..256706097d8b 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.h +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.h @@ -48,7 +48,7 @@ private: bool UsingSSL() const { return mUsingSSL; } bool UsingHttpProxy() const - { return !!(mProxyInfo && !nsCRT::strcmp(mProxyInfo->Type(), "http")); } + { return mProxyInfo && (mProxyInfo->IsHTTP() || mProxyInfo->IsHTTPS()); } nsresult PrepareForAuthentication(bool proxyAuth); nsresult GenCredsAndSetEntry(nsIHttpAuthenticator *, bool proxyAuth, From 29d2ce2ffee830e3e0bf285294a7a0da15e99258 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Mon, 7 Jul 2014 11:43:11 -0400 Subject: [PATCH 24/38] bug 1037082 - part 3/3 407 proxy auth for https over https r=hurley --- netwerk/protocol/http/Http2Session.cpp | 17 ++++-- netwerk/protocol/http/Http2Stream.cpp | 26 +++++++-- netwerk/protocol/http/Http2Stream.h | 2 + netwerk/protocol/http/SpdySession3.cpp | 17 ++++-- netwerk/protocol/http/SpdySession31.cpp | 17 ++++-- netwerk/protocol/http/SpdyStream3.cpp | 30 +++++++--- netwerk/protocol/http/SpdyStream3.h | 2 + netwerk/protocol/http/SpdyStream31.cpp | 30 +++++++--- netwerk/protocol/http/SpdyStream31.h | 2 + netwerk/protocol/http/TunnelUtils.cpp | 58 +++++++++++++++++-- netwerk/protocol/http/TunnelUtils.h | 7 ++- netwerk/protocol/http/nsHttpConnection.cpp | 3 +- netwerk/protocol/http/nsHttpConnection.h | 8 +++ netwerk/protocol/http/nsHttpConnectionMgr.cpp | 15 ++++- netwerk/protocol/http/nsHttpConnectionMgr.h | 6 ++ netwerk/protocol/http/nsHttpTransaction.h | 1 + 16 files changed, 189 insertions(+), 52 deletions(-) diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index bf809c7ccbde..644c1781c36f 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -2858,10 +2858,14 @@ Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, // this transaction has done its work of setting up a tunnel, let // the connection manager queue it if necessary trans->SetDontRouteViaWildCard(true); + trans->EnableKeepAlive(); if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) { LOG3(("Http2Session::DispatchOnTunnel %p create on new tunnel %s", this, ci->HashKey().get())); + // The connect transaction will hold onto the underlying http + // transaction so that an auth created by the connect can be mappped + // to the correct security callbacks nsRefPtr connectTrans = new SpdyConnectTransaction(ci, aCallbacks, trans->Caps(), trans, this); @@ -2870,13 +2874,14 @@ Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, Http2Stream *tunnel = mStreamTransactionHash.Get(connectTrans); MOZ_ASSERT(tunnel); RegisterTunnel(tunnel); + } else { + // requeue it. The connection manager is responsible for actually putting + // this on the tunnel connection with the specific ci now that it + // has DontRouteViaWildCard set. + LOG3(("Http2Session::DispatchOnTunnel %p trans=%p queue in connection manager", + this, trans)); + gHttpHandler->InitiateTransaction(trans, trans->Priority()); } - - // requeue it. The connection manager is responsible for actually putting - // this on the tunnel connection with the specific ci now that it - // has DontRouteViaWildCard set. - trans->EnableKeepAlive(); - gHttpHandler->InitiateTransaction(trans, trans->Priority()); } diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 43bc1e30c371..afa9e97c02fd 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -69,6 +69,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction, , mTotalRead(0) , mPushSource(nullptr) , mIsTunnel(false) + , mPlainTextTunnel(false) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); @@ -219,7 +220,7 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader, } // WriteSegments() is used to read data off the socket. Generally this is -// just a call through to the associate nsHttpTransaciton for this stream +// just a call through to the associated nsHttpTransaction for this stream // for the remaining data bytes indicated by the current DATA frame. nsresult @@ -862,9 +863,11 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor, if (mIsTunnel) { nsresult errcode; - if (status.ToInteger(&errcode) != 200) { - LOG3(("Http2Stream %p Tunnel not 200", this)); - return NS_ERROR_ABORT; + + int32_t code = status.ToInteger(&errcode); + LOG3(("Http2Stream %p Tunnel Response code %d", this, code)); + if ((code / 100) != 2) { + MapStreamToPlainText(); } } @@ -875,12 +878,14 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor, Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio); } + // The decoding went ok. Now we can customize and clean up. + aHeadersIn.Truncate(); aHeadersOut.Append("X-Firefox-Spdy: " NS_HTTP2_DRAFT_TOKEN "\r\n\r\n"); LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading())); - if (mIsTunnel) { + if (mIsTunnel && !mPlainTextTunnel) { aHeadersOut.Truncate(); - LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n", + LOG(("Http2Stream::ConvertHeaders %p 0x%X headers removed for tunnel\n", this, mStreamID)); } return NS_OK; @@ -1201,6 +1206,15 @@ Http2Stream::ClearTransactionsBlockedOnTunnel() gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo()); } +void +Http2Stream::MapStreamToPlainText() +{ + nsRefPtr qiTrans(mTransaction->QuerySpdyConnectTransaction()); + MOZ_ASSERT(qiTrans); + mPlainTextTunnel = true; + qiTrans->ForcePlainText(); +} + void Http2Stream::MapStreamToHttpConnection() { diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h index 1c0d7cf0a7e6..ef6fa3e11009 100644 --- a/netwerk/protocol/http/Http2Stream.h +++ b/netwerk/protocol/http/Http2Stream.h @@ -281,9 +281,11 @@ public: bool IsTunnel() { return mIsTunnel; } private: void ClearTransactionsBlockedOnTunnel(); + void MapStreamToPlainText(); void MapStreamToHttpConnection(); bool mIsTunnel; + bool mPlainTextTunnel; }; } // namespace mozilla::net diff --git a/netwerk/protocol/http/SpdySession3.cpp b/netwerk/protocol/http/SpdySession3.cpp index 519df398df27..4b934c526079 100644 --- a/netwerk/protocol/http/SpdySession3.cpp +++ b/netwerk/protocol/http/SpdySession3.cpp @@ -2527,10 +2527,14 @@ SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, // this transaction has done its work of setting up a tunnel, let // the connection manager queue it if necessary trans->SetDontRouteViaWildCard(true); + trans->EnableKeepAlive(); if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) { LOG3(("SpdySession3::DispatchOnTunnel %p create on new tunnel %s", this, ci->HashKey().get())); + // The connect transaction will hold onto the underlying http + // transaction so that an auth created by the connect can be mappped + // to the correct security callbacks nsRefPtr connectTrans = new SpdyConnectTransaction(ci, aCallbacks, trans->Caps(), trans, this); @@ -2539,13 +2543,14 @@ SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, SpdyStream3 *tunnel = mStreamTransactionHash.Get(connectTrans); MOZ_ASSERT(tunnel); RegisterTunnel(tunnel); + } else { + // requeue it. The connection manager is responsible for actually putting + // this on the tunnel connection with the specific ci now that it + // has DontRouteViaWildCard set. + LOG3(("SpdySession3::DispatchOnTunnel %p trans=%p queue in connection manager", + this, trans)); + gHttpHandler->InitiateTransaction(trans, trans->Priority()); } - - // requeue it. The connection manager is responsible for actually putting - // this on the tunnel connection with the specific ci now that it - // has DontRouteViaWildCard set. - trans->EnableKeepAlive(); - gHttpHandler->InitiateTransaction(trans, trans->Priority()); } //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp index ea7c29901084..f9f9d4874197 100644 --- a/netwerk/protocol/http/SpdySession31.cpp +++ b/netwerk/protocol/http/SpdySession31.cpp @@ -2659,10 +2659,14 @@ SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, // this transaction has done its work of setting up a tunnel, let // the connection manager queue it if necessary trans->SetDontRouteViaWildCard(true); + trans->EnableKeepAlive(); if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) { LOG3(("SpdySession31::DispatchOnTunnel %p create on new tunnel %s", this, ci->HashKey().get())); + // The connect transaction will hold onto the underlying http + // transaction so that an auth created by the connect can be mappped + // to the correct security callbacks nsRefPtr connectTrans = new SpdyConnectTransaction(ci, aCallbacks, trans->Caps(), trans, this); @@ -2671,13 +2675,14 @@ SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction, SpdyStream31 *tunnel = mStreamTransactionHash.Get(connectTrans); MOZ_ASSERT(tunnel); RegisterTunnel(tunnel); + } else { + // requeue it. The connection manager is responsible for actually putting + // this on the tunnel connection with the specific ci now that it + // has DontRouteViaWildCard set. + LOG3(("SpdySession31::DispatchOnTunnel %p trans=%p queue in connection manager", + this, trans)); + gHttpHandler->InitiateTransaction(trans, trans->Priority()); } - - // requeue it. The connection manager is responsible for actually putting - // this on the tunnel connection with the specific ci now that it - // has DontRouteViaWildCard set. - trans->EnableKeepAlive(); - gHttpHandler->InitiateTransaction(trans, trans->Priority()); } nsresult diff --git a/netwerk/protocol/http/SpdyStream3.cpp b/netwerk/protocol/http/SpdyStream3.cpp index 3599ec2f0cba..609313a026cd 100644 --- a/netwerk/protocol/http/SpdyStream3.cpp +++ b/netwerk/protocol/http/SpdyStream3.cpp @@ -72,6 +72,7 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction, , mTotalRead(0) , mPushSource(nullptr) , mIsTunnel(false) + , mPlainTextTunnel(false) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); @@ -194,7 +195,7 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader, } // WriteSegments() is used to read data off the socket. Generally this is -// just a call through to the associate nsHttpTransaciton for this stream +// just a call through to the associated nsHttpTransaction for this stream // for the remaining data bytes indicated by the current DATA frame. nsresult @@ -1277,6 +1278,8 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut) nvpair += 4; } while (lastHeaderByte >= nvpair); + // The decoding went ok. Now we can customize and clean up. + aHeadersOut.AppendLiteral("X-Firefox-Spdy: 3\r\n\r\n"); LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading())); @@ -1286,7 +1289,7 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut) mDecompressBufferSize = 0; mDecompressBufferUsed = 0; - if (mIsTunnel) { + if (mIsTunnel && !mPlainTextTunnel) { aHeadersOut.Truncate(); LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n", this, mStreamID)); @@ -1371,18 +1374,18 @@ SpdyStream3::SetFullyOpen() MOZ_ASSERT(!mFullyOpen); mFullyOpen = 1; if (mIsTunnel) { + int32_t code = 0; nsDependentCSubstring statusSubstring; - nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), - statusSubstring); + nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), statusSubstring); if (NS_SUCCEEDED(rv)) { nsCString status(statusSubstring); nsresult errcode; + code = status.ToInteger(&errcode); + } - if (status.ToInteger(&errcode) != 200) { - LOG3(("SpdyStream3::SetFullyOpen %p Tunnel not 200", this)); - return NS_ERROR_FAILURE; - } - LOG3(("SpdyStream3::SetFullyOpen %p Tunnel 200 OK", this)); + LOG3(("SpdyStream3::SetFullyOpen %p Tunnel Response code %d", this, code)); + if ((code / 100) != 2) { + MapStreamToPlainText(); } MapStreamToHttpConnection(); @@ -1561,6 +1564,15 @@ SpdyStream3::ClearTransactionsBlockedOnTunnel() gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo()); } +void +SpdyStream3::MapStreamToPlainText() +{ + nsRefPtr qiTrans(mTransaction->QuerySpdyConnectTransaction()); + MOZ_ASSERT(qiTrans); + mPlainTextTunnel = true; + qiTrans->ForcePlainText(); +} + void SpdyStream3::MapStreamToHttpConnection() { diff --git a/netwerk/protocol/http/SpdyStream3.h b/netwerk/protocol/http/SpdyStream3.h index d788fa5cdf01..b4ed01c8b52f 100644 --- a/netwerk/protocol/http/SpdyStream3.h +++ b/netwerk/protocol/http/SpdyStream3.h @@ -257,9 +257,11 @@ public: bool IsTunnel() { return mIsTunnel; } private: void ClearTransactionsBlockedOnTunnel(); + void MapStreamToPlainText(); void MapStreamToHttpConnection(); bool mIsTunnel; + bool mPlainTextTunnel; }; }} // namespace mozilla::net diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp index ad1a9264a6f4..d66c87ed7b76 100644 --- a/netwerk/protocol/http/SpdyStream31.cpp +++ b/netwerk/protocol/http/SpdyStream31.cpp @@ -70,6 +70,7 @@ SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction, , mTotalRead(0) , mPushSource(nullptr) , mIsTunnel(false) + , mPlainTextTunnel(false) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); @@ -199,7 +200,7 @@ SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader, } // WriteSegments() is used to read data off the socket. Generally this is -// just a call through to the associate nsHttpTransaciton for this stream +// just a call through to the associated nsHttpTransaction for this stream // for the remaining data bytes indicated by the current DATA frame. nsresult @@ -1293,6 +1294,8 @@ SpdyStream31::ConvertHeaders(nsACString &aHeadersOut) nvpair += 4; } while (lastHeaderByte >= nvpair); + // The decoding went ok. Now we can customize and clean up. + aHeadersOut.AppendLiteral("X-Firefox-Spdy: 3.1\r\n\r\n"); LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading())); @@ -1302,7 +1305,7 @@ SpdyStream31::ConvertHeaders(nsACString &aHeadersOut) mDecompressBufferSize = 0; mDecompressBufferUsed = 0; - if (mIsTunnel) { + if (mIsTunnel && !mPlainTextTunnel) { aHeadersOut.Truncate(); LOG(("SpdyStream31::ConvertHeaders %p 0x%X headers removed for tunnel\n", this, mStreamID)); @@ -1385,18 +1388,18 @@ SpdyStream31::SetFullyOpen() MOZ_ASSERT(!mFullyOpen); mFullyOpen = 1; if (mIsTunnel) { + int32_t code = 0; nsDependentCSubstring statusSubstring; - nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), - statusSubstring); + nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), statusSubstring); if (NS_SUCCEEDED(rv)) { nsCString status(statusSubstring); nsresult errcode; + code = status.ToInteger(&errcode); + } - if (status.ToInteger(&errcode) != 200) { - LOG3(("SpdyStream31::SetFullyOpen %p Tunnel not 200", this)); - return NS_ERROR_FAILURE; - } - LOG3(("SpdyStream31::SetFullyOpen %p Tunnel 200 OK", this)); + LOG3(("SpdyStream31::SetFullyOpen %p Tunnel Response code %d", this, code)); + if ((code / 100) != 2) { + MapStreamToPlainText(); } MapStreamToHttpConnection(); @@ -1585,6 +1588,15 @@ SpdyStream31::ClearTransactionsBlockedOnTunnel() gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo()); } +void +SpdyStream31::MapStreamToPlainText() +{ + nsRefPtr qiTrans(mTransaction->QuerySpdyConnectTransaction()); + MOZ_ASSERT(qiTrans); + mPlainTextTunnel = true; + qiTrans->ForcePlainText(); +} + void SpdyStream31::MapStreamToHttpConnection() { diff --git a/netwerk/protocol/http/SpdyStream31.h b/netwerk/protocol/http/SpdyStream31.h index bbfbfe5591ab..77d12c8b2222 100644 --- a/netwerk/protocol/http/SpdyStream31.h +++ b/netwerk/protocol/http/SpdyStream31.h @@ -252,9 +252,11 @@ public: bool IsTunnel() { return mIsTunnel; } private: void ClearTransactionsBlockedOnTunnel(); + void MapStreamToPlainText(); void MapStreamToHttpConnection(); bool mIsTunnel; + bool mPlainTextTunnel; }; }} // namespace mozilla::net diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp index f6551b20dd98..3de5e3c1c721 100644 --- a/netwerk/protocol/http/TunnelUtils.cpp +++ b/netwerk/protocol/http/TunnelUtils.cpp @@ -15,6 +15,7 @@ #include "nsISocketProviderService.h" #include "nsISSLSocketControl.h" #include "nsISocketTransport.h" +#include "nsISupportsPriority.h" #include "nsNetAddr.h" #include "prerror.h" #include "prio.h" @@ -825,7 +826,7 @@ private: SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci, nsIInterfaceRequestor *callbacks, uint32_t caps, - nsAHttpTransaction *trans, + nsHttpTransaction *trans, nsAHttpConnection *session) : NullHttpTransaction(ci, callbacks, caps | NS_HTTP_ALLOW_KEEPALIVE) , mConnectStringOffset(0) @@ -837,12 +838,14 @@ SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci, , mOutputDataSize(0) , mOutputDataUsed(0) , mOutputDataOffset(0) + , mForcePlainText(false) { LOG(("SpdyConnectTransaction ctor %p\n", this)); mTimestampSyn = TimeStamp::Now(); mRequestHead = new nsHttpRequestHead(); nsHttpConnection::MakeConnectString(trans, mRequestHead, mConnectString); + mDrivingTransaction = trans; } SpdyConnectTransaction::~SpdyConnectTransaction() @@ -851,6 +854,24 @@ SpdyConnectTransaction::~SpdyConnectTransaction() if (mRequestHead) { delete mRequestHead; } + + if (mDrivingTransaction) { + // requeue it I guess. This should be gone. + gHttpHandler->InitiateTransaction(mDrivingTransaction, + mDrivingTransaction->Priority()); + } +} + +void +SpdyConnectTransaction::ForcePlainText() +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + MOZ_ASSERT(!mInputDataUsed && !mInputDataSize && !mInputDataOffset); + MOZ_ASSERT(!mForcePlainText); + MOZ_ASSERT(!mTunnelTransport, "call before mapstreamtohttpconnection"); + + mForcePlainText = true; + return; } void @@ -880,10 +901,23 @@ SpdyConnectTransaction::MapStreamToHttpConnection(nsISocketTransport *aTransport true, callbacks, PR_MillisecondsToInterval( static_cast(rtt.ToMilliseconds()))); - mTunneledConn->SetupSecondaryTLS(); - mTunneledConn->SetInSpdyTunnel(true); + if (mForcePlainText) { + mTunneledConn->ForcePlainText(); + } else { + mTunneledConn->SetupSecondaryTLS(); + mTunneledConn->SetInSpdyTunnel(true); + } - gHttpHandler->ConnMgr()->ReclaimConnection(mTunneledConn); + // make the originating transaction stick to the tunneled conn + nsRefPtr wrappedConn = + gHttpHandler->ConnMgr()->MakeConnectionHandle(mTunneledConn); + mDrivingTransaction->SetConnection(wrappedConn); + mDrivingTransaction->MakeSticky(); + + // jump the priority and start the dispatcher + gHttpHandler->InitiateTransaction( + mDrivingTransaction, nsISupportsPriority::PRIORITY_HIGHEST - 60); + mDrivingTransaction = nullptr; } nsresult @@ -933,7 +967,8 @@ SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader, uint32_t *countRead) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - LOG(("SpdyConnectTransaction::ReadSegments %p count %d\n", this, count)); + LOG(("SpdyConnectTransaction::ReadSegments %p count %d conn %p\n", + this, count, mTunneledConn.get())); mSegmentReader = reader; @@ -962,6 +997,17 @@ SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader, return NS_BASE_STREAM_WOULD_BLOCK; } + if (mForcePlainText) { + // this path just ignores sending the request so that we can + // send a synthetic reply in writesegments() + LOG(("SpdyConnectTransaciton::ReadSegments %p dropping %d output bytes " + "due to synthetic reply\n", this, mOutputDataUsed - mOutputDataOffset)); + *countRead = mOutputDataUsed - mOutputDataOffset; + mOutputDataOffset = mOutputDataUsed = 0; + mTunneledConn->DontReuse(); + return NS_OK; + } + *countRead = 0; Flush(count, countRead); if (!mTunnelStreamOut->mCallback) { @@ -1020,7 +1066,7 @@ SpdyConnectTransaction::WriteSegments(nsAHttpSegmentWriter *writer, count, countWritten); if (NS_FAILED(rv)) { if (rv != NS_BASE_STREAM_WOULD_BLOCK) { - LOG(("SpdyConnectTransaction::Flush %p Error %x\n", this, rv)); + LOG(("SpdyConnectTransaction::WriteSegments wrapped writer %p Error %x\n", this, rv)); CreateShimError(rv); } return rv; diff --git a/netwerk/protocol/http/TunnelUtils.h b/netwerk/protocol/http/TunnelUtils.h index 635cbfdb70c5..9ce271fcca6b 100644 --- a/netwerk/protocol/http/TunnelUtils.h +++ b/netwerk/protocol/http/TunnelUtils.h @@ -175,12 +175,15 @@ public: SpdyConnectTransaction(nsHttpConnectionInfo *ci, nsIInterfaceRequestor *callbacks, uint32_t caps, - nsAHttpTransaction *trans, + nsHttpTransaction *trans, nsAHttpConnection *session); ~SpdyConnectTransaction(); SpdyConnectTransaction *QuerySpdyConnectTransaction() { return this; } + // A transaction is forced into plaintext when it is intended to be used as a CONNECT + // tunnel but the setup fails. The plaintext only carries the CONNECT error. + void ForcePlainText(); void MapStreamToHttpConnection(nsISocketTransport *aTransport, nsHttpConnectionInfo *aConnInfo); @@ -215,6 +218,7 @@ private: uint32_t mOutputDataUsed; uint32_t mOutputDataOffset; + bool mForcePlainText; TimeStamp mTimestampSyn; nsRefPtr mConnInfo; @@ -226,6 +230,7 @@ private: nsRefPtr mTunnelTransport; nsRefPtr mTunnelStreamIn; nsRefPtr mTunnelStreamOut; + nsRefPtr mDrivingTransaction; }; }} // namespace mozilla::net diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 3644a619de1f..ba08dcb98fbc 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -68,6 +68,7 @@ nsHttpConnection::nsHttpConnection() , mProxyConnectInProgress(false) , mExperienced(false) , mInSpdyTunnel(false) + , mForcePlainText(false) , mHttp1xTransactionCount(0) , mRemainingConnectionUses(0xffffffff) , mClassification(nsAHttpTransaction::CLASS_GENERAL) @@ -460,7 +461,7 @@ nsHttpConnection::SetupSSL() // of this function mNPNComplete = true; - if (!mConnInfo->FirstHopSSL()) { + if (!mConnInfo->FirstHopSSL() || mForcePlainText) { return; } diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 18b9a01f68e7..bf2aea537a26 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -111,6 +111,13 @@ public: return mConnInfo->UsingHttpsProxy() && !mTLSFilter && mConnInfo->UsingConnect(); } + // A connection is forced into plaintext when it is intended to be used as a CONNECT + // tunnel but the setup fails. The plaintext only carries the CONNECT error. + void ForcePlainText() + { + mForcePlainText = true; + } + nsISocketTransport *Transport() { return mSocketTransport; } nsAHttpTransaction *Transaction() { return mTransaction; } nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; } @@ -283,6 +290,7 @@ private: bool mProxyConnectInProgress; bool mExperienced; bool mInSpdyTunnel; + bool mForcePlainText; // The number of <= HTTP/1.1 transactions performed on this connection. This // excludes spdy transactions. diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index f0af691d1578..92675877799d 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -1984,10 +1984,21 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) if (conn) { MOZ_ASSERT(trans->Caps() & NS_HTTP_STICKY_CONNECTION); - MOZ_ASSERT(((int32_t)ent->mActiveConns.IndexOf(conn)) != -1, - "Sticky Connection Not In Active List"); LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p " "sticky connection=%p\n", trans, conn.get())); + + if (static_cast(ent->mActiveConns.IndexOf(conn)) == -1) { + LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p " + "sticky connection=%p needs to go on the active list\n", trans, conn.get())); + + // make sure it isn't on the idle list - we expect this to be an + // unknown fresh connection + MOZ_ASSERT(static_cast(ent->mIdleConns.IndexOf(conn)) == -1); + MOZ_ASSERT(!conn->IsExperienced()); + + AddActiveConn(conn, ent); // make it active + } + trans->SetConnection(nullptr); rv = DispatchTransaction(ent, trans, conn); } else { diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h index 8339c501b23a..7be89c180af7 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.h +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h @@ -405,6 +405,12 @@ private: nsHttpConnection *mConn; }; +public: + static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped) + { + return new nsConnectionHandle(aWrapped); + } +private: // nsHalfOpenSocket is used to hold the state of an opening TCP socket // while we wait for it to establish and bind it to a connection diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index 61f8c2f6138b..fdffec045d7e 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -109,6 +109,7 @@ public: void SetDontRouteViaWildCard(bool var) { mDontRouteViaWildCard = var; } bool DontRouteViaWildCard() { return mDontRouteViaWildCard; } void EnableKeepAlive() { mCaps |= NS_HTTP_ALLOW_KEEPALIVE; } + void MakeSticky() { mCaps |= NS_HTTP_STICKY_CONNECTION; } // SetPriority() may only be used by the connection manager. void SetPriority(int32_t priority) { mPriority = priority; } From 78e56ed33abcce51c5ce1005f1f6a185b73f5e0a Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 14 Jul 2014 11:57:06 -0400 Subject: [PATCH 25/38] Bug 1002354 - Proxy nsIScreenManager and nsIScreen's from the child process to the parent process, with caching. r=roc,jimm,smichaud,snorp. Changes to nsIScreen and nsIScreenManager were reviewed by roc. Changes to dom/ipc were reviewed by jimm. Changes to gfx/src/nsDeviceContext.cpp were reviewed by roc. Changes to widget/android were reviewed by snorp. Changes to widget/cocoa were reviewed by smichaud. Changes to widget/gtk were reviewed by roc. Changes to widget/windows were reviewed by jimm. Changes to widget/xpwidgets were reviewed by roc. --HG-- extra : rebase_source : 90d263235b40f6f6937d361705a4dfa44253318e extra : histedit_source : bab4e689269c67fe3eb65033b6987b93caf9a482%2C86645be32f82f0d80724532e528e597db165b1d1 --- dom/ipc/ContentChild.cpp | 24 ++ dom/ipc/ContentChild.h | 6 + dom/ipc/ContentParent.cpp | 17 ++ dom/ipc/ContentParent.h | 6 + dom/ipc/PContent.ipdl | 7 + dom/ipc/PScreenManager.ipdl | 57 +++++ dom/ipc/ScreenManagerParent.cpp | 195 +++++++++++++++ dom/ipc/ScreenManagerParent.h | 56 +++++ dom/ipc/TabParent.h | 3 +- dom/ipc/moz.build | 2 + gfx/src/nsDeviceContext.cpp | 10 +- widget/android/nsScreenManagerAndroid.cpp | 14 ++ widget/android/nsScreenManagerAndroid.h | 1 + widget/cocoa/nsScreenCocoa.h | 2 + widget/cocoa/nsScreenCocoa.mm | 14 ++ widget/cocoa/nsScreenManagerCocoa.mm | 24 ++ widget/cocoa/nsWidgetFactory.mm | 6 +- widget/gonk/nsScreenManagerGonk.h | 1 + widget/gonk/nsWindow.cpp | 14 ++ widget/gtk/nsScreenGtk.cpp | 20 +- widget/gtk/nsScreenGtk.h | 2 + widget/gtk/nsScreenManagerGtk.cpp | 24 ++ widget/gtk/nsWidgetFactory.cpp | 6 +- widget/nsIScreen.idl | 8 +- widget/nsIScreenManager.idl | 13 +- widget/windows/nsScreenManagerWin.cpp | 17 ++ widget/windows/nsScreenWin.cpp | 10 + widget/windows/nsScreenWin.h | 3 + widget/windows/nsWidgetFactory.cpp | 5 +- widget/xpwidgets/PuppetWidget.cpp | 16 +- widget/xpwidgets/PuppetWidget.h | 1 + widget/xpwidgets/ScreenProxy.cpp | 157 ++++++++++++ widget/xpwidgets/ScreenProxy.h | 60 +++++ widget/xpwidgets/moz.build | 2 + .../nsContentProcessWidgetFactory.cpp | 6 + widget/xpwidgets/nsScreenManagerProxy.cpp | 226 ++++++++++++++++++ widget/xpwidgets/nsScreenManagerProxy.h | 67 ++++++ 37 files changed, 1087 insertions(+), 15 deletions(-) create mode 100644 dom/ipc/PScreenManager.ipdl create mode 100644 dom/ipc/ScreenManagerParent.cpp create mode 100644 dom/ipc/ScreenManagerParent.h create mode 100644 widget/xpwidgets/ScreenProxy.cpp create mode 100644 widget/xpwidgets/ScreenProxy.h create mode 100644 widget/xpwidgets/nsScreenManagerProxy.cpp create mode 100644 widget/xpwidgets/nsScreenManagerProxy.h diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 29b40df5f774..578e9f23d9a7 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -59,6 +59,7 @@ #include "nsIMutable.h" #include "nsIObserverService.h" #include "nsIScriptSecurityManager.h" +#include "nsScreenManagerProxy.h" #include "nsMemoryInfoDumper.h" #include "nsServiceManagerUtils.h" #include "nsStyleSheetService.h" @@ -169,6 +170,7 @@ using namespace mozilla::jsipc; #if defined(MOZ_WIDGET_GONK) using namespace mozilla::system; #endif +using namespace mozilla::widget; #ifdef MOZ_NUWA_PROCESS static bool sNuwaForking = false; @@ -1200,6 +1202,28 @@ ContentChild::DeallocPNeckoChild(PNeckoChild* necko) return true; } +PScreenManagerChild* +ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) +{ + // The ContentParent should never attempt to allocate the + // nsScreenManagerProxy. Instead, the nsScreenManagerProxy + // service is requested and instantiated via XPCOM, and the + // constructor of nsScreenManagerProxy sets up the IPC connection. + NS_NOTREACHED("Should never get here!"); + return nullptr; +} + +bool +ContentChild::DeallocPScreenManagerChild(PScreenManagerChild* aService) +{ + // nsScreenManagerProxy is AddRef'd in its constructor. + nsScreenManagerProxy *child = static_cast(aService); + child->Release(); + return true; +} + PExternalHelperAppChild* ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 3db0d5983668..134d3efd184f 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -193,6 +193,12 @@ public: virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE; virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE; + virtual PScreenManagerChild* + AllocPScreenManagerChild(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) MOZ_OVERRIDE; + virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) MOZ_OVERRIDE; + virtual PExternalHelperAppChild *AllocPExternalHelperAppChild( const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 8eb6e61bbe24..c098d44694a7 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -113,6 +113,7 @@ #include "PreallocatedProcessManager.h" #include "ProcessPriorityManager.h" #include "SandboxHal.h" +#include "ScreenManagerParent.h" #include "StructuredCloneUtils.h" #include "TabParent.h" #include "URIUtils.h" @@ -189,6 +190,7 @@ using namespace mozilla::ipc; using namespace mozilla::layers; using namespace mozilla::net; using namespace mozilla::jsipc; +using namespace mozilla::widget; #ifdef ENABLE_TESTS @@ -2903,6 +2905,21 @@ ContentParent::DeallocPNeckoParent(PNeckoParent* necko) return true; } +PScreenManagerParent* +ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) +{ + return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess); +} + +bool +ContentParent::DeallocPScreenManagerParent(PScreenManagerParent* aActor) +{ + delete aActor; + return true; +} + PExternalHelperAppParent* ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index c074f9191e35..d10537b5ef56 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -230,6 +230,12 @@ public: return PContentParent::RecvPNeckoConstructor(aActor); } + virtual PScreenManagerParent* + AllocPScreenManagerParent(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) MOZ_OVERRIDE; + virtual bool DeallocPScreenManagerParent(PScreenManagerParent* aActor) MOZ_OVERRIDE; + virtual PHalParent* AllocPHalParent() MOZ_OVERRIDE; virtual bool RecvPHalConstructor(PHalParent* aActor) MOZ_OVERRIDE { return PContentParent::RecvPHalConstructor(aActor); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index bd85b0986b77..37772ed50473 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -23,6 +23,7 @@ include protocol PImageBridge; include protocol PIndexedDB; include protocol PMemoryReportRequest; include protocol PNecko; +include protocol PScreenManager; include protocol PSharedBufferManager; include protocol PSms; include protocol PSpeechSynthesis; @@ -303,6 +304,7 @@ intr protocol PContent manages PIndexedDB; manages PMemoryReportRequest; manages PNecko; + manages PScreenManager; manages PSms; manages PSpeechSynthesis; manages PStorage; @@ -479,6 +481,11 @@ parent: PNecko(); + sync PScreenManager() + returns (uint32_t numberOfScreens, + float systemDefaultScale, + bool success); + PSms(); PSpeechSynthesis(); diff --git a/dom/ipc/PScreenManager.ipdl b/dom/ipc/PScreenManager.ipdl new file mode 100644 index 000000000000..28ccea251e34 --- /dev/null +++ b/dom/ipc/PScreenManager.ipdl @@ -0,0 +1,57 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* 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 protocol PBrowser; +include protocol PContent; + +using struct nsIntRect from "nsRect.h"; + +namespace mozilla { +namespace dom { + +struct ScreenDetails { + uint32_t id; + nsIntRect rect; + nsIntRect availRect; + int32_t pixelDepth; + int32_t colorDepth; + double contentsScaleFactor; +}; + +sync protocol PScreenManager +{ + manager PContent; + +parent: + sync Refresh() + returns (uint32_t numberOfScreens, + float systemDefaultScale, + bool success); + + sync ScreenRefresh(uint32_t aId) + returns (ScreenDetails screen, + bool success); + + sync GetPrimaryScreen() + returns (ScreenDetails screen, + bool success); + + sync ScreenForRect(int32_t aLeft, + int32_t aTop, + int32_t aWidth, + int32_t aHeight) + returns (ScreenDetails screen, + bool success); + + sync ScreenForBrowser(PBrowser aBrowser) + returns (ScreenDetails screen, + bool success); + +child: + __delete__(); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp new file mode 100644 index 000000000000..0da23df5f6ce --- /dev/null +++ b/dom/ipc/ScreenManagerParent.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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/dom/TabParent.h" +#include "mozilla/unused.h" +#include "nsIWidget.h" +#include "nsServiceManagerUtils.h" +#include "ScreenManagerParent.h" + +namespace mozilla { +namespace dom { + +static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1"; + +ScreenManagerParent::ScreenManagerParent(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) +{ + mScreenMgr = do_GetService(sScreenManagerContractID); + if (!mScreenMgr) { + MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent."); + } + + unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess); +} + +bool +ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) +{ + *aSuccess = false; + + nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens); + if (NS_FAILED(rv)) { + return true; + } + + rv = mScreenMgr->GetSystemDefaultScale(aSystemDefaultScale); + if (NS_FAILED(rv)) { + return true; + } + + *aSuccess = true; + return true; +} + +bool +ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId, + ScreenDetails* aRetVal, + bool* aSuccess) +{ + *aSuccess = false; + + nsCOMPtr screen; + nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen)); + if (NS_FAILED(rv)) { + return true; + } + + ScreenDetails details; + unused << ExtractScreenDetails(screen, details); + + *aRetVal = details; + *aSuccess = true; + return true; +} + +bool +ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal, + bool* aSuccess) +{ + *aSuccess = false; + + nsCOMPtr screen; + nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen)); + + NS_ENSURE_SUCCESS(rv, true); + + ScreenDetails details; + if (!ExtractScreenDetails(screen, details)) { + return true; + } + + *aRetVal = details; + *aSuccess = true; + return true; +} + +bool +ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft, + const int32_t& aTop, + const int32_t& aWidth, + const int32_t& aHeight, + ScreenDetails* aRetVal, + bool* aSuccess) +{ + *aSuccess = false; + + nsCOMPtr screen; + nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen)); + + NS_ENSURE_SUCCESS(rv, true); + + ScreenDetails details; + if (!ExtractScreenDetails(screen, details)) { + return true; + } + + *aRetVal = details; + *aSuccess = true; + return true; +} + +bool +ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser, + ScreenDetails* aRetVal, + bool* aSuccess) +{ + *aSuccess = false; + + // Find the mWidget associated with the tabparent, and then return + // the nsIScreen it's on. + TabParent* tabParent = static_cast(aBrowser); + nsCOMPtr widget = tabParent->GetWidget(); + if (!widget) { + return true; + } + + nsCOMPtr screen; + if (widget->GetNativeData(NS_NATIVE_WINDOW)) { + mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), + getter_AddRefs(screen)); + } + + NS_ENSURE_TRUE(screen, true); + + ScreenDetails details; + if (!ExtractScreenDetails(screen, details)) { + return true; + } + + *aRetVal = details; + *aSuccess = true; + return true; +} + +bool +ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails) +{ + uint32_t id; + nsresult rv = aScreen->GetId(&id); + NS_ENSURE_SUCCESS(rv, false); + aDetails.id() = id; + + nsIntRect rect; + rv = aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height); + NS_ENSURE_SUCCESS(rv, false); + aDetails.rect() = rect; + + nsIntRect availRect; + rv = aScreen->GetAvailRect(&availRect.x, &availRect.y, &availRect.width, + &availRect.height); + NS_ENSURE_SUCCESS(rv, false); + aDetails.availRect() = availRect; + + int32_t pixelDepth = 0; + rv = aScreen->GetPixelDepth(&pixelDepth); + NS_ENSURE_SUCCESS(rv, false); + aDetails.pixelDepth() = pixelDepth; + + int32_t colorDepth = 0; + rv = aScreen->GetColorDepth(&colorDepth); + NS_ENSURE_SUCCESS(rv, false); + aDetails.colorDepth() = colorDepth; + + double contentsScaleFactor = 1.0; + rv = aScreen->GetContentsScaleFactor(&contentsScaleFactor); + NS_ENSURE_SUCCESS(rv, false); + aDetails.contentsScaleFactor() = contentsScaleFactor; + + return true; +} + +void +ScreenManagerParent::ActorDestroy(ActorDestroyReason why) +{ +} + +} // namespace dom +} // namespace mozilla + diff --git a/dom/ipc/ScreenManagerParent.h b/dom/ipc/ScreenManagerParent.h new file mode 100644 index 000000000000..88dc8733469c --- /dev/null +++ b/dom/ipc/ScreenManagerParent.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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 mozilla_dom_ScreenManagerParent_h +#define mozilla_dom_ScreenManagerParent_h + +#include "mozilla/dom/PScreenManagerParent.h" +#include "nsIScreenManager.h" + +namespace mozilla { +namespace dom { + +class ScreenManagerParent : public PScreenManagerParent +{ + public: + ScreenManagerParent(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess); + ~ScreenManagerParent() {}; + + virtual bool RecvRefresh(uint32_t* aNumberOfScreens, + float* aSystemDefaultScale, + bool* aSuccess) MOZ_OVERRIDE; + + virtual bool RecvScreenRefresh(const uint32_t& aId, + ScreenDetails* aRetVal, + bool* aSuccess) MOZ_OVERRIDE; + + virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; + + virtual bool RecvGetPrimaryScreen(ScreenDetails* aRetVal, + bool* aSuccess) MOZ_OVERRIDE; + + virtual bool RecvScreenForRect(const int32_t& aLeft, + const int32_t& aTop, + const int32_t& aWidth, + const int32_t& aHeight, + ScreenDetails* aRetVal, + bool* aSuccess) MOZ_OVERRIDE; + + virtual bool RecvScreenForBrowser(PBrowserParent* aBrowser, + ScreenDetails* aRetVal, + bool* aSuccess); + + private: + bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails); + nsCOMPtr mScreenMgr; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_ScreenManagerParent_h diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 9d4369ca3af2..bc33b215549f 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -309,6 +309,8 @@ public: */ bool IsDestroyed() const { return mIsDestroyed; } + already_AddRefed GetWidget() const; + protected: bool ReceiveMessage(const nsString& aMessage, bool aSync, @@ -380,7 +382,6 @@ protected: private: already_AddRefed GetFrameLoader() const; - already_AddRefed GetWidget() const; layout::RenderFrameParent* GetRenderFrame(); nsRefPtr mManager; void TryCacheDPIAndScale(); diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index 6e3f7ed57f1d..2fa35ed83c23 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -59,6 +59,7 @@ UNIFIED_SOURCES += [ 'PermissionMessageUtils.cpp', 'PreallocatedProcessManager.cpp', 'ProcessPriorityManager.cpp', + 'ScreenManagerParent.cpp', 'StructuredCloneUtils.cpp', 'TabChild.cpp', 'TabContext.cpp', @@ -92,6 +93,7 @@ IPDL_SOURCES += [ 'PFileDescriptorSet.ipdl', 'PFilePicker.ipdl', 'PMemoryReportRequest.ipdl', + 'PScreenManager.ipdl', 'PTabContext.ipdlh', ] diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index ba7ec2d62c03..dd1ee0d198b7 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -631,11 +631,17 @@ nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect) void nsDeviceContext::FindScreen(nsIScreen** outScreen) { - if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) + if (mWidget && mWidget->GetOwningTabChild()) { + mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(), + outScreen); + } + else if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) { mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW), outScreen); - else + } + else { mScreenManager->GetPrimaryScreen(outScreen); + } } void diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index 6bf5600b6b6a..36028a217f18 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -19,6 +19,13 @@ nsScreenAndroid::~nsScreenAndroid() { } +NS_IMETHODIMP +nsScreenAndroid::GetId(uint32_t *outId) +{ + *outId = 1; + return NS_OK; +} + NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { @@ -80,6 +87,13 @@ nsScreenManagerAndroid::GetPrimaryScreen(nsIScreen **outScreen) return NS_OK; } +NS_IMETHODIMP +nsScreenManagerAndroid::ScreenForId(uint32_t aId, + nsIScreen **outScreen) +{ + return GetPrimaryScreen(outScreen); +} + NS_IMETHODIMP nsScreenManagerAndroid::ScreenForRect(int32_t inLeft, int32_t inTop, diff --git a/widget/android/nsScreenManagerAndroid.h b/widget/android/nsScreenManagerAndroid.h index 21e3aaa1c385..a07976ef7777 100644 --- a/widget/android/nsScreenManagerAndroid.h +++ b/widget/android/nsScreenManagerAndroid.h @@ -18,6 +18,7 @@ public: nsScreenAndroid(void *nativeScreen); ~nsScreenAndroid(); + NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); diff --git a/widget/cocoa/nsScreenCocoa.h b/widget/cocoa/nsScreenCocoa.h index 024badad86f3..8e19a4d143f7 100644 --- a/widget/cocoa/nsScreenCocoa.h +++ b/widget/cocoa/nsScreenCocoa.h @@ -16,6 +16,7 @@ public: nsScreenCocoa (NSScreen *screen); ~nsScreenCocoa (); + NS_IMETHOD GetId(uint32_t* outId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); @@ -30,6 +31,7 @@ private: CGFloat BackingScaleFactor(); NSScreen *mScreen; + uint32_t mId; }; #endif // nsScreenCocoa_h_ diff --git a/widget/cocoa/nsScreenCocoa.mm b/widget/cocoa/nsScreenCocoa.mm index 5780a4c7eab2..5a9ccb6e26cb 100644 --- a/widget/cocoa/nsScreenCocoa.mm +++ b/widget/cocoa/nsScreenCocoa.mm @@ -7,11 +7,14 @@ #include "nsObjCExceptions.h" #include "nsCocoaUtils.h" +static uint32_t sScreenId = 0; + nsScreenCocoa::nsScreenCocoa (NSScreen *screen) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; mScreen = [screen retain]; + mId = ++sScreenId; NS_OBJC_END_TRY_ABORT_BLOCK; } @@ -25,6 +28,17 @@ nsScreenCocoa::~nsScreenCocoa () NS_OBJC_END_TRY_ABORT_BLOCK; } +NS_IMETHODIMP +nsScreenCocoa::GetId(uint32_t *outId) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + *outId = mId; + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + NS_IMETHODIMP nsScreenCocoa::GetRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/cocoa/nsScreenManagerCocoa.mm b/widget/cocoa/nsScreenManagerCocoa.mm index 3325bece9355..c3fd5431f3dd 100644 --- a/widget/cocoa/nsScreenManagerCocoa.mm +++ b/widget/cocoa/nsScreenManagerCocoa.mm @@ -35,6 +35,30 @@ nsScreenManagerCocoa::ScreenForCocoaScreen(NSScreen *screen) return sc.get(); } +NS_IMETHODIMP +nsScreenManagerCocoa::ScreenForId (uint32_t aId, nsIScreen **outScreen) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT + + *outScreen = nullptr; + + for (uint32_t i = 0; i < mScreenList.Length(); ++i) { + nsScreenCocoa* sc = mScreenList[i]; + uint32_t id; + nsresult rv = sc->GetId(&id); + + if (NS_SUCCEEDED(rv) && id == aId) { + *outScreen = sc; + NS_ADDREF(*outScreen); + return NS_OK; + } + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + NS_IMETHODIMP nsScreenManagerCocoa::ScreenForRect (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, nsIScreen **outScreen) diff --git a/widget/cocoa/nsWidgetFactory.mm b/widget/cocoa/nsWidgetFactory.mm index 043f68af5892..d4f6b5b0e563 100644 --- a/widget/cocoa/nsWidgetFactory.mm +++ b/widget/cocoa/nsWidgetFactory.mm @@ -134,7 +134,8 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { mozilla::Module::MAIN_PROCESS_ONLY }, { &kNS_BIDIKEYBOARD_CID, false, NULL, nsBidiKeyboardConstructor }, { &kNS_THEMERENDERER_CID, false, NULL, nsNativeThemeCocoaConstructor }, - { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerCocoaConstructor }, + { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerCocoaConstructor, + mozilla::Module::MAIN_PROCESS_ONLY }, { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecXConstructor, mozilla::Module::MAIN_PROCESS_ONLY }, { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor, @@ -172,7 +173,8 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { mozilla::Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, + mozilla::Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID, mozilla::Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID, diff --git a/widget/gonk/nsScreenManagerGonk.h b/widget/gonk/nsScreenManagerGonk.h index de3114793f2a..fc2ab4f4d355 100644 --- a/widget/gonk/nsScreenManagerGonk.h +++ b/widget/gonk/nsScreenManagerGonk.h @@ -31,6 +31,7 @@ public: nsScreenGonk(void* nativeScreen); ~nsScreenGonk(); + NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp index c670252eafdb..c4e8ba76eb4e 100644 --- a/widget/gonk/nsWindow.cpp +++ b/widget/gonk/nsWindow.cpp @@ -609,6 +609,13 @@ nsScreenGonk::~nsScreenGonk() { } +NS_IMETHODIMP +nsScreenGonk::GetId(uint32_t *outId) +{ + *outId = 1; + return NS_OK; +} + NS_IMETHODIMP nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) @@ -754,6 +761,13 @@ nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen) return NS_OK; } +NS_IMETHODIMP +nsScreenManagerGonk::ScreenForId(uint32_t aId, + nsIScreen **outScreen) +{ + return GetPrimaryScreen(outScreen); +} + NS_IMETHODIMP nsScreenManagerGonk::ScreenForRect(int32_t inLeft, int32_t inTop, diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp index 7840c9b7414e..84a093e93912 100644 --- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -12,10 +12,14 @@ #endif #include +static uint32_t sScreenId = 0; + + nsScreenGtk :: nsScreenGtk ( ) : mScreenNum(0), mRect(0, 0, 0, 0), - mAvailRect(0, 0, 0, 0) + mAvailRect(0, 0, 0, 0), + mId(++sScreenId) { } @@ -25,6 +29,20 @@ nsScreenGtk :: ~nsScreenGtk() } +nsScreenGtk :: GetId(uint32_t *aId) +{ + *aId = mId; + return NS_OK; +} // GetId + +NS_IMETHODIMP +nsScreenGtk :: GetId(uint32_t *aId) +{ + *aId = mId; + return NS_OK; +} // GetId + + NS_IMETHODIMP nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/gtk/nsScreenGtk.h b/widget/gtk/nsScreenGtk.h index 16a8f090ca59..4434b5fa8711 100644 --- a/widget/gtk/nsScreenGtk.h +++ b/widget/gtk/nsScreenGtk.h @@ -30,6 +30,7 @@ public: nsScreenGtk(); ~nsScreenGtk(); + NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); @@ -44,6 +45,7 @@ private: uint32_t mScreenNum; nsIntRect mRect; nsIntRect mAvailRect; + uint32_t mId; }; #endif // nsScreenGtk_h___ diff --git a/widget/gtk/nsScreenManagerGtk.cpp b/widget/gtk/nsScreenManagerGtk.cpp index 1bb0f3680f9e..83513553d9bd 100644 --- a/widget/gtk/nsScreenManagerGtk.cpp +++ b/widget/gtk/nsScreenManagerGtk.cpp @@ -188,6 +188,30 @@ nsScreenManagerGtk :: Init() return NS_OK; } +NS_IMETHODIMP +nsScreenManagerGtk :: ScreenForId ( uint32_t aId, nsIScreen **outScreen ) +{ + *outScreen = nullptr; + + nsresult rv; + rv = EnsureInit(); + if (NS_FAILED(rv)) { + NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from ScreenForId"); + return rv; + } + + for (int32_t i = 0, i_end = mCachedScreenArray.Count(); i < i_end; ++i) { + uint32_t id; + rv = mCachedScreenArray[i]->GetId(&id); + if (NS_SUCCEEDED(rv) && id == aId) { + NS_IF_ADDREF(*outScreen = mCachedScreenArray[i]); + return NS_OK; + } + } + + return NS_ERROR_FAILURE; +} + // // ScreenForRect diff --git a/widget/gtk/nsWidgetFactory.cpp b/widget/gtk/nsWidgetFactory.cpp index 266262877840..1286dc0fa4cb 100644 --- a/widget/gtk/nsWidgetFactory.cpp +++ b/widget/gtk/nsWidgetFactory.cpp @@ -214,7 +214,8 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { #endif { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor }, { &kNS_BIDIKEYBOARD_CID, false, nullptr, nsBidiKeyboardConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerGtkConstructor }, + { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerGtkConstructor, + Module::MAIN_PROCESS_ONLY }, { &kNS_THEMERENDERER_CID, false, nullptr, nsNativeThemeGTKConstructor }, #ifdef NS_PRINTING { &kNS_PRINTSETTINGSSERVICE_CID, false, nullptr, nsPrintOptionsGTKConstructor }, @@ -250,7 +251,8 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { #endif { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, + Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, #ifdef NS_PRINTING { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID }, diff --git a/widget/nsIScreen.idl b/widget/nsIScreen.idl index 3c99585789ec..104cd9f9f7cc 100644 --- a/widget/nsIScreen.idl +++ b/widget/nsIScreen.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" -[scriptable, uuid(D6F13AF4-8ACA-4A10-8687-3F99C3692AC0)] +[scriptable, uuid(826e80c8-d70f-42e2-8aa9-82c05f2a370a)] interface nsIScreen : nsISupports { /** @@ -29,6 +29,12 @@ interface nsIScreen : nsISupports const unsigned long ROTATION_180_DEG = 2; const unsigned long ROTATION_270_DEG = 3; + /** + * A unique identifier for this device, useful for requerying + * for it via nsIScreenManager. + */ + readonly attribute unsigned long id; + /** * These report screen dimensions in (screen-specific) device pixels */ diff --git a/widget/nsIScreenManager.idl b/widget/nsIScreenManager.idl index 445e4e513811..400b5d33b575 100644 --- a/widget/nsIScreenManager.idl +++ b/widget/nsIScreenManager.idl @@ -7,7 +7,7 @@ #include "nsISupports.idl" #include "nsIScreen.idl" -[scriptable, uuid(1C195990-FF9E-412B-AFE7-67D1C660BB27)] +[scriptable, uuid(e8a96e60-6b61-4a14-bacc-53891604b502)] interface nsIScreenManager : nsISupports { // @@ -17,11 +17,18 @@ interface nsIScreenManager : nsISupports // The coordinates are in pixels (not twips) and in screen coordinates. // nsIScreen screenForRect ( in long left, in long top, in long width, in long height ) ; - + + // + // Returns the screen corresponding to the id. If no such screen exists, + // this will throw NS_ERROR_FAILURE. The id is a unique numeric value + // assigned to each screen, and is an attribute available on the nsIScreen + // interface. + nsIScreen screenForId ( in unsigned long id ) ; + // The screen with the menubar/taskbar. This shouldn't be needed very // often. readonly attribute nsIScreen primaryScreen; - + // Holds the number of screens that are available readonly attribute unsigned long numberOfScreens; diff --git a/widget/windows/nsScreenManagerWin.cpp b/widget/windows/nsScreenManagerWin.cpp index c0c1b24caa56..17ba65949daf 100644 --- a/widget/windows/nsScreenManagerWin.cpp +++ b/widget/windows/nsScreenManagerWin.cpp @@ -59,6 +59,23 @@ nsScreenManagerWin :: CreateNewScreenObject ( HMONITOR inScreen ) return retScreen; } +NS_IMETHODIMP +nsScreenManagerWin::ScreenForId(uint32_t aId, nsIScreen **outScreen) +{ + *outScreen = nullptr; + + for (unsigned i = 0; i < mScreenList.Length(); ++i) { + ScreenListItem& curr = mScreenList[i]; + uint32_t id; + nsresult rv = curr.mScreen->GetId(&id); + if (NS_SUCCEEDED(rv) && id == aId) { + NS_IF_ADDREF(*outScreen = curr.mScreen.get()); + return NS_OK; + } + } + + return NS_ERROR_FAILURE; +} // // ScreenForRect diff --git a/widget/windows/nsScreenWin.cpp b/widget/windows/nsScreenWin.cpp index 6fcab20674ba..ecfc5d15990f 100644 --- a/widget/windows/nsScreenWin.cpp +++ b/widget/windows/nsScreenWin.cpp @@ -8,9 +8,11 @@ #include "gfxWindowsPlatform.h" #include "nsIWidget.h" +static uint32_t sScreenId; nsScreenWin :: nsScreenWin ( HMONITOR inScreen ) : mScreen(inScreen) + , mId(++sScreenId) { #ifdef DEBUG HDC hDCScreen = ::GetDC(nullptr); @@ -31,6 +33,14 @@ nsScreenWin :: ~nsScreenWin() } +NS_IMETHODIMP +nsScreenWin::GetId(uint32_t *outId) +{ + *outId = mId; + return NS_OK; +} + + NS_IMETHODIMP nsScreenWin :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/windows/nsScreenWin.h b/widget/windows/nsScreenWin.h index f7b42dd7ae85..08476876f244 100644 --- a/widget/windows/nsScreenWin.h +++ b/widget/windows/nsScreenWin.h @@ -17,6 +17,8 @@ public: nsScreenWin ( HMONITOR inScreen ); ~nsScreenWin(); + NS_IMETHOD GetId(uint32_t* aId); + // These methods return the size in device (physical) pixels NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); @@ -34,6 +36,7 @@ public: private: HMONITOR mScreen; + uint32_t mId; }; #endif // nsScreenWin_h___ diff --git a/widget/windows/nsWidgetFactory.cpp b/widget/windows/nsWidgetFactory.cpp index fce89c222aa6..4b00ef8678b7 100644 --- a/widget/windows/nsWidgetFactory.cpp +++ b/widget/windows/nsWidgetFactory.cpp @@ -221,7 +221,8 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_FILEPICKER_CID, false, nullptr, FilePickerConstructor, Module::MAIN_PROCESS_ONLY }, { &kNS_COLORPICKER_CID, false, nullptr, ColorPickerConstructor, Module::MAIN_PROCESS_ONLY }, { &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerWinConstructor }, + { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerWinConstructor, + Module::MAIN_PROCESS_ONLY }, { &kNS_GFXINFO_CID, false, nullptr, GfxInfoConstructor }, { &kNS_THEMERENDERER_CID, false, nullptr, NS_NewNativeTheme }, { &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceWinConstructor }, @@ -259,7 +260,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/widget/appshell/win;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, diff --git a/widget/xpwidgets/PuppetWidget.cpp b/widget/xpwidgets/PuppetWidget.cpp index 563daac687bc..3928abe49e1e 100644 --- a/widget/xpwidgets/PuppetWidget.cpp +++ b/widget/xpwidgets/PuppetWidget.cpp @@ -803,6 +803,13 @@ ScreenConfig() return config; } +NS_IMETHODIMP +PuppetScreen::GetId(uint32_t *outId) +{ + *outId = 1; + return NS_OK; +} + NS_IMETHODIMP PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) @@ -822,7 +829,6 @@ PuppetScreen::GetAvailRect(int32_t *outLeft, int32_t *outTop, return GetRect(outLeft, outTop, outWidth, outHeight); } - NS_IMETHODIMP PuppetScreen::GetPixelDepth(int32_t *aPixelDepth) { @@ -862,6 +868,14 @@ PuppetScreenManager::~PuppetScreenManager() { } +NS_IMETHODIMP +PuppetScreenManager::ScreenForId(uint32_t aId, + nsIScreen** outScreen) +{ + NS_IF_ADDREF(*outScreen = mOneScreen.get()); + return NS_OK; +} + NS_IMETHODIMP PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) { diff --git a/widget/xpwidgets/PuppetWidget.h b/widget/xpwidgets/PuppetWidget.h index 5f53b3b532b7..6799ec2b0f97 100644 --- a/widget/xpwidgets/PuppetWidget.h +++ b/widget/xpwidgets/PuppetWidget.h @@ -305,6 +305,7 @@ public: PuppetScreen(void* nativeScreen); ~PuppetScreen(); + NS_IMETHOD GetId(uint32_t* aId) MOZ_OVERRIDE; NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) MOZ_OVERRIDE; NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) MOZ_OVERRIDE; NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) MOZ_OVERRIDE; diff --git a/widget/xpwidgets/ScreenProxy.cpp b/widget/xpwidgets/ScreenProxy.cpp new file mode 100644 index 000000000000..fe51b3dbc80a --- /dev/null +++ b/widget/xpwidgets/ScreenProxy.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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/unused.h" +#include "nsIAppShell.h" +#include "nsScreenManagerProxy.h" +#include "nsServiceManagerUtils.h" +#include "nsWidgetsCID.h" +#include "ScreenProxy.h" + +namespace mozilla { +namespace widget { + +using namespace mozilla::dom; + +static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + +ScreenProxy::ScreenProxy(nsScreenManagerProxy* aScreenManager, ScreenDetails aDetails) + : mScreenManager(aScreenManager) + , mCacheValid(false) + , mCacheWillInvalidate(false) +{ + PopulateByDetails(aDetails); +} + +NS_IMETHODIMP +ScreenProxy::GetId(uint32_t *outId) +{ + *outId = mId; + return NS_OK; +} + +NS_IMETHODIMP +ScreenProxy::GetRect(int32_t *outLeft, + int32_t *outTop, + int32_t *outWidth, + int32_t *outHeight) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *outLeft = mRect.x; + *outTop = mRect.y; + *outWidth = mRect.width; + *outHeight = mRect.height; + return NS_OK; +} + +NS_IMETHODIMP +ScreenProxy::GetAvailRect(int32_t *outLeft, + int32_t *outTop, + int32_t *outWidth, + int32_t *outHeight) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *outLeft = mAvailRect.x; + *outTop = mAvailRect.y; + *outWidth = mAvailRect.width; + *outHeight = mAvailRect.height; + return NS_OK; +} + +NS_IMETHODIMP +ScreenProxy::GetPixelDepth(int32_t *aPixelDepth) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *aPixelDepth = mPixelDepth; + return NS_OK; +} + +NS_IMETHODIMP +ScreenProxy::GetColorDepth(int32_t *aColorDepth) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *aColorDepth = mColorDepth; + return NS_OK; +} + +void +ScreenProxy::PopulateByDetails(ScreenDetails aDetails) +{ + mId = aDetails.id(); + mRect = nsIntRect(aDetails.rect()); + mAvailRect = nsIntRect(aDetails.availRect()); + mPixelDepth = aDetails.pixelDepth(); + mColorDepth = aDetails.colorDepth(); + mContentsScaleFactor = aDetails.contentsScaleFactor(); +} + +bool +ScreenProxy::EnsureCacheIsValid() +{ + if (mCacheValid) { + return true; + } + + bool success = false; + // Kick off a synchronous IPC call to the parent to get the + // most up-to-date information. + ScreenDetails details; + unused << mScreenManager->SendScreenRefresh(mId, &details, &success); + if (!success) { + NS_WARNING("Updating a ScreenProxy in the child process failed on parent side."); + return false; + } + + PopulateByDetails(details); + mCacheValid = true; + + InvalidateCacheOnNextTick(); + return true; +} + +void +ScreenProxy::InvalidateCacheOnNextTick() +{ + if (mCacheWillInvalidate) { + return; + } + + mCacheWillInvalidate = true; + + nsCOMPtr appShell = do_GetService(kAppShellCID); + if (appShell) { + appShell->RunInStableState( + NS_NewRunnableMethod(this, &ScreenProxy::InvalidateCache) + ); + } else { + // It's pretty bad news if we can't get the appshell. In that case, + // let's just invalidate the cache right away. + InvalidateCache(); + } +} + +void +ScreenProxy::InvalidateCache() +{ + mCacheValid = false; + mCacheWillInvalidate = false; +} + +} // namespace widget +} // namespace mozilla + diff --git a/widget/xpwidgets/ScreenProxy.h b/widget/xpwidgets/ScreenProxy.h new file mode 100644 index 000000000000..519284171e5b --- /dev/null +++ b/widget/xpwidgets/ScreenProxy.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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 mozilla_widget_ScreenProxy_h +#define mozilla_widget_ScreenProxy_h + +#include "nsBaseScreen.h" +#include "mozilla/dom/PScreenManagerChild.h" +#include "mozilla/dom/TabChild.h" + +class nsScreenManagerProxy; + +namespace mozilla { +namespace widget { + +class ScreenProxy : public nsBaseScreen +{ +public: + ScreenProxy(nsScreenManagerProxy* aScreenManager, + mozilla::dom::ScreenDetails aDetails); + ~ScreenProxy() {}; + + NS_IMETHOD GetId(uint32_t* aId) MOZ_OVERRIDE; + + NS_IMETHOD GetRect(int32_t* aLeft, + int32_t* aTop, + int32_t* aWidth, + int32_t* aHeight) MOZ_OVERRIDE; + NS_IMETHOD GetAvailRect(int32_t* aLeft, + int32_t* aTop, + int32_t* aWidth, + int32_t* aHeight) MOZ_OVERRIDE; + NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) MOZ_OVERRIDE; + NS_IMETHOD GetColorDepth(int32_t* aColorDepth) MOZ_OVERRIDE; + +private: + + void PopulateByDetails(mozilla::dom::ScreenDetails aDetails); + bool EnsureCacheIsValid(); + void InvalidateCacheOnNextTick(); + void InvalidateCache(); + + double mContentsScaleFactor; + nsRefPtr mScreenManager; + uint32_t mId; + int32_t mPixelDepth; + int32_t mColorDepth; + nsIntRect mRect; + nsIntRect mAvailRect; + bool mCacheValid; + bool mCacheWillInvalidate; +}; + +} // namespace widget +} // namespace mozilla +#endif + diff --git a/widget/xpwidgets/moz.build b/widget/xpwidgets/moz.build index 8c0afb681a8a..a2aee17d3cdd 100644 --- a/widget/xpwidgets/moz.build +++ b/widget/xpwidgets/moz.build @@ -34,9 +34,11 @@ UNIFIED_SOURCES += [ 'nsPrintOptionsImpl.cpp', 'nsPrintSession.cpp', 'nsPrintSettingsImpl.cpp', + 'nsScreenManagerProxy.cpp', 'nsTransferable.cpp', 'nsXPLookAndFeel.cpp', 'PuppetWidget.cpp', + 'ScreenProxy.cpp', 'WidgetUtils.cpp', ] diff --git a/widget/xpwidgets/nsContentProcessWidgetFactory.cpp b/widget/xpwidgets/nsContentProcessWidgetFactory.cpp index 85b3db597911..f7b7a6e08cd6 100644 --- a/widget/xpwidgets/nsContentProcessWidgetFactory.cpp +++ b/widget/xpwidgets/nsContentProcessWidgetFactory.cpp @@ -10,6 +10,7 @@ #include "nsClipboardProxy.h" #include "nsColorPickerProxy.h" #include "nsFilePickerProxy.h" +#include "nsScreenManagerProxy.h" using namespace mozilla; @@ -18,10 +19,12 @@ using namespace mozilla; NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPickerProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePickerProxy) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerProxy) NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID); NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID); NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); +NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardProxyConstructor, @@ -30,6 +33,8 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { Module::CONTENT_PROCESS_ONLY }, { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerProxyConstructor, Module::CONTENT_PROCESS_ONLY }, + { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerProxyConstructor, + Module::CONTENT_PROCESS_ONLY }, { nullptr } }; @@ -37,6 +42,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::CONTENT_PROCESS_ONLY }, { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::CONTENT_PROCESS_ONLY }, { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::CONTENT_PROCESS_ONLY }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::CONTENT_PROCESS_ONLY }, { nullptr } }; diff --git a/widget/xpwidgets/nsScreenManagerProxy.cpp b/widget/xpwidgets/nsScreenManagerProxy.cpp new file mode 100644 index 000000000000..747e2fbe6170 --- /dev/null +++ b/widget/xpwidgets/nsScreenManagerProxy.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; 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 "mozilla/unused.h" +#include "mozilla/dom/ContentChild.h" +#include "nsScreenManagerProxy.h" +#include "nsServiceManagerUtils.h" +#include "nsIAppShell.h" +#include "nsIScreen.h" +#include "nsIScreenManager.h" +#include "nsWidgetsCID.h" + +static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::widget; + +NS_IMPL_ISUPPORTS(nsScreenManagerProxy, nsIScreenManager) + +nsScreenManagerProxy::nsScreenManagerProxy() + : mNumberOfScreens(-1) + , mSystemDefaultScale(1.0) + , mCacheValid(true) + , mCacheWillInvalidate(false) +{ + bool success = false; + unused << ContentChild::GetSingleton()->SendPScreenManagerConstructor( + this, + &mNumberOfScreens, + &mSystemDefaultScale, + &success); + + if (!success) { + // We're in bad shape. We'll return the default values, but we'll basically + // be lying. + NS_WARNING("Setting up communications with the parent nsIScreenManager failed."); + } + + InvalidateCacheOnNextTick(); + + // nsScreenManagerProxy is a service, which will always have a reference + // held to it by the Component Manager once the service is requested. + // However, nsScreenManagerProxy also implements PScreenManagerChild, and + // that means that the manager of the PScreenManager protocol (PContent + // in this case) needs to know how to deallocate this actor. We AddRef here + // so that in the event that PContent tries to deallocate us either before + // or after process shutdown, we don't try to do a double-free. + AddRef(); +} + +/** + * nsIScreenManager + **/ + +NS_IMETHODIMP +nsScreenManagerProxy::GetPrimaryScreen(nsIScreen** outScreen) +{ + InvalidateCacheOnNextTick(); + + if (!mPrimaryScreen) { + ScreenDetails details; + bool success = false; + unused << SendGetPrimaryScreen(&details, &success); + if (!success) { + return NS_ERROR_FAILURE; + } + + mPrimaryScreen = new ScreenProxy(this, details); + } + NS_ADDREF(*outScreen = mPrimaryScreen); + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerProxy::ScreenForId(uint32_t aId, nsIScreen** outScreen) +{ + // At this time, there's no need for child processes to query for + // screens by ID. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsScreenManagerProxy::ScreenForRect(int32_t inLeft, + int32_t inTop, + int32_t inWidth, + int32_t inHeight, + nsIScreen** outScreen) +{ + bool success = false; + ScreenDetails details; + unused << SendScreenForRect(inLeft, inTop, inWidth, inHeight, &details, &success); + if (!success) { + return NS_ERROR_FAILURE; + } + + nsRefPtr screen = new ScreenProxy(this, details); + NS_ADDREF(*outScreen = screen); + + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerProxy::ScreenForNativeWidget(void* aWidget, + nsIScreen** outScreen) +{ + // Because ScreenForNativeWidget can be called numerous times + // indirectly from content via the DOM Screen API, we cache the + // results for this tick of the event loop. + TabChild* tabChild = static_cast(aWidget); + + // Enumerate the cached screen array, looking for one that has + // the TabChild that we're looking for... + for (uint32_t i = 0; i < mScreenCache.Length(); ++i) { + ScreenCacheEntry& curr = mScreenCache[i]; + if (curr.mTabChild == aWidget) { + NS_ADDREF(*outScreen = static_cast(curr.mScreenProxy)); + return NS_OK; + } + } + + // Never cached this screen, so we have to ask the parent process + // for it. + bool success = false; + ScreenDetails details; + unused << SendScreenForBrowser(tabChild, &details, &success); + if (!success) { + return NS_ERROR_FAILURE; + } + + ScreenCacheEntry newEntry; + nsRefPtr screen = new ScreenProxy(this, details); + + newEntry.mScreenProxy = screen; + newEntry.mTabChild = tabChild; + + mScreenCache.AppendElement(newEntry); + + NS_ADDREF(*outScreen = screen); + + InvalidateCacheOnNextTick(); + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerProxy::GetNumberOfScreens(uint32_t* aNumberOfScreens) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *aNumberOfScreens = mNumberOfScreens; + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerProxy::GetSystemDefaultScale(float *aSystemDefaultScale) +{ + if (!EnsureCacheIsValid()) { + return NS_ERROR_FAILURE; + } + + *aSystemDefaultScale = mSystemDefaultScale; + return NS_OK; +} + +bool +nsScreenManagerProxy::EnsureCacheIsValid() +{ + if (mCacheValid) { + return true; + } + + bool success = false; + // Kick off a synchronous IPC call to the parent to get the + // most up-to-date information. + unused << SendRefresh(&mNumberOfScreens, &mSystemDefaultScale, &success); + if (!success) { + NS_WARNING("Refreshing nsScreenManagerProxy failed in the parent process."); + return false; + } + + mCacheValid = true; + + InvalidateCacheOnNextTick(); + return true; +} + +void +nsScreenManagerProxy::InvalidateCacheOnNextTick() +{ + if (mCacheWillInvalidate) { + return; + } + + mCacheWillInvalidate = true; + + nsCOMPtr appShell = do_GetService(kAppShellCID); + if (appShell) { + appShell->RunInStableState( + NS_NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache) + ); + } else { + // It's pretty bad news if we can't get the appshell. In that case, + // let's just invalidate the cache right away. + InvalidateCache(); + } +} + +void +nsScreenManagerProxy::InvalidateCache() +{ + mCacheValid = false; + mCacheWillInvalidate = false; + + if (mPrimaryScreen) { + mPrimaryScreen = nullptr; + } + for (int32_t i = mScreenCache.Length() - 1; i >= 0; --i) { + mScreenCache.RemoveElementAt(i); + } +} + diff --git a/widget/xpwidgets/nsScreenManagerProxy.h b/widget/xpwidgets/nsScreenManagerProxy.h new file mode 100644 index 000000000000..83f1d7c0fb2e --- /dev/null +++ b/widget/xpwidgets/nsScreenManagerProxy.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; 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 nsScreenManagerProxy_h +#define nsScreenManagerProxy_h + +#include "nsIScreenManager.h" +#include "mozilla/dom/PScreenManagerChild.h" +#include "mozilla/dom/TabChild.h" +#include "ScreenProxy.h" + +/** + * The nsScreenManagerProxy is used by the content process to get + * information about system screens. It uses the PScreenManager protocol + * to communicate with a PScreenManagerParent to get this information, + * and also caches the information it gets back. + * + * We cache both the system screen information that nsIScreenManagers + * provide, as well as the nsIScreens that callers can query for. + * + * Both of these caches are invalidated on the next tick of the event + * loop. + */ +class nsScreenManagerProxy MOZ_FINAL : public nsIScreenManager, + public mozilla::dom::PScreenManagerChild +{ +public: + nsScreenManagerProxy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSISCREENMANAGER + +private: + ~nsScreenManagerProxy() {}; + + bool EnsureCacheIsValid(); + void InvalidateCacheOnNextTick(); + void InvalidateCache(); + + uint32_t mNumberOfScreens; + float mSystemDefaultScale; + bool mCacheValid; + bool mCacheWillInvalidate; + + nsRefPtr mPrimaryScreen; + + // nsScreenManagerProxy caches the results to repeated calls to + // ScreenForNativeWidget, which can be triggered indirectly by + // web content using the DOM Screen API. This allows us to bypass + // a lot of IPC traffic. + // + // The cache stores ScreenProxy's mapped to the TabChild that + // asked for the ScreenForNativeWidget was called with via + // ScreenCacheEntry's. The cache is cleared on the next tick of + // the event loop. + struct ScreenCacheEntry + { + nsRefPtr mScreenProxy; + nsRefPtr mTabChild; + }; + + nsTArray mScreenCache; +}; + +#endif // nsScreenManagerProxy_h From 53b48d65d24999a50e57e454ecd49af1adfec276 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 14 Jul 2014 12:10:34 -0400 Subject: [PATCH 26/38] Follow-up for Bug 1002354 - remove dual GetId in nsScreenGtk injected during rebase foul-up. r=bustage-fix on a CLOSED TREE. --HG-- extra : histedit_source : c510de9918cfd73652e9e1c278e0bee93c7fdcdc --- widget/gtk/nsScreenGtk.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp index 84a093e93912..339a009cc038 100644 --- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -35,13 +35,6 @@ nsScreenGtk :: GetId(uint32_t *aId) return NS_OK; } // GetId -NS_IMETHODIMP -nsScreenGtk :: GetId(uint32_t *aId) -{ - *aId = mId; - return NS_OK; -} // GetId - NS_IMETHODIMP nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) From 1e3e0c9c00e1a7ac8e844e69c12c8f7223c9b31e Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 14 Jul 2014 12:19:23 -0400 Subject: [PATCH 27/38] Backed out e623938ea6c7 to fix a CLOSED TREE. --HG-- extra : histedit_source : b4c9b387a8007748f9421df5c347b2f96e537f27 --- widget/gtk/nsScreenGtk.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp index 339a009cc038..84a093e93912 100644 --- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -35,6 +35,13 @@ nsScreenGtk :: GetId(uint32_t *aId) return NS_OK; } // GetId +NS_IMETHODIMP +nsScreenGtk :: GetId(uint32_t *aId) +{ + *aId = mId; + return NS_OK; +} // GetId + NS_IMETHODIMP nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) From 64b781e2f30a3d3dc6645e13333143ef03ef49e1 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 14 Jul 2014 12:20:16 -0400 Subject: [PATCH 28/38] Backed out bdf72cebcd85 to fix a CLOSED TREE. --HG-- extra : histedit_source : 0a3977407abecc55d5564a69531d5d6ca804cd86 --- dom/ipc/ContentChild.cpp | 24 -- dom/ipc/ContentChild.h | 6 - dom/ipc/ContentParent.cpp | 17 -- dom/ipc/ContentParent.h | 6 - dom/ipc/PContent.ipdl | 7 - dom/ipc/PScreenManager.ipdl | 57 ----- dom/ipc/ScreenManagerParent.cpp | 195 --------------- dom/ipc/ScreenManagerParent.h | 56 ----- dom/ipc/TabParent.h | 3 +- dom/ipc/moz.build | 2 - gfx/src/nsDeviceContext.cpp | 10 +- widget/android/nsScreenManagerAndroid.cpp | 14 -- widget/android/nsScreenManagerAndroid.h | 1 - widget/cocoa/nsScreenCocoa.h | 2 - widget/cocoa/nsScreenCocoa.mm | 14 -- widget/cocoa/nsScreenManagerCocoa.mm | 24 -- widget/cocoa/nsWidgetFactory.mm | 6 +- widget/gonk/nsScreenManagerGonk.h | 1 - widget/gonk/nsWindow.cpp | 14 -- widget/gtk/nsScreenGtk.cpp | 20 +- widget/gtk/nsScreenGtk.h | 2 - widget/gtk/nsScreenManagerGtk.cpp | 24 -- widget/gtk/nsWidgetFactory.cpp | 6 +- widget/nsIScreen.idl | 8 +- widget/nsIScreenManager.idl | 13 +- widget/windows/nsScreenManagerWin.cpp | 17 -- widget/windows/nsScreenWin.cpp | 10 - widget/windows/nsScreenWin.h | 3 - widget/windows/nsWidgetFactory.cpp | 5 +- widget/xpwidgets/PuppetWidget.cpp | 16 +- widget/xpwidgets/PuppetWidget.h | 1 - widget/xpwidgets/ScreenProxy.cpp | 157 ------------ widget/xpwidgets/ScreenProxy.h | 60 ----- widget/xpwidgets/moz.build | 2 - .../nsContentProcessWidgetFactory.cpp | 6 - widget/xpwidgets/nsScreenManagerProxy.cpp | 226 ------------------ widget/xpwidgets/nsScreenManagerProxy.h | 67 ------ 37 files changed, 15 insertions(+), 1087 deletions(-) delete mode 100644 dom/ipc/PScreenManager.ipdl delete mode 100644 dom/ipc/ScreenManagerParent.cpp delete mode 100644 dom/ipc/ScreenManagerParent.h delete mode 100644 widget/xpwidgets/ScreenProxy.cpp delete mode 100644 widget/xpwidgets/ScreenProxy.h delete mode 100644 widget/xpwidgets/nsScreenManagerProxy.cpp delete mode 100644 widget/xpwidgets/nsScreenManagerProxy.h diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 578e9f23d9a7..29b40df5f774 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -59,7 +59,6 @@ #include "nsIMutable.h" #include "nsIObserverService.h" #include "nsIScriptSecurityManager.h" -#include "nsScreenManagerProxy.h" #include "nsMemoryInfoDumper.h" #include "nsServiceManagerUtils.h" #include "nsStyleSheetService.h" @@ -170,7 +169,6 @@ using namespace mozilla::jsipc; #if defined(MOZ_WIDGET_GONK) using namespace mozilla::system; #endif -using namespace mozilla::widget; #ifdef MOZ_NUWA_PROCESS static bool sNuwaForking = false; @@ -1202,28 +1200,6 @@ ContentChild::DeallocPNeckoChild(PNeckoChild* necko) return true; } -PScreenManagerChild* -ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) -{ - // The ContentParent should never attempt to allocate the - // nsScreenManagerProxy. Instead, the nsScreenManagerProxy - // service is requested and instantiated via XPCOM, and the - // constructor of nsScreenManagerProxy sets up the IPC connection. - NS_NOTREACHED("Should never get here!"); - return nullptr; -} - -bool -ContentChild::DeallocPScreenManagerChild(PScreenManagerChild* aService) -{ - // nsScreenManagerProxy is AddRef'd in its constructor. - nsScreenManagerProxy *child = static_cast(aService); - child->Release(); - return true; -} - PExternalHelperAppChild* ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 134d3efd184f..3db0d5983668 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -193,12 +193,6 @@ public: virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE; virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE; - virtual PScreenManagerChild* - AllocPScreenManagerChild(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) MOZ_OVERRIDE; - virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) MOZ_OVERRIDE; - virtual PExternalHelperAppChild *AllocPExternalHelperAppChild( const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index c098d44694a7..8eb6e61bbe24 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -113,7 +113,6 @@ #include "PreallocatedProcessManager.h" #include "ProcessPriorityManager.h" #include "SandboxHal.h" -#include "ScreenManagerParent.h" #include "StructuredCloneUtils.h" #include "TabParent.h" #include "URIUtils.h" @@ -190,7 +189,6 @@ using namespace mozilla::ipc; using namespace mozilla::layers; using namespace mozilla::net; using namespace mozilla::jsipc; -using namespace mozilla::widget; #ifdef ENABLE_TESTS @@ -2905,21 +2903,6 @@ ContentParent::DeallocPNeckoParent(PNeckoParent* necko) return true; } -PScreenManagerParent* -ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) -{ - return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess); -} - -bool -ContentParent::DeallocPScreenManagerParent(PScreenManagerParent* aActor) -{ - delete aActor; - return true; -} - PExternalHelperAppParent* ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri, const nsCString& aMimeContentType, diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index d10537b5ef56..c074f9191e35 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -230,12 +230,6 @@ public: return PContentParent::RecvPNeckoConstructor(aActor); } - virtual PScreenManagerParent* - AllocPScreenManagerParent(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) MOZ_OVERRIDE; - virtual bool DeallocPScreenManagerParent(PScreenManagerParent* aActor) MOZ_OVERRIDE; - virtual PHalParent* AllocPHalParent() MOZ_OVERRIDE; virtual bool RecvPHalConstructor(PHalParent* aActor) MOZ_OVERRIDE { return PContentParent::RecvPHalConstructor(aActor); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 37772ed50473..bd85b0986b77 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -23,7 +23,6 @@ include protocol PImageBridge; include protocol PIndexedDB; include protocol PMemoryReportRequest; include protocol PNecko; -include protocol PScreenManager; include protocol PSharedBufferManager; include protocol PSms; include protocol PSpeechSynthesis; @@ -304,7 +303,6 @@ intr protocol PContent manages PIndexedDB; manages PMemoryReportRequest; manages PNecko; - manages PScreenManager; manages PSms; manages PSpeechSynthesis; manages PStorage; @@ -481,11 +479,6 @@ parent: PNecko(); - sync PScreenManager() - returns (uint32_t numberOfScreens, - float systemDefaultScale, - bool success); - PSms(); PSpeechSynthesis(); diff --git a/dom/ipc/PScreenManager.ipdl b/dom/ipc/PScreenManager.ipdl deleted file mode 100644 index 28ccea251e34..000000000000 --- a/dom/ipc/PScreenManager.ipdl +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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 protocol PBrowser; -include protocol PContent; - -using struct nsIntRect from "nsRect.h"; - -namespace mozilla { -namespace dom { - -struct ScreenDetails { - uint32_t id; - nsIntRect rect; - nsIntRect availRect; - int32_t pixelDepth; - int32_t colorDepth; - double contentsScaleFactor; -}; - -sync protocol PScreenManager -{ - manager PContent; - -parent: - sync Refresh() - returns (uint32_t numberOfScreens, - float systemDefaultScale, - bool success); - - sync ScreenRefresh(uint32_t aId) - returns (ScreenDetails screen, - bool success); - - sync GetPrimaryScreen() - returns (ScreenDetails screen, - bool success); - - sync ScreenForRect(int32_t aLeft, - int32_t aTop, - int32_t aWidth, - int32_t aHeight) - returns (ScreenDetails screen, - bool success); - - sync ScreenForBrowser(PBrowser aBrowser) - returns (ScreenDetails screen, - bool success); - -child: - __delete__(); -}; - -} // namespace dom -} // namespace mozilla diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp deleted file mode 100644 index 0da23df5f6ce..000000000000 --- a/dom/ipc/ScreenManagerParent.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* 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/dom/TabParent.h" -#include "mozilla/unused.h" -#include "nsIWidget.h" -#include "nsServiceManagerUtils.h" -#include "ScreenManagerParent.h" - -namespace mozilla { -namespace dom { - -static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1"; - -ScreenManagerParent::ScreenManagerParent(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) -{ - mScreenMgr = do_GetService(sScreenManagerContractID); - if (!mScreenMgr) { - MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent."); - } - - unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess); -} - -bool -ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) -{ - *aSuccess = false; - - nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens); - if (NS_FAILED(rv)) { - return true; - } - - rv = mScreenMgr->GetSystemDefaultScale(aSystemDefaultScale); - if (NS_FAILED(rv)) { - return true; - } - - *aSuccess = true; - return true; -} - -bool -ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId, - ScreenDetails* aRetVal, - bool* aSuccess) -{ - *aSuccess = false; - - nsCOMPtr screen; - nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen)); - if (NS_FAILED(rv)) { - return true; - } - - ScreenDetails details; - unused << ExtractScreenDetails(screen, details); - - *aRetVal = details; - *aSuccess = true; - return true; -} - -bool -ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal, - bool* aSuccess) -{ - *aSuccess = false; - - nsCOMPtr screen; - nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen)); - - NS_ENSURE_SUCCESS(rv, true); - - ScreenDetails details; - if (!ExtractScreenDetails(screen, details)) { - return true; - } - - *aRetVal = details; - *aSuccess = true; - return true; -} - -bool -ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft, - const int32_t& aTop, - const int32_t& aWidth, - const int32_t& aHeight, - ScreenDetails* aRetVal, - bool* aSuccess) -{ - *aSuccess = false; - - nsCOMPtr screen; - nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen)); - - NS_ENSURE_SUCCESS(rv, true); - - ScreenDetails details; - if (!ExtractScreenDetails(screen, details)) { - return true; - } - - *aRetVal = details; - *aSuccess = true; - return true; -} - -bool -ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser, - ScreenDetails* aRetVal, - bool* aSuccess) -{ - *aSuccess = false; - - // Find the mWidget associated with the tabparent, and then return - // the nsIScreen it's on. - TabParent* tabParent = static_cast(aBrowser); - nsCOMPtr widget = tabParent->GetWidget(); - if (!widget) { - return true; - } - - nsCOMPtr screen; - if (widget->GetNativeData(NS_NATIVE_WINDOW)) { - mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), - getter_AddRefs(screen)); - } - - NS_ENSURE_TRUE(screen, true); - - ScreenDetails details; - if (!ExtractScreenDetails(screen, details)) { - return true; - } - - *aRetVal = details; - *aSuccess = true; - return true; -} - -bool -ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails) -{ - uint32_t id; - nsresult rv = aScreen->GetId(&id); - NS_ENSURE_SUCCESS(rv, false); - aDetails.id() = id; - - nsIntRect rect; - rv = aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height); - NS_ENSURE_SUCCESS(rv, false); - aDetails.rect() = rect; - - nsIntRect availRect; - rv = aScreen->GetAvailRect(&availRect.x, &availRect.y, &availRect.width, - &availRect.height); - NS_ENSURE_SUCCESS(rv, false); - aDetails.availRect() = availRect; - - int32_t pixelDepth = 0; - rv = aScreen->GetPixelDepth(&pixelDepth); - NS_ENSURE_SUCCESS(rv, false); - aDetails.pixelDepth() = pixelDepth; - - int32_t colorDepth = 0; - rv = aScreen->GetColorDepth(&colorDepth); - NS_ENSURE_SUCCESS(rv, false); - aDetails.colorDepth() = colorDepth; - - double contentsScaleFactor = 1.0; - rv = aScreen->GetContentsScaleFactor(&contentsScaleFactor); - NS_ENSURE_SUCCESS(rv, false); - aDetails.contentsScaleFactor() = contentsScaleFactor; - - return true; -} - -void -ScreenManagerParent::ActorDestroy(ActorDestroyReason why) -{ -} - -} // namespace dom -} // namespace mozilla - diff --git a/dom/ipc/ScreenManagerParent.h b/dom/ipc/ScreenManagerParent.h deleted file mode 100644 index 88dc8733469c..000000000000 --- a/dom/ipc/ScreenManagerParent.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* 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 mozilla_dom_ScreenManagerParent_h -#define mozilla_dom_ScreenManagerParent_h - -#include "mozilla/dom/PScreenManagerParent.h" -#include "nsIScreenManager.h" - -namespace mozilla { -namespace dom { - -class ScreenManagerParent : public PScreenManagerParent -{ - public: - ScreenManagerParent(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess); - ~ScreenManagerParent() {}; - - virtual bool RecvRefresh(uint32_t* aNumberOfScreens, - float* aSystemDefaultScale, - bool* aSuccess) MOZ_OVERRIDE; - - virtual bool RecvScreenRefresh(const uint32_t& aId, - ScreenDetails* aRetVal, - bool* aSuccess) MOZ_OVERRIDE; - - virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; - - virtual bool RecvGetPrimaryScreen(ScreenDetails* aRetVal, - bool* aSuccess) MOZ_OVERRIDE; - - virtual bool RecvScreenForRect(const int32_t& aLeft, - const int32_t& aTop, - const int32_t& aWidth, - const int32_t& aHeight, - ScreenDetails* aRetVal, - bool* aSuccess) MOZ_OVERRIDE; - - virtual bool RecvScreenForBrowser(PBrowserParent* aBrowser, - ScreenDetails* aRetVal, - bool* aSuccess); - - private: - bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails); - nsCOMPtr mScreenMgr; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_ScreenManagerParent_h diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index bc33b215549f..9d4369ca3af2 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -309,8 +309,6 @@ public: */ bool IsDestroyed() const { return mIsDestroyed; } - already_AddRefed GetWidget() const; - protected: bool ReceiveMessage(const nsString& aMessage, bool aSync, @@ -382,6 +380,7 @@ protected: private: already_AddRefed GetFrameLoader() const; + already_AddRefed GetWidget() const; layout::RenderFrameParent* GetRenderFrame(); nsRefPtr mManager; void TryCacheDPIAndScale(); diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index 2fa35ed83c23..6e3f7ed57f1d 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -59,7 +59,6 @@ UNIFIED_SOURCES += [ 'PermissionMessageUtils.cpp', 'PreallocatedProcessManager.cpp', 'ProcessPriorityManager.cpp', - 'ScreenManagerParent.cpp', 'StructuredCloneUtils.cpp', 'TabChild.cpp', 'TabContext.cpp', @@ -93,7 +92,6 @@ IPDL_SOURCES += [ 'PFileDescriptorSet.ipdl', 'PFilePicker.ipdl', 'PMemoryReportRequest.ipdl', - 'PScreenManager.ipdl', 'PTabContext.ipdlh', ] diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index dd1ee0d198b7..ba7ec2d62c03 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -631,17 +631,11 @@ nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect) void nsDeviceContext::FindScreen(nsIScreen** outScreen) { - if (mWidget && mWidget->GetOwningTabChild()) { - mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(), - outScreen); - } - else if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) { + if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW), outScreen); - } - else { + else mScreenManager->GetPrimaryScreen(outScreen); - } } void diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index 36028a217f18..6bf5600b6b6a 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -19,13 +19,6 @@ nsScreenAndroid::~nsScreenAndroid() { } -NS_IMETHODIMP -nsScreenAndroid::GetId(uint32_t *outId) -{ - *outId = 1; - return NS_OK; -} - NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { @@ -87,13 +80,6 @@ nsScreenManagerAndroid::GetPrimaryScreen(nsIScreen **outScreen) return NS_OK; } -NS_IMETHODIMP -nsScreenManagerAndroid::ScreenForId(uint32_t aId, - nsIScreen **outScreen) -{ - return GetPrimaryScreen(outScreen); -} - NS_IMETHODIMP nsScreenManagerAndroid::ScreenForRect(int32_t inLeft, int32_t inTop, diff --git a/widget/android/nsScreenManagerAndroid.h b/widget/android/nsScreenManagerAndroid.h index a07976ef7777..21e3aaa1c385 100644 --- a/widget/android/nsScreenManagerAndroid.h +++ b/widget/android/nsScreenManagerAndroid.h @@ -18,7 +18,6 @@ public: nsScreenAndroid(void *nativeScreen); ~nsScreenAndroid(); - NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); diff --git a/widget/cocoa/nsScreenCocoa.h b/widget/cocoa/nsScreenCocoa.h index 8e19a4d143f7..024badad86f3 100644 --- a/widget/cocoa/nsScreenCocoa.h +++ b/widget/cocoa/nsScreenCocoa.h @@ -16,7 +16,6 @@ public: nsScreenCocoa (NSScreen *screen); ~nsScreenCocoa (); - NS_IMETHOD GetId(uint32_t* outId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); @@ -31,7 +30,6 @@ private: CGFloat BackingScaleFactor(); NSScreen *mScreen; - uint32_t mId; }; #endif // nsScreenCocoa_h_ diff --git a/widget/cocoa/nsScreenCocoa.mm b/widget/cocoa/nsScreenCocoa.mm index 5a9ccb6e26cb..5780a4c7eab2 100644 --- a/widget/cocoa/nsScreenCocoa.mm +++ b/widget/cocoa/nsScreenCocoa.mm @@ -7,14 +7,11 @@ #include "nsObjCExceptions.h" #include "nsCocoaUtils.h" -static uint32_t sScreenId = 0; - nsScreenCocoa::nsScreenCocoa (NSScreen *screen) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; mScreen = [screen retain]; - mId = ++sScreenId; NS_OBJC_END_TRY_ABORT_BLOCK; } @@ -28,17 +25,6 @@ nsScreenCocoa::~nsScreenCocoa () NS_OBJC_END_TRY_ABORT_BLOCK; } -NS_IMETHODIMP -nsScreenCocoa::GetId(uint32_t *outId) -{ - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - - *outId = mId; - return NS_OK; - - NS_OBJC_END_TRY_ABORT_BLOCK; -} - NS_IMETHODIMP nsScreenCocoa::GetRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/cocoa/nsScreenManagerCocoa.mm b/widget/cocoa/nsScreenManagerCocoa.mm index c3fd5431f3dd..3325bece9355 100644 --- a/widget/cocoa/nsScreenManagerCocoa.mm +++ b/widget/cocoa/nsScreenManagerCocoa.mm @@ -35,30 +35,6 @@ nsScreenManagerCocoa::ScreenForCocoaScreen(NSScreen *screen) return sc.get(); } -NS_IMETHODIMP -nsScreenManagerCocoa::ScreenForId (uint32_t aId, nsIScreen **outScreen) -{ - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT - - *outScreen = nullptr; - - for (uint32_t i = 0; i < mScreenList.Length(); ++i) { - nsScreenCocoa* sc = mScreenList[i]; - uint32_t id; - nsresult rv = sc->GetId(&id); - - if (NS_SUCCEEDED(rv) && id == aId) { - *outScreen = sc; - NS_ADDREF(*outScreen); - return NS_OK; - } - } - - return NS_ERROR_FAILURE; - - NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; -} - NS_IMETHODIMP nsScreenManagerCocoa::ScreenForRect (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, nsIScreen **outScreen) diff --git a/widget/cocoa/nsWidgetFactory.mm b/widget/cocoa/nsWidgetFactory.mm index d4f6b5b0e563..043f68af5892 100644 --- a/widget/cocoa/nsWidgetFactory.mm +++ b/widget/cocoa/nsWidgetFactory.mm @@ -134,8 +134,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { mozilla::Module::MAIN_PROCESS_ONLY }, { &kNS_BIDIKEYBOARD_CID, false, NULL, nsBidiKeyboardConstructor }, { &kNS_THEMERENDERER_CID, false, NULL, nsNativeThemeCocoaConstructor }, - { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerCocoaConstructor, - mozilla::Module::MAIN_PROCESS_ONLY }, + { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerCocoaConstructor }, { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecXConstructor, mozilla::Module::MAIN_PROCESS_ONLY }, { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor, @@ -173,8 +172,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { mozilla::Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, - mozilla::Module::MAIN_PROCESS_ONLY }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID, mozilla::Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID, diff --git a/widget/gonk/nsScreenManagerGonk.h b/widget/gonk/nsScreenManagerGonk.h index fc2ab4f4d355..de3114793f2a 100644 --- a/widget/gonk/nsScreenManagerGonk.h +++ b/widget/gonk/nsScreenManagerGonk.h @@ -31,7 +31,6 @@ public: nsScreenGonk(void* nativeScreen); ~nsScreenGonk(); - NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp index c4e8ba76eb4e..c670252eafdb 100644 --- a/widget/gonk/nsWindow.cpp +++ b/widget/gonk/nsWindow.cpp @@ -609,13 +609,6 @@ nsScreenGonk::~nsScreenGonk() { } -NS_IMETHODIMP -nsScreenGonk::GetId(uint32_t *outId) -{ - *outId = 1; - return NS_OK; -} - NS_IMETHODIMP nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) @@ -761,13 +754,6 @@ nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen) return NS_OK; } -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForId(uint32_t aId, - nsIScreen **outScreen) -{ - return GetPrimaryScreen(outScreen); -} - NS_IMETHODIMP nsScreenManagerGonk::ScreenForRect(int32_t inLeft, int32_t inTop, diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp index 84a093e93912..7840c9b7414e 100644 --- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -12,14 +12,10 @@ #endif #include -static uint32_t sScreenId = 0; - - nsScreenGtk :: nsScreenGtk ( ) : mScreenNum(0), mRect(0, 0, 0, 0), - mAvailRect(0, 0, 0, 0), - mId(++sScreenId) + mAvailRect(0, 0, 0, 0) { } @@ -29,20 +25,6 @@ nsScreenGtk :: ~nsScreenGtk() } -nsScreenGtk :: GetId(uint32_t *aId) -{ - *aId = mId; - return NS_OK; -} // GetId - -NS_IMETHODIMP -nsScreenGtk :: GetId(uint32_t *aId) -{ - *aId = mId; - return NS_OK; -} // GetId - - NS_IMETHODIMP nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/gtk/nsScreenGtk.h b/widget/gtk/nsScreenGtk.h index 4434b5fa8711..16a8f090ca59 100644 --- a/widget/gtk/nsScreenGtk.h +++ b/widget/gtk/nsScreenGtk.h @@ -30,7 +30,6 @@ public: nsScreenGtk(); ~nsScreenGtk(); - NS_IMETHOD GetId(uint32_t* aId); NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); @@ -45,7 +44,6 @@ private: uint32_t mScreenNum; nsIntRect mRect; nsIntRect mAvailRect; - uint32_t mId; }; #endif // nsScreenGtk_h___ diff --git a/widget/gtk/nsScreenManagerGtk.cpp b/widget/gtk/nsScreenManagerGtk.cpp index 83513553d9bd..1bb0f3680f9e 100644 --- a/widget/gtk/nsScreenManagerGtk.cpp +++ b/widget/gtk/nsScreenManagerGtk.cpp @@ -188,30 +188,6 @@ nsScreenManagerGtk :: Init() return NS_OK; } -NS_IMETHODIMP -nsScreenManagerGtk :: ScreenForId ( uint32_t aId, nsIScreen **outScreen ) -{ - *outScreen = nullptr; - - nsresult rv; - rv = EnsureInit(); - if (NS_FAILED(rv)) { - NS_ERROR("nsScreenManagerGtk::EnsureInit() failed from ScreenForId"); - return rv; - } - - for (int32_t i = 0, i_end = mCachedScreenArray.Count(); i < i_end; ++i) { - uint32_t id; - rv = mCachedScreenArray[i]->GetId(&id); - if (NS_SUCCEEDED(rv) && id == aId) { - NS_IF_ADDREF(*outScreen = mCachedScreenArray[i]); - return NS_OK; - } - } - - return NS_ERROR_FAILURE; -} - // // ScreenForRect diff --git a/widget/gtk/nsWidgetFactory.cpp b/widget/gtk/nsWidgetFactory.cpp index 1286dc0fa4cb..266262877840 100644 --- a/widget/gtk/nsWidgetFactory.cpp +++ b/widget/gtk/nsWidgetFactory.cpp @@ -214,8 +214,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { #endif { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor }, { &kNS_BIDIKEYBOARD_CID, false, nullptr, nsBidiKeyboardConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerGtkConstructor, - Module::MAIN_PROCESS_ONLY }, + { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerGtkConstructor }, { &kNS_THEMERENDERER_CID, false, nullptr, nsNativeThemeGTKConstructor }, #ifdef NS_PRINTING { &kNS_PRINTSETTINGSSERVICE_CID, false, nullptr, nsPrintOptionsGTKConstructor }, @@ -251,8 +250,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { #endif { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, { "@mozilla.org/widget/bidikeyboard;1", &kNS_BIDIKEYBOARD_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, - Module::MAIN_PROCESS_ONLY }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, #ifdef NS_PRINTING { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID }, diff --git a/widget/nsIScreen.idl b/widget/nsIScreen.idl index 104cd9f9f7cc..3c99585789ec 100644 --- a/widget/nsIScreen.idl +++ b/widget/nsIScreen.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" -[scriptable, uuid(826e80c8-d70f-42e2-8aa9-82c05f2a370a)] +[scriptable, uuid(D6F13AF4-8ACA-4A10-8687-3F99C3692AC0)] interface nsIScreen : nsISupports { /** @@ -29,12 +29,6 @@ interface nsIScreen : nsISupports const unsigned long ROTATION_180_DEG = 2; const unsigned long ROTATION_270_DEG = 3; - /** - * A unique identifier for this device, useful for requerying - * for it via nsIScreenManager. - */ - readonly attribute unsigned long id; - /** * These report screen dimensions in (screen-specific) device pixels */ diff --git a/widget/nsIScreenManager.idl b/widget/nsIScreenManager.idl index 400b5d33b575..445e4e513811 100644 --- a/widget/nsIScreenManager.idl +++ b/widget/nsIScreenManager.idl @@ -7,7 +7,7 @@ #include "nsISupports.idl" #include "nsIScreen.idl" -[scriptable, uuid(e8a96e60-6b61-4a14-bacc-53891604b502)] +[scriptable, uuid(1C195990-FF9E-412B-AFE7-67D1C660BB27)] interface nsIScreenManager : nsISupports { // @@ -17,18 +17,11 @@ interface nsIScreenManager : nsISupports // The coordinates are in pixels (not twips) and in screen coordinates. // nsIScreen screenForRect ( in long left, in long top, in long width, in long height ) ; - - // - // Returns the screen corresponding to the id. If no such screen exists, - // this will throw NS_ERROR_FAILURE. The id is a unique numeric value - // assigned to each screen, and is an attribute available on the nsIScreen - // interface. - nsIScreen screenForId ( in unsigned long id ) ; - + // The screen with the menubar/taskbar. This shouldn't be needed very // often. readonly attribute nsIScreen primaryScreen; - + // Holds the number of screens that are available readonly attribute unsigned long numberOfScreens; diff --git a/widget/windows/nsScreenManagerWin.cpp b/widget/windows/nsScreenManagerWin.cpp index 17ba65949daf..c0c1b24caa56 100644 --- a/widget/windows/nsScreenManagerWin.cpp +++ b/widget/windows/nsScreenManagerWin.cpp @@ -59,23 +59,6 @@ nsScreenManagerWin :: CreateNewScreenObject ( HMONITOR inScreen ) return retScreen; } -NS_IMETHODIMP -nsScreenManagerWin::ScreenForId(uint32_t aId, nsIScreen **outScreen) -{ - *outScreen = nullptr; - - for (unsigned i = 0; i < mScreenList.Length(); ++i) { - ScreenListItem& curr = mScreenList[i]; - uint32_t id; - nsresult rv = curr.mScreen->GetId(&id); - if (NS_SUCCEEDED(rv) && id == aId) { - NS_IF_ADDREF(*outScreen = curr.mScreen.get()); - return NS_OK; - } - } - - return NS_ERROR_FAILURE; -} // // ScreenForRect diff --git a/widget/windows/nsScreenWin.cpp b/widget/windows/nsScreenWin.cpp index ecfc5d15990f..6fcab20674ba 100644 --- a/widget/windows/nsScreenWin.cpp +++ b/widget/windows/nsScreenWin.cpp @@ -8,11 +8,9 @@ #include "gfxWindowsPlatform.h" #include "nsIWidget.h" -static uint32_t sScreenId; nsScreenWin :: nsScreenWin ( HMONITOR inScreen ) : mScreen(inScreen) - , mId(++sScreenId) { #ifdef DEBUG HDC hDCScreen = ::GetDC(nullptr); @@ -33,14 +31,6 @@ nsScreenWin :: ~nsScreenWin() } -NS_IMETHODIMP -nsScreenWin::GetId(uint32_t *outId) -{ - *outId = mId; - return NS_OK; -} - - NS_IMETHODIMP nsScreenWin :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { diff --git a/widget/windows/nsScreenWin.h b/widget/windows/nsScreenWin.h index 08476876f244..f7b42dd7ae85 100644 --- a/widget/windows/nsScreenWin.h +++ b/widget/windows/nsScreenWin.h @@ -17,8 +17,6 @@ public: nsScreenWin ( HMONITOR inScreen ); ~nsScreenWin(); - NS_IMETHOD GetId(uint32_t* aId); - // These methods return the size in device (physical) pixels NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); @@ -36,7 +34,6 @@ public: private: HMONITOR mScreen; - uint32_t mId; }; #endif // nsScreenWin_h___ diff --git a/widget/windows/nsWidgetFactory.cpp b/widget/windows/nsWidgetFactory.cpp index 4b00ef8678b7..fce89c222aa6 100644 --- a/widget/windows/nsWidgetFactory.cpp +++ b/widget/windows/nsWidgetFactory.cpp @@ -221,8 +221,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_FILEPICKER_CID, false, nullptr, FilePickerConstructor, Module::MAIN_PROCESS_ONLY }, { &kNS_COLORPICKER_CID, false, nullptr, ColorPickerConstructor, Module::MAIN_PROCESS_ONLY }, { &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerWinConstructor, - Module::MAIN_PROCESS_ONLY }, + { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerWinConstructor }, { &kNS_GFXINFO_CID, false, nullptr, GfxInfoConstructor }, { &kNS_THEMERENDERER_CID, false, nullptr, NS_NewNativeTheme }, { &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceWinConstructor }, @@ -260,7 +259,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::MAIN_PROCESS_ONLY }, { "@mozilla.org/widget/appshell/win;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::MAIN_PROCESS_ONLY }, + { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, diff --git a/widget/xpwidgets/PuppetWidget.cpp b/widget/xpwidgets/PuppetWidget.cpp index 3928abe49e1e..563daac687bc 100644 --- a/widget/xpwidgets/PuppetWidget.cpp +++ b/widget/xpwidgets/PuppetWidget.cpp @@ -803,13 +803,6 @@ ScreenConfig() return config; } -NS_IMETHODIMP -PuppetScreen::GetId(uint32_t *outId) -{ - *outId = 1; - return NS_OK; -} - NS_IMETHODIMP PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) @@ -829,6 +822,7 @@ PuppetScreen::GetAvailRect(int32_t *outLeft, int32_t *outTop, return GetRect(outLeft, outTop, outWidth, outHeight); } + NS_IMETHODIMP PuppetScreen::GetPixelDepth(int32_t *aPixelDepth) { @@ -868,14 +862,6 @@ PuppetScreenManager::~PuppetScreenManager() { } -NS_IMETHODIMP -PuppetScreenManager::ScreenForId(uint32_t aId, - nsIScreen** outScreen) -{ - NS_IF_ADDREF(*outScreen = mOneScreen.get()); - return NS_OK; -} - NS_IMETHODIMP PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) { diff --git a/widget/xpwidgets/PuppetWidget.h b/widget/xpwidgets/PuppetWidget.h index 6799ec2b0f97..5f53b3b532b7 100644 --- a/widget/xpwidgets/PuppetWidget.h +++ b/widget/xpwidgets/PuppetWidget.h @@ -305,7 +305,6 @@ public: PuppetScreen(void* nativeScreen); ~PuppetScreen(); - NS_IMETHOD GetId(uint32_t* aId) MOZ_OVERRIDE; NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) MOZ_OVERRIDE; NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) MOZ_OVERRIDE; NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) MOZ_OVERRIDE; diff --git a/widget/xpwidgets/ScreenProxy.cpp b/widget/xpwidgets/ScreenProxy.cpp deleted file mode 100644 index fe51b3dbc80a..000000000000 --- a/widget/xpwidgets/ScreenProxy.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* 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/unused.h" -#include "nsIAppShell.h" -#include "nsScreenManagerProxy.h" -#include "nsServiceManagerUtils.h" -#include "nsWidgetsCID.h" -#include "ScreenProxy.h" - -namespace mozilla { -namespace widget { - -using namespace mozilla::dom; - -static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); - -ScreenProxy::ScreenProxy(nsScreenManagerProxy* aScreenManager, ScreenDetails aDetails) - : mScreenManager(aScreenManager) - , mCacheValid(false) - , mCacheWillInvalidate(false) -{ - PopulateByDetails(aDetails); -} - -NS_IMETHODIMP -ScreenProxy::GetId(uint32_t *outId) -{ - *outId = mId; - return NS_OK; -} - -NS_IMETHODIMP -ScreenProxy::GetRect(int32_t *outLeft, - int32_t *outTop, - int32_t *outWidth, - int32_t *outHeight) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *outLeft = mRect.x; - *outTop = mRect.y; - *outWidth = mRect.width; - *outHeight = mRect.height; - return NS_OK; -} - -NS_IMETHODIMP -ScreenProxy::GetAvailRect(int32_t *outLeft, - int32_t *outTop, - int32_t *outWidth, - int32_t *outHeight) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *outLeft = mAvailRect.x; - *outTop = mAvailRect.y; - *outWidth = mAvailRect.width; - *outHeight = mAvailRect.height; - return NS_OK; -} - -NS_IMETHODIMP -ScreenProxy::GetPixelDepth(int32_t *aPixelDepth) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *aPixelDepth = mPixelDepth; - return NS_OK; -} - -NS_IMETHODIMP -ScreenProxy::GetColorDepth(int32_t *aColorDepth) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *aColorDepth = mColorDepth; - return NS_OK; -} - -void -ScreenProxy::PopulateByDetails(ScreenDetails aDetails) -{ - mId = aDetails.id(); - mRect = nsIntRect(aDetails.rect()); - mAvailRect = nsIntRect(aDetails.availRect()); - mPixelDepth = aDetails.pixelDepth(); - mColorDepth = aDetails.colorDepth(); - mContentsScaleFactor = aDetails.contentsScaleFactor(); -} - -bool -ScreenProxy::EnsureCacheIsValid() -{ - if (mCacheValid) { - return true; - } - - bool success = false; - // Kick off a synchronous IPC call to the parent to get the - // most up-to-date information. - ScreenDetails details; - unused << mScreenManager->SendScreenRefresh(mId, &details, &success); - if (!success) { - NS_WARNING("Updating a ScreenProxy in the child process failed on parent side."); - return false; - } - - PopulateByDetails(details); - mCacheValid = true; - - InvalidateCacheOnNextTick(); - return true; -} - -void -ScreenProxy::InvalidateCacheOnNextTick() -{ - if (mCacheWillInvalidate) { - return; - } - - mCacheWillInvalidate = true; - - nsCOMPtr appShell = do_GetService(kAppShellCID); - if (appShell) { - appShell->RunInStableState( - NS_NewRunnableMethod(this, &ScreenProxy::InvalidateCache) - ); - } else { - // It's pretty bad news if we can't get the appshell. In that case, - // let's just invalidate the cache right away. - InvalidateCache(); - } -} - -void -ScreenProxy::InvalidateCache() -{ - mCacheValid = false; - mCacheWillInvalidate = false; -} - -} // namespace widget -} // namespace mozilla - diff --git a/widget/xpwidgets/ScreenProxy.h b/widget/xpwidgets/ScreenProxy.h deleted file mode 100644 index 519284171e5b..000000000000 --- a/widget/xpwidgets/ScreenProxy.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ -/* 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 mozilla_widget_ScreenProxy_h -#define mozilla_widget_ScreenProxy_h - -#include "nsBaseScreen.h" -#include "mozilla/dom/PScreenManagerChild.h" -#include "mozilla/dom/TabChild.h" - -class nsScreenManagerProxy; - -namespace mozilla { -namespace widget { - -class ScreenProxy : public nsBaseScreen -{ -public: - ScreenProxy(nsScreenManagerProxy* aScreenManager, - mozilla::dom::ScreenDetails aDetails); - ~ScreenProxy() {}; - - NS_IMETHOD GetId(uint32_t* aId) MOZ_OVERRIDE; - - NS_IMETHOD GetRect(int32_t* aLeft, - int32_t* aTop, - int32_t* aWidth, - int32_t* aHeight) MOZ_OVERRIDE; - NS_IMETHOD GetAvailRect(int32_t* aLeft, - int32_t* aTop, - int32_t* aWidth, - int32_t* aHeight) MOZ_OVERRIDE; - NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) MOZ_OVERRIDE; - NS_IMETHOD GetColorDepth(int32_t* aColorDepth) MOZ_OVERRIDE; - -private: - - void PopulateByDetails(mozilla::dom::ScreenDetails aDetails); - bool EnsureCacheIsValid(); - void InvalidateCacheOnNextTick(); - void InvalidateCache(); - - double mContentsScaleFactor; - nsRefPtr mScreenManager; - uint32_t mId; - int32_t mPixelDepth; - int32_t mColorDepth; - nsIntRect mRect; - nsIntRect mAvailRect; - bool mCacheValid; - bool mCacheWillInvalidate; -}; - -} // namespace widget -} // namespace mozilla -#endif - diff --git a/widget/xpwidgets/moz.build b/widget/xpwidgets/moz.build index a2aee17d3cdd..8c0afb681a8a 100644 --- a/widget/xpwidgets/moz.build +++ b/widget/xpwidgets/moz.build @@ -34,11 +34,9 @@ UNIFIED_SOURCES += [ 'nsPrintOptionsImpl.cpp', 'nsPrintSession.cpp', 'nsPrintSettingsImpl.cpp', - 'nsScreenManagerProxy.cpp', 'nsTransferable.cpp', 'nsXPLookAndFeel.cpp', 'PuppetWidget.cpp', - 'ScreenProxy.cpp', 'WidgetUtils.cpp', ] diff --git a/widget/xpwidgets/nsContentProcessWidgetFactory.cpp b/widget/xpwidgets/nsContentProcessWidgetFactory.cpp index f7b7a6e08cd6..85b3db597911 100644 --- a/widget/xpwidgets/nsContentProcessWidgetFactory.cpp +++ b/widget/xpwidgets/nsContentProcessWidgetFactory.cpp @@ -10,7 +10,6 @@ #include "nsClipboardProxy.h" #include "nsColorPickerProxy.h" #include "nsFilePickerProxy.h" -#include "nsScreenManagerProxy.h" using namespace mozilla; @@ -19,12 +18,10 @@ using namespace mozilla; NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPickerProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePickerProxy) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerProxy) NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID); NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID); NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); -NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardProxyConstructor, @@ -33,8 +30,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { Module::CONTENT_PROCESS_ONLY }, { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerProxyConstructor, Module::CONTENT_PROCESS_ONLY }, - { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerProxyConstructor, - Module::CONTENT_PROCESS_ONLY }, { nullptr } }; @@ -42,7 +37,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::CONTENT_PROCESS_ONLY }, { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::CONTENT_PROCESS_ONLY }, { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::CONTENT_PROCESS_ONLY }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::CONTENT_PROCESS_ONLY }, { nullptr } }; diff --git a/widget/xpwidgets/nsScreenManagerProxy.cpp b/widget/xpwidgets/nsScreenManagerProxy.cpp deleted file mode 100644 index 747e2fbe6170..000000000000 --- a/widget/xpwidgets/nsScreenManagerProxy.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; 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 "mozilla/unused.h" -#include "mozilla/dom/ContentChild.h" -#include "nsScreenManagerProxy.h" -#include "nsServiceManagerUtils.h" -#include "nsIAppShell.h" -#include "nsIScreen.h" -#include "nsIScreenManager.h" -#include "nsWidgetsCID.h" - -static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); - -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::widget; - -NS_IMPL_ISUPPORTS(nsScreenManagerProxy, nsIScreenManager) - -nsScreenManagerProxy::nsScreenManagerProxy() - : mNumberOfScreens(-1) - , mSystemDefaultScale(1.0) - , mCacheValid(true) - , mCacheWillInvalidate(false) -{ - bool success = false; - unused << ContentChild::GetSingleton()->SendPScreenManagerConstructor( - this, - &mNumberOfScreens, - &mSystemDefaultScale, - &success); - - if (!success) { - // We're in bad shape. We'll return the default values, but we'll basically - // be lying. - NS_WARNING("Setting up communications with the parent nsIScreenManager failed."); - } - - InvalidateCacheOnNextTick(); - - // nsScreenManagerProxy is a service, which will always have a reference - // held to it by the Component Manager once the service is requested. - // However, nsScreenManagerProxy also implements PScreenManagerChild, and - // that means that the manager of the PScreenManager protocol (PContent - // in this case) needs to know how to deallocate this actor. We AddRef here - // so that in the event that PContent tries to deallocate us either before - // or after process shutdown, we don't try to do a double-free. - AddRef(); -} - -/** - * nsIScreenManager - **/ - -NS_IMETHODIMP -nsScreenManagerProxy::GetPrimaryScreen(nsIScreen** outScreen) -{ - InvalidateCacheOnNextTick(); - - if (!mPrimaryScreen) { - ScreenDetails details; - bool success = false; - unused << SendGetPrimaryScreen(&details, &success); - if (!success) { - return NS_ERROR_FAILURE; - } - - mPrimaryScreen = new ScreenProxy(this, details); - } - NS_ADDREF(*outScreen = mPrimaryScreen); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerProxy::ScreenForId(uint32_t aId, nsIScreen** outScreen) -{ - // At this time, there's no need for child processes to query for - // screens by ID. - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsScreenManagerProxy::ScreenForRect(int32_t inLeft, - int32_t inTop, - int32_t inWidth, - int32_t inHeight, - nsIScreen** outScreen) -{ - bool success = false; - ScreenDetails details; - unused << SendScreenForRect(inLeft, inTop, inWidth, inHeight, &details, &success); - if (!success) { - return NS_ERROR_FAILURE; - } - - nsRefPtr screen = new ScreenProxy(this, details); - NS_ADDREF(*outScreen = screen); - - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerProxy::ScreenForNativeWidget(void* aWidget, - nsIScreen** outScreen) -{ - // Because ScreenForNativeWidget can be called numerous times - // indirectly from content via the DOM Screen API, we cache the - // results for this tick of the event loop. - TabChild* tabChild = static_cast(aWidget); - - // Enumerate the cached screen array, looking for one that has - // the TabChild that we're looking for... - for (uint32_t i = 0; i < mScreenCache.Length(); ++i) { - ScreenCacheEntry& curr = mScreenCache[i]; - if (curr.mTabChild == aWidget) { - NS_ADDREF(*outScreen = static_cast(curr.mScreenProxy)); - return NS_OK; - } - } - - // Never cached this screen, so we have to ask the parent process - // for it. - bool success = false; - ScreenDetails details; - unused << SendScreenForBrowser(tabChild, &details, &success); - if (!success) { - return NS_ERROR_FAILURE; - } - - ScreenCacheEntry newEntry; - nsRefPtr screen = new ScreenProxy(this, details); - - newEntry.mScreenProxy = screen; - newEntry.mTabChild = tabChild; - - mScreenCache.AppendElement(newEntry); - - NS_ADDREF(*outScreen = screen); - - InvalidateCacheOnNextTick(); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerProxy::GetNumberOfScreens(uint32_t* aNumberOfScreens) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *aNumberOfScreens = mNumberOfScreens; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerProxy::GetSystemDefaultScale(float *aSystemDefaultScale) -{ - if (!EnsureCacheIsValid()) { - return NS_ERROR_FAILURE; - } - - *aSystemDefaultScale = mSystemDefaultScale; - return NS_OK; -} - -bool -nsScreenManagerProxy::EnsureCacheIsValid() -{ - if (mCacheValid) { - return true; - } - - bool success = false; - // Kick off a synchronous IPC call to the parent to get the - // most up-to-date information. - unused << SendRefresh(&mNumberOfScreens, &mSystemDefaultScale, &success); - if (!success) { - NS_WARNING("Refreshing nsScreenManagerProxy failed in the parent process."); - return false; - } - - mCacheValid = true; - - InvalidateCacheOnNextTick(); - return true; -} - -void -nsScreenManagerProxy::InvalidateCacheOnNextTick() -{ - if (mCacheWillInvalidate) { - return; - } - - mCacheWillInvalidate = true; - - nsCOMPtr appShell = do_GetService(kAppShellCID); - if (appShell) { - appShell->RunInStableState( - NS_NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache) - ); - } else { - // It's pretty bad news if we can't get the appshell. In that case, - // let's just invalidate the cache right away. - InvalidateCache(); - } -} - -void -nsScreenManagerProxy::InvalidateCache() -{ - mCacheValid = false; - mCacheWillInvalidate = false; - - if (mPrimaryScreen) { - mPrimaryScreen = nullptr; - } - for (int32_t i = mScreenCache.Length() - 1; i >= 0; --i) { - mScreenCache.RemoveElementAt(i); - } -} - diff --git a/widget/xpwidgets/nsScreenManagerProxy.h b/widget/xpwidgets/nsScreenManagerProxy.h deleted file mode 100644 index 83f1d7c0fb2e..000000000000 --- a/widget/xpwidgets/nsScreenManagerProxy.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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 nsScreenManagerProxy_h -#define nsScreenManagerProxy_h - -#include "nsIScreenManager.h" -#include "mozilla/dom/PScreenManagerChild.h" -#include "mozilla/dom/TabChild.h" -#include "ScreenProxy.h" - -/** - * The nsScreenManagerProxy is used by the content process to get - * information about system screens. It uses the PScreenManager protocol - * to communicate with a PScreenManagerParent to get this information, - * and also caches the information it gets back. - * - * We cache both the system screen information that nsIScreenManagers - * provide, as well as the nsIScreens that callers can query for. - * - * Both of these caches are invalidated on the next tick of the event - * loop. - */ -class nsScreenManagerProxy MOZ_FINAL : public nsIScreenManager, - public mozilla::dom::PScreenManagerChild -{ -public: - nsScreenManagerProxy(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISCREENMANAGER - -private: - ~nsScreenManagerProxy() {}; - - bool EnsureCacheIsValid(); - void InvalidateCacheOnNextTick(); - void InvalidateCache(); - - uint32_t mNumberOfScreens; - float mSystemDefaultScale; - bool mCacheValid; - bool mCacheWillInvalidate; - - nsRefPtr mPrimaryScreen; - - // nsScreenManagerProxy caches the results to repeated calls to - // ScreenForNativeWidget, which can be triggered indirectly by - // web content using the DOM Screen API. This allows us to bypass - // a lot of IPC traffic. - // - // The cache stores ScreenProxy's mapped to the TabChild that - // asked for the ScreenForNativeWidget was called with via - // ScreenCacheEntry's. The cache is cleared on the next tick of - // the event loop. - struct ScreenCacheEntry - { - nsRefPtr mScreenProxy; - nsRefPtr mTabChild; - }; - - nsTArray mScreenCache; -}; - -#endif // nsScreenManagerProxy_h From cadac9394d154c817a26a4052e2cfa7a553accfd Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 14 Jul 2014 12:48:48 -0400 Subject: [PATCH 29/38] Bug 1037409 - Remove some gtests that don't map to real-world scenarios. r=nicklebedev --- .../gtest/TestAsyncPanZoomController.cpp | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index fbca6aa1544b..469da5a90cb8 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -548,27 +548,6 @@ TEST_F(AsyncPanZoomControllerTester, Pinch_DefaultGestures_NoTouchAction) { DoPinchTest(false, true); } -TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionNone) { - nsTArray behaviors; - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE); - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE); - DoPinchTest(false, false, &behaviors); -} - -TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionZoom) { - nsTArray behaviors; - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); - DoPinchTest(false, true, &behaviors); -} - -TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionNotAllowZoom) { - nsTArray behaviors; - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN); - behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); - DoPinchTest(false, false, &behaviors); -} - TEST_F(AsyncPanZoomControllerTester, Pinch_UseGestureDetector_NoTouchAction) { DoPinchTest(true, true); } From 393cf7b7551721deaad8e6589e5bc42eed14ad02 Mon Sep 17 00:00:00 2001 From: Octoploid Date: Sat, 12 Jul 2014 06:26:00 -0700 Subject: [PATCH 30/38] Bug 1035092 - "bool functions shouldn't return nullptr" [r=sfink] --HG-- extra : rebase_source : 0a0f2549b0a34c759384d8293f6227e112610147 --- content/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp | 2 +- js/src/jsapi.cpp | 2 +- js/xpconnect/src/ExportHelpers.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp b/content/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp index fac680fd262a..daf0d6d08aac 100644 --- a/content/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/content/media/fmp4/ffmpeg/FFmpegRuntimeLinker.cpp @@ -73,7 +73,7 @@ FFmpegRuntimeLinker::Link() Unlink(); sLinkStatus = LinkStatus_FAILED; - return nullptr; + return false; } /* static */ bool diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 5b82cf2b84a2..2f2ebf0446a3 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4733,7 +4733,7 @@ JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOption else chars = InflateString(cx, bytes, &length); if (!chars) - return nullptr; + return false; return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun); } diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 5101b5d312b8..de6b5d9cc76b 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -229,7 +229,7 @@ CloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp) if (!JS_WrapObject(cx, &argObj)) return false; if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, argObj, innerOptions, args[i])) - return nullptr; + return false; } else if (!StackScopedClone(cx, cloneOptions, args[i])) { return false; } From 22be9ff3ec1e69dd653af112e56aba0de8c9a111 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:06 -0700 Subject: [PATCH 31/38] Bug 856067 - Fix Object Actor Previews. r=past --- toolkit/devtools/server/actors/script.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index e48f1649517a..18cc8e08474c 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -3699,18 +3699,21 @@ DebuggerServer.ObjectActorPreviewers = { let raw = obj.unsafeDereference(); let entries = aGrip.preview.entries = []; - // We don't have Xrays to Iterators, so .entries returns [key, value] - // Arrays that live in content. But since we have Array Xrays, - // we'll deny access depending on the nature of those values. So we need - // to waive Xrays on those tuples (and re-apply them on the underlying - // values) until we fix bug 1023984. + // Iterating over a Map via .entries goes through various intermediate + // objects - an Iterator object, then a 2-element Array object, then the + // actual values we care about. We don't have Xrays to Iterator objects, + // so we get Opaque wrappers for them. And even though we have Xrays to + // Arrays, the semantics often deny access to the entires based on the + // nature of the values. So we need waive Xrays for the iterator object + // and the tupes, and then re-apply them on the underlying values until + // we fix bug 1023984. // // Even then though, we might want to continue waiving Xrays here for the // same reason we do so for Arrays above - this filtering behavior is likely // to be more confusing than beneficial in the case of Object previews. - for (let keyValuePair of Map.prototype.entries.call(raw)) { - let key = Cu.unwaiveXrays(Cu.waiveXrays(keyValuePair)[0]); - let value = Cu.unwaiveXrays(Cu.waiveXrays(keyValuePair)[1]); + for (let keyValuePair of Cu.waiveXrays(Map.prototype.entries.call(raw))) { + let key = Cu.unwaiveXrays(keyValuePair[0]); + let value = Cu.unwaiveXrays(keyValuePair[1]); key = makeDebuggeeValueIfNeeded(obj, key); value = makeDebuggeeValueIfNeeded(obj, value); entries.push([threadActor.createValueGrip(key), From 65bed4527bc1dce41aaeab8b6f66b3b1d613017d Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:06 -0700 Subject: [PATCH 32/38] Bug 856067 - Fix up test_xrayToJS.xul. r=gabor --- js/xpconnect/tests/chrome/test_xrayToJS.xul | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 6c0aac35691f..a2353716e36c 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -54,14 +54,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 "we end up with the appropriate constructor: " + c); is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c], "constructor property is set up right: " + c); - is(Object.getPrototypeOf(new iwin[c]), iwin[c].prototype, + let expectedProto = /Opaque/.test(new iwin[c]) ? iwin['Object'].prototype + : iwin[c].prototype; + is(Object.getPrototypeOf(new iwin[c]), expectedProto, "prototype is correct: " + c); is(global(new iwin[c]), iwin, "Got the right global: " + c); } // Test Object in more detail. var num = new iwin.Object(4); - is(num.valueOf(), 4, "primitive object construction works"); + is(Cu.waiveXrays(num).valueOf(), 4, "primitive object construction works"); is(global(num), iwin, "correct global for num"); var obj = new iwin.Object(); obj.foo = 2; @@ -105,26 +107,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 ok(Object.getOwnPropertyNames(foopyFunction).indexOf('prototype') == -1, "Should not list prototype"); ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor"); - // Test interface objects that don't actually construct things. - is(iwin.Math.tan(4.5), Math.tan(4.5), "Math.tan works"); - is(iwin.Math.E, Math.E, "Math.E works"); - var json = JSON.stringify({a: 2, b: 'hi', c: {d: 'there'}}); - is(global(iwin.JSON.parse(json)), iwin, "JSON rehydrated into the right context"); - is(iwin.JSON.stringify(iwin.JSON.parse(json)), json, "JSON composition identity holds"); - // Test proxies. var targetObject = new iwin.Object(); targetObject.foo = 9; var forwardingProxy = new iwin.Proxy(targetObject, new iwin.Object()); is(global(forwardingProxy), iwin, "proxy global correct"); - is(forwardingProxy.foo, 9, "forwards correctly"); + is(Cu.waiveXrays(forwardingProxy).foo, 9, "forwards correctly"); // NB: COW-implemented proxy handlers are super dangerous, and we should not // encourage them. var handler = {get: function(target, name) { return name * 2; }, __exposedProps__: {get: 'r'}}; var doublingProxy = new iwin.Proxy(targetObject, handler); is(global(doublingProxy), iwin, "doubling proxy global correct"); - is(doublingProxy[3], 6, "Doubles correctly"); - is(doublingProxy[20], 40, "Doubles correctly"); + is(Cu.waiveXrays(doublingProxy)[3], 6, "Doubles correctly"); + is(Cu.waiveXrays(doublingProxy)[20], 40, "Doubles correctly"); // Test eval. var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})"; @@ -250,8 +245,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 if (method.length == 0) { is(method.call(xray) + "", local.call(xray) + "", "Xray and local method results stringify identically"); - is(method.call(xray) + "", lookupCallable(xray.wrappedJSObject).call(xray.wrappedJSObject) + "", - "Xray and waived method results stringify identically"); + + // If invoking this method returns something non-Xrayable, the + // stringification is going to return [object Opaque]. This happens for + // xrayedTypedArray.buffer, for instance, since we don't have Xrays + // To ArrayBuffers. Just check for that case. + if (!/Opaque/.test(method.call(xray))) { + is(method.call(xray) + "", + lookupCallable(xray.wrappedJSObject).call(xray.wrappedJSObject) + "", + "Xray and waived method results stringify identically"); + } } } is(Object.getOwnPropertyNames(xrayProto).sort().toSource(), From a8b3c456f156a945b9809a2e81f91cea750b935f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:06 -0700 Subject: [PATCH 33/38] Bug 856067 - Waive Xrays when SpecialPowers encounters an Opaque XrayWrapper. r=gabor --- testing/specialpowers/content/specialpowersAPI.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 94aedf6ea1eb..05c09be396e6 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -98,9 +98,16 @@ function isObjectOrArray(obj) { // security in general, but tends to break tests that try to pass object // literals into SpecialPowers. So we waive [[Object]] and [[Array]] // instances before inspecting properties. +// +// * When we don't have meaningful Xray semantics, we create an Opaque +// XrayWrapper for security reasons. For test code, we generally want to see +// through that sort of thing. function waiveXraysIfAppropriate(obj, propName) { - if (propName == 'toString' || isObjectOrArray(obj)) + if (propName == 'toString' || isObjectOrArray(obj) || + /Opaque/.test(Object.prototype.toString.call(obj))) +{ return XPCNativeWrapper.unwrap(obj); +} return obj; } From 1ef8a8645914c9607c202d6c8c222c286a34462c Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:07 -0700 Subject: [PATCH 34/38] Bug 856067 - Make unwaived non-Xrayable objects opaque from privileged code. r=gabor --- js/xpconnect/wrappers/WrapperFactory.cpp | 8 +++++--- js/xpconnect/wrappers/XrayWrapper.cpp | 9 ++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 26702ba8d8b9..2b0b7e9b3d87 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -370,8 +370,10 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, return &PermissiveXrayXPCWN::singleton; else if (xrayType == XrayForDOMObject) return &PermissiveXrayDOM::singleton; - MOZ_ASSERT(xrayType == XrayForJSObject); - return &PermissiveXrayJS::singleton; + else if (xrayType == XrayForJSObject) + return &PermissiveXrayJS::singleton; + MOZ_ASSERT(xrayType == XrayForOpaqueObject); + return &PermissiveXrayOpaque::singleton; } // This is a security wrapper. Use the security versions and filter. @@ -389,7 +391,7 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, // functions exposed from the XBL scope. We could remove this exception, // if needed, by using ExportFunction to generate the content-side // representations of XBL methods. - MOZ_ASSERT(xrayType == XrayForJSObject); + MOZ_ASSERT(xrayType == XrayForJSObject || xrayType == XrayForOpaqueObject); if (originIsXBLScope) return &FilteringWrapper::singleton; return &FilteringWrapper::singleton; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index e5d31fa442b3..643481ad0428 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -103,7 +103,14 @@ GetXrayType(JSObject *obj) if (IsJSXraySupported(standardProto)) return XrayForJSObject; - return NotXray; + // Modulo a few exceptions, everything else counts as an XrayWrapper to an + // opaque object, which means that more-privileged code sees nothing from + // the underlying object. This is very important for security. In some cases + // though, we need to make an exception for compatibility. + if (IsSandbox(obj)) + return NotXray; + + return XrayForOpaqueObject; } JSObject * From 2fac4671d3bcfa3c8e8013619f729ef7ec30e37f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:07 -0700 Subject: [PATCH 35/38] Bug 856067 - Remove special case for content XBL scopes. r=gabor This is now the default behavior. \o/ --- js/xpconnect/wrappers/WrapperFactory.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 2b0b7e9b3d87..6b5300518bf8 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -445,20 +445,6 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj, wrapper = &ChromeObjectWrapper::singleton; } - // Normally, a non-xrayable non-waived content object that finds itself in - // a privileged scope is wrapped with a CrossCompartmentWrapper, even though - // the lack of a waiver _really_ should give it an opaque wrapper. This is - // a bit too entrenched to change for content-chrome, but we can at least fix - // it for XBL scopes. - // - // See bug 843829. - else if (targetSubsumesOrigin && !originSubsumesTarget && - !waiveXrayFlag && xrayType == NotXray && - IsContentXBLScope(target)) - { - wrapper = &PermissiveXrayOpaque::singleton; - } - // // Now, handle the regular cases. // From d65aa88546a3bbe90e9f28319e8bd390b088953c Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:07 -0700 Subject: [PATCH 36/38] Bug 856067 - Add some helpful logging to the console when we deny access to a non-Xrayable object. r=gabor --- js/xpconnect/wrappers/XrayWrapper.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 643481ad0428..7cbb8c07e2bc 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -69,6 +69,8 @@ IsTypedArrayKey(JSProtoKey key) return key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray; } +bool SilentFailure(JSContext *cx, JS::HandleId id, const char *reason); + // Whitelist for the standard ES classes we can Xray to. static bool IsJSXraySupported(JSProtoKey key) @@ -493,6 +495,17 @@ public: MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1"); } + virtual bool resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, HandleObject wrapper, + HandleObject holder, HandleId id, + MutableHandle desc) MOZ_OVERRIDE + { + bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, id, desc); + if (!ok || desc.object()) + return ok; + + return SilentFailure(cx, id, "Object is not safely Xrayable"); + } + bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc, Handle existingDesc, bool *defined) @@ -560,7 +573,7 @@ public: static OpaqueXrayTraits singleton; }; -inline bool +bool SilentFailure(JSContext *cx, HandleId id, const char *reason) { #ifdef DEBUG @@ -570,7 +583,7 @@ SilentFailure(JSContext *cx, HandleId id, const char *reason) AutoFilename filename; unsigned line = 0; DescribeScriptedCaller(cx, &filename, &line); - NS_WARNING(nsPrintfCString("Denied access to property |%s| on Xrayed Object: %s (@%s:%u)", + NS_WARNING(nsPrintfCString("Silently denied access to property |%s|: %s (@%s:%u)", NS_LossyConvertUTF16toASCII(name).get(), reason, filename.get(), line).get()); #endif From b37b624cfac66ffc65b9b8f608d11065ec3ff461 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:09:07 -0700 Subject: [PATCH 37/38] Bug 856067 - Tests. r=me --- js/xpconnect/tests/unit/xpcshell.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index 1db1412a26d6..1f5425c5bd6a 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -35,6 +35,7 @@ support-files = [test_bug849730.js] [test_bug851895.js] [test_bug854558.js] +[test_bug856067.js] [test_bug868675.js] [test_bug867486.js] [test_bug872772.js] From 2b91ca141d4920b91a757f70c49b3f175a7b05d1 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 14 Jul 2014 10:22:51 -0700 Subject: [PATCH 38/38] Bug 856067 - Actually push the test. r=me CLOSED TREE --- js/xpconnect/tests/unit/test_bug856067.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 js/xpconnect/tests/unit/test_bug856067.js diff --git a/js/xpconnect/tests/unit/test_bug856067.js b/js/xpconnect/tests/unit/test_bug856067.js new file mode 100644 index 000000000000..105e9cb6bd93 --- /dev/null +++ b/js/xpconnect/tests/unit/test_bug856067.js @@ -0,0 +1,10 @@ +const Cu = Components.utils; + +function run_test() { + var sb = new Cu.Sandbox('http://www.example.com'); + let w = Cu.evalInSandbox('var w = WeakMap(); w.__proto__ = new Set(); w.foopy = 12; w', sb); + do_check_eq(Object.getPrototypeOf(w), sb.Object.prototype); + do_check_eq(Object.getOwnPropertyNames(w).length, 0); + do_check_eq(w.wrappedJSObject.foopy, 12); + do_check_eq(w.foopy, undefined); +}