From e9644d49d446e41dbdbdb4ee22c7bb803c391888 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Wed, 15 Oct 2014 17:48:04 +0300 Subject: [PATCH 001/100] Bug 874050, Make Nofification's click event cancelable, r=wchen --HG-- extra : rebase_source : 155ceeec566a9726d9280be0eeeb6e0209df456c --- .../browser_notification_tab_switching.js | 153 +++++++++++------- .../test/general/file_dom_notifications.html | 63 +++++--- dom/events/Event.cpp | 11 +- dom/events/Event.h | 37 ++++- dom/events/EventListenerManager.cpp | 2 +- dom/notification/Notification.cpp | 27 +++- 6 files changed, 202 insertions(+), 91 deletions(-) diff --git a/browser/base/content/test/general/browser_notification_tab_switching.js b/browser/base/content/test/general/browser_notification_tab_switching.js index f1f568daad33..75af0f4e6f70 100644 --- a/browser/base/content/test/general/browser_notification_tab_switching.js +++ b/browser/base/content/test/general/browser_notification_tab_switching.js @@ -1,58 +1,95 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -"use strict"; - -let tab; -let notification; -let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; - -function test () { - waitForExplicitFinish(); - - let pm = Services.perms; - registerCleanupFunction(function() { - pm.remove(notificationURL, "desktop-notification"); - gBrowser.removeTab(tab); - window.restore(); - }); - - pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); - - tab = gBrowser.addTab(notificationURL); - tab.linkedBrowser.addEventListener("load", onLoad, true); -} - -function onLoad() { - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - tab.linkedBrowser.removeEventListener("load", onLoad, true); - let win = tab.linkedBrowser.contentWindow.wrappedJSObject; - notification = win.showNotification(); - notification.addEventListener("show", onAlertShowing); -} - -function onAlertShowing() { - info("Notification alert showing"); - notification.removeEventListener("show", onAlertShowing); - - let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); - if (!alertWindow) { - todo(false, "Notifications don't use XUL windows on all platforms."); - notification.close(); - finish(); - return; - } - gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); - EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); - info("Clicked on notification"); - alertWindow.close(); -} - -function onTabSelect() { - gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); - is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, - "Notification tab should be selected."); - - finish(); -} +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +let tab; +let notification; +let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; +let newWindowOpenedFromTab; + +function test () { + waitForExplicitFinish(); + + let pm = Services.perms; + registerCleanupFunction(function() { + pm.remove(notificationURL, "desktop-notification"); + gBrowser.removeTab(tab); + window.restore(); + }); + + pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); + + tab = gBrowser.addTab(notificationURL); + tab.linkedBrowser.addEventListener("load", onLoad, true); +} + +function onLoad() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + tab.linkedBrowser.removeEventListener("load", onLoad, true); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + win.newWindow = win.open("about:blank", "", "height=100,width=100"); + newWindowOpenedFromTab = win.newWindow; + win.newWindow.addEventListener("load", function() { + info("new window loaded"); + win.newWindow.addEventListener("blur", function b() { + info("new window got blur"); + win.newWindow.removeEventListener("blur", b); + notification = win.showNotification1(); + win.newWindow.addEventListener("focus", onNewWindowFocused); + notification.addEventListener("show", onAlertShowing); + }); + + function waitUntilNewWindowHasFocus() { + if (!win.newWindow.document.hasFocus()) { + setTimeout(waitUntilNewWindowHasFocus, 50); + } else { + // Focus another window so that new window gets blur event. + gBrowser.selectedTab.linkedBrowser.contentWindow.focus(); + } + } + win.newWindow.focus(); + waitUntilNewWindowHasFocus(); + }); +} + +function onAlertShowing() { + info("Notification alert showing"); + notification.removeEventListener("show", onAlertShowing); + + let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); + if (!alertWindow) { + todo(false, "Notifications don't use XUL windows on all platforms."); + notification.close(); + newWindowOpenedFromTab.close(); + finish(); + return; + } + gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); + EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); + info("Clicked on notification"); + alertWindow.close(); +} + +function onNewWindowFocused(event) { + event.target.close(); + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + // Using timeout to test that something do *not* happen! + setTimeout(openSecondNotification, 50); +} + +function openSecondNotification() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + notification = win.showNotification2(); + notification.addEventListener("show", onAlertShowing); +} + +function onTabSelect() { + gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); + is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, + "Notification tab should be selected."); + + finish(); +} diff --git a/browser/base/content/test/general/file_dom_notifications.html b/browser/base/content/test/general/file_dom_notifications.html index 8791d5a1a5be..078c94a42d18 100644 --- a/browser/base/content/test/general/file_dom_notifications.html +++ b/browser/base/content/test/general/file_dom_notifications.html @@ -1,23 +1,40 @@ - - - - - -
- -
- - + + + + + +
+ +
+ + diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index cebeeffad75e..d2be9cf83985 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -76,6 +76,7 @@ Event::ConstructorInit(EventTarget* aOwner, } mPrivateDataDuplicated = false; + mWantsPopupControlCheck = false; if (aEvent) { mEvent = aEvent; @@ -655,12 +656,20 @@ PopupAllowedForEvent(const char *eventName) // static PopupControlState -Event::GetEventPopupControlState(WidgetEvent* aEvent) +Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) { // generally if an event handler is running, new windows are disallowed. // check for exceptions: PopupControlState abuse = openAbused; + if (aDOMEvent && aDOMEvent->InternalDOMEvent()->GetWantsPopupControlCheck()) { + nsAutoString type; + aDOMEvent->GetType(type); + if (PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())) { + return openAllowed; + } + } + switch(aEvent->mClass) { case eBasicEventClass: // For these following events only allow popups if they're diff --git a/dom/events/Event.h b/dom/events/Event.h index de2c1db7bc85..1ffd085fe84c 100644 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -30,6 +30,7 @@ namespace dom { class EventTarget; class ErrorEvent; class ProgressEvent; +class WantsPopupControlCheck; // Dummy class so we can cast through it to get from nsISupports to // Event subclasses with only two non-ambiguous static casts. @@ -113,7 +114,8 @@ public: // Returns true if the event should be trusted. bool Init(EventTarget* aGlobal); - static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent); + static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent, + nsIDOMEvent* aDOMEvent = nullptr); static void PopupAllowedEventsChanged(); @@ -235,6 +237,17 @@ protected: void SetEventType(const nsAString& aEventTypeArg); already_AddRefed GetTargetFromFrame(); + friend class WantsPopupControlCheck; + void SetWantsPopupControlCheck(bool aCheck) + { + mWantsPopupControlCheck = aCheck; + } + + bool GetWantsPopupControlCheck() + { + return IsTrusted() && mWantsPopupControlCheck; + } + /** * IsChrome() returns true if aCx is chrome context or the event is created * in chrome's thread. Otherwise, false. @@ -248,6 +261,28 @@ protected: bool mEventIsInternal; bool mPrivateDataDuplicated; bool mIsMainThreadEvent; + // True when popup control check should rely on event.type, not + // WidgetEvent.message. + bool mWantsPopupControlCheck; +}; + +class MOZ_STACK_CLASS WantsPopupControlCheck +{ +public: + WantsPopupControlCheck(nsIDOMEvent* aEvent) : mEvent(aEvent->InternalDOMEvent()) + { + mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck(); + mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted()); + } + + ~WantsPopupControlCheck() + { + mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck); + } + +private: + Event* mEvent; + bool mOriginalWantsPopupControlCheck; }; } // namespace dom diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 288707af9c2c..82a55045d631 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -976,7 +976,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext, nsAutoTObserverArray::EndLimitedIterator iter(mListeners); Maybe popupStatePusher; if (mIsMainThreadELM) { - popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent)); + popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent)); } bool hasListener = false; diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 74e388cf9406..0d33cd14673c 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -24,6 +24,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIXPConnect.h" #include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/Event.h" #include "mozilla/Services.h" #include "nsContentPermissionHelper.h" #ifdef MOZ_B2G @@ -360,19 +361,31 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { nsCOMPtr window = mNotification->GetOwner(); - if (!window) { + if (!window || !window->IsCurrentInnerWindow()) { // Window has been closed, this observer is not valid anymore return NS_ERROR_FAILURE; } if (!strcmp("alertclickcallback", aTopic)) { - nsIDocument* doc = window ? window->GetExtantDoc() : nullptr; - if (doc) { - nsContentUtils::DispatchChromeEvent(doc, window, - NS_LITERAL_STRING("DOMWebNotificationClicked"), - true, true); + + nsCOMPtr event; + NS_NewDOMEvent(getter_AddRefs(event), mNotification, nullptr, nullptr); + nsresult rv = event->InitEvent(NS_LITERAL_STRING("click"), false, true); + NS_ENSURE_SUCCESS(rv, rv); + event->SetTrusted(true); + WantsPopupControlCheck popupControlCheck(event); + bool doDefaultAction = true; + mNotification->DispatchEvent(event, &doDefaultAction); + if (doDefaultAction) { + nsIDocument* doc = window ? window->GetExtantDoc() : nullptr; + if (doc) { + // Browser UI may use DOMWebNotificationClicked to focus the tab + // from which the event was dispatched. + nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(), + NS_LITERAL_STRING("DOMWebNotificationClicked"), + true, true); + } } - mNotification->DispatchTrustedEvent(NS_LITERAL_STRING("click")); } else if (!strcmp("alertfinished", aTopic)) { nsCOMPtr notificationStorage = do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID); From d65caebbb00ef9d8b082270c6fdf865dd6670d2b Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:20 -0700 Subject: [PATCH 002/100] Bug 1079628 - Record the number of bytes decoded on a per-decoder basis. r=tn --HG-- extra : rebase_source : d479aeb16595648f61adee8e0ad18558f5d9e6ba --- image/src/Decoder.cpp | 8 +++- image/src/Decoder.h | 3 ++ image/src/RasterImage.cpp | 83 ++++++++++++++++++++------------------- image/src/RasterImage.h | 1 - 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 4694958b0cc2..24664b063901 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -20,6 +20,7 @@ Decoder::Decoder(RasterImage &aImage) , mImageData(nullptr) , mColormap(nullptr) , mDecodeFlags(0) + , mBytesDecoded(0) , mDecodeDone(false) , mDataError(false) , mFrameCount(0) @@ -93,8 +94,11 @@ Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) MOZ_ASSERT(NS_IsMainThread() || aStrategy == DECODE_ASYNC); // We're strict about decoder errors - NS_ABORT_IF_FALSE(!HasDecoderError(), - "Not allowed to make more decoder calls after error!"); + MOZ_ASSERT(!HasDecoderError(), + "Not allowed to make more decoder calls after error!"); + + // Keep track of the total number of bytes written. + mBytesDecoded += aCount; // If a data error occured, just ignore future data if (HasDataError()) diff --git a/image/src/Decoder.h b/image/src/Decoder.h index 9cd4b8bc8084..077f8f5ed85c 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -101,6 +101,8 @@ public: mObserver = aObserver; } + size_t BytesDecoded() const { return mBytesDecoded; } + // The number of frames we have, including anything in-progress. Thus, this // is only 0 if we haven't begun any frames. uint32_t GetFrameCount() { return mFrameCount; } @@ -234,6 +236,7 @@ protected: uint32_t mColormapSize; uint32_t mDecodeFlags; + size_t mBytesDecoded; bool mDecodeDone; bool mDataError; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 09f2beb81f00..05307d6117d0 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -62,7 +62,9 @@ using namespace gfx; using namespace layers; namespace image { + using std::ceil; +using std::min; // a mask for flags that will affect the decoding #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) @@ -319,7 +321,6 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker, #endif mDecodingMonitor("RasterImage Decoding Monitor"), mDecoder(nullptr), - mBytesDecoded(0), mInDecoder(false), mStatusDiff(ImageStatusDiff::NoChange()), mNotifying(false), @@ -1535,7 +1536,7 @@ RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount) // Starting a new part's frames, let's clean up before we add any // This needs to happen just before we start getting EnsureFrame() call(s), // so that there's no gap for anything to miss us. - if (mMultipart && mBytesDecoded == 0) { + if (mMultipart && (!mDecoder || mDecoder->BytesDecoded() == 0)) { // Our previous state may have been animated, so let's clean up if (mAnimating) StopAnimation(); @@ -2095,8 +2096,6 @@ RasterImage::ShutdownDecoder(eShutdownIntent aIntent) mSourceData.Clear(); } - mBytesDecoded = 0; - return NS_OK; } @@ -2117,10 +2116,6 @@ RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError()); - // Keep track of the total number of bytes written over the lifetime of the - // decoder - mBytesDecoded += aCount; - return NS_OK; } @@ -2252,7 +2247,7 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) // If we've already got a full decoder running, and have already decoded // some bytes, we have nothing to do if we haven't been asked to do some // sync decoding - if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded && + if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0 && aDecodeType != SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) { return NS_OK; } @@ -2260,10 +2255,11 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) ReentrantMonitorAutoEnter lock(mDecodingMonitor); // If we don't have any bytes to flush to the decoder, we can't do anything. - // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing - // the source data. - if (mBytesDecoded > mSourceData.Length()) + // mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're + // not storing the source data. + if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) { return NS_OK; + } // After acquiring the lock we may have finished some more decoding, so // we need to repeat the following three checks after getting the lock. @@ -2285,8 +2281,8 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) } // If we've already got a full decoder running, and have already - // decoded some bytes, we have nothing to do - if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded) { + // decoded some bytes, we have nothing to do. + if (mDecoder && !mDecoder->IsSizeDecode() && mDecoder->BytesDecoded() > 0) { return NS_OK; } @@ -2304,13 +2300,14 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) rv = FinishedSomeDecoding(); CONTAINER_ENSURE_SUCCESS(rv); - - MOZ_ASSERT(mDecoder); } + MOZ_ASSERT(mDecoder); + // If we've read all the data we have, we're done - if (mHasSourceData && mBytesDecoded == mSourceData.Length()) + if (mHasSourceData && mDecoder->BytesDecoded() == mSourceData.Length()) { return NS_OK; + } // If we can do decoding now, do so. Small images will decode completely, // large images will decode a bit and post themselves to the event loop @@ -2377,10 +2374,11 @@ RasterImage::SyncDecode() return NS_OK; // If we don't have any bytes to flush to the decoder, we can't do anything. - // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing - // the source data. - if (mBytesDecoded > mSourceData.Length()) + // mDecoder->BytesDecoded() can be bigger than mSourceData.Length() if we're + // not storing the source data. + if (mDecoder && mDecoder->BytesDecoded() > mSourceData.Length()) { return NS_OK; + } // If we have a decoder open with different flags than what we need, shut it // down @@ -2411,8 +2409,11 @@ RasterImage::SyncDecode() CONTAINER_ENSURE_SUCCESS(rv); } + MOZ_ASSERT(mDecoder); + // Write everything we have - rv = DecodeSomeData(mSourceData.Length() - mBytesDecoded, DECODE_SYNC); + rv = DecodeSomeData(mSourceData.Length() - mDecoder->BytesDecoded(), + DECODE_SYNC); CONTAINER_ENSURE_SUCCESS(rv); // When we're doing a sync decode, we want to get as much information from the @@ -2772,8 +2773,7 @@ RasterImage::RequestDiscard() nsresult RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy) { - // We should have a decoder if we get here - NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!"); + MOZ_ASSERT(mDecoder, "Should have a decoder"); mDecodingMonitor.AssertCurrentThreadIn(); @@ -2788,20 +2788,20 @@ RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy) } } - // If we have nothing else to decode, return - if (mBytesDecoded == mSourceData.Length()) + // If we have nothing else to decode, return. + if (mDecoder->BytesDecoded() == mSourceData.Length()) { return NS_OK; + } - MOZ_ASSERT(mBytesDecoded < mSourceData.Length()); + MOZ_ASSERT(mDecoder->BytesDecoded() < mSourceData.Length()); // write the proper amount of data - size_t bytesToDecode = std::min(aMaxBytes, - mSourceData.Length() - mBytesDecoded); - nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded, - bytesToDecode, - aStrategy); + size_t bytesToDecode = min(aMaxBytes, + mSourceData.Length() - mDecoder->BytesDecoded()); + return WriteToDecoder(mSourceData.Elements() + mDecoder->BytesDecoded(), + bytesToDecode, + aStrategy); - return rv; } // There are various indicators that tell us we're finished with the decode @@ -2813,7 +2813,7 @@ RasterImage::IsDecodeFinished() { // Precondition mDecodingMonitor.AssertCurrentThreadIn(); - NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!"); + MOZ_ASSERT(mDecoder, "Should have a decoder"); // The decode is complete if we got what we wanted. if (mDecoder->IsSizeDecode()) { @@ -2838,7 +2838,7 @@ RasterImage::IsDecodeFinished() // (NB - This can be the case even for non-erroneous images because // Decoder::GetDecodeDone() might not return true until after we call // Decoder::Finish() in ShutdownDecoder()) - if (mHasSourceData && (mBytesDecoded == mSourceData.Length())) { + if (mHasSourceData && (mDecoder->BytesDecoded() == mSourceData.Length())) { return true; } @@ -3031,7 +3031,7 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D // SpeedHistogram return HistogramCount. Telemetry::ID id = decoder->SpeedHistogram(); if (id < Telemetry::HistogramCount) { - int32_t KBps = int32_t(request->mImage->mBytesDecoded / + int32_t KBps = int32_t(decoder->BytesDecoded() / (1024 * request->mDecodeTime.ToSeconds())); Telemetry::Accumulate(id, KBps); } @@ -3207,7 +3207,8 @@ RasterImage::DecodePool::RequestDecode(RasterImage* aImg) if (!aImg->mDecoder->NeedsNewFrame()) { // No matter whether this is currently being decoded, we need to update the // number of bytes we want it to decode. - aImg->mDecodeRequest->mBytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded; + aImg->mDecodeRequest->mBytesToDecode = + aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded(); if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING || aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) { @@ -3255,7 +3256,7 @@ RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrateg if (aImg->mDecoder && !aImg->mError && !aImg->IsDecodeFinished() && - aImg->mSourceData.Length() > aImg->mBytesDecoded) { + aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded()) { RequestDecode(aImg); } } @@ -3299,7 +3300,7 @@ RasterImage::DecodePool::DecodeJob::Run() mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE; - size_t oldByteCount = mImage->mBytesDecoded; + size_t oldByteCount = mImage->mDecoder->BytesDecoded(); DecodeType type = DECODE_TYPE_UNTIL_DONE_BYTES; @@ -3311,7 +3312,7 @@ RasterImage::DecodePool::DecodeJob::Run() DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, type, mRequest->mBytesToDecode); - size_t bytesDecoded = mImage->mBytesDecoded - oldByteCount; + size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount; mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE; @@ -3442,7 +3443,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, } if (bytesToDecode == 0) { - bytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded; + bytesToDecode = aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded(); } int32_t chunkCount = 0; @@ -3456,7 +3457,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, // * we run out of time. // We also try to decode at least one "chunk" if we've allocated a new frame, // even if we have no more data to send to the decoder. - while ((aImg->mSourceData.Length() > aImg->mBytesDecoded && + while ((aImg->mSourceData.Length() > aImg->mDecoder->BytesDecoded() && bytesToDecode > 0 && !aImg->IsDecodeFinished() && !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) && diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 2ef4899ad6b6..9dd2cde72c8d 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -656,7 +656,6 @@ private: // data // Decoder and friends nsRefPtr mDecoder; nsRefPtr mDecodeRequest; - size_t mBytesDecoded; bool mInDecoder; // END LOCKED MEMBER VARIABLES From 754c9d71fd2b4a274ea0bd6c50f1642558e79e45 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:21 -0700 Subject: [PATCH 003/100] Bug 1079653 (Part 1) - Move decode telemetry data from DecodeRequest to Decoder. r=tn --HG-- extra : rebase_source : cd86116a2df649eb14ce2db55c5b2c2b90b0f4f8 --- image/src/Decoder.cpp | 10 +++++++++- image/src/Decoder.h | 10 ++++++++++ image/src/RasterImage.cpp | 20 +++++++------------- image/src/RasterImage.h | 8 -------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 24664b063901..4f40b6be4ca4 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -19,6 +19,7 @@ Decoder::Decoder(RasterImage &aImage) , mCurrentFrame(nullptr) , mImageData(nullptr) , mColormap(nullptr) + , mChunkCount(0) , mDecodeFlags(0) , mBytesDecoded(0) , mDecodeDone(false) @@ -97,10 +98,14 @@ Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) MOZ_ASSERT(!HasDecoderError(), "Not allowed to make more decoder calls after error!"); + // Begin recording telemetry data. + TimeStamp start = TimeStamp::Now(); + mChunkCount++; + // Keep track of the total number of bytes written. mBytesDecoded += aCount; - // If a data error occured, just ignore future data + // If a data error occured, just ignore future data. if (HasDataError()) return; @@ -122,6 +127,9 @@ Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) WriteInternal(nullptr, 0, aStrategy); } } + + // Finish telemetry. + mDecodeTime += (TimeStamp::Now() - start); } void diff --git a/image/src/Decoder.h b/image/src/Decoder.h index 077f8f5ed85c..e37ad434c00d 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -103,6 +103,12 @@ public: size_t BytesDecoded() const { return mBytesDecoded; } + // The amount of time we've spent inside Write() so far for this decoder. + TimeDuration DecodeTime() const { return mDecodeTime; } + + // The number of times Write() has been called so far for this decoder. + uint32_t ChunkCount() const { return mChunkCount; } + // The number of frames we have, including anything in-progress. Thus, this // is only 0 if we haven't begun any frames. uint32_t GetFrameCount() { return mFrameCount; } @@ -235,6 +241,10 @@ protected: uint32_t* mColormap; // Current colormap to be used in Cairo format uint32_t mColormapSize; + // Telemetry data for this decoder. + TimeDuration mDecodeTime; + uint32_t mChunkCount; + uint32_t mDecodeFlags; size_t mBytesDecoded; bool mDecodeDone; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 05307d6117d0..46a708564e62 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -3004,8 +3004,9 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D nsresult rv = NS_OK; if (image->mDecoder) { - if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) { - Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount); + if (!image->mDecoder->IsSizeDecode() && image->mDecoder->ChunkCount()) { + Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, + image->mDecoder->ChunkCount()); } if (!image->mHasSize && image->mDecoder->HasSize()) { @@ -3025,14 +3026,14 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D // Do some telemetry if this isn't a size decode. if (request && !wasSize) { Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME, - int32_t(request->mDecodeTime.ToMicroseconds())); + int32_t(decoder->DecodeTime().ToMicroseconds())); // We record the speed for only some decoders. The rest have // SpeedHistogram return HistogramCount. Telemetry::ID id = decoder->SpeedHistogram(); if (id < Telemetry::HistogramCount) { int32_t KBps = int32_t(decoder->BytesDecoded() / - (1024 * request->mDecodeTime.ToSeconds())); + (1024 * decoder->DecodeTime().ToSeconds())); Telemetry::Accumulate(id, KBps); } } @@ -3446,9 +3447,8 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, bytesToDecode = aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded(); } - int32_t chunkCount = 0; - TimeStamp start = TimeStamp::Now(); - TimeStamp deadline = start + TimeDuration::FromMilliseconds(gfxPrefs::ImageMemMaxMSBeforeYield()); + TimeStamp deadline = TimeStamp::Now() + + TimeDuration::FromMilliseconds(gfxPrefs::ImageMemMaxMSBeforeYield()); // We keep decoding chunks until: // * we don't have any data left to decode, @@ -3463,7 +3463,6 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) && !aImg->mDecoder->NeedsNewFrame()) || (aImg->mDecodeRequest && aImg->mDecodeRequest->mAllocatedNewFrame)) { - chunkCount++; uint32_t chunkSize = std::min(bytesToDecode, maxBytes); nsresult rv = aImg->DecodeSomeData(chunkSize, aStrategy); if (NS_FAILED(rv)) { @@ -3479,11 +3478,6 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, break; } - if (aImg->mDecodeRequest) { - aImg->mDecodeRequest->mDecodeTime += (TimeStamp::Now() - start); - aImg->mDecodeRequest->mChunkCount += chunkCount; - } - // Flush invalidations (and therefore paint) now that we've decoded all the // chunks we're going to. // diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 9dd2cde72c8d..eb3677efeb43 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -331,7 +331,6 @@ private: : mImage(aImage) , mBytesToDecode(0) , mRequestStatus(REQUEST_INACTIVE) - , mChunkCount(0) , mAllocatedNewFrame(false) { MOZ_ASSERT(aImage, "aImage cannot be null"); @@ -359,13 +358,6 @@ private: REQUEST_STOPPED } mRequestStatus; - /* Keeps track of how much time we've burned decoding this particular decode - * request. */ - TimeDuration mDecodeTime; - - /* The number of chunks it took to decode this image. */ - int32_t mChunkCount; - /* True if a new frame has been allocated, but DecodeSomeData hasn't yet * been called to flush data to it */ bool mAllocatedNewFrame; From bac58c196da82d00a0a9dcc6cb569d2bd1ad3f48 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:21 -0700 Subject: [PATCH 004/100] Bug 1079653 (Part 2) - Remove DecodeRequest::mBytesToDecode. r=tn --HG-- extra : rebase_source : 44b8aa4989b504e10854534cb26a2a2567676fa9 --- image/src/RasterImage.cpp | 12 +++++------- image/src/RasterImage.h | 3 --- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 46a708564e62..12e93fb42237 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -3206,11 +3206,6 @@ RasterImage::DecodePool::RequestDecode(RasterImage* aImg) // If we're currently waiting on a new frame for this image, we can't do any // decoding. if (!aImg->mDecoder->NeedsNewFrame()) { - // No matter whether this is currently being decoded, we need to update the - // number of bytes we want it to decode. - aImg->mDecodeRequest->mBytesToDecode = - aImg->mSourceData.Length() - aImg->mDecoder->BytesDecoded(); - if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING || aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) { // The image is already in our list of images to decode, or currently being @@ -3311,7 +3306,10 @@ RasterImage::DecodePool::DecodeJob::Run() type = DECODE_TYPE_UNTIL_TIME; } - DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, type, mRequest->mBytesToDecode); + size_t maxBytes = mImage->mSourceData.Length() - + mImage->mDecoder->BytesDecoded(); + DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, + type, maxBytes); size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount; @@ -3328,7 +3326,7 @@ RasterImage::DecodePool::DecodeJob::Run() !mImage->mError && !mImage->mPendingError && !mImage->IsDecodeFinished() && - bytesDecoded < mRequest->mBytesToDecode && + bytesDecoded < maxBytes && bytesDecoded > 0) { DecodePool::Singleton()->RequestDecode(mImage); } else { diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index eb3677efeb43..5497712076d6 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -329,7 +329,6 @@ private: { explicit DecodeRequest(RasterImage* aImage) : mImage(aImage) - , mBytesToDecode(0) , mRequestStatus(REQUEST_INACTIVE) , mAllocatedNewFrame(false) { @@ -347,8 +346,6 @@ private: RasterImage* mImage; - size_t mBytesToDecode; - enum DecodeRequestStatus { REQUEST_INACTIVE, From 987dbea9f57000a9c83d8ad4770bcdbeaca1539b Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:21 -0700 Subject: [PATCH 005/100] Bug 1079653 (Part 3) - Make decoders track whether they need to flush data after getting a new frame. r=tn --HG-- extra : rebase_source : c2022c4dd83dbcc87199b4b51335215cbc9adcb0 --- image/src/Decoder.cpp | 13 +++++++++++++ image/src/Decoder.h | 11 +++++++++++ image/src/RasterImage.cpp | 15 ++++----------- image/src/RasterImage.h | 5 ----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 4f40b6be4ca4..d2447b49a11a 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -27,6 +27,7 @@ Decoder::Decoder(RasterImage &aImage) , mFrameCount(0) , mFailCode(NS_OK) , mNeedsNewFrame(false) + , mNeedsToFlushData(false) , mInitialized(false) , mSizeDecode(false) , mInFrame(false) @@ -105,6 +106,12 @@ Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) // Keep track of the total number of bytes written. mBytesDecoded += aCount; + // If we're flushing data, clear the flag. + if (aBuffer == nullptr && aCount == 0) { + MOZ_ASSERT(mNeedsToFlushData, "Flushing when we don't need to"); + mNeedsToFlushData = false; + } + // If a data error occured, just ignore future data. if (HasDataError()) return; @@ -250,6 +257,12 @@ Decoder::AllocateFrame() // so they can tell us if they need yet another. mNeedsNewFrame = false; + // If we've received any data at all, we may have pending data that needs to + // be flushed now that we have a frame to decode into. + if (mBytesDecoded > 0) { + mNeedsToFlushData = true; + } + return rv; } diff --git a/image/src/Decoder.h b/image/src/Decoder.h index e37ad434c00d..92c898254293 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -44,6 +44,11 @@ public: /** * Writes data to the decoder. * + * If aBuffer is null and aCount is 0, Write() flushes any buffered data to + * the decoder. Data is buffered if the decoder wasn't able to completely + * decode it because it needed a new frame. If it's necessary to flush data, + * NeedsToFlushData() will return true. + * * @param aBuffer buffer containing the data to be written * @param aCount the number of bytes to write * @@ -164,6 +169,11 @@ public: virtual bool NeedsNewFrame() const { return mNeedsNewFrame; } + // Returns true if we may have stored data that we need to flush now that we + // have a new frame to decode into. Callers can use Write() to actually + // flush the data; see the documentation for that method. + bool NeedsToFlushData() const { return mNeedsToFlushData; } + // Try to allocate a frame as described in mNewFrameData and return the // status code from that attempt. Clears mNewFrameData. virtual nsresult AllocateFrame(); @@ -283,6 +293,7 @@ private: }; NewFrameData mNewFrameData; bool mNeedsNewFrame; + bool mNeedsToFlushData; bool mInitialized; bool mSizeDecode; bool mInFrame; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 12e93fb42237..6a580a434334 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -2396,11 +2396,9 @@ RasterImage::SyncDecode() } } - // If we're currently waiting on a new frame for this image, we have to create - // it now. + // If we're currently waiting on a new frame for this image, create it now. if (mDecoder && mDecoder->NeedsNewFrame()) { mDecoder->AllocateFrame(); - mDecodeRequest->mAllocatedNewFrame = true; } // If we don't have a decoder, create one @@ -2780,8 +2778,7 @@ RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy) // First, if we've just been called because we allocated a frame on the main // thread, let the decoder deal with the data it set aside at that time by // passing it a null buffer. - if (mDecodeRequest->mAllocatedNewFrame) { - mDecodeRequest->mAllocatedNewFrame = false; + if (mDecoder->NeedsToFlushData()) { nsresult rv = WriteToDecoder(nullptr, 0, aStrategy); if (NS_FAILED(rv) || mDecoder->NeedsNewFrame()) { return rv; @@ -2827,8 +2824,7 @@ RasterImage::IsDecodeFinished() // If the decoder returned because it needed a new frame and we haven't // written to it since then, the decoder may be storing data that it hasn't // decoded yet. - if (mDecoder->NeedsNewFrame() || - (mDecodeRequest && mDecodeRequest->mAllocatedNewFrame)) { + if (mDecoder->NeedsNewFrame() || mDecoder->NeedsToFlushData()) { return false; } @@ -3417,9 +3413,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, // this image, get it now. if (aStrategy == DECODE_SYNC && aImg->mDecoder->NeedsNewFrame()) { MOZ_ASSERT(NS_IsMainThread()); - aImg->mDecoder->AllocateFrame(); - aImg->mDecodeRequest->mAllocatedNewFrame = true; } // If we're not synchronous, we can't allocate a frame right now. @@ -3460,7 +3454,7 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, !aImg->IsDecodeFinished() && !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) && !aImg->mDecoder->NeedsNewFrame()) || - (aImg->mDecodeRequest && aImg->mDecodeRequest->mAllocatedNewFrame)) { + aImg->mDecoder->NeedsToFlushData()) { uint32_t chunkSize = std::min(bytesToDecode, maxBytes); nsresult rv = aImg->DecodeSomeData(chunkSize, aStrategy); if (NS_FAILED(rv)) { @@ -3551,7 +3545,6 @@ RasterImage::FrameNeededWorker::Run() // anything. if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) { rv = mImage->mDecoder->AllocateFrame(); - mImage->mDecodeRequest->mAllocatedNewFrame = true; } if (NS_SUCCEEDED(rv) && mImage->mDecoder) { diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 5497712076d6..c1232e3e6671 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -330,7 +330,6 @@ private: explicit DecodeRequest(RasterImage* aImage) : mImage(aImage) , mRequestStatus(REQUEST_INACTIVE) - , mAllocatedNewFrame(false) { MOZ_ASSERT(aImage, "aImage cannot be null"); MOZ_ASSERT(aImage->mStatusTracker, @@ -355,10 +354,6 @@ private: REQUEST_STOPPED } mRequestStatus; - /* True if a new frame has been allocated, but DecodeSomeData hasn't yet - * been called to flush data to it */ - bool mAllocatedNewFrame; - private: ~DecodeRequest() {} }; From 4cd6dd5c3731a912d8b218d996f1a89dfb0e5982 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:22 -0700 Subject: [PATCH 006/100] Bug 1079653 (Part 4) - Move the recording imgStatusTracker onto RasterImage. r=tn --HG-- extra : rebase_source : ee06a99abfaf5c2a6f53f562088ceb453bfe2259 --- image/src/RasterImage.cpp | 55 ++++++++++++++++++++------------------- image/src/RasterImage.h | 35 +++++++++++-------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 6a580a434334..b0db5c4682b7 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -1767,6 +1767,7 @@ RasterImage::OnNewSourceData() mHasSize = false; mWantFullDecode = true; mDecodeRequest = nullptr; + mDecodeStatusTracker = nullptr; if (mAnim) { mAnim->SetDoneDecoding(false); @@ -1868,6 +1869,7 @@ RasterImage::Discard(bool force) mStatusTracker->OnDiscard(); mDecodeRequest = nullptr; + mDecodeStatusTracker = nullptr; if (force) DiscardTracker::Remove(&mDiscardTrackerNode); @@ -1988,11 +1990,14 @@ RasterImage::InitDecoder(bool aDoSizeDecode) // Initialize the decoder if (!mDecodeRequest) { - mDecodeRequest = new DecodeRequest(this); + mDecodeRequest = new DecodeRequest(); } - MOZ_ASSERT(mDecodeRequest->mStatusTracker); - MOZ_ASSERT(mDecodeRequest->mStatusTracker->GetDecoderObserver()); - mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver()); + if (!mDecodeStatusTracker) { + MOZ_ASSERT(mStatusTracker, "Should have an imgStatusTracker"); + mDecodeStatusTracker = mStatusTracker->CloneForRecording(); + } + MOZ_ASSERT(mDecodeStatusTracker->GetDecoderObserver()); + mDecoder->SetObserver(mDecodeStatusTracker->GetDecoderObserver()); mDecoder->SetSizeDecode(aDoSizeDecode); mDecoder->SetDecodeFlags(mFrameDecodeFlags); if (!aDoSizeDecode) { @@ -2978,18 +2983,15 @@ RasterImage::RequestDecodeIfNeeded(nsresult aStatus, nsresult RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_Done */, - DecodeRequest* aRequest /* = nullptr */) + imgStatusTracker* aDecodeTracker /* = nullptr */) { MOZ_ASSERT(NS_IsMainThread()); mDecodingMonitor.AssertCurrentThreadIn(); - nsRefPtr request; - if (aRequest) { - request = aRequest; - } else { - request = mDecodeRequest; - } + nsRefPtr statusTracker = aDecodeTracker + ? aDecodeTracker + : mDecodeStatusTracker.get(); // Ensure that, if the decoder is the last reference to the image, we don't // destroy it by destroying the decoder. @@ -3020,7 +3022,7 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D wasSize = decoder->IsSizeDecode(); // Do some telemetry if this isn't a size decode. - if (request && !wasSize) { + if (!wasSize) { Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME, int32_t(decoder->DecodeTime().ToMicroseconds())); @@ -3043,9 +3045,9 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D } } - ImageStatusDiff diff = - request ? image->mStatusTracker->Difference(request->mStatusTracker) - : image->mStatusTracker->DecodeStateAsDifference(); + ImageStatusDiff diff = statusTracker + ? image->mStatusTracker->Difference(statusTracker) + : image->mStatusTracker->DecodeStateAsDifference(); image->mStatusTracker->ApplyDifference(diff); if (mNotifying) { @@ -3273,13 +3275,15 @@ RasterImage::DecodePool::DecodeJob::Run() // If we were interrupted, we shouldn't do any work. if (mRequest->mRequestStatus == DecodeRequest::REQUEST_STOPPED) { - DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest); + DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, + mImage->mDecodeStatusTracker); return NS_OK; } // If someone came along and synchronously decoded us, there's nothing for us to do. if (!mImage->mDecoder || mImage->IsDecodeFinished()) { - DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest); + DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, + mImage->mDecodeStatusTracker); return NS_OK; } @@ -3327,7 +3331,8 @@ RasterImage::DecodePool::DecodeJob::Run() DecodePool::Singleton()->RequestDecode(mImage); } else { // Nothing more for us to do - let everyone know what happened. - DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest); + DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, + mImage->mDecodeStatusTracker); } return NS_OK; @@ -3498,17 +3503,13 @@ RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg, return NS_OK; } -RasterImage::DecodeDoneWorker::DecodeDoneWorker(RasterImage* image, DecodeRequest* request) - : mImage(image) - , mRequest(request) -{} - void -RasterImage::DecodeDoneWorker::NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request) +RasterImage::DecodeDoneWorker::NotifyFinishedSomeDecoding(RasterImage* aImage, + imgStatusTracker* aTracker) { - image->mDecodingMonitor.AssertCurrentThreadIn(); + aImage->mDecodingMonitor.AssertCurrentThreadIn(); - nsCOMPtr worker = new DecodeDoneWorker(image, request); + nsCOMPtr worker = new DecodeDoneWorker(aImage, aTracker); NS_DispatchToMainThread(worker); } @@ -3518,7 +3519,7 @@ RasterImage::DecodeDoneWorker::Run() MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor); - mImage->FinishedSomeDecoding(eShutdownIntent_Done, mRequest); + mImage->FinishedSomeDecoding(eShutdownIntent_Done, mTracker); return NS_OK; } diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index c1232e3e6671..0ccd4d7b4f12 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -313,8 +313,8 @@ private: { mDecodingMonitor.AssertCurrentThreadIn(); nsRefPtr statusTracker; - statusTracker = mDecodeRequest ? mDecodeRequest->mStatusTracker - : mStatusTracker; + statusTracker = mDecodeStatusTracker ? mDecodeStatusTracker + : mStatusTracker; MOZ_ASSERT(statusTracker); return statusTracker.forget(); } @@ -327,22 +327,12 @@ private: */ struct DecodeRequest { - explicit DecodeRequest(RasterImage* aImage) - : mImage(aImage) - , mRequestStatus(REQUEST_INACTIVE) - { - MOZ_ASSERT(aImage, "aImage cannot be null"); - MOZ_ASSERT(aImage->mStatusTracker, - "aImage should have an imgStatusTracker"); - mStatusTracker = aImage->mStatusTracker->CloneForRecording(); - } + explicit DecodeRequest() + : mRequestStatus(REQUEST_INACTIVE) + { } NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest) - // The status tracker that is associated with a given decode request, to - // ensure their lifetimes are linked. - nsRefPtr mStatusTracker; - RasterImage* mImage; enum DecodeRequestStatus @@ -479,17 +469,21 @@ private: * Ensures the decode state accumulated by the decoding process gets * applied to the image. */ - static void NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request); + static void NotifyFinishedSomeDecoding(RasterImage* aImage, + imgStatusTracker* aTracker); NS_IMETHOD Run(); private: /* methods */ - DecodeDoneWorker(RasterImage* image, DecodeRequest* request); + DecodeDoneWorker(RasterImage* aImage, imgStatusTracker* aTracker) + : mImage(aImage) + , mTracker(aTracker) + { } private: /* members */ nsRefPtr mImage; - nsRefPtr mRequest; + nsRefPtr mTracker; }; class FrameNeededWorker : public nsRunnable @@ -514,8 +508,8 @@ private: nsRefPtr mImage; }; - nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done, - DecodeRequest* request = nullptr); + nsresult FinishedSomeDecoding(eShutdownIntent aIntent = eShutdownIntent_Done, + imgStatusTracker* aDecodeTracker = nullptr); void DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef, gfxContext* aContext, @@ -640,6 +634,7 @@ private: // data // Decoder and friends nsRefPtr mDecoder; nsRefPtr mDecodeRequest; + nsRefPtr mDecodeStatusTracker; bool mInDecoder; // END LOCKED MEMBER VARIABLES From 8b1914763b6a5a99a3b50889b62d01ff98e7000a Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Wed, 15 Oct 2014 13:52:22 -0700 Subject: [PATCH 007/100] Bug 1079653 (Part 5) - Move decode status tracking onto RasterImage and remove DecodeRequest. r=tn --HG-- extra : rebase_source : 1276b94c41d240fba2ad4df4d5812483c10f6f27 --- image/src/RasterImage.cpp | 65 ++++++++++++++++----------------------- image/src/RasterImage.h | 48 ++++++++--------------------- 2 files changed, 38 insertions(+), 75 deletions(-) diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index b0db5c4682b7..111686122199 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -321,6 +321,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker, #endif mDecodingMonitor("RasterImage Decoding Monitor"), mDecoder(nullptr), + mDecodeStatus(DecodeStatus::INACTIVE), mInDecoder(false), mStatusDiff(ImageStatusDiff::NoChange()), mNotifying(false), @@ -1766,7 +1767,7 @@ RasterImage::OnNewSourceData() mHasSourceData = false; mHasSize = false; mWantFullDecode = true; - mDecodeRequest = nullptr; + mDecodeStatus = DecodeStatus::INACTIVE; mDecodeStatusTracker = nullptr; if (mAnim) { @@ -1868,7 +1869,7 @@ RasterImage::Discard(bool force) if (mStatusTracker) mStatusTracker->OnDiscard(); - mDecodeRequest = nullptr; + mDecodeStatus = DecodeStatus::INACTIVE; mDecodeStatusTracker = nullptr; if (force) @@ -1989,9 +1990,6 @@ RasterImage::InitDecoder(bool aDoSizeDecode) } // Initialize the decoder - if (!mDecodeRequest) { - mDecodeRequest = new DecodeRequest(); - } if (!mDecodeStatusTracker) { MOZ_ASSERT(mStatusTracker, "Should have an imgStatusTracker"); mDecodeStatusTracker = mStatusTracker->CloneForRecording(); @@ -2233,8 +2231,7 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) } // If the image is waiting for decode work to be notified, go ahead and do that. - if (mDecodeRequest && - mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE && + if (mDecodeStatus == DecodeStatus::WORK_DONE && aDecodeType == SYNCHRONOUS_NOTIFY) { ReentrantMonitorAutoEnter lock(mDecodingMonitor); nsresult rv = FinishedSomeDecoding(); @@ -2270,9 +2267,7 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType) // we need to repeat the following three checks after getting the lock. // If the image is waiting for decode work to be notified, go ahead and do that. - if (mDecodeRequest && - mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE && - aDecodeType != ASYNCHRONOUS) { + if (mDecodeStatus == DecodeStatus::WORK_DONE && aDecodeType != ASYNCHRONOUS) { nsresult rv = FinishedSomeDecoding(); CONTAINER_ENSURE_SUCCESS(rv); } @@ -2363,12 +2358,10 @@ RasterImage::SyncDecode() // disallow this type of call in the API, and check for it in API methods. NS_ABORT_IF_FALSE(!mInDecoder, "Yikes, forcing sync in reentrant call!"); - if (mDecodeRequest) { - // If the image is waiting for decode work to be notified, go ahead and do that. - if (mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) { - nsresult rv = FinishedSomeDecoding(); - CONTAINER_ENSURE_SUCCESS(rv); - } + // If the image is waiting for decode work to be notified, go ahead and do that. + if (mDecodeStatus == DecodeStatus::WORK_DONE) { + nsresult rv = FinishedSomeDecoding(); + CONTAINER_ENSURE_SUCCESS(rv); } nsresult rv; @@ -3204,15 +3197,15 @@ RasterImage::DecodePool::RequestDecode(RasterImage* aImg) // If we're currently waiting on a new frame for this image, we can't do any // decoding. if (!aImg->mDecoder->NeedsNewFrame()) { - if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING || - aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) { + if (aImg->mDecodeStatus == DecodeStatus::PENDING || + aImg->mDecodeStatus == DecodeStatus::ACTIVE) { // The image is already in our list of images to decode, or currently being // decoded, so we don't have to do anything else. return; } - aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_PENDING; - nsRefPtr job = new DecodeJob(aImg->mDecodeRequest, aImg); + aImg->mDecodeStatus = DecodeStatus::PENDING; + nsRefPtr job = new DecodeJob(aImg); MutexAutoLock threadPoolLock(mThreadPoolMutex); if (!gfxPrefs::ImageMTDecodingEnabled() || !mThreadPool) { @@ -3229,11 +3222,9 @@ RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrateg MOZ_ASSERT(NS_IsMainThread()); aImg->mDecodingMonitor.AssertCurrentThreadIn(); - if (aImg->mDecodeRequest) { - // If the image is waiting for decode work to be notified, go ahead and do that. - if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) { - aImg->FinishedSomeDecoding(); - } + // If the image is waiting for decode work to be notified, go ahead and do that. + if (aImg->mDecodeStatus == DecodeStatus::WORK_DONE) { + aImg->FinishedSomeDecoding(); } DecodeSomeOfImage(aImg, aStrategy); @@ -3263,9 +3254,7 @@ RasterImage::DecodePool::StopDecoding(RasterImage* aImg) // If we haven't got a decode request, we're not currently decoding. (Having // a decode request doesn't imply we *are* decoding, though.) - if (aImg->mDecodeRequest) { - aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_STOPPED; - } + aImg->mDecodeStatus = DecodeStatus::STOPPED; } NS_IMETHODIMP @@ -3274,7 +3263,7 @@ RasterImage::DecodePool::DecodeJob::Run() ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor); // If we were interrupted, we shouldn't do any work. - if (mRequest->mRequestStatus == DecodeRequest::REQUEST_STOPPED) { + if (mImage->mDecodeStatus == DecodeStatus::STOPPED) { DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mImage->mDecodeStatusTracker); return NS_OK; @@ -3294,7 +3283,7 @@ RasterImage::DecodePool::DecodeJob::Run() return NS_OK; } - mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE; + mImage->mDecodeStatus = DecodeStatus::ACTIVE; size_t oldByteCount = mImage->mDecoder->BytesDecoded(); @@ -3313,7 +3302,7 @@ RasterImage::DecodePool::DecodeJob::Run() size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount; - mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE; + mImage->mDecodeStatus = DecodeStatus::WORK_DONE; // If the decoder needs a new frame, enqueue an event to get it; that event // will enqueue another decode request when it's done. @@ -3360,14 +3349,12 @@ RasterImage::DecodePool::DecodeUntilSizeAvailable(RasterImage* aImg) MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter lock(aImg->mDecodingMonitor); - if (aImg->mDecodeRequest) { - // If the image is waiting for decode work to be notified, go ahead and do that. - if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) { - nsresult rv = aImg->FinishedSomeDecoding(); - if (NS_FAILED(rv)) { - aImg->DoError(); - return rv; - } + // If the image is waiting for decode work to be notified, go ahead and do that. + if (aImg->mDecodeStatus == DecodeStatus::WORK_DONE) { + nsresult rv = aImg->FinishedSomeDecoding(); + if (NS_FAILED(rv)) { + aImg->DoError(); + return rv; } } diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 0ccd4d7b4f12..5e983ffdf1e2 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -33,6 +33,7 @@ #include "mozilla/Mutex.h" #include "mozilla/ReentrantMonitor.h" #include "mozilla/TimeStamp.h" +#include "mozilla/TypedEnum.h" #include "mozilla/StaticPtr.h" #include "mozilla/WeakPtr.h" #include "mozilla/UniquePtr.h" @@ -136,6 +137,14 @@ class Decoder; class FrameAnimator; class ScaleRunner; +MOZ_BEGIN_ENUM_CLASS(DecodeStatus, uint8_t) + INACTIVE, + PENDING, + ACTIVE, + WORK_DONE, + STOPPED +MOZ_END_ENUM_CLASS(DecodeStatus) + class RasterImage MOZ_FINAL : public ImageResource , public nsIProperties , public SupportsWeakPtr @@ -319,35 +328,6 @@ private: return statusTracker.forget(); } - nsresult OnImageDataCompleteCore(nsIRequest* aRequest, nsISupports*, nsresult aStatus); - - /** - * Each RasterImage has a pointer to one or zero heap-allocated - * DecodeRequests. - */ - struct DecodeRequest - { - explicit DecodeRequest() - : mRequestStatus(REQUEST_INACTIVE) - { } - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest) - - RasterImage* mImage; - - enum DecodeRequestStatus - { - REQUEST_INACTIVE, - REQUEST_PENDING, - REQUEST_ACTIVE, - REQUEST_WORK_DONE, - REQUEST_STOPPED - } mRequestStatus; - - private: - ~DecodeRequest() {} - }; - /* * DecodePool is a singleton class we use when decoding large images. * @@ -435,18 +415,14 @@ private: class DecodeJob : public nsRunnable { public: - DecodeJob(DecodeRequest* aRequest, RasterImage* aImg) - : mRequest(aRequest) - , mImage(aImg) - {} + DecodeJob(RasterImage* aImage) : mImage(aImage) { } - NS_IMETHOD Run(); + NS_IMETHOD Run() MOZ_OVERRIDE; protected: virtual ~DecodeJob(); private: - nsRefPtr mRequest; nsRefPtr mImage; }; @@ -633,8 +609,8 @@ private: // data // Decoder and friends nsRefPtr mDecoder; - nsRefPtr mDecodeRequest; nsRefPtr mDecodeStatusTracker; + DecodeStatus mDecodeStatus; bool mInDecoder; // END LOCKED MEMBER VARIABLES From 4ca86f8969c51f5aa8d02301683715f30a8801d6 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Wed, 15 Oct 2014 17:13:14 -0400 Subject: [PATCH 008/100] Bug 1082745 - Avoid reoptimizing optimized SourceSurfaceCairos, r=bas --- gfx/2d/DrawTargetCairo.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index a270469426e8..96e6dd21766e 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -1275,7 +1275,14 @@ TemporaryRef DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const { #ifdef CAIRO_HAS_XLIB_SURFACE - if (cairo_surface_get_type(mSurface) != CAIRO_SURFACE_TYPE_XLIB) { + cairo_surface_type_t ctype = cairo_surface_get_type(mSurface); + if (aSurface->GetType() == SurfaceType::CAIRO && + cairo_surface_get_type( + static_cast(aSurface)->GetSurface()) == ctype) { + return aSurface; + } + + if (ctype != CAIRO_SURFACE_TYPE_XLIB) { return aSurface; } From 71bba5063f03b482e85832a40c2842e23841cd67 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Wed, 15 Oct 2014 17:13:14 -0400 Subject: [PATCH 009/100] Bug 1083393 - Remove unused thebes things in nsLayoutUtils, r=mattwoodrow --- layout/base/nsCSSRendering.h | 1 + layout/base/nsLayoutUtils.h | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index f2f1c7be613a..04dcbc1dfe89 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -14,6 +14,7 @@ #include "nsStyleStruct.h" #include "nsIFrame.h" +class gfxDrawable; class nsStyleContext; class nsPresContext; class nsRenderingContext; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 835fbc5f486f..8cf4ce6a3fae 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -47,8 +47,6 @@ class nsIImageLoadingContent; class nsStyleContext; class nsBlockFrame; class nsContainerFrame; -class gfxASurface; -class gfxDrawable; class nsView; class nsIFrame; class nsStyleCoord; @@ -1713,7 +1711,7 @@ public: static bool IsReallyFixedPos(nsIFrame* aFrame); /** - * Obtain a gfxASurface from the given DOM element, if possible. + * Obtain a SourceSurface from the given DOM element, if possible. * This obtains the most natural surface from the element; that * is, the one that can be obtained with the fewest conversions. * @@ -1759,8 +1757,7 @@ public: struct SurfaceFromElementResult { SurfaceFromElementResult(); - /* mSurface will contain the resulting surface, or will be nullptr on error */ - nsRefPtr mSurface; + /* mSourceSurface will contain the resulting surface, or will be nullptr on error */ mozilla::RefPtr mSourceSurface; /* Contains info for drawing when there is no mSourceSurface. */ DirectDrawInfo mDrawInfo; From 8bfb973b6e41a6dfe366e402d328c5b26a731052 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 15 Oct 2014 09:09:44 -0500 Subject: [PATCH 010/100] Bug 1082107 - OdinMonkey: add maximum-length requirement to change-heap definition (r=bbouvier) --HG-- extra : rebase_source : 71f2500219da94cf38c4f76ba52b0d1d61c97e38 --- js/src/asmjs/AsmJSLink.cpp | 13 +- js/src/asmjs/AsmJSModule.cpp | 1 + js/src/asmjs/AsmJSModule.h | 11 +- js/src/asmjs/AsmJSValidate.cpp | 64 ++++--- js/src/jit-test/tests/asm.js/testResize.js | 159 ++++++++++-------- .../tests/asm.js/testTimeout7-nosignals.js | 2 +- js/src/jit-test/tests/asm.js/testTimeout7.js | 2 +- 7 files changed, 152 insertions(+), 100 deletions(-) diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 891dc01e7f07..95681a2b7043 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -472,6 +472,14 @@ LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle module.maxHeapLength()) { + ScopedJSFreePtr msg( + JS_smprintf("ArrayBuffer byteLength 0x%x is greater than maximum length of 0x%x", + heapLength, + module.maxHeapLength())); + return LinkFail(cx, msg.get()); + } + // If we've generated the code with signal handlers in mind (for bounds // checks on x64 and for interrupt callback requesting on all platforms), // we need to be able to use signals at runtime. In particular, a module @@ -571,7 +579,10 @@ ChangeHeap(JSContext *cx, AsmJSModule &module, CallArgs args) Rooted newBuffer(cx, &bufferArg.toObject().as()); uint32_t heapLength = newBuffer->byteLength(); - if (heapLength & module.heapLengthMask() || heapLength < module.minHeapLength()) { + if (heapLength & module.heapLengthMask() || + heapLength < module.minHeapLength() || + heapLength > module.maxHeapLength()) + { args.rval().set(BooleanValue(false)); return true; } diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 572fe9f4b5b1..e6bb9cb521f4 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -88,6 +88,7 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t pod.funcPtrTableAndExitBytes_ = SIZE_MAX; pod.functionBytes_ = UINT32_MAX; pod.minHeapLength_ = RoundUpToNextValidAsmJSHeapLength(0); + pod.maxHeapLength_ = 0x80000000; pod.strict_ = strict; pod.usesSignalHandlers_ = canUseSignalHandlers; diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 0bb8a38df398..95733e114abb 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -774,6 +774,7 @@ class AsmJSModule size_t codeBytes_; // function bodies and stubs size_t totalBytes_; // function bodies, stubs, and global data uint32_t minHeapLength_; + uint32_t maxHeapLength_; uint32_t heapLengthMask_; uint32_t numGlobalScalarVars_; uint32_t numGlobalSimdVars_; @@ -884,6 +885,9 @@ class AsmJSModule uint32_t minHeapLength() const { return pod.minHeapLength_; } + uint32_t maxHeapLength() const { + return pod.maxHeapLength_; + } uint32_t heapLengthMask() const { MOZ_ASSERT(pod.hasFixedMinHeapLength_); return pod.heapLengthMask_; @@ -1044,19 +1048,24 @@ class AsmJSModule /*************************************************************************/ // These functions are called while parsing/compiling function bodies: - void addChangeHeap(uint32_t mask, uint32_t min) { + void addChangeHeap(uint32_t mask, uint32_t min, uint32_t max) { MOZ_ASSERT(isFinishedWithModulePrologue()); MOZ_ASSERT(!pod.hasFixedMinHeapLength_); MOZ_ASSERT(IsValidAsmJSHeapLength(mask + 1)); MOZ_ASSERT(min >= RoundUpToNextValidAsmJSHeapLength(0)); + MOZ_ASSERT(max <= pod.maxHeapLength_); + MOZ_ASSERT(min <= max); pod.heapLengthMask_ = mask; pod.minHeapLength_ = min; + pod.maxHeapLength_ = max; pod.hasFixedMinHeapLength_ = true; } bool tryRequireHeapLengthToBeAtLeast(uint32_t len) { MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); if (pod.hasFixedMinHeapLength_ && len > pod.minHeapLength_) return false; + if (len > pod.maxHeapLength_) + return false; len = RoundUpToNextValidAsmJSHeapLength(len); if (len > pod.minHeapLength_) pod.minHeapLength_ = len; diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 0aec45a6a6e4..51fe374ce59f 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -1658,9 +1658,9 @@ class MOZ_STACK_CLASS ModuleCompiler Global *global = moduleLifo_.new_(Global::ByteLength); return global && globals_.putNew(name, global); } - bool addChangeHeap(PropertyName *name, ParseNode *fn, uint32_t mask, uint32_t min) { + bool addChangeHeap(PropertyName *name, ParseNode *fn, uint32_t mask, uint32_t min, uint32_t max) { hasChangeHeap_ = true; - module_->addChangeHeap(mask, min); + module_->addChangeHeap(mask, min, max); Global *global = moduleLifo_.new_(Global::ChangeHeap); if (!global) return false; @@ -4164,8 +4164,9 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, Scalar::Type *viewType, unsigned elementSize = 1 << TypedArrayShift(*viewType); if (!f.m().tryRequireHeapLengthToBeAtLeast(byteOffset + elementSize)) { - return f.failf(indexExpr, "constant index outside heap size declared by the " - "change-heap function (0x%x)", f.m().minHeapLength()); + return f.failf(indexExpr, "constant index outside heap size range declared by the " + "change-heap function (0x%x - 0x%x)", + f.m().minHeapLength(), f.m().module().maxHeapLength()); } *needsBoundsCheck = NO_BOUNDS_CHECK; @@ -6545,41 +6546,58 @@ CheckByteLengthCall(ModuleCompiler &m, ParseNode *pn, PropertyName *newBufferNam static bool CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBufferName, - uint32_t *mask, uint32_t *minimumLength) + uint32_t *mask, uint32_t *minLength, uint32_t *maxLength) { - if (!cond->isKind(PNK_OR)) - return m.fail(cond, "expecting byteLength & K || byteLength <= L"); + if (!cond->isKind(PNK_OR) || !BinaryLeft(cond)->isKind(PNK_OR)) + return m.fail(cond, "expecting byteLength & K || byteLength <= L || byteLength > M"); - ParseNode *leftCond = BinaryLeft(cond); - ParseNode *rightCond = BinaryRight(cond); + ParseNode *cond1 = BinaryLeft(BinaryLeft(cond)); + ParseNode *cond2 = BinaryRight(BinaryLeft(cond)); + ParseNode *cond3 = BinaryRight(cond); - if (!leftCond->isKind(PNK_BITAND)) - return m.fail(leftCond, "expecting byteLength & K"); + if (!cond1->isKind(PNK_BITAND)) + return m.fail(cond1, "expecting byteLength & K"); - if (!CheckByteLengthCall(m, BinaryLeft(leftCond), newBufferName)) + if (!CheckByteLengthCall(m, BinaryLeft(cond1), newBufferName)) return false; - ParseNode *maskNode = BinaryRight(leftCond); + ParseNode *maskNode = BinaryRight(cond1); if (!IsLiteralInt(m, maskNode, mask)) return m.fail(maskNode, "expecting integer literal mask"); if ((*mask & 0xffffff) != 0xffffff) return m.fail(maskNode, "mask value must have the bits 0xffffff set"); - if (!rightCond->isKind(PNK_LE)) - return m.fail(rightCond, "expecting byteLength <= L"); + if (!cond2->isKind(PNK_LE)) + return m.fail(cond2, "expecting byteLength <= L"); - if (!CheckByteLengthCall(m, BinaryLeft(rightCond), newBufferName)) + if (!CheckByteLengthCall(m, BinaryLeft(cond2), newBufferName)) return false; - ParseNode *minLengthNode = BinaryRight(rightCond); + ParseNode *minLengthNode = BinaryRight(cond2); uint32_t minLengthExclusive; if (!IsLiteralInt(m, minLengthNode, &minLengthExclusive)) - return m.fail(minLengthNode, "expecting integer limit literal"); + return m.fail(minLengthNode, "expecting integer literal"); if (minLengthExclusive < 0xffffff) - return m.fail(minLengthNode, "limit value must be >= 0xffffff"); + return m.fail(minLengthNode, "literal must be >= 0xffffff"); // Add one to convert from exclusive (the branch rejects if ==) to inclusive. - *minimumLength = minLengthExclusive + 1; + *minLength = minLengthExclusive + 1; + + if (!cond3->isKind(PNK_GT)) + return m.fail(cond3, "expecting byteLength > M"); + + if (!CheckByteLengthCall(m, BinaryLeft(cond3), newBufferName)) + return false; + + ParseNode *maxLengthNode = BinaryRight(cond3); + if (!IsLiteralInt(m, maxLengthNode, maxLength)) + return m.fail(maxLengthNode, "expecting integer literal"); + if (*maxLength > 0x80000000) + return m.fail(maxLengthNode, "literal must be <= 0x80000000"); + + if (*maxLength < *minLength) + return m.fail(maxLengthNode, "maximum length must be greater or equal to minimum length"); + return true; } @@ -6665,8 +6683,8 @@ CheckChangeHeap(ModuleCompiler &m, ParseNode *fn, bool *validated) if (ParseNode *elseStmt = TernaryKid3(stmtIter)) return m.fail(elseStmt, "unexpected else statement"); - uint32_t mask, min; - if (!CheckHeapLengthCondition(m, cond, newBufferName, &mask, &min)) + uint32_t mask, min, max; + if (!CheckHeapLengthCondition(m, cond, newBufferName, &mask, &min, &max)) return false; if (!CheckReturnBoolLiteral(m, thenStmt, false)) @@ -6713,7 +6731,7 @@ CheckChangeHeap(ModuleCompiler &m, ParseNode *fn, bool *validated) if (stmtIter) return m.fail(stmtIter, "expecting end of function"); - return m.addChangeHeap(changeHeapName, fn, mask, min); + return m.addChangeHeap(changeHeapName, fn, mask, min, max); } static bool diff --git a/js/src/jit-test/tests/asm.js/testResize.js b/js/src/jit-test/tests/asm.js/testResize.js index 6d5e08cbba5b..b8140a96e085 100644 --- a/js/src/jit-test/tests/asm.js/testResize.js +++ b/js/src/jit-test/tests/asm.js/testResize.js @@ -72,69 +72,80 @@ const IMPORT1 = "var I8=glob.Int8Array; var i8=new I8(b); " + BYTELENGTH_IMPORT; const IMPORT2 = "var I8=glob.Int8Array; var i8=new I8(b); var I32=glob.Int32Array; var i32=new I32(b); var II32=glob.Int32Array; " + BYTELENGTH_IMPORT; asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function b(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2=1) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,xyz) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch({b2}) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { ;if((len((b2))) & (0xffffff) || (len((b2)) <= (0xffffff))) {;;return false;;} ; i8=new I8(b2);; b=b2;; return true;; } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function ch2(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { 3; if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { b2=b2|0; if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function b(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2=1) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,xyz) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch({b2}) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { ;if((len((b2))) & (0xffffff) || (len((b2)) <= (0xffffff)) || len(b2) > 0x80000000) {;;return false;;} ; i8=new I8(b2);; b=b2;; return true;; } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function ch2(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { 3; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { b2=b2|0; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(i8(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(xyz) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff && len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) | 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) == 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xfffffe || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x1ffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) < 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xfffffe) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) ; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) {} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) {return false} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return true; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT0 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i7=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=1; b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new 1; b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I7(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new b(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8; b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(1); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2,1); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); xyz=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=1; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; 1; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true } function f() { return 42 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I32(b2); i32=new I8(b2); b=b2; return true } function f() { return 42 } return f'); - asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new II32(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || 1 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(i8(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(xyz) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff && len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) | 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) == 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xfffffe || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x1ffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) < 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xfffffe || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) < 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1 > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0.0) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) ; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {return false} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return true; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT0 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i7=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=1; b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new 1; b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I7(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new b(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8; b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(1); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2,1); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); xyz=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=1; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; 1; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true } function f() { return 42 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I32(b2); i32=new I8(b2); b=b2; return true } function f() { return 42 } return f'); + asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new II32(b2); b=b2; return true } function f() { return 42 } return f'); // Tests for no calls in heap index expressions -const SETUP = USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }'; +const SETUP = USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }'; asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] } return f'); asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] = 0 } return f'); @@ -152,26 +163,28 @@ assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i // Tests for constant heap accesses when change-heap is used -const HEADER = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & MASK || len(b2) <= MIN) return false; i8=new I8(b2); b=b2; return true } '; -assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { i8[0x1000000] = 0 } return f'); - asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { i8[0xffffff] = 0 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { i8[0x1000001] = 0 } return f'); - asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { i8[0x1000000] = 0 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { return i8[0x1000000]|0 } return f'); - asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0xffffff') + 'function f() { return i8[0xffffff]|0 } return f'); -assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { return i8[0x1000001]|0 } return f'); - asmCompile('glob', 'ffis', 'b', HEADER.replace('MASK', '0xffffff').replace('MIN', '0x1000000') + 'function f() { return i8[0x1000000]|0 } return f'); +const HEADER = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= MIN || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } '; +assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0x1000000] = 0 } return f'); + asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0xffffff] = 0 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000001] = 0 } return f'); + asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000000] = 0 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0x1000000]|0 } return f'); + asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0xffffff]|0 } return f'); +assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000001]|0 } return f'); + asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000000]|0 } return f'); // Tests for validation of heap length -var body = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & MASK || len(b2) <= MIN) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return ch'; -var m = asmCompile('glob', 'ffis', 'b', body.replace('MASK', '0xffffff').replace('MIN', '0x1ffffff')); +var body = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1ffffff || len(b2) > 0x4000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return ch'; +var m = asmCompile('glob', 'ffis', 'b', body); assertAsmLinkFail(m, this, null, new ArrayBuffer(BUF_CHANGE_MIN)); assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1000000)); var changeHeap = asmLink(m, this, null, new ArrayBuffer(0x2000000)); assertEq(changeHeap(new ArrayBuffer(0x1000000)), false); assertEq(changeHeap(new ArrayBuffer(0x2000000)), true); assertEq(changeHeap(new ArrayBuffer(0x2000001)), false); +assertEq(changeHeap(new ArrayBuffer(0x4000000)), true); +assertEq(changeHeap(new ArrayBuffer(0x5000000)), false); assertThrowsInstanceOf(() => changeHeap(null), TypeError); assertThrowsInstanceOf(() => changeHeap({}), TypeError); assertThrowsInstanceOf(() => changeHeap(new Int32Array(100)), TypeError); @@ -184,7 +197,7 @@ assertEq(changeHeap(detached), false); const CHANGE_HEAP = 'var changeHeap = glob.byteLength;'; -var changeHeapSource = `function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true }`; +var changeHeapSource = `function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }`; var body = `var I32=glob.Int32Array; var i32=new I32(b); var len=glob.byteLength;` + changeHeapSource + @@ -229,7 +242,7 @@ new Int32Array(buf2)[0] = 42; var m = asmCompile('glob', 'ffis', 'b', USE_ASM + `var len=glob.byteLength; - function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; b=b2; return true } + function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } return ch`); var changeHeap = asmLink(m, this, null, buf1); changeHeap(buf2); @@ -246,7 +259,7 @@ var m = asmCompile('glob', 'ffis', 'b', USE_ASM + `var ffi=ffis.ffi; var I32=glob.Int32Array; var i32=new I32(b); var len=glob.byteLength; - function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true } + function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function test(i) { i=i|0; var sum=0; sum = i32[i>>2]|0; sum = (sum + (ffi()|0))|0; sum = (sum + (i32[i>>2]|0))|0; return sum|0 } return {test:test, changeHeap:ch}`); var ffi = function() { changeHeap(changeToBuf); return 1 } diff --git a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js b/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js index 8d460685013a..bde496899cc1 100644 --- a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js +++ b/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js @@ -20,7 +20,7 @@ new Int32Array(buf2)[0] = 42; var m = asmCompile('glob', 'ffis', 'b', USE_ASM + `var I32=glob.Int32Array; var i32=new I32(b); var len=glob.byteLength; - function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true } + function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() {} function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } } return {loop:loop, changeHeap:changeHeap}`); diff --git a/js/src/jit-test/tests/asm.js/testTimeout7.js b/js/src/jit-test/tests/asm.js/testTimeout7.js index ee4df4519256..ce85cebb09c9 100644 --- a/js/src/jit-test/tests/asm.js/testTimeout7.js +++ b/js/src/jit-test/tests/asm.js/testTimeout7.js @@ -18,7 +18,7 @@ new Int32Array(buf2)[0] = 42; var m = asmCompile('glob', 'ffis', 'b', USE_ASM + `var I32=glob.Int32Array; var i32=new I32(b); var len=glob.byteLength; - function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i32=new I32(b2); b=b2; return true } + function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() {} function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } } return {loop:loop, changeHeap:changeHeap}`); From 8a4529b2bdffefe8e826d0988619c7b56a205f43 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 14 Oct 2014 10:58:21 -0500 Subject: [PATCH 011/100] Bug 1081277 - OdinMonkey: maintain list of asm.js modules in the runtime (r=bbouvier) --HG-- extra : rebase_source : e8bbae4bf9af31aa31dd14da0bcbdbc4b342fc5c --- js/src/asmjs/AsmJSLink.cpp | 2 +- js/src/asmjs/AsmJSModule.cpp | 7 +++++++ js/src/asmjs/AsmJSModule.h | 18 ++++++++++++++++-- js/src/vm/Runtime.cpp | 1 + js/src/vm/Runtime.h | 6 +++++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 95681a2b7043..3210cf578be8 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -501,7 +501,7 @@ LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handleruntime()); HandleValue globalVal = args.get(0); HandleValue importVal = args.get(1); diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index e6bb9cb521f4..6bb467b2872a 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -78,6 +78,8 @@ AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t bufferArgumentName_(nullptr), code_(nullptr), interruptExit_(nullptr), + prevLinked_(nullptr), + nextLinked_(nullptr), dynamicallyLinked_(false), loadedFromCache_(false), profilingEnabled_(false), @@ -116,6 +118,11 @@ AsmJSModule::~AsmJSModule() for (size_t i = 0; i < numFunctionCounts(); i++) js_delete(functionCounts(i)); + + if (prevLinked_) + *prevLinked_ = nextLinked_; + if (nextLinked_) + nextLinked_->prevLinked_ = prevLinked_; } void diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 95733e114abb..cdb13a751df3 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -819,6 +819,8 @@ class AsmJSModule uint8_t * interruptExit_; StaticLinkData staticLinkData_; HeapPtrArrayBufferObjectMaybeShared maybeHeap_; + AsmJSModule ** prevLinked_; + AsmJSModule * nextLinked_; bool dynamicallyLinked_; bool loadedFromCache_; bool profilingEnabled_; @@ -1449,12 +1451,20 @@ class AsmJSModule // specializes it to a particular set of arguments. In particular, this // binds the code to a particular heap (via initHeap) and set of global // variables. A given asm.js module cannot be dynamically linked more than - // once so, if JS tries, the module is cloned. - void setIsDynamicallyLinked() { + // once so, if JS tries, the module is cloned. When linked, an asm.js module + // is kept in a list so that it can be updated if the linked buffer is + // detached. + void setIsDynamicallyLinked(JSRuntime *rt) { MOZ_ASSERT(!isDynamicallyLinked()); dynamicallyLinked_ = true; + nextLinked_ = rt->linkedAsmJSModules; + prevLinked_ = &rt->linkedAsmJSModules; + if (nextLinked_) + nextLinked_->prevLinked_ = &nextLinked_; + rt->linkedAsmJSModules = this; MOZ_ASSERT(isDynamicallyLinked()); } + void initHeap(Handle heap, JSContext *cx); void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer); void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, @@ -1466,6 +1476,10 @@ class AsmJSModule /*************************************************************************/ // Functions that can be called after dynamic linking succeeds: + AsmJSModule *nextLinked() const { + MOZ_ASSERT(isDynamicallyLinked()); + return nextLinked_; + } CodePtr entryTrampoline(const ExportedFunction &func) const { MOZ_ASSERT(isDynamicallyLinked()); MOZ_ASSERT(!func.isChangeHeap()); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index f2acafe72b71..3a8f51bccb6d 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -197,6 +197,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) structuredCloneCallbacks(nullptr), telemetryCallback(nullptr), errorReporter(nullptr), + linkedAsmJSModules(nullptr), propertyRemovals(0), #if !EXPOSE_INTL_API thousandsSeparator(0), diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 8696d73a9b36..af13738617af 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -78,6 +78,7 @@ namespace js { class Activation; class ActivationIterator; class AsmJSActivation; +class AsmJSModule; class MathCache; namespace jit { @@ -1080,7 +1081,10 @@ struct JSRuntime : public JS::shadow::Runtime, JSErrorReporter errorReporter; /* AsmJSCache callbacks are runtime-wide. */ - JS::AsmJSCacheOps asmJSCacheOps; + JS::AsmJSCacheOps asmJSCacheOps; + + /* Head of the linked list of linked asm.js modules. */ + js::AsmJSModule *linkedAsmJSModules; /* * The propertyRemovals counter is incremented for every JSObject::clear, From 65b1efb5a43c1b1d2c27b62995d006fd7fcb3c5a Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 14 Oct 2014 10:59:37 -0500 Subject: [PATCH 012/100] Bug 1081277 - OdinMonkey: move detachment logic into AsmJSModule (r=bbouvier,sfink) --HG-- extra : rebase_source : b763dee7f3fd1c49ce92a3ea0219d58fee932bb4 --- js/src/asmjs/AsmJSLink.cpp | 22 +++--- js/src/asmjs/AsmJSModule.cpp | 91 +++++++++++++++------- js/src/asmjs/AsmJSModule.h | 20 +++-- js/src/jit-test/tests/asm.js/testNeuter.js | 2 +- js/src/jit-test/tests/asm.js/testResize.js | 13 +++- js/src/vm/ArrayBufferObject.cpp | 59 +++++--------- js/src/vm/ArrayBufferObject.h | 6 +- 7 files changed, 119 insertions(+), 94 deletions(-) diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 3210cf578be8..f7dec84460ee 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -587,6 +587,11 @@ ChangeHeap(JSContext *cx, AsmJSModule &module, CallArgs args) return true; } + if (!module.hasArrayView()) { + args.rval().set(BooleanValue(true)); + return true; + } + MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength)); MOZ_ASSERT(!IsDeprecatedAsmJSHeapLength(heapLength)); @@ -689,15 +694,14 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) } } - // An asm.js module is specialized to its heap's base address and length - // which is normally immutable except for the neuter operation that occurs - // when an ArrayBuffer is transfered. Throw an internal error if we're - // about to run with a neutered heap. - if (module.maybeHeapBufferObject() && - module.maybeHeapBufferObject()->is() && - module.maybeHeapBufferObject()->as().isNeutered()) - { - js_ReportOverRecursed(cx); + // The correct way to handle this situation would be to allocate a new range + // of PROT_NONE memory and module.changeHeap to this memory. That would + // cause every access to take the out-of-bounds signal-handler path which + // does the right thing. For now, just throw an out-of-memory exception + // since these can technically pop out anywhere and the full fix may + // actually OOM when trying to allocate the PROT_NONE memory. + if (module.hasDetachedHeap()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY); return false; } diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 6bb467b2872a..812dd59567d6 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -54,6 +54,36 @@ using mozilla::PodEqual; using mozilla::Compression::LZ4; using mozilla::Swap; +// At any time, the executable code of an asm.js module can be protected (as +// part of RequestInterruptForAsmJSCode). When we touch the executable outside +// of executing it (which the AsmJSFaultHandler will correctly handle), we need +// to guard against this by unprotecting the code (if it has been protected) and +// preventing it from being protected while we are touching it. +class AutoUnprotectCode +{ + JSRuntime *rt_; + JSRuntime::AutoLockForInterrupt lock_; + const AsmJSModule &module_; + const bool protectedBefore_; + + public: + AutoUnprotectCode(JSContext *cx, const AsmJSModule &module) + : rt_(cx->runtime()), + lock_(rt_), + module_(module), + protectedBefore_(module_.codeIsProtected(rt_)) + { + if (protectedBefore_) + module_.unprotectCode(rt_); + } + + ~AutoUnprotectCode() + { + if (protectedBefore_) + module_.protectCode(rt_); + } +}; + static uint8_t * AllocateExecutableMemory(ExclusiveContext *cx, size_t bytes) { @@ -844,6 +874,35 @@ AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer restoreHeapToInitialState(maybePrevBuffer); } +bool +AsmJSModule::detachHeap(JSContext *cx) +{ + MOZ_ASSERT(isDynamicallyLinked()); + MOZ_ASSERT(maybeHeap_); + + AutoUnprotectCode auc(cx, *this); + restoreHeapToInitialState(maybeHeap_); + + MOZ_ASSERT(hasDetachedHeap()); + return true; +} + +bool +js::OnDetachAsmJSArrayBuffer(JSContext *cx, Handle buffer) +{ + for (AsmJSModule *m = cx->runtime()->linkedAsmJSModules; m; m = m->nextLinked()) { + if (buffer == m->maybeHeapBufferObject()) { + if (m->active()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY); + return false; + } + if (!m->detachHeap(cx)) + return false; + } + } + return true; +} + static void AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj) { @@ -1485,36 +1544,6 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor) return cursor; } -// At any time, the executable code of an asm.js module can be protected (as -// part of RequestInterruptForAsmJSCode). When we touch the executable outside -// of executing it (which the AsmJSFaultHandler will correctly handle), we need -// to guard against this by unprotecting the code (if it has been protected) and -// preventing it from being protected while we are touching it. -class AutoUnprotectCode -{ - JSRuntime *rt_; - JSRuntime::AutoLockForInterrupt lock_; - const AsmJSModule &module_; - const bool protectedBefore_; - - public: - AutoUnprotectCode(JSContext *cx, const AsmJSModule &module) - : rt_(cx->runtime()), - lock_(rt_), - module_(module), - protectedBefore_(module_.codeIsProtected(rt_)) - { - if (protectedBefore_) - module_.unprotectCode(rt_); - } - - ~AutoUnprotectCode() - { - if (protectedBefore_) - module_.protectCode(rt_); - } -}; - bool AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const { @@ -1569,6 +1598,8 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) con bool AsmJSModule::changeHeap(Handle newHeap, JSContext *cx) { + MOZ_ASSERT(hasArrayView()); + // Content JS should not be able to run (and change heap) from within an // interrupt callback, but in case it does, fail to change heap. Otherwise, // the heap can change at every single instruction which would prevent diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index cdb13a751df3..0a353e17b850 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -830,6 +830,10 @@ class AsmJSModule // Access must be synchronized via the runtime's interrupt lock. mutable bool codeIsProtected_; + void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer); + void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, uint8_t *prevCode, + ExclusiveContext *cx); + public: explicit AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t srcBodyStart, bool strict, bool canUseSignalHandlers); @@ -1466,12 +1470,10 @@ class AsmJSModule } void initHeap(Handle heap, JSContext *cx); - void restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer); - void restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer, - uint8_t *prevCode, - ExclusiveContext *cx); - bool clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const; bool changeHeap(Handle newHeap, JSContext *cx); + bool detachHeap(JSContext *cx); + + bool clone(JSContext *cx, ScopedJSDeletePtr *moduleOut) const; /*************************************************************************/ // Functions that can be called after dynamic linking succeeds: @@ -1480,6 +1482,10 @@ class AsmJSModule MOZ_ASSERT(isDynamicallyLinked()); return nextLinked_; } + bool hasDetachedHeap() const { + MOZ_ASSERT(isDynamicallyLinked()); + return hasArrayView() && !heapDatum(); + } CodePtr entryTrampoline(const ExportedFunction &func) const { MOZ_ASSERT(isDynamicallyLinked()); MOZ_ASSERT(!func.isChangeHeap()); @@ -1534,6 +1540,10 @@ LookupAsmJSModuleInCache(ExclusiveContext *cx, ScopedJSDeletePtr *module, ScopedJSFreePtr *compilationTimeReport); +// This function must be called for every detached ArrayBuffer. +extern bool +OnDetachAsmJSArrayBuffer(JSContext *cx, Handle buffer); + // An AsmJSModuleObject is an internal implementation object (i.e., not exposed // directly to user script) which manages the lifetime of an AsmJSModule. A // JSObject is necessary since we want LinkAsmJS/CallAsmJS JSFunctions to be diff --git a/js/src/jit-test/tests/asm.js/testNeuter.js b/js/src/jit-test/tests/asm.js/testNeuter.js index a8d89ff17b9e..5ef98caaa44b 100644 --- a/js/src/jit-test/tests/asm.js/testNeuter.js +++ b/js/src/jit-test/tests/asm.js/testNeuter.js @@ -29,7 +29,7 @@ assertEq(get(4), 42); neuter(buffer, "change-data"); neuter(buffer, "same-data"); -// These operations may throw internal errors +// These operations may throw errors try { assertEq(get(4), 0); set(0, 42); diff --git a/js/src/jit-test/tests/asm.js/testResize.js b/js/src/jit-test/tests/asm.js/testResize.js index b8140a96e085..a94a67d14fa1 100644 --- a/js/src/jit-test/tests/asm.js/testResize.js +++ b/js/src/jit-test/tests/asm.js/testResize.js @@ -236,16 +236,21 @@ set(BUF_CHANGE_MIN, 262); assertEq(get(BUF_CHANGE_MIN), 0); var buf1 = new ArrayBuffer(BUF_CHANGE_MIN); -new Int32Array(buf1)[0] = 13; var buf2 = new ArrayBuffer(BUF_CHANGE_MIN); -new Int32Array(buf2)[0] = 42; - var m = asmCompile('glob', 'ffis', 'b', USE_ASM + `var len=glob.byteLength; function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } return ch`); var changeHeap = asmLink(m, this, null, buf1); -changeHeap(buf2); +assertEq(changeHeap(buf2), true); +neuter(buf2, "change-data"); +assertEq(changeHeap(buf1), true); +neuter(buf1, "change-data"); + +var buf1 = new ArrayBuffer(BUF_CHANGE_MIN); +new Int32Array(buf1)[0] = 13; +var buf2 = new ArrayBuffer(BUF_CHANGE_MIN); +new Int32Array(buf2)[0] = 42; // Tests for changing heap during an FFI: diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 5a8fd50b537d..33a1a22c6140 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -277,17 +277,6 @@ AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes) return ArrayBufferObject::BufferContents::create(p); } -bool -ArrayBufferObject::canNeuter(JSContext *cx) -{ - if (isAsmJSArrayBuffer()) { - if (!ArrayBufferObject::canNeuterAsmJSArrayBuffer(cx, *this)) - return false; - } - - return true; -} - void ArrayBufferObject::neuterView(JSContext *cx, ArrayBufferViewObject *view, BufferContents newContents) @@ -298,11 +287,12 @@ ArrayBufferObject::neuterView(JSContext *cx, ArrayBufferViewObject *view, MarkObjectStateChange(cx, view); } -/* static */ void +/* static */ bool ArrayBufferObject::neuter(JSContext *cx, Handle buffer, BufferContents newContents) { - MOZ_ASSERT(buffer->canNeuter(cx)); + if (buffer->isAsmJSArrayBuffer() && !OnDetachAsmJSArrayBuffer(cx, buffer)) + return false; // Neuter all views on the buffer, clear out the list of views and the // buffer's data. @@ -321,6 +311,7 @@ ArrayBufferObject::neuter(JSContext *cx, Handle buffer, buffer->setByteLength(0); buffer->setIsNeutered(); + return true; } void @@ -495,20 +486,6 @@ ArrayBufferObject::releaseAsmJSArray(FreeOp *fop) } #endif -bool -ArrayBufferObject::canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer) -{ - AsmJSActivation *act = cx->mainThread().asmJSActivationStack(); - for (; act; act = act->prevAsmJS()) { - if (act->module().maybeHeapBufferObject() == &buffer) - break; - } - if (!act) - return true; - - return false; -} - ArrayBufferObject::BufferContents ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length) { @@ -708,11 +685,6 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle buffe { MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents()); - if (!buffer->canNeuter(cx)) { - js_ReportOverRecursed(cx); - return BufferContents::createUnowned(nullptr); - } - BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind()); BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength()); if (!newContents) @@ -723,14 +695,20 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle buffe // freshly allocated memory that we will never write to and should // never get committed. buffer->setOwnsData(DoesntOwnData); - ArrayBufferObject::neuter(cx, buffer, newContents); + if (!ArrayBufferObject::neuter(cx, buffer, newContents)) { + js_free(newContents.data()); + return BufferContents::createUnowned(nullptr); + } return oldContents; } // Create a new chunk of memory to return since we cannot steal the // existing contents away from the buffer. memcpy(newContents.data(), oldContents.data(), buffer->byteLength()); - ArrayBufferObject::neuter(cx, buffer, oldContents); + if (!ArrayBufferObject::neuter(cx, buffer, oldContents)) { + js_free(newContents.data()); + return BufferContents::createUnowned(nullptr); + } return newContents; } @@ -1068,19 +1046,18 @@ JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj, Rooted buffer(cx, &obj->as()); - if (!buffer->canNeuter(cx)) { - js_ReportOverRecursed(cx); - return false; - } - if (changeData == ChangeData && buffer->hasStealableContents()) { ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength()); if (!newContents) return false; - ArrayBufferObject::neuter(cx, buffer, newContents); + if (!ArrayBufferObject::neuter(cx, buffer, newContents)) { + js_free(newContents.data()); + return false; + } } else { - ArrayBufferObject::neuter(cx, buffer, buffer->contents()); + if (!ArrayBufferObject::neuter(cx, buffer, buffer->contents())) + return false; } return true; diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index bd5a68038264..e35935dd693e 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -237,10 +237,9 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared */ static bool ensureNonInline(JSContext *cx, Handle buffer); - bool canNeuter(JSContext *cx); - /* Neuter this buffer and all its views. */ - static void neuter(JSContext *cx, Handle buffer, BufferContents newContents); + static MOZ_WARN_UNUSED_RESULT bool + neuter(JSContext *cx, Handle buffer, BufferContents newContents); private: void neuterView(JSContext *cx, ArrayBufferViewObject *view, @@ -279,7 +278,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared static bool prepareForAsmJS(JSContext *cx, Handle buffer, bool usesSignalHandlers); static bool prepareForAsmJSNoSignals(JSContext *cx, Handle buffer); - static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer); static void finalize(FreeOp *fop, JSObject *obj); From 06d62e88808d03bec0ab2613422c4d858c74b27a Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 14 Oct 2014 11:03:14 -0500 Subject: [PATCH 013/100] Bug 1081277 - OdinMonkey: allow change heap after detachment in FFI (r=bbouvier) --HG-- extra : rebase_source : ed10d6fefe6c1f5849c5b7f8f1951603e8c12890 --- js/src/asmjs/AsmJSModule.cpp | 34 +++- js/src/asmjs/AsmJSModule.h | 8 +- js/src/asmjs/AsmJSValidate.cpp | 56 +++++- js/src/jit-test/tests/asm.js/testNeuter.js | 174 +++++++++++------- js/src/jit-test/tests/asm.js/testProfiling.js | 10 + js/src/jit/shared/Assembler-shared.h | 1 + 6 files changed, 192 insertions(+), 91 deletions(-) diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 812dd59567d6..6db17357ec55 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -484,6 +484,14 @@ AsmJSReportOverRecursed() js_ReportOverRecursed(cx); } +static void +OnDetached() +{ + // See hasDetachedHeap comment in LinkAsmJS. + JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx(); + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY); +} + static bool AsmJSHandleExecutionInterrupt() { @@ -667,6 +675,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx) return cx->stackLimitAddressForJitCode(StackForUntrustedScript); case AsmJSImm_ReportOverRecursed: return RedirectCall(FuncCast(AsmJSReportOverRecursed), Args_General0); + case AsmJSImm_OnDetached: + return RedirectCall(FuncCast(OnDetached), Args_General0); case AsmJSImm_HandleExecutionInterrupt: return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0); case AsmJSImm_InvokeFromAsmJS_Ignore: @@ -880,6 +890,20 @@ AsmJSModule::detachHeap(JSContext *cx) MOZ_ASSERT(isDynamicallyLinked()); MOZ_ASSERT(maybeHeap_); + // Content JS should not be able to run (and detach heap) from within an + // interrupt callback, but in case it does, fail. Otherwise, the heap can + // change at an arbitrary instruction and break the assumption below. + if (interrupted_) { + JS_ReportError(cx, "attempt to detach from inside interrupt handler"); + return false; + } + + // Even if this->active(), to reach here, the activation must have called + // out via an FFI stub. FFI stubs check if heapDatum() is null on reentry + // and throw an exception if so. + MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_IonFFI || + activation()->exitReason() == AsmJSExit::Reason_SlowFFI); + AutoUnprotectCode auc(cx, *this); restoreHeapToInitialState(maybeHeap_); @@ -891,14 +915,8 @@ bool js::OnDetachAsmJSArrayBuffer(JSContext *cx, Handle buffer) { for (AsmJSModule *m = cx->runtime()->linkedAsmJSModules; m; m = m->nextLinked()) { - if (buffer == m->maybeHeapBufferObject()) { - if (m->active()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY); - return false; - } - if (!m->detachHeap(cx)) - return false; - } + if (buffer == m->maybeHeapBufferObject() && !m->detachHeap(cx)) + return false; } return true; } diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 0a353e17b850..4b7a464eebd0 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -1054,6 +1054,10 @@ class AsmJSModule /*************************************************************************/ // These functions are called while parsing/compiling function bodies: + bool hasArrayView() const { + MOZ_ASSERT(isFinishedWithModulePrologue()); + return pod.hasArrayView_; + } void addChangeHeap(uint32_t mask, uint32_t min, uint32_t max) { MOZ_ASSERT(isFinishedWithModulePrologue()); MOZ_ASSERT(!pod.hasFixedMinHeapLength_); @@ -1243,10 +1247,6 @@ class AsmJSModule /*************************************************************************/ // These accessor functions can be used after finish(): - bool hasArrayView() const { - MOZ_ASSERT(isFinished()); - return pod.hasArrayView_; - } unsigned numFFIs() const { MOZ_ASSERT(isFinished()); return pod.numFFIs_; diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 51fe374ce59f..6f808e7830f2 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -1329,6 +1329,7 @@ class MOZ_STACK_CLASS ModuleCompiler NonAssertingLabel stackOverflowLabel_; NonAssertingLabel asyncInterruptLabel_; NonAssertingLabel syncInterruptLabel_; + NonAssertingLabel onDetachedLabel_; UniquePtr errorString_; uint32_t errorOffset_; @@ -1522,6 +1523,7 @@ class MOZ_STACK_CLASS ModuleCompiler Label &stackOverflowLabel() { return stackOverflowLabel_; } Label &asyncInterruptLabel() { return asyncInterruptLabel_; } Label &syncInterruptLabel() { return syncInterruptLabel_; } + Label &onDetachedLabel() { return onDetachedLabel_; } bool hasError() const { return errorString_ != nullptr; } const AsmJSModule &module() const { return *module_.get(); } bool usesSignalHandlersForInterrupt() const { return module_->usesSignalHandlersForInterrupt(); } @@ -7638,6 +7640,27 @@ FillArgumentArray(ModuleCompiler &m, const VarTypeVector &argTypes, } } +// If an FFI detaches its heap (viz., via ArrayBuffer.transfer), it must +// call change-heap to another heap (viz., the new heap returned by transfer) +// before returning to asm.js code. If the application fails to do this (if the +// heap pointer is null), jump to a stub. +static void +GenerateCheckForHeapDetachment(ModuleCompiler &m, Register scratch) +{ + if (!m.module().hasArrayView()) + return; + + MacroAssembler &masm = m.masm(); + AssertStackAlignment(masm, ABIStackAlignment); +#if defined(JS_CODEGEN_X86) + CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), scratch); + masm.append(AsmJSGlobalAccess(label, AsmJSHeapGlobalDataOffset)); + masm.branchTestPtr(Assembler::Zero, scratch, scratch, &m.onDetachedLabel()); +#else + masm.branchTestPtr(Assembler::Zero, HeapReg, HeapReg, &m.onDetachedLabel()); +#endif +} + static bool GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit, unsigned exitIndex, Label *throwLabel) @@ -7721,8 +7744,10 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); } - // The heap pointer may have changed during the FFI, so reload it. + // The heap pointer may have changed during the FFI, so reload it and test + // for detachment. masm.loadAsmJSHeapRegisterFromGlobalData(); + GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0); Label profilingReturn; GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::SlowFFI, &profilingReturn); @@ -7931,14 +7956,18 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit MOZ_ASSERT(masm.framePushed() == framePushed); - // Reload pinned registers after all calls into arbitrary JS. + // Reload the global register since Ion code can clobber any register. #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) JS_STATIC_ASSERT(MaybeSavedGlobalReg > 0); masm.loadPtr(Address(StackPointer, savedGlobalOffset), GlobalReg); #else JS_STATIC_ASSERT(MaybeSavedGlobalReg == 0); #endif + + // The heap pointer has to be reloaded anyway since Ion could have clobbered + // it. Additionally, the FFI may have detached the heap buffer. masm.loadAsmJSHeapRegisterFromGlobalData(); + GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0); Label profilingReturn; GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::IonFFI, &profilingReturn); @@ -8099,6 +8128,20 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel) return m.finishGeneratingInlineStub(&m.stackOverflowLabel()) && !masm.oom(); } +static bool +GenerateOnDetachedLabelExit(ModuleCompiler &m, Label *throwLabel) +{ + MacroAssembler &masm = m.masm(); + masm.bind(&m.onDetachedLabel()); + masm.assertStackAlignment(ABIStackAlignment); + + // For now, OnDetached always throws (see OnDetached comment). + masm.call(AsmJSImmPtr(AsmJSImm_OnDetached)); + masm.jump(throwLabel); + + return m.finishGeneratingInlineStub(&m.onDetachedLabel()) && !masm.oom(); +} + static const RegisterSet AllRegsExceptSP = RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(uint32_t(1) << Registers::StackPointer)), @@ -8152,7 +8195,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // Restore the machine state to before the interrupt. masm.PopRegsInMask(AllRegsExceptSP, AllRegsExceptSP.fpus()); // restore all GP/FP registers (except SP) - masm.loadAsmJSHeapRegisterFromGlobalData(); // In case there was a changeHeap masm.popFlags(); // after this, nothing that sets conditions masm.ret(); // pop resumePC into PC #elif defined(JS_CODEGEN_MIPS) @@ -8194,7 +8236,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) // during jump delay slot. masm.pop(HeapReg); masm.as_jr(HeapReg); - masm.loadAsmJSHeapRegisterFromGlobalData(); // In case there was a changeHeap #elif defined(JS_CODEGEN_ARM) masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<>2] = j; - } - function get(i) { - i=i|0; - return i32[i>>2]|0 - } - return {get:get, set:set} -} -if (isAsmJSCompilationAvailable()) - assertEq(isAsmJSModule(f), true); +if (!isAsmJSCompilationAvailable()) + quit(); -var i32 = new Int32Array(1024); -var buffer = i32.buffer; -var {get, set} = f(this, null, buffer); -if (isAsmJSCompilationAvailable()) - assertEq(isAsmJSFunction(get) && isAsmJSFunction(set), true); +var m = asmCompile('stdlib', 'foreign', 'buffer', + `"use asm"; + var i32 = new stdlib.Int32Array(buffer); + function set(i,j) { + i=i|0; + j=j|0; + i32[i>>2] = j; + } + function get(i) { + i=i|0; + return i32[i>>2]|0 + } + return {get:get, set:set}`); +var buffer = new ArrayBuffer(BUF_MIN); +var {get, set} = asmLink(m, this, null, buffer); set(4, 42); assertEq(get(4), 42); - neuter(buffer, "change-data"); neuter(buffer, "same-data"); +assertThrowsInstanceOf(() => get(4), InternalError); -// These operations may throw errors -try { - assertEq(get(4), 0); - set(0, 42); - assertEq(get(0), 0); -} catch (e) { - assertEq(String(e).indexOf("InternalError"), 0); +var buf1 = new ArrayBuffer(BUF_MIN); +var buf2 = new ArrayBuffer(BUF_MIN); +var {get:get1, set:set1} = asmLink(m, this, null, buf1); +var {get:get2, set:set2} = asmLink(m, this, null, buf2); +set1(0, 13); +set2(0, 42); +neuter(buf1, "change-data"); +assertThrowsInstanceOf(() => get1(0), InternalError); +assertEq(get2(0), 42); + +var m = asmCompile('stdlib', 'foreign', 'buffer', + `"use asm"; + var i32 = new stdlib.Int32Array(buffer); + var ffi = foreign.ffi; + function inner(i) { + i=i|0; + ffi(); + return i32[i>>2]|0 + } + return inner`); + +var buffer = new ArrayBuffer(BUF_MIN); +function ffi1() { neuter(buffer, "change-data"); } +var inner = asmLink(m, this, {ffi:ffi1}, buffer); +assertThrowsInstanceOf(() => inner(8), InternalError); + +var byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get); +var m = asmCompile('stdlib', 'foreign', 'buffer', + `"use asm"; + var ffi = foreign.ffi; + var I32 = stdlib.Int32Array; + var i32 = new I32(buffer); + var len = stdlib.byteLength; + function changeHeap(newBuffer) { + if (len(newBuffer) & 0xffffff || len(newBuffer) <= 0xffffff || len(newBuffer) > 0x80000000) + return false; + i32 = new I32(newBuffer); + buffer = newBuffer; + return true; + } + function get(i) { + i=i|0; + return i32[i>>2]|0; + } + function inner(i) { + i=i|0; + ffi(); + return get(i)|0; + } + return {changeHeap:changeHeap, get:get, inner:inner}`); + +var buf1 = new ArrayBuffer(BUF_CHANGE_MIN); +var buf2 = new ArrayBuffer(BUF_CHANGE_MIN); +var buf3 = new ArrayBuffer(BUF_CHANGE_MIN); +var buf4 = new ArrayBuffer(BUF_CHANGE_MIN); +new Int32Array(buf2)[13] = 42; +new Int32Array(buf3)[13] = 1024; +new Int32Array(buf4)[13] = 1337; + +function ffi2() { neuter(buf1, "change-data"); assertEq(changeHeap(buf2), true); } +var {changeHeap, get:get2, inner} = asmLink(m, this, {ffi:ffi2}, buf1); +assertEq(inner(13*4), 42); + +function ffi3() { + assertEq(get2(13*4), 42); + assertEq(get2(BUF_CHANGE_MIN), 0) + assertEq(get3(13*4), 42); + assertEq(get3(BUF_CHANGE_MIN), 0) + neuter(buf2, "change-data"); + assertThrowsInstanceOf(()=>get2(13*4), InternalError); + assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError); + assertThrowsInstanceOf(()=>get3(13*4), InternalError); + assertThrowsInstanceOf(()=>get3(BUF_CHANGE_MIN), InternalError); + assertEq(changeHeap(buf3), true); + assertThrowsInstanceOf(()=>get2(13*4), InternalError); + assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError); + assertEq(get3(13*4), 1024); + assertEq(get3(BUF_CHANGE_MIN), 0); + assertEq(changeHeap(buf4), true); } - -function f2(stdlib, foreign, buffer) { - "use asm"; - var i32 = new stdlib.Int32Array(buffer); - var ffi = foreign.ffi; - function inner(i) { - i=i|0; - ffi(); - return i32[i>>2]|0 - } - return inner -} -if (isAsmJSCompilationAvailable()) - assertEq(isAsmJSModule(f2), true); - -var i32 = new Int32Array(1024); -var buffer = i32.buffer; -var threw = false; -function ffi() { - try { - neuter(buffer, "same-data"); - } catch (e) { - assertEq(String(e).indexOf("InternalError"), 0); - threw = true; - } - try { - neuter(buffer, "change-data"); - } catch (e) { - assertEq(String(e).indexOf("InternalError"), 0); - threw = true; - } -} -var inner = f2(this, {ffi:ffi}, buffer); -if (isAsmJSCompilationAvailable()) - assertEq(isAsmJSFunction(inner), true); -i32[2] = 13; -var result = inner(8); -if (threw) - assertEq(result, 13); -else - assertEq(result, 0); - +var {changeHeap, get:get3, inner} = asmLink(m, this, {ffi:ffi3}, buf2); +assertEq(inner(13*4), 1337); +assertThrowsInstanceOf(()=>get2(0), InternalError); +assertEq(get3(BUF_CHANGE_MIN), 0); +assertEq(get3(13*4), 1337); diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js index 144fa90b3009..e1e2c1dc0d81 100644 --- a/js/src/jit-test/tests/asm.js/testProfiling.js +++ b/js/src/jit-test/tests/asm.js/testProfiling.js @@ -1,4 +1,5 @@ load(libdir + "asm.js"); +load(libdir + "asserts.js"); // Single-step profiling currently only works in the ARM simulator if (!getBuildConfiguration()["arm-simulator"]) @@ -124,6 +125,15 @@ assertEq(f1(), 32); var stacks = disableSingleStepProfiling(); assertEqualStacks(stacks, ",>,f1>,,>,f2>,,f2>,>,,f1>,>,"); +// Detachment exit +var buf = new ArrayBuffer(BUF_CHANGE_MIN); +var ffi = function() { neuter(buf, 'change-data') } +var f = asmLink(asmCompile('g','ffis','buf', USE_ASM + 'var ffi = ffis.ffi; var i32 = new g.Int32Array(buf); function f() { ffi() } return f'), this, {ffi:ffi}, buf); +enableSingleStepProfiling(); +assertThrowsInstanceOf(f, InternalError); +var stacks = disableSingleStepProfiling(); +assertEqualStacks(stacks, ",>,f>,,inline stubf>,,inline stubf>,"); + // This takes forever to run. // Stack-overflow exit test //var limit = -1; diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index d2a495e55d13..9a20c1ad9778 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -767,6 +767,7 @@ enum AsmJSImmKind AsmJSImm_RuntimeInterrupt, AsmJSImm_StackLimit, AsmJSImm_ReportOverRecursed, + AsmJSImm_OnDetached, AsmJSImm_HandleExecutionInterrupt, AsmJSImm_InvokeFromAsmJS_Ignore, AsmJSImm_InvokeFromAsmJS_ToInt32, From 51d895a3bf8e619ed8a0ea8cd7ba928d70720d0f Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 15 Oct 2014 09:10:46 -0500 Subject: [PATCH 014/100] Bug 1081379 - Move js_InitArrayBufferClass into the right file (r=sfink) --HG-- extra : rebase_source : a3dfdd55bcfc895bcc922c4d1c13483a43053c14 --- js/src/vm/ArrayBufferObject.cpp | 46 +++++++++++++++++++++++++++++++++ js/src/vm/TypedArrayObject.cpp | 45 -------------------------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 33a1a22c6140..a6ab1c6cbd82 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1259,3 +1259,49 @@ js::GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data) *length = AsArrayBuffer(obj).byteLength(); *data = AsArrayBuffer(obj).dataPointer(); } + +JSObject * +js_InitArrayBufferClass(JSContext *cx, HandleObject obj) +{ + Rooted global(cx, cx->compartment()->maybeGlobal()); + if (global->isStandardClassResolved(JSProto_ArrayBuffer)) + return &global->getPrototype(JSProto_ArrayBuffer).toObject(); + + RootedNativeObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass)); + if (!arrayBufferProto) + return nullptr; + + RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor, + cx->names().ArrayBuffer, 1)); + if (!ctor) + return nullptr; + + if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer, + ctor, arrayBufferProto)) + { + return nullptr; + } + + if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto)) + return nullptr; + + RootedId byteLengthId(cx, NameToId(cx->names().byteLength)); + unsigned attrs = JSPROP_SHARED | JSPROP_GETTER; + JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0, + JSFunction::NATIVE_FUN, global, NullPtr()); + if (!getter) + return nullptr; + + if (!DefineNativeProperty(cx, arrayBufferProto, byteLengthId, UndefinedHandleValue, + JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs)) + return nullptr; + + if (!JS_DefineFunctions(cx, ctor, ArrayBufferObject::jsstaticfuncs)) + return nullptr; + + if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs)) + return nullptr; + + return arrayBufferProto; +} + diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 351a5fe9ce22..b2f237689ff8 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -1815,51 +1815,6 @@ const Class TypedArrayObject::protoClasses[Scalar::TypeMax] = { IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray) }; -JSObject * -js_InitArrayBufferClass(JSContext *cx, HandleObject obj) -{ - Rooted global(cx, cx->compartment()->maybeGlobal()); - if (global->isStandardClassResolved(JSProto_ArrayBuffer)) - return &global->getPrototype(JSProto_ArrayBuffer).toObject(); - - RootedNativeObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass)); - if (!arrayBufferProto) - return nullptr; - - RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor, - cx->names().ArrayBuffer, 1)); - if (!ctor) - return nullptr; - - if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer, - ctor, arrayBufferProto)) - { - return nullptr; - } - - if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto)) - return nullptr; - - RootedId byteLengthId(cx, NameToId(cx->names().byteLength)); - unsigned attrs = JSPROP_SHARED | JSPROP_GETTER; - JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0, - JSFunction::NATIVE_FUN, global, NullPtr()); - if (!getter) - return nullptr; - - if (!DefineNativeProperty(cx, arrayBufferProto, byteLengthId, UndefinedHandleValue, - JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs)) - return nullptr; - - if (!JS_DefineFunctions(cx, ctor, ArrayBufferObject::jsstaticfuncs)) - return nullptr; - - if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs)) - return nullptr; - - return arrayBufferProto; -} - /* static */ bool TypedArrayObject::isOriginalLengthGetter(Native native) { From a857807a23b37410d345c829697d7f6aaddde6fa Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Wed, 15 Oct 2014 14:14:30 -0700 Subject: [PATCH 015/100] Bug 1081415 - Traverse and Unlink nsXMLHttpRequest::mResponseBlob and ::mDOMFile. r=baku --- content/base/src/nsXMLHttpRequest.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 108d8fa75b60..3a8f39e018f1 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -474,6 +474,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest, NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink) @@ -492,6 +496,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest, NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink) NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink) From c631cc28b8eedb1185b34f222be4ad3ab45cd8c3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 15 Oct 2014 14:14:34 -0700 Subject: [PATCH 016/100] WebGL2: Add support for TEXTURE_BINDING_3D. (bug 1082952 r=jgilbert) --HG-- extra : rebase_source : aac040bf24280dfcbc0fbbe4a20459f0b609a971 --- dom/canvas/WebGLContextState.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index 768742d4161b..474734bbfac7 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -186,6 +186,10 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) gl->fGetIntegerv(pname, &val); return JS::NumberValue(uint32_t(val)); } + + case LOCAL_GL_TEXTURE_BINDING_3D: { + return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv); + } } } From f1a4b62967228b1dce4086cdd84adc1ac5f68bb8 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 15 Oct 2014 17:20:17 -0400 Subject: [PATCH 017/100] Bug 1083447 - texParameter and getTexParameter should accept the TEXTURE_3D target in WebGL2 mode - r=jgilbert --- dom/canvas/WebGLContextValidate.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 16df08f9a1a7..265358a8a550 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -219,6 +219,13 @@ bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info) case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP: return true; + case LOCAL_GL_TEXTURE_3D: { + const bool isValid = IsWebGL2(); + if (!isValid) { + ErrorInvalidEnumInfo(info, target); + } + return isValid; + } default: ErrorInvalidEnumInfo(info, target); return false; From 120dbbef83d7b25a118213095dee9a36df02db75 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 15 Oct 2014 02:07:34 -0700 Subject: [PATCH 018/100] WebGL2: support TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL. (bug 1080957, r=jgilbert) --HG-- extra : rebase_source : 599bd05e07d9a9f1b1e9f73255c5ef275358806a --- dom/canvas/WebGL2ContextTextures.cpp | 2 ++ dom/canvas/WebGLContextGL.cpp | 15 +++++++++- dom/canvas/WebGLTexture.cpp | 41 +++++++++++++--------------- dom/canvas/WebGLTexture.h | 14 ++++++++++ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/dom/canvas/WebGL2ContextTextures.cpp b/dom/canvas/WebGL2ContextTextures.cpp index e134ed100c28..21028d09e5b6 100644 --- a/dom/canvas/WebGL2ContextTextures.cpp +++ b/dom/canvas/WebGL2ContextTextures.cpp @@ -351,6 +351,8 @@ WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname) { switch (pname) { case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT: + case LOCAL_GL_TEXTURE_BASE_LEVEL: + case LOCAL_GL_TEXTURE_MAX_LEVEL: { GLint i = 0; gl->fGetTexParameteriv(target.get(), pname, &i); diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index cf8be3fed833..74e67e38a489 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -922,7 +922,7 @@ WebGLContext::GenerateMipmap(GLenum rawTarget) const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; - if (!tex->HasImageInfoAt(imageTarget, 0)) + if (!tex->HasImageInfoAt(imageTarget, tex->GetBaseMipmapLevel())) { return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined."); } @@ -1510,6 +1510,19 @@ void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname, bool paramValueInvalid = false; switch (pname) { + case LOCAL_GL_TEXTURE_BASE_LEVEL: + case LOCAL_GL_TEXTURE_MAX_LEVEL: + if (!IsWebGL2()) + return ErrorInvalidEnumInfo("texParameter: pname", pname); + if (intParam < 0) { + paramValueInvalid = true; + break; + } + if (pname == LOCAL_GL_TEXTURE_BASE_LEVEL) + tex->SetBaseMipmapLevel(intParam); + else + tex->SetMaxMipmapLevel(intParam); + break; case LOCAL_GL_TEXTURE_MIN_FILTER: switch (intParam) { case LOCAL_GL_NEAREST: diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 45914f8e9794..e14bbc4d7c7a 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -33,6 +33,8 @@ WebGLTexture::WebGLTexture(WebGLContext *context) , mMaxLevelWithCustomImages(0) , mHaveGeneratedMipmap(false) , mImmutable(false) + , mBaseMipmapLevel(0) + , mMaxMipmapLevel(1000) , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture) { mContext->MakeContextCurrent(); @@ -62,22 +64,8 @@ WebGLTexture::MemoryUsage() const { return 0; size_t result = 0; for(size_t face = 0; face < mFacesCount; face++) { - if (mHaveGeneratedMipmap) { - size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage(); - // Each mipmap level is 1/(2^d) the size of the previous level, - // where d is 2 or 3 depending on whether the images are 2D or 3D - // 1 + x + x^2 + ... = 1/(1-x) - // for x = 1/(2^2), we get 1/(1-1/4) = 4/3 - // for x = 1/(2^3), we get 1/(1-1/8) = 8/7 - size_t allLevelsMemoryUsage = - mTarget == LOCAL_GL_TEXTURE_3D - ? level0MemoryUsage * 8 / 7 - : level0MemoryUsage * 4 / 3; - result += allLevelsMemoryUsage; - } else { - for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++) - result += ImageInfoAtFace(face, level).MemoryUsage(); - } + for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++) + result += ImageInfoAtFace(face, level).MemoryUsage(); } return result; } @@ -88,15 +76,24 @@ WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImage if (mHaveGeneratedMipmap) return true; + if (GetMaxMipmapLevel() < GetBaseMipmapLevel()) + return false; + // We want a copy here so we can modify it temporarily. - ImageInfo expected = ImageInfoAt(texImageTarget, 0); + ImageInfo expected = ImageInfoAt(texImageTarget, GetBaseMipmapLevel()); // checks if custom level>0 images are all defined up to the highest level defined // and have the expected dimensions - for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { + for (size_t level = GetBaseMipmapLevel(); level <= GetMaxMipmapLevel(); ++level) { const ImageInfo& actual = ImageInfoAt(texImageTarget, level); if (actual != expected) return false; + + // Check the raw value here, not the clamped one, since we don't want + // to terminate early if there aren't enough levels defined. + if (level == mMaxMipmapLevel) + return true; + expected.mWidth = std::max(1, expected.mWidth / 2); expected.mHeight = std::max(1, expected.mHeight / 2); expected.mDepth = std::max(1, expected.mDepth / 2); @@ -185,7 +182,7 @@ WebGLTexture::SetCustomMipmap() { // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info, // and are power-of-two. - ImageInfo imageInfo = ImageInfoAtFace(0, 0); + ImageInfo imageInfo = ImageInfoAtFace(0, GetBaseMipmapLevel()); NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?"); @@ -198,7 +195,7 @@ WebGLTexture::SetCustomMipmap() { EnsureMaxLevelWithCustomImagesAtLeast(maxLevel); - for (size_t level = 1; level <= maxLevel; ++level) { + for (size_t level = GetBaseMipmapLevel() + 1; level <= GetMaxMipmapLevel(); ++level) { imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1); imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1); imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1); @@ -223,7 +220,7 @@ WebGLTexture::IsMipmapComplete() const { MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D || mTarget == LOCAL_GL_TEXTURE_3D); - if (!ImageInfoAtFace(0, 0).IsPositive()) + if (!ImageInfoAtFace(0, GetBaseMipmapLevel()).IsPositive()) return false; if (mHaveGeneratedMipmap) return true; @@ -262,7 +259,7 @@ WebGLTexture::ResolvedFakeBlackStatus() { // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec. for (size_t face = 0; face < mFacesCount; ++face) { - if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) { + if (ImageInfoAtFace(face, GetBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) { // In case of undefined texture image, we don't print any message because this is a very common // and often legitimate case (asynchronous texture loading). mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index b7cca286be05..134f25094677 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -213,6 +213,9 @@ protected: bool mHaveGeneratedMipmap; // set by generateMipmap bool mImmutable; // set by texStorage* + size_t mBaseMipmapLevel; // set by texParameter (defaults to 0) + size_t mMaxMipmapLevel; // set by texParameter (defaults to 1000) + WebGLTextureFakeBlackStatus mFakeBlackStatus; void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) { @@ -283,6 +286,17 @@ public: bool IsImmutable() const { return mImmutable; } void SetImmutable() { mImmutable = true; } + void SetBaseMipmapLevel(unsigned level) { mBaseMipmapLevel = level; } + void SetMaxMipmapLevel(unsigned level) { mMaxMipmapLevel = level; } + size_t GetBaseMipmapLevel() const { + // Clamp to [0, levels - 1] + return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages); + } + size_t GetMaxMipmapLevel() const { + // Clamp to [base, levels - 1] + return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages); + } + size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; } // Returns the current fake-black-status, except if it was Unknown, From 62c11f371994075c0129c15ef055dd0d7b8fb316 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 15 Oct 2014 10:40:04 -0700 Subject: [PATCH 019/100] Bug 1081260 - Do not leak onOutOfMemory's allocation; r=luke --HG-- extra : rebase_source : f37bd362ecb450ef479323d74b84cb8101e3faf9 --- js/src/vm/MallocProvider.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h index b05bb94cf577..86eb79d49efd 100644 --- a/js/src/vm/MallocProvider.h +++ b/js/src/vm/MallocProvider.h @@ -68,8 +68,7 @@ struct MallocProvider client()->reportAllocationOverflow(); return nullptr; } - client()->onOutOfMemory(nullptr, numElems * sizeof(T)); - return nullptr; + return (T *)client()->onOutOfMemory(nullptr, numElems * sizeof(T)); } template @@ -88,8 +87,7 @@ struct MallocProvider client()->updateMallocCounter(bytes); return p; } - client()->onOutOfMemory(nullptr, bytes); - return nullptr; + return (T *)client()->onOutOfMemory(nullptr, bytes); } template @@ -114,8 +112,7 @@ struct MallocProvider client()->reportAllocationOverflow(); return nullptr; } - client()->onOutOfMemory(nullptr, numElems * sizeof(T)); - return nullptr; + return (T *)client()->onOutOfMemory(nullptr, numElems * sizeof(T)); } template @@ -134,8 +131,7 @@ struct MallocProvider client()->updateMallocCounter(bytes); return p; } - client()->onOutOfMemory(nullptr, bytes); - return nullptr; + return (T *)client()->onOutOfMemory(nullptr, bytes); } template @@ -159,8 +155,7 @@ struct MallocProvider client()->reportAllocationOverflow(); return nullptr; } - client()->onOutOfMemory(prior, newSize * sizeof(T)); - return nullptr; + return (T *)client()->onOutOfMemory(prior, newSize * sizeof(T)); } JS_DECLARE_NEW_METHODS(new_, pod_malloc, MOZ_ALWAYS_INLINE) From 5aebfb4322de94fe84f17aa340dd0d93efc72e97 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 14 Oct 2014 13:03:23 -0700 Subject: [PATCH 020/100] Bug 1082794 - Use Maybe instead of a separate constructor to maybe construct an AutoLockGC; r=jonco --HG-- extra : rebase_source : 7a4c24509fd6ac4b6f1bea403fd04638536d90d6 --- js/src/jsgc.cpp | 13 +++++++------ js/src/vm/Runtime.h | 20 +++----------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9c12e7704a7b..25f8e76a28f8 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1011,9 +1011,10 @@ Chunk::releaseArena(ArenaHeader *aheader) MOZ_ASSERT(!aheader->hasDelayedMarking); Zone *zone = aheader->zone; JSRuntime *rt = zone->runtimeFromAnyThread(); - AutoLockGC maybeLock; + + Maybe maybeLock; if (rt->gc.isBackgroundSweeping()) - maybeLock.lock(rt); + maybeLock.emplace(rt); if (rt->gc.isBackgroundSweeping()) zone->threshold.updateForRemovedArena(rt->gc.tunables); @@ -1924,11 +1925,11 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind, AutoMaybeStartBackgroundAllocation &maybeStartBGAlloc) { JSRuntime *rt = zone->runtimeFromAnyThread(); - AutoLockGC maybeLock; + Maybe maybeLock; // See if we can proceed without taking the GC lock. if (backgroundFinalizeState[thingKind] != BFS_DONE) - maybeLock.lock(rt); + maybeLock.emplace(rt); ArenaList &al = arenaLists[thingKind]; ArenaHeader *aheader = al.takeNextArena(); @@ -1941,8 +1942,8 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind, // Parallel threads have their own ArenaLists, but chunks are shared; // if we haven't already, take the GC lock now to avoid racing. - if (!maybeLock.locked()) - maybeLock.lock(rt); + if (maybeLock.isNothing()) + maybeLock.emplace(rt); Chunk *chunk = rt->gc.pickChunk(zone, maybeStartBGAlloc); if (!chunk) diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index af13738617af..572bd27ab374 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1496,31 +1496,17 @@ FreeOp::freeLater(void *p) class AutoLockGC { public: - explicit AutoLockGC(JSRuntime *rt = nullptr + explicit AutoLockGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : runtime(rt) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - // Avoid MSVC warning C4390 for non-threadsafe builds. - if (rt) - rt->lockGC(); + rt->lockGC(); } ~AutoLockGC() { - if (runtime) - runtime->unlockGC(); - } - - bool locked() const { - return !!runtime; - } - - void lock(JSRuntime *rt) { - MOZ_ASSERT(rt); - MOZ_ASSERT(!runtime); - runtime = rt; - rt->lockGC(); + runtime->unlockGC(); } private: From cf51caee995a0b92a41905595af38a4669b0e339 Mon Sep 17 00:00:00 2001 From: Romain Gauthier Date: Fri, 19 Sep 2014 19:31:47 +0200 Subject: [PATCH 021/100] Bug 971110: Prettify about:webrtc r=niko,pkerr --- docshell/base/nsAboutRedirector.cpp | 2 +- toolkit/content/aboutWebrtc.xhtml | 440 --------------- toolkit/content/aboutwebrtc/README.txt | 21 + toolkit/content/aboutwebrtc/aboutWebrtc.css | 78 +++ toolkit/content/aboutwebrtc/aboutWebrtc.js | 529 ++++++++++++++++++ toolkit/content/aboutwebrtc/aboutWebrtc.jsx | 529 ++++++++++++++++++ toolkit/content/aboutwebrtc/aboutWebrtc.xhtml | 22 + toolkit/content/jar.mn | 4 +- 8 files changed, 1183 insertions(+), 442 deletions(-) delete mode 100644 toolkit/content/aboutWebrtc.xhtml create mode 100644 toolkit/content/aboutwebrtc/README.txt create mode 100644 toolkit/content/aboutwebrtc/aboutWebrtc.css create mode 100644 toolkit/content/aboutwebrtc/aboutWebrtc.js create mode 100644 toolkit/content/aboutwebrtc/aboutWebrtc.jsx create mode 100644 toolkit/content/aboutwebrtc/aboutWebrtc.xhtml diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index bc62441bf5b7..5e6fbeb1090a 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -67,7 +67,7 @@ static RedirEntry kRedirMap[] = { nsIAboutModule::ALLOW_SCRIPT }, { "networking", "chrome://global/content/aboutNetworking.xhtml", nsIAboutModule::ALLOW_SCRIPT }, - { "webrtc", "chrome://global/content/aboutWebrtc.xhtml", + { "webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.xhtml", nsIAboutModule::ALLOW_SCRIPT }, // about:srcdoc is unresolvable by specification. It is included here // because the security manager would disallow srcdoc iframes otherwise. diff --git a/toolkit/content/aboutWebrtc.xhtml b/toolkit/content/aboutWebrtc.xhtml deleted file mode 100644 index e60f75ef9faf..000000000000 --- a/toolkit/content/aboutWebrtc.xhtml +++ /dev/null @@ -1,440 +0,0 @@ - - - - - %htmlDTD; -]> - - - - Webrtc Internals - - - - -
-
- - - -
-
- - - diff --git a/toolkit/content/aboutwebrtc/README.txt b/toolkit/content/aboutwebrtc/README.txt new file mode 100644 index 000000000000..76f51c8a2418 --- /dev/null +++ b/toolkit/content/aboutwebrtc/README.txt @@ -0,0 +1,21 @@ +Working with React JSX files +============================ + +The about:webrtc page uses [React](http://facebook.github.io/react/). +The UI is written in JSX files and transpiled to JS before we +commit. You need to install the JSX compiler using npm in order to +compile the .jsx files into regular .js ones: + + npm install -g react-tools + +Run the following command: + + jsx -w -x jsx . . + +jsx can also be do a one-time compile pass instead of watching if the +-w argument is omitted. Be sure to commit any transpiled files at the +same time as changes to their sources. + +IMPORTANT: do not modify the generated files, only their JSX +counterpart. + diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.css b/toolkit/content/aboutwebrtc/aboutWebrtc.css new file mode 100644 index 000000000000..73743988f38f --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.css @@ -0,0 +1,78 @@ +html { + background-color: #EDECEB; + font: message-box; +} + +#logs { + font-family: monospace; +} + +.peer-connections { + padding: 2em; + margin: 1em 0em; + border: 1px solid #AFACA9; + border-radius: 10px; + background: none repeat scroll 0% 0% #FFF; +} + +.peer-connection h3 { + background-color: #DDD; + cursor: pointer; +} + +.peer-connection h3 span:last-child { + float: right; +} + +.peer-connection section { + border: 1px solid #AFACA9; + padding: 10px; +} + +.peer-connection table { + width: 100%; + text-align: center; + border: none; +} + +.peer-connection table th, +.peer-connection table td { + padding: 0.4em; +} + +.peer-connection table tr:nth-child(even) { + background-color: #DDD; +} + +.pcid span:first-child { + font-weight: bold; +} + +.tabs > ul { + list-style-type: none; + margin: 0; + padding: 3px 10px; +} + +.tabs li { + display: inline; + position: relative; + top: 1px; + padding: 3px 10px; +} + +.tabs li > a { + text-decoration: none; + padding: 0 2em; +} + +.tabs li.active { + background-color: #FFF; + border: 1px solid #AFACA9; + border-bottom: none; +} + +.tabs section { + clear: both; +} + diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.js b/toolkit/content/aboutwebrtc/aboutWebrtc.js new file mode 100644 index 000000000000..ffd89e1ee1ae --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.js @@ -0,0 +1,529 @@ +/** @jsx React.DOM */ +/* 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/. */ + +"use strict"; + +var Tabs = React.createClass({displayName: 'Tabs', + getDefaultProps: function() { + return {selectedIndex: 0}; + }, + + getInitialState: function() { + return {selectedIndex: this.props.selectedIndex}; + }, + + selectTab: function(index) { + return function(event) { + event.preventDefault(); + this.setState({selectedIndex: index}); + }.bind(this); + }, + + _findSelectedTabContent: function() { + // Using map() to filter children… + // https://github.com/facebook/react/issues/1644#issuecomment-45138113 + return React.Children.map(this.props.children, function(tab, i) { + return i === this.state.selectedIndex ? tab : null; + }.bind(this)) + }, + + render: function() { + var cx = React.addons.classSet; + return ( + React.DOM.div({className: "tabs"}, + React.DOM.ul(null, + React.Children.map(this.props.children, function(tab, i) { + return ( + React.DOM.li({className: cx({active: i === this.state.selectedIndex})}, + React.DOM.a({href: "#", key: i, onClick: this.selectTab(i)}, + tab.props.title + ) + ) + ); + }.bind(this)) + ), + this._findSelectedTabContent() + ) + ); + } +}); + +var Tab = React.createClass({displayName: 'Tab', + render: function() { + return React.DOM.section(null, this.props.children); + } +}); + +var AboutWebRTC = React.createClass({displayName: 'AboutWebRTC', + getInitialState: function() { + return {logs: null, reports: this.props.reports}; + }, + + displayLogs: function() { + WebrtcGlobalInformation.getLogging('', function(logs) { + this.setState({logs: logs, reports: this.state.reports}); + }.bind(this)) + }, + + render: function() { + return ( + React.DOM.div(null, + React.DOM.div({id: "stats"}, + PeerConnections({reports: this.state.reports}) + ), + React.DOM.div({id: "buttons"}, + LogsButton({handler: this.displayLogs}), + DebugButton(null), + AECButton(null) + ), + React.DOM.div({id: "logs"}, + this.state.logs ? Logs({logs: this.state.logs}) : null + ) + ) + ); + } +}); + +var PeerConnections = React.createClass({displayName: 'PeerConnections', + getInitialState: function() { + // Sort the reports to have the more recent at the top + var reports = this.props.reports.slice().sort(function(r1, r2) { + return r2.timestamp - r1.timestamp; + }); + + return {reports: reports}; + }, + + render: function() { + return ( + React.DOM.div({className: "peer-connections"}, + + this.state.reports.map(function(report, i) { + return PeerConnection({key: i, report: report}); + }) + + ) + ); + } +}); + +var PeerConnection = React.createClass({displayName: 'PeerConnection', + getPCInfo: function(report) { + return { + id: report.pcid.match(/id=(\S+)/)[1], + url: report.pcid.match(/http[^)]+/)[0], + closed: report.closed + }; + }, + + getIceCandidatePairs: function(report) { + var candidates = + report.iceCandidateStats.reduce(function(candidates, candidate) { + candidates[candidate.id] = candidate; + + return candidates; + }, {}); + + var pairs = report.iceCandidatePairStats.map(function(pair) { + var localCandidate = candidates[pair.localCandidateId]; + var remoteCandidate = candidates[pair.remoteCandidateId]; + + return { + localCandidate: candidateToString(localCandidate), + remoteCandidate: candidateToString(remoteCandidate), + state: pair.state, + priority: pair.mozPriority, + nominated: pair.nominated, + selected: pair.selected + }; + }); + + var pairedCandidates = pairs.reduce(function(paired, pair) { + paired.add(pair.localCandidate.id); + paired.add(pair.remoteCandidate.id); + + return paired + }, new Set()); + + var unifiedPairs = + report.iceCandidateStats.reduce(function(pairs, candidate) { + if (pairedCandidates.has(candidate)) { + return pairs; + } + + var isLocal = candidate.type === "localcandidate"; + + pairs.push({ + localCandidate: isLocal ? candidateToString(candidate) : null, + remoteCandidate: isLocal ? null : candidateToString(candidate), + state: null, + priority: null, + nominated: null, + selected: null + }); + + return pairs; + }, pairs); + + return unifiedPairs; + }, + + getInitialState: function() { + return { + unfolded: false + }; + }, + + onFold: function() { + this.setState({unfolded: !this.state.unfolded}); + }, + + body: function(report, pairs) { + return ( + React.DOM.div(null, + React.DOM.p({className: "pcid"}, "PeerConnection ID: ", report.pcid), + Tabs(null, + Tab({title: "Ice Stats"}, + IceStats({pairs: pairs}) + ), + Tab({title: "SDP"}, + SDP({type: "local", sdp: report.localSdp}), + SDP({type: "remote", sdp: report.remoteSdp}) + ), + Tab({title: "RTP Stats"}, + RTPStats({report: report}) + ) + ) + ) + ); + }, + + render: function() { + var report = this.props.report; + var pcInfo = this.getPCInfo(report); + var pairs = this.getIceCandidatePairs(report); + + return ( + React.DOM.div({className: "peer-connection"}, + React.DOM.h3({onClick: this.onFold}, + "[", pcInfo.id, "] ", pcInfo.url, " ", pcInfo.closed ? "(closed)" : null, + new Date(report.timestamp).toTimeString() + ), + this.state.unfolded ? this.body(report, pairs) : undefined + ) + ); + } +}); + +var IceStats = React.createClass({displayName: 'IceStats', + sortHeadings: { + "Local candidate": "localCandidate", + "Remote candidate": "remoteCandidate", + "Ice State": "state", + "Priority": "priority", + "Nominated": "nominated", + "Selected": "selected" + }, + + sort: function(key) { + var sorting = this.state.sorting; + var pairs = this.state.pairs.slice().sort(function(pair1, pair2) { + var value1 = pair1[key] ? pair1[key].toString() : ""; + var value2 = pair2[key] ? pair2[key].toString() : ""; + + // Reverse sorting + if (key === sorting) { + return value2.localeCompare(value1); + } + + return value1.localeCompare(value2); + }.bind(this)); + + sorting = (key === sorting) ? null : key; + this.setState({pairs: pairs, sorting: sorting}); + }, + + generateSortHeadings: function() { + return Object.keys(this.sortHeadings).map(function(heading, i) { + var sortKey = this.sortHeadings[heading]; + return ( + React.DOM.th(null, + React.DOM.a({href: "#", onClick: this.sort.bind(this, sortKey)}, + heading + ) + ) + ); + }.bind(this)); + }, + + getInitialState: function() { + return {pairs: this.props.pairs, sorting: null}; + }, + + render: function() { + return ( + React.DOM.table(null, + React.DOM.tbody(null, + React.DOM.tr(null, this.generateSortHeadings()), + this.state.pairs.map(function(pair, i) { + return IceCandidatePair({key: i, pair: pair}); + }) + ) + ) + ); + } +}); + +var IceCandidatePair = React.createClass({displayName: 'IceCandidatePair', + render: function() { + var pair = this.props.pair; + return ( + React.DOM.tr(null, + React.DOM.td(null, pair.localCandidate), + React.DOM.td(null, pair.remoteCandidate), + React.DOM.td(null, pair.state), + React.DOM.td(null, pair.priority), + React.DOM.td(null, pair.nominated ? '✔' : null), + React.DOM.td(null, pair.selected ? '✔' : null) + ) + ); + } +}); + +var SDP = React.createClass({displayName: 'SDP', + render: function() { + var type = labelize(this.props.type); + + return ( + React.DOM.div(null, + React.DOM.h4(null, type, " SDP"), + React.DOM.pre(null, + this.props.sdp + ) + ) + ); + } +}); + +var RTPStats = React.createClass({displayName: 'RTPStats', + getRtpStats: function(report) { + var remoteRtpStats = {}; + var rtpStats = []; + + rtpStats = rtpStats.concat(report.inboundRTPStreamStats || []); + rtpStats = rtpStats.concat(report.outboundRTPStreamStats || []); + + rtpStats.forEach(function(stats) { + if (stats.isRemote) { + remoteRtpStats[stats.id] = stats; + } + }); + + rtpStats.forEach(function(stats) { + if (stats.remoteId) { + stats.remoteRtpStats = remoteRtpStats[stats.remoteId]; + } + }); + + return rtpStats; + }, + + dumpAvStats: function(stats) { + var statsString = ""; + if (stats.mozAvSyncDelay) { + statsString += `A/V sync: ${stats.mozAvSyncDelay} ms `; + } + if (stats.mozJitterBufferDelay) { + statsString += `Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`; + } + + return React.DOM.div(null, statsString); + }, + + dumpCoderStats: function(stats) { + var statsString = ""; + var label; + + if (stats.bitrateMean) { + statsString += ` Avg. bitrate: ${(stats.bitrateMean/1000000).toFixed(2)} Mbps`; + if (stats.bitrateStdDev) { + statsString += ` (${(stats.bitrateStdDev/1000000).toFixed(2)} SD)`; + } + } + + if (stats.framerateMean) { + statsString += ` Avg. framerate: ${(stats.framerateMean).toFixed(2)} fps`; + if (stats.framerateStdDev) { + statsString += ` (${stats.framerateStdDev.toFixed(2)} SD)`; + } + } + + if (stats.droppedFrames) { + statsString += ` Dropped frames: ${stats.droppedFrames}`; + } + if (stats.discardedPackets) { + statsString += ` Discarded packets: ${stats.discardedPackets}`; + } + + if (statsString) { + label = (stats.packetsReceived)? " Decoder:" : " Encoder:"; + statsString = label + statsString; + } + + return React.DOM.div(null, statsString); + }, + + dumpRtpStats: function(stats, type) { + var label = labelize(type); + var time = new Date(stats.timestamp).toTimeString(); + + var statsString = `${label}: ${time} ${stats.type} SSRC: ${stats.ssrc}`; + + if (stats.packetsReceived) { + statsString += ` Received: ${stats.packetsReceived} packets`; + + if (stats.bytesReceived) { + statsString += ` (${round00(stats.bytesReceived/1024)} Kb)`; + } + + statsString += ` Lost: ${stats.packetsLost} Jitter: ${stats.jitter}`; + + if (stats.mozRtt) { + statsString += ` RTT: ${stats.mozRtt} ms`; + } + } else if (stats.packetsSent) { + statsString += ` Sent: ${stats.packetsSent} packets`; + if (stats.bytesSent) { + statsString += ` (${round00(stats.bytesSent/1024)} Kb)`; + } + } + + return React.DOM.div(null, statsString); + }, + + render: function() { + var rtpStats = this.getRtpStats(this.props.report); + + return ( + React.DOM.div(null, + rtpStats.map(function(stats) { + var isAvStats = (stats.mozAvSyncDelay || stats.mozJitterBufferDelay); + var remoteRtpStats = stats.remoteId ? stats.remoteRtpStats : null; + + return [ + React.DOM.h5(null, stats.id), + isAvStats ? this.dumpAvStats(stats) : null, + this.dumpCoderStats(stats), + this.dumpRtpStats(stats, "local"), + remoteRtpStats ? this.dumpRtpStats(remoteRtpStats, "remote") : null + ] + }.bind(this)) + ) + ); + } +}); + +var LogsButton = React.createClass({displayName: 'LogsButton', + render: function() { + return ( + React.DOM.button({onClick: this.props.handler}, "Connection log") + ); + } +}); + +var DebugButton = React.createClass({displayName: 'DebugButton', + getInitialState: function() { + var on = (WebrtcGlobalInformation.debugLevel > 0); + return {on: on}; + }, + + onClick: function() { + if (this.state.on) + WebrtcGlobalInformation.debugLevel = 0; + else + WebrtcGlobalInformation.debugLevel = 65535; + + this.setState({on: !this.state.on}); + }, + + render: function() { + return ( + React.DOM.button({onClick: this.onClick}, + this.state.on ? "Stop debug mode" : "Start debug mode" + ) + ); + } +}); + +var AECButton = React.createClass({displayName: 'AECButton', + getInitialState: function() { + return {on: WebrtcGlobalInformation.aecDebug}; + }, + + onClick: function() { + WebrtcGlobalInformation.aecDebug = !this.state.on; + this.setState({on: WebrtcGlobalInformation.aecDebug}); + }, + + render: function() { + return ( + React.DOM.button({onClick: this.onClick}, + this.state.on ? "Stop AEC logging" : "Start AEC logging" + ) + ); + } +}); + +var Logs = React.createClass({displayName: 'Logs', + render: function() { + return ( + React.DOM.div(null, + React.DOM.h3(null, "Logging:"), + React.DOM.div(null, + this.props.logs.map(function(line, i) { + return React.DOM.div({key: i}, line); + }) + ) + ) + ); + } +}); + +function iceCandidateMapping(iceCandidates) { + var candidates = {}; + iceCandidates = iceCandidates || []; + + iceCandidates.forEach(function(candidate) { + candidates[candidate.id] = candidate; + }); + + return candidates; +} + +function round00(num) { + return Math.round(num * 100) / 100; +} + +function labelize(label) { + return `${label.charAt(0).toUpperCase()}${label.slice(1)}`; +} + +function candidateToString(c) { + var type = c.candidateType; + + if (c.type == "localcandidate" && c.candidateType == "relayed") { + type = `${c.candidateType}-${c.mozLocalTransport}`; + } + + return `${c.ipAddress}:${c.portNumber}/${c.transport}(${type})` +} + +function onLoad() { + WebrtcGlobalInformation.getAllStats(function(globalReport) { + var reports = globalReport.reports; + React.renderComponent(AboutWebRTC({reports: reports}), + document.querySelector("#body")); + }); +} diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.jsx b/toolkit/content/aboutwebrtc/aboutWebrtc.jsx new file mode 100644 index 000000000000..d458f8bfc3ed --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.jsx @@ -0,0 +1,529 @@ +/** @jsx React.DOM */ +/* 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/. */ + +"use strict"; + +var Tabs = React.createClass({ + getDefaultProps: function() { + return {selectedIndex: 0}; + }, + + getInitialState: function() { + return {selectedIndex: this.props.selectedIndex}; + }, + + selectTab: function(index) { + return function(event) { + event.preventDefault(); + this.setState({selectedIndex: index}); + }.bind(this); + }, + + _findSelectedTabContent: function() { + // Using map() to filter children… + // https://github.com/facebook/react/issues/1644#issuecomment-45138113 + return React.Children.map(this.props.children, function(tab, i) { + return i === this.state.selectedIndex ? tab : null; + }.bind(this)) + }, + + render: function() { + var cx = React.addons.classSet; + return ( +
+
    { + React.Children.map(this.props.children, function(tab, i) { + return ( +
  • + + {tab.props.title} + +
  • + ); + }.bind(this)) + }
+ {this._findSelectedTabContent()} +
+ ); + } +}); + +var Tab = React.createClass({ + render: function() { + return
{this.props.children}
; + } +}); + +var AboutWebRTC = React.createClass({ + getInitialState: function() { + return {logs: null, reports: this.props.reports}; + }, + + displayLogs: function() { + WebrtcGlobalInformation.getLogging('', function(logs) { + this.setState({logs: logs, reports: this.state.reports}); + }.bind(this)) + }, + + render: function() { + return ( +
+
+ +
+
+ + + +
+
{ + this.state.logs ? : null + }
+
+ ); + } +}); + +var PeerConnections = React.createClass({ + getInitialState: function() { + // Sort the reports to have the more recent at the top + var reports = this.props.reports.slice().sort(function(r1, r2) { + return r2.timestamp - r1.timestamp; + }); + + return {reports: reports}; + }, + + render: function() { + return ( +
+ { + this.state.reports.map(function(report, i) { + return ; + }) + } +
+ ); + } +}); + +var PeerConnection = React.createClass({ + getPCInfo: function(report) { + return { + id: report.pcid.match(/id=(\S+)/)[1], + url: report.pcid.match(/http[^)]+/)[0], + closed: report.closed + }; + }, + + getIceCandidatePairs: function(report) { + var candidates = + report.iceCandidateStats.reduce(function(candidates, candidate) { + candidates[candidate.id] = candidate; + + return candidates; + }, {}); + + var pairs = report.iceCandidatePairStats.map(function(pair) { + var localCandidate = candidates[pair.localCandidateId]; + var remoteCandidate = candidates[pair.remoteCandidateId]; + + return { + localCandidate: candidateToString(localCandidate), + remoteCandidate: candidateToString(remoteCandidate), + state: pair.state, + priority: pair.mozPriority, + nominated: pair.nominated, + selected: pair.selected + }; + }); + + var pairedCandidates = pairs.reduce(function(paired, pair) { + paired.add(pair.localCandidate.id); + paired.add(pair.remoteCandidate.id); + + return paired + }, new Set()); + + var unifiedPairs = + report.iceCandidateStats.reduce(function(pairs, candidate) { + if (pairedCandidates.has(candidate)) { + return pairs; + } + + var isLocal = candidate.type === "localcandidate"; + + pairs.push({ + localCandidate: isLocal ? candidateToString(candidate) : null, + remoteCandidate: isLocal ? null : candidateToString(candidate), + state: null, + priority: null, + nominated: null, + selected: null + }); + + return pairs; + }, pairs); + + return unifiedPairs; + }, + + getInitialState: function() { + return { + unfolded: false + }; + }, + + onFold: function() { + this.setState({unfolded: !this.state.unfolded}); + }, + + body: function(report, pairs) { + return ( +
+

PeerConnection ID: {report.pcid}

+ + + + + + + + + + + + +
+ ); + }, + + render: function() { + var report = this.props.report; + var pcInfo = this.getPCInfo(report); + var pairs = this.getIceCandidatePairs(report); + + return ( +
+

+ [{pcInfo.id}] {pcInfo.url} {pcInfo.closed ? "(closed)" : null} + {new Date(report.timestamp).toTimeString()} +

+ {this.state.unfolded ? this.body(report, pairs) : undefined} +
+ ); + } +}); + +var IceStats = React.createClass({ + sortHeadings: { + "Local candidate": "localCandidate", + "Remote candidate": "remoteCandidate", + "Ice State": "state", + "Priority": "priority", + "Nominated": "nominated", + "Selected": "selected" + }, + + sort: function(key) { + var sorting = this.state.sorting; + var pairs = this.state.pairs.slice().sort(function(pair1, pair2) { + var value1 = pair1[key] ? pair1[key].toString() : ""; + var value2 = pair2[key] ? pair2[key].toString() : ""; + + // Reverse sorting + if (key === sorting) { + return value2.localeCompare(value1); + } + + return value1.localeCompare(value2); + }.bind(this)); + + sorting = (key === sorting) ? null : key; + this.setState({pairs: pairs, sorting: sorting}); + }, + + generateSortHeadings: function() { + return Object.keys(this.sortHeadings).map(function(heading, i) { + var sortKey = this.sortHeadings[heading]; + return ( + + + {heading} + + + ); + }.bind(this)); + }, + + getInitialState: function() { + return {pairs: this.props.pairs, sorting: null}; + }, + + render: function() { + return ( + + + {this.generateSortHeadings()} + {this.state.pairs.map(function(pair, i) { + return ; + })} + +
+ ); + } +}); + +var IceCandidatePair = React.createClass({ + render: function() { + var pair = this.props.pair; + return ( + + {pair.localCandidate} + {pair.remoteCandidate} + {pair.state} + {pair.priority} + {pair.nominated ? '✔' : null} + {pair.selected ? '✔' : null} + + ); + } +}); + +var SDP = React.createClass({ + render: function() { + var type = labelize(this.props.type); + + return ( +
+

{type} SDP

+
+          {this.props.sdp}
+        
+
+ ); + } +}); + +var RTPStats = React.createClass({ + getRtpStats: function(report) { + var remoteRtpStats = {}; + var rtpStats = []; + + rtpStats = rtpStats.concat(report.inboundRTPStreamStats || []); + rtpStats = rtpStats.concat(report.outboundRTPStreamStats || []); + + rtpStats.forEach(function(stats) { + if (stats.isRemote) { + remoteRtpStats[stats.id] = stats; + } + }); + + rtpStats.forEach(function(stats) { + if (stats.remoteId) { + stats.remoteRtpStats = remoteRtpStats[stats.remoteId]; + } + }); + + return rtpStats; + }, + + dumpAvStats: function(stats) { + var statsString = ""; + if (stats.mozAvSyncDelay) { + statsString += `A/V sync: ${stats.mozAvSyncDelay} ms `; + } + if (stats.mozJitterBufferDelay) { + statsString += `Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`; + } + + return
{statsString}
; + }, + + dumpCoderStats: function(stats) { + var statsString = ""; + var label; + + if (stats.bitrateMean) { + statsString += ` Avg. bitrate: ${(stats.bitrateMean/1000000).toFixed(2)} Mbps`; + if (stats.bitrateStdDev) { + statsString += ` (${(stats.bitrateStdDev/1000000).toFixed(2)} SD)`; + } + } + + if (stats.framerateMean) { + statsString += ` Avg. framerate: ${(stats.framerateMean).toFixed(2)} fps`; + if (stats.framerateStdDev) { + statsString += ` (${stats.framerateStdDev.toFixed(2)} SD)`; + } + } + + if (stats.droppedFrames) { + statsString += ` Dropped frames: ${stats.droppedFrames}`; + } + if (stats.discardedPackets) { + statsString += ` Discarded packets: ${stats.discardedPackets}`; + } + + if (statsString) { + label = (stats.packetsReceived)? " Decoder:" : " Encoder:"; + statsString = label + statsString; + } + + return
{statsString}
; + }, + + dumpRtpStats: function(stats, type) { + var label = labelize(type); + var time = new Date(stats.timestamp).toTimeString(); + + var statsString = `${label}: ${time} ${stats.type} SSRC: ${stats.ssrc}`; + + if (stats.packetsReceived) { + statsString += ` Received: ${stats.packetsReceived} packets`; + + if (stats.bytesReceived) { + statsString += ` (${round00(stats.bytesReceived/1024)} Kb)`; + } + + statsString += ` Lost: ${stats.packetsLost} Jitter: ${stats.jitter}`; + + if (stats.mozRtt) { + statsString += ` RTT: ${stats.mozRtt} ms`; + } + } else if (stats.packetsSent) { + statsString += ` Sent: ${stats.packetsSent} packets`; + if (stats.bytesSent) { + statsString += ` (${round00(stats.bytesSent/1024)} Kb)`; + } + } + + return
{statsString}
; + }, + + render: function() { + var rtpStats = this.getRtpStats(this.props.report); + + return ( +
{ + rtpStats.map(function(stats) { + var isAvStats = (stats.mozAvSyncDelay || stats.mozJitterBufferDelay); + var remoteRtpStats = stats.remoteId ? stats.remoteRtpStats : null; + + return [ +
{stats.id}
, + isAvStats ? this.dumpAvStats(stats) : null, + this.dumpCoderStats(stats), + this.dumpRtpStats(stats, "local"), + remoteRtpStats ? this.dumpRtpStats(remoteRtpStats, "remote") : null + ] + }.bind(this)) + }
+ ); + } +}); + +var LogsButton = React.createClass({ + render: function() { + return ( + + ); + } +}); + +var DebugButton = React.createClass({ + getInitialState: function() { + var on = (WebrtcGlobalInformation.debugLevel > 0); + return {on: on}; + }, + + onClick: function() { + if (this.state.on) + WebrtcGlobalInformation.debugLevel = 0; + else + WebrtcGlobalInformation.debugLevel = 65535; + + this.setState({on: !this.state.on}); + }, + + render: function() { + return ( + + ); + } +}); + +var AECButton = React.createClass({ + getInitialState: function() { + return {on: WebrtcGlobalInformation.aecDebug}; + }, + + onClick: function() { + WebrtcGlobalInformation.aecDebug = !this.state.on; + this.setState({on: WebrtcGlobalInformation.aecDebug}); + }, + + render: function() { + return ( + + ); + } +}); + +var Logs = React.createClass({ + render: function() { + return ( +
+

Logging:

+
{ + this.props.logs.map(function(line, i) { + return
{line}
; + }) + }
+
+ ); + } +}); + +function iceCandidateMapping(iceCandidates) { + var candidates = {}; + iceCandidates = iceCandidates || []; + + iceCandidates.forEach(function(candidate) { + candidates[candidate.id] = candidate; + }); + + return candidates; +} + +function round00(num) { + return Math.round(num * 100) / 100; +} + +function labelize(label) { + return `${label.charAt(0).toUpperCase()}${label.slice(1)}`; +} + +function candidateToString(c) { + var type = c.candidateType; + + if (c.type == "localcandidate" && c.candidateType == "relayed") { + type = `${c.candidateType}-${c.mozLocalTransport}`; + } + + return `${c.ipAddress}:${c.portNumber}/${c.transport}(${type})` +} + +function onLoad() { + WebrtcGlobalInformation.getAllStats(function(globalReport) { + var reports = globalReport.reports; + React.renderComponent(, + document.querySelector("#body")); + }); +} diff --git a/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml b/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml new file mode 100644 index 000000000000..08268b055d23 --- /dev/null +++ b/toolkit/content/aboutwebrtc/aboutWebrtc.xhtml @@ -0,0 +1,22 @@ + + + + + %htmlDTD; +]> + + + + Webrtc Internals + + + + + + + \n"; - - -# -# If this is SurfingSafari, then catch a wave and you're sitting on top of the world!! -# (and also blat this out to tegu, cause we got no 'dump' statement. -# -if ($request->cgi->var("HTTP_USER_AGENT") =~ /Safari/) { - my %machineMap = - ( - "10.169.105.26" => "boxset", - "10.169.105.21" => "pawn" - ); - my $ip = $request->cgi->var('REMOTE_ADDR'); - my $machine = $machineMap{$ip}; - my $res = eval q{ - use LWP::UserAgent; - use HTTP::Request::Common qw(POST); - my $ua = LWP::UserAgent->new; - $ua->timeout(10); # seconds - my $req = POST('http://tegu.mozilla.org/graph/collect.cgi', - [testname => 'pageload', - tbox => "$machine" . "-aux", - value => $rs->{avgmedian}, - data => $data]); - my $res = $ua->request($req); - return $res; - }; - if ($@) { - warn "Failed to submit startup results: $@"; - } else { - warn "Startup results submitted to server: \n", - $res->status_line, "\n", $res->content, "\n"; - } -} - - -if ($request->param('purge')) { - # now move any old stuff into archive and clean stale entries - # just going with the simple approach of "whoever sees old entries - # first, cleans em up, whether they 'own' them or not". Hopefully, - # the default locking will be sufficient to prevent a race. - close(STDOUT); - sleep(1); - $dbroot = "db"; - $dbh = DBI->connect("DBI:CSV:f_dir=./$dbroot", - {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - $arc = DBI->connect("DBI:CSV:f_dir=./$dbroot/archive", - {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - purgeStaleEntries($id); - $dbh->disconnect(); - $arc->disconnect(); -} - -exit 0; diff --git a/tools/page-loader/echo.pl b/tools/page-loader/echo.pl deleted file mode 100755 index 2d74d115b2a0..000000000000 --- a/tools/page-loader/echo.pl +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/perl -# -# 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/. -use Time::HiRes qw(gettimeofday tv_interval); - -sub encodeHiResTime { - my $timeref = shift; - return unless ref($timeref); - my $time = $$timeref[0] . "-" . $$timeref[1]; - return $time; -} - -my $time = encodeHiResTime([gettimeofday()]); - -print "Content-type: text/html\n\n"; -print <<"ENDOFHTML"; - - - - - -

- This page starts the test. -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

-

- dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page - dummy page dummy page dummy page dummy page dummy page dummy page -

- - - -ENDOFHTML - -exit 0; diff --git a/tools/page-loader/graph.pl b/tools/page-loader/graph.pl deleted file mode 100755 index bb8b04d12992..000000000000 --- a/tools/page-loader/graph.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl -# -# 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/. -use CGI::Carp qw(fatalsToBrowser); -use CGI::Request; -use URLTimingDataSet; -use URLTimingGraph; - -my $request = new CGI::Request; - -my $id = $request->param('id'); #XXX need to check for valid parameter id -my $id2 = $request->param('id2') || undef; # possible comparison test - -# set up the data for the first graph -my $rs = URLTimingDataSet->new($id); -my @data = (); -push @data, [ map($_->[1], @{$rs->{sorted}}) ]; # URL -push @data, [ map($_->[4], @{$rs->{sorted}}) ]; # median -# '7' is the first slot for individual test run data -for (my $idx = 7; $idx < (7+$rs->{count}); $idx++) { - push @data, [ map($_->[$idx], @{$rs->{sorted}}) ]; -} - - -# set up the data for the second graph, if requested a second id -# need to sort according to the first chart's ordering -my $rs2; -if ($id2) { - $rs2 = URLTimingDataSet->new($id2); - my @order = map($_->[0], @{$rs->{sorted}}); # get the first chart's order - my @resort = (); - for my $i (@order) { - for (@{$rs2->{sorted}}) { - if ($i == $_->[0]) { - push @resort, $_; - last; - } - } - } - push @data, [ map($_->[4], @resort) ]; # median - for (my $idx = 7; $idx < (7+$rs2->{count}); $idx++) { - push @data, [ map($_->[$idx], @resort) ]; - } -} - -# and now convert 'NaN' to undef, if they exist in the data. -for (@data) { for (@$_) { $_ = undef if $_ eq "NaN"; } } - -# set up the chart parameters -my $args = {}; -$args->{cgimode} = 1; -$args->{title} = "id=$id"; - -# need to draw first visit as dotted with points -my $types = ['lines','lines']; for (1..$rs->{count}-1) { push @$types, undef; } -my $dclrs = []; for (0..$rs->{count}) { push @$dclrs, 'lred'; } -my $legend = [$id]; for (1..$rs->{count}) { push @$legend, undef; } -if ($id2) { - push @$types, 'lines'; for (1..$rs2->{count}) { push @$types, undef; } - for (0..$rs2->{count}) { push @$dclrs, 'lblue'; } - push @$legend, $id2; for (1..$rs2->{count}) { push @$legend, undef; } -} -$args->{types} = $types; -$args->{dclrs} = $dclrs; -$args->{legend} = $legend; - -#XXX set min to zero, and round max to 1000 -$args->{y_max_value} = maxDataOrCap(); -## nope $args->{y_min_value} = 1000; -$args->{width} = 800; -$args->{height} = 720; - -my $g = URLTimingGraph->new(\@data, $args); -$g->plot(); - -exit; - - -sub maxDataOrCap { - my $max; - warn $rs->{maximum}; - if ($rs2 && ($rs->{maximum} < $rs2->{maximum})) { - $max = $rs2->{maximum}; - } else { - $max = $rs->{maximum}; - } - warn $max; - #return $max > 10000 ? 10000 : 1000*int($max/1000)+1000; - # just return whatever, rounded to 1000 - return 1000*int($max/1000)+1000; -} diff --git a/tools/page-loader/loader.pl b/tools/page-loader/loader.pl deleted file mode 100755 index 3130237f2ad7..000000000000 --- a/tools/page-loader/loader.pl +++ /dev/null @@ -1,618 +0,0 @@ -#!/usr/bin/perl -# -# 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/. - -use strict; -use CGI::Request; -use CGI::Carp qw(fatalsToBrowser); -use Time::HiRes qw(gettimeofday tv_interval); -use POSIX qw(strftime); -use DBI; - -# list of test pages, JS to insert, httpbase, filebase, etc. -use PageData; - -use vars qw(%params $req $cgi $dbh $pagedata - $gStartNow $gStartNowStr - $gResponseNow $gLogging); - -$gStartNow = [gettimeofday]; # checkpoint the time -$gStartNowStr = strftime "%Y%m%d%H%M%S", localtime; -$gLogging = 1; - -$req = new CGI::Request; # get the HTTP/CGI request -$cgi = $req->cgi; - -$pagedata = PageData->new; - -setDefaultParams(); - -#XXXdebugcrap -#warn $params{index}, " ", $params{maxidx}; - -if (!defined($req->param('delay'))) { - # give the user a form to pick options (but note that going - # to "loader.pl?delay=1000" immediately starts the test run - outputForm(); -} -elsif (!$req->param('id')) { - initialize(); # do redirect to start the cycle -} -elsif ($params{index} > $params{maxidx}) { - redirectToReport(); # the test is over; spit out a summary - markTestAsComplete(); # close the meta table entry -} -elsif (!isRequestStale()) { - outputPage(); # otherwise, keep dishing out pages - updateDataBase(); # client has the response; now write out stats to db -} - -# cleanup -$req = undef; -$dbh->disconnect() if $dbh; # not strictly required (ignored in some cases anyways) - -#logMessage(sprintf("Page load server responded in %3d msec, total time %3d msec, pid: %d", -# 1000*tv_interval($gStartNow, $gResponseNow), 1000*tv_interval($gStartNow), $$)) -# if $gResponseNow; # log only when a test page has been dished out - -exit 0; - -####################################################################### - -sub logMessage { - print STDERR strftime("[%a %b %d %H:%M:%S %Y] ", localtime), @_, "\n" - if $gLogging; -} - - -sub isRequestStale { - my $limit = 30*60; # 30 minutes, although if we never stalled on mac I'd make it 3 minutes - my $ts = decodeHiResTime($params{s_ts}); - my $delta = tv_interval($ts, $gStartNow); - return undef if $delta < $limit; - # otherwise, punt this request - print "Content-type: text/html\n\n"; - print <<"ENDOFHTML"; -Page Loading Times Test -

The timestamp on the request is too old to continue:
-s_ts=$params{s_ts} was $delta seconds ago. Limit is $limit seconds.

- -ENDOFHTML - return 1; # it's stale -} - - -sub initialize { - updateMetaTable(); - createDataSetTable(); - - # start the test by bouncing off of an echo page - my $script = $cgi->var("SCRIPT_NAME"); - my $server = $cgi->var("SERVER_NAME"); - my $proto = $ENV{SERVER_PORT} == 443 ? 'https://' : 'http://'; - my $me = $proto . $server . $script; - $script =~ /^(.*\/).*$/; - my $loc = "Location: ". $proto . $server . $1 . "echo.pl?"; - for (qw(id index maxcyc delay replace nocache timeout)) { - $loc .= "$_=$params{$_}\&"; - } - $loc .= "url=" . $me; - print $loc, "\n\n"; -} - - -sub redirectToReport { - # n.b., can also add '&sort=1' to get a time sorted list - my $proto = $ENV{SERVER_PORT} == 443 ? 'https://' : 'http://'; - my $loc = "Location: " . $proto . $cgi->var("SERVER_NAME"); - $cgi->var("SCRIPT_NAME") =~ /^(.*\/).*$/; - $loc .= $1 . "report.pl?id=" . $params{id}; - # To use for a tinderbox, comment out the line above and uncomment this: - # $loc .= $1 . "dump.pl?id=" . $params{id} . "&purge=1"; - print $loc, "\n\n"; -} - - -sub generateTestId { - # use the epoch time, in hex, plus a two-character random. - return sprintf "%8X%02X", time(), int(256*rand()); -} - - -sub setDefaultParams { - $params{id} = $req->param('id') || generateTestId(); # "unique" id for this run - $params{index} = $req->param('index') || 0; # request index for the test - $params{maxcyc} = defined($req->param('maxcyc')) ? - $req->param('maxcyc') : 3; # max visits (zero-based count) - $params{delay} = $req->param('delay') || 1000; # setTimeout on the next request (msec) - $params{replace} = $req->param('replace') || 0; # use Location.replace (1) or Location.href (0) - $params{nocache} = $req->param('nocache') || 0; # serve content via uncacheable path - $params{c_part} = $req->param('c_part') || 0; # client time elapsed; page head to onload (msec) - $params{c_intvl} = $req->param('c_intvl') || 0; # client time elapsed; onload to onload event (msec) - $params{c_ts} = $req->param('c_ts') || 0; # client timestamp (.getTime()) (msec) - $params{content} = $req->param('content') || "UNKNOWN"; # name of content page for this data - $params{s_ts} = $req->param('s_ts') || undef; # server timestamp; no default - $params{timeout} = $req->param('timeout') || 30000; # msec; timer will cancel stalled page loading - $params{maxidx} = ($params{maxcyc}+1) * $pagedata->length; # total pages loads to be done - $params{curidx} = $params{index} % $pagedata->length; # current request index into page list - $params{curcyc} = int(($params{index}-1) / $pagedata->length); # current "cycle" (visit) -} - - -sub outputPage { - my $relpath = $pagedata->url($params{curidx}); - my $file = $pagedata->filebase . $relpath; - open (HTML, "<$file") || - die "Can't open file: $file, $!"; - - my $hook = "\n"; - - my $basepath = $pagedata->httpbase; - $basepath =~ s/^http:/https:/i - if $ENV{SERVER_PORT} == 443; - #warn "basepath: $basepath"; - $basepath =~ s#^(.*?)(/base/)$#$1/nocache$2# if ($params{nocache}); - $hook .= ""; - - my $magic = $pagedata->magicString; - my $content = ""; - while () { - s/$magic/$hook/; - $content .= $_; - } - - my $contentTypeHeader; - my $mimetype = $pagedata->mimetype($params{curidx}); - my $charset = $pagedata->charset($params{curidx}); - if ($charset) { - $contentTypeHeader = qq{Content-type: $mimetype; charset="$charset"\n\n}; - } else { - $contentTypeHeader = qq{Content-type: $mimetype\n\n}; - } - #warn $contentTypeHeader; #XXXjrgm testing... - - # N.B., these two cookie headers are obsolete, since I pass server info in - # JS now, to work around a bug in winEmbed with document.cookie. But - # since I _was_ sending two cookies as part of the test, I have to keep - # sending two cookies (at least for now, and it's not a bad thing to test) - #XXX other headers to test/use? - - $gResponseNow = [gettimeofday]; # for logging - { # turn on output autoflush, locally in this block - print "Set-Cookie: moztest_SomeRandomCookie1=somerandomstring\n"; - print "Set-Cookie: moztest_SomeRandomCookie2=somerandomstring\n"; - print $contentTypeHeader; - local $| = 1; - print $content; - } - - return; -} - - -sub encodeHiResTime { - my $timeref = shift; - return unless ref($timeref); - return $$timeref[0] . "-" . $$timeref[1]; -} - - -sub decodeHiResTime { - my $timestr = shift; - return [ split('-', $timestr) ]; -} - - -sub elapsedMilliSeconds { - my ($r_time, $timestr) = @_; - return "NaN" unless $timestr; - my $delta = tv_interval( [ split('-', $timestr) ], $r_time ); - my $delta = int(($delta*1000) - $params{delay}); # adjust for delay (in msec) - return $delta; -} - - -sub updateDataBase { - connectToDataBase(); # (may already be cached) - updateMetaTable(); - updateDataSetTable() unless $params{c_part} == -1; # the initial request -} - - -sub connectToDataBase { - # don't reconnect if already connected. (Other drivers provide this - # for free I think, but not this one). - if (!ref($dbh)) { - $dbh = DBI->connect("DBI:CSV:f_dir=./db", {RaiseError => 1, AutoCommit => 1}) - || die "Cannot connect: " . $DBI::errstr; - } -} - - -# -# Holds the individual page load data for this id. -# -# (Of course, this should really be a single table for all datasets, but -# that was becoming punitively slow with DBD::CSV. I could have moved to -# a "real" database, but I didn't want to make that a requirement for -# installing this on another server and using this test (e.g., install a -# few modules and you can run this; no sql installation/maintenance required). -# At some point though, I may switch to some sql db, but hopefully still allow -# this to be used with a simple flat file db. (Hmm, maybe I should try a *dbm -# as a compromise (disk based but indexed)). -# -sub createDataSetTable { - my $table = "t" . $params{id}; - return if -f "db/$table"; # don't create it if it exists - logMessage("createDataSetTable:\tdb/$table"); - connectToDataBase(); # cached - - my ($sth, $sql); - $sql = qq{ - CREATE TABLE $table - (DATETIME CHAR(14), - ID CHAR(10), - INDEX INTEGER, - CUR_IDX INTEGER, - CUR_CYC INTEGER, - C_PART INTEGER, - S_INTVL INTEGER, - C_INTVL INTEGER, - CONTENT CHAR(128) - ) - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); - return 1; -} - - -# -# holds the information about all test runs -# -sub createMetaTable { - my $table = shift; - return if -f "db/$table"; # don't create it if it exists - logMessage("createMetaTable:\tdb/$table"); - - my ($sth, $sql); - - $sql = qq{ - CREATE TABLE $table - (DATETIME CHAR(14), - LASTPING CHAR(14), - ID CHAR(8), - INDEX INTEGER, - CUR_IDX INTEGER, - CUR_CYC INTEGER, - CUR_CONTENT CHAR(128), - STATE INTEGER, - BLESSED INTEGER, - MAXCYC INTEGER, - MAXIDX INTEGER, - REPLACE INTEGER, - NOCACHE INTEGER, - DELAY INTEGER, - REMOTE_USER CHAR(16), - HTTP_USER_AGENT CHAR(128), - REMOTE_ADDR CHAR(15), - USER_EMAIL CHAR(32), - USER_COMMENT CHAR(256) - ) - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); - warn 'created meta table'; - return 1; -} - - -sub updateMetaTable { - - connectToDataBase(); # if not already connected - - my $table = "tMetaTable"; - createMetaTable($table); # just returns if already created - - my ($sth, $sql); - - $sql = qq{ - SELECT INDEX, MAXCYC, MAXIDX, REPLACE, NOCACHE, - DELAY, REMOTE_USER, HTTP_USER_AGENT, REMOTE_ADDR - FROM $table - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - - my @dataset = (); - while (my @data = $sth->fetchrow_array()) { - push @dataset, {index => shift @data, - maxcyc => shift @data, - maxidx => shift @data, - replace => shift @data, - nocache => shift @data, - delay => shift @data, - remote_user => shift @data, - http_user_agent => shift @data, - remote_addr => shift @data - }; - } - $sth->finish(); - warn "More than one ID: $params{id} ??" if scalar(@dataset) > 1; - - if (scalar(@dataset) == 0) { - # this is a new dataset and id - initMetaTableRecord($table); - return; - } - - #XXX need to check that values are sane, and not update if they don't - # match certain params. This should not happen in a normal test run. - # However, if a test url was bookmarked or in history, I might get bogus - # data collected after the fact. But I have a stale date set on the URL, - # so that is good enough for now. - # my $ref = shift @dataset; # check some $ref->{foo} - - $sql = qq{ - UPDATE $table - SET LASTPING = ?, - INDEX = ?, - CUR_IDX = ?, - CUR_CYC = ?, - CUR_CONTENT = ?, - STATE = ? - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $params{index}-1, # (index-1) is complete; (index) in progress - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{content}, - 'OPEN' - ); - $sth->finish(); - -} - - -sub markTestAsComplete { - connectToDataBase(); # if not already connected - my $table = "tMetaTable"; - createMetaTable($table); # just returns if already created - my ($sth, $sql); - #XXX should probably check if this ID exists first - $sql = qq{ - UPDATE $table - SET STATE = "COMPLETE" - WHERE ID = '$params{id}' - }; - $sth = $dbh->prepare($sql); - $sth->execute(); - $sth->finish(); -} - - -sub initMetaTableRecord { - # we know this record doesn't exist, so put in the initial values - my $table = shift; - my ($sth, $sql); - $sql = qq{ - INSERT INTO $table - (DATETIME, - LASTPING, - ID, - INDEX, - CUR_IDX, - CUR_CYC, - CUR_CONTENT, - STATE, - BLESSED, - MAXCYC, - MAXIDX, - REPLACE, - NOCACHE, - DELAY, - REMOTE_USER, - HTTP_USER_AGENT, - REMOTE_ADDR, - USER_EMAIL, - USER_COMMENT - ) - VALUES (?,?,?,?, - ?,?,?,?, - ?,?,?,?, - ?,?,?,?, - ?,?,?) - }; - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $gStartNowStr, - $params{id}, - $params{index}-1, - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{content}, - "INIT", - 0, - $params{maxcyc}, - $params{maxidx}, - $params{replace}, - $params{nocache}, - $params{delay}, - $cgi->var("REMOTE_USER"), - $cgi->var("HTTP_USER_AGENT"), - $cgi->var("REMOTE_ADDR"), - "", - "" - ); - $sth->finish(); -} - - -sub updateDataSetTable { - my $table = shift; - my $table = "t" . $params{id}; - - my ($sth, $sql); - $sql = qq{ - INSERT INTO $table - (DATETIME, - ID, - INDEX, - CUR_IDX, - CUR_CYC, - C_PART, - S_INTVL, - C_INTVL, - CONTENT - ) - VALUES (?,?,?,?, - ?,?,?,?,?) - }; - - my $s_intvl = elapsedMilliSeconds( $gStartNow, $params{s_ts} ); - - $sth = $dbh->prepare($sql); - $sth->execute($gStartNowStr, - $params{id}, - $params{index}-1, - ($params{curidx}-1) % $pagedata->length, - $params{curcyc}, - $params{c_part}, - $s_intvl, - $params{c_intvl}, - $req->param('content'), - ); - $sth->finish(); - -} - - -sub outputForm { - my @prog = split('/', $0); my $prog = $prog[$#prog]; - print "Content-type: text/html\n\n"; - my $bgcolor = $ENV{SERVER_PORT} == 443 ? '#eebb66' : '#ffffff'; - print <<"ENDOFHTML"; - - - Page Loading Times Test - - -

Page Loading Times Test

- -

Questions: John Morrison - -ENDOFHTML - print "  -  "; - my $script = $cgi->var("SCRIPT_NAME"); - my $server = $cgi->var("SERVER_NAME"); - # pick the "other" protocol (i.e., test is inverted) - my $proto = $ENV{SERVER_PORT} == 443 ? 'http://' : 'https://'; - my $other = $proto . $server . $script; - if ($ENV{SERVER_PORT} == 443) { - print "[ With no SSL | With SSL ]
"; - } else { - print "[ With no SSL | With SSL ]
"; - } - print <<"ENDOFHTML"; - -

- - - - - - - - - - - - - - - - - -
- Page-load to Page-load Delay (msec):
- (Use 1000. Be nice.) -
- -
- Number of test cycles to run:
-
-
- -
- How long to wait before cancelling (msec):
- (Don't change this unless on a very slow link, or very slow machine.) -
- -
- - - -
- -
-

- You can visit the content that will be loaded, minus the embedded - javascript, by clicking on any of the links below. -

- - -ENDOFHTML - - my $i; - print "\n"; - my $base = $pagedata->httpbase; - $base =~ s/^http:/https:/i - if $ENV{SERVER_PORT} == 443; - for ($i=0; $i<$pagedata->length; $i++) { - print "\n" if (($i+1)%4 == 0); - } - print "" if (($i+1)%4 != 0); - print "
"; - print $pagedata->name($i); - print "\n"; - print "
\n"; - return; -} - diff --git a/tools/page-loader/report.pl b/tools/page-loader/report.pl deleted file mode 100755 index 6a4aeac15e72..000000000000 --- a/tools/page-loader/report.pl +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl -# -# 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/. -use CGI::Carp qw(fatalsToBrowser); -use CGI::Request; -use URLTimingDataSet; -use strict; - -my $request = new CGI::Request; -my $id = $request->param('id'); #XXX need to check for valid parameter id - -print "Content-type: text/html\n\n"; - -print "

See Notes at the bottom of this page for some details.

\n"; -print "
\n";
-my $rs = URLTimingDataSet->new($id);
-
-print  "Test id: $id
Avg. Median : ", $rs->{avgmedian}, - " msec\t\tMinimum : ", $rs->{minimum}, " msec\n"; -print "Average : ", $rs->{average}, - " msec\t\tMaximum : ", $rs->{maximum}, " msec
\n\n\n"; - -#XXX print more info (test id, ua, start time, user, IP, etc.) - -# draw the chart sorted -# XXX enable this line to draw a chart, sorted by time. However, in order -# to draw the chart, you will need to have installed the 'gd' drawing library, -# and the GD and GD::Graph Perl modules. -###print "\n


\n"; - - -print "
\nIDX PATH                           AVG    MED    MAX    MIN  TIMES ...\n";
-
-if ($request->param('sort')) {
-    print $rs->as_string_sorted();
-} else {
-    print $rs->as_string();
-}
-print "
\n"; -printEndNotes(); - -exit; - - -sub printEndNotes { - print <<"EndOfNotes"; - -
-

-

    -
  1. Times are in milliseconds. - -
  2. AVG, MED, MIN and MAX are the average, median, maximum and -minimum of the (non-NaN) test results for a given page. - -
  3. If a page fails to fire the onload event within 30 seconds, -the test for that page is "aborted": a different JS function kicks in, -cleans up, and reports the time as "NaN". (The rest of the pages in -the series should still be loaded normally after this). - -
  4. The value for AVG reported for 'All Pages' is the average of -the averages for all the pages loaded. - -
  5. The value for MAX and MIN reported for 'All Pages' are the -overall maximum and minimum for all pages loaded (keeping in mind that -a load that never finishes is recorded as "NaN".) - -
  6. The value for MED reported for 'All Pages' is the _average_ of -the medians for all the pages loaded (i.e., it is not the median of -the medians). - -
- -

-EndOfNotes -} diff --git a/tools/page-loader/urllist.txt b/tools/page-loader/urllist.txt deleted file mode 100644 index d0e429259332..000000000000 --- a/tools/page-loader/urllist.txt +++ /dev/null @@ -1,65 +0,0 @@ -# -# 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/. - -# Config file for page loading test -# -# HTTPBASE: is the URL to the root of the content pages -# FILEBASE: is the file path to the same location (I need both) -# -# Remaining lines are the names of top level directories under FILEBASE -# which contain the content files, followed by an optional filename in -# that directory (index.html is assumed if no filename given), and then -# followed by an optional 'charset' value to ship in the 'Content-type' -# header. [Note: if you want to set the charset, then you must also -# explicitly set the filename field]. -# -# Warning: you don't want to casually changing the set of urls that you are -# testing against, if you want to be able to make any reasonable comparison over -# time. And don't change this file while a test is in progress, as it will -# competely scramble the results for that test. - -HTTPBASE: http://somehost.somedomain.sometld/content/base/ -FILEBASE: /var/www/html/content/base/ - -home.netscape.com index.html # optionally specify a filename -my.netscape.com index.html text/html iso-8859-1 # optionally specify a filename, mime type and charset -www.aol.com index.html text/html # optionally specify a filename and mime type -www.mapquest.com -www.moviefone.com -www.digitalcity.com -www.iplanet.com -web.icq.com -www.compuserve.com -www.msnbc.com -www.yahoo.com -bugzilla.mozilla.org -www.msn.com -slashdot.org -www.nytimes.com -www.nytimes.com_Table -www.w3.org_DOML2Core -lxr.mozilla.org -espn.go.com -www.voodooextreme.com -www.wired.com -hotwired.lycos.com -www.ebay.com -www.apple.com -www.amazon.com -www.altavista.com -www.zdnet.com_Gamespot.com -www.spinner.com -www.microsoft.com -www.time.com -www.travelocity.com -www.expedia.com -www.quicken.com -www.zdnet.com -www.excite.com -www.google.com -www.tomshardware.com -www.cnn.com -news.cnet.com -www.sun.com From 7b2c55eff6b639762fa5d4b0efba316282166bb8 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Fri, 26 Sep 2014 16:41:15 -0700 Subject: [PATCH 055/100] Bug 1039846 - Response implementation. r=baku --HG-- extra : rebase_source : 0da394758a5ccf6c1fe87d1a51ed0c4c27d9350e --- dom/base/URLSearchParams.h | 2 +- dom/bindings/Errors.msg | 1 + dom/fetch/Fetch.cpp | 367 +++++++++++++++--- dom/fetch/Fetch.h | 77 ++++ dom/fetch/InternalResponse.cpp | 24 ++ dom/fetch/InternalResponse.h | 102 +++++ dom/fetch/Request.cpp | 206 +--------- dom/fetch/Request.h | 45 +-- dom/fetch/Response.cpp | 165 ++++---- dom/fetch/Response.h | 43 +- dom/fetch/moz.build | 2 + dom/workers/test/fetch/mochitest.ini | 2 + dom/workers/test/fetch/test_response.html | 48 +++ .../test/fetch/worker_test_response.js | 124 ++++++ 14 files changed, 805 insertions(+), 403 deletions(-) create mode 100644 dom/fetch/InternalResponse.cpp create mode 100644 dom/fetch/InternalResponse.h create mode 100644 dom/workers/test/fetch/test_response.html create mode 100644 dom/workers/test/fetch/worker_test_response.js diff --git a/dom/base/URLSearchParams.h b/dom/base/URLSearchParams.h index 1fab838b4790..ec1afad5505d 100644 --- a/dom/base/URLSearchParams.h +++ b/dom/base/URLSearchParams.h @@ -75,7 +75,7 @@ public: void Delete(const nsAString& aName); - void Stringify(nsString& aRetval) + void Stringify(nsString& aRetval) const { Serialize(aRetval); } diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 333a435513d4..8b8048d5d404 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -62,3 +62,4 @@ MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-o MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, "Missing required {0}.") MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, "Invalid request method {0}.") MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, "Request body has already been consumed.") +MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, "Response statusText may not contain newline or carriage return.") diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index fbc87aa7515b..3ba6e1c59816 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -6,16 +6,98 @@ #include "Fetch.h" #include "nsIStringStream.h" +#include "nsIUnicodeDecoder.h" #include "nsIUnicodeEncoder.h" +#include "nsDOMString.h" +#include "nsNetUtil.h" +#include "nsStreamUtils.h" #include "nsStringStream.h" +#include "mozilla/ErrorResult.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/Headers.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/Request.h" +#include "mozilla/dom/Response.h" #include "mozilla/dom/URLSearchParams.h" namespace mozilla { namespace dom { +namespace { +nsresult +ExtractFromArrayBuffer(const ArrayBuffer& aBuffer, + nsIInputStream** aStream) +{ + aBuffer.ComputeLengthAndData(); + //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. + return NS_NewByteInputStream(aStream, + reinterpret_cast(aBuffer.Data()), + aBuffer.Length(), NS_ASSIGNMENT_COPY); +} + +nsresult +ExtractFromArrayBufferView(const ArrayBufferView& aBuffer, + nsIInputStream** aStream) +{ + aBuffer.ComputeLengthAndData(); + //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. + return NS_NewByteInputStream(aStream, + reinterpret_cast(aBuffer.Data()), + aBuffer.Length(), NS_ASSIGNMENT_COPY); +} + +nsresult +ExtractFromScalarValueString(const nsString& aStr, + nsIInputStream** aStream, + nsCString& aContentType) +{ + nsCOMPtr encoder = EncodingUtils::EncoderForEncoding("UTF-8"); + if (!encoder) { + return NS_ERROR_OUT_OF_MEMORY; + } + + int32_t destBufferLen; + nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCString encoded; + if (!encoded.SetCapacity(destBufferLen, fallible_t())) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char* destBuffer = encoded.BeginWriting(); + int32_t srcLen = (int32_t) aStr.Length(); + int32_t outLen = destBufferLen; + rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(outLen <= destBufferLen); + encoded.SetLength(outLen); + + aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8"); + + return NS_NewCStringInputStream(aStream, encoded); +} + +nsresult +ExtractFromURLSearchParams(const URLSearchParams& aParams, + nsIInputStream** aStream, + nsCString& aContentType) +{ + nsAutoString serialized; + aParams.Stringify(serialized); + aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8"); + return NS_NewStringInputStream(aStream, serialized); +} +} + nsresult ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit, nsIInputStream** aStream, @@ -23,78 +105,239 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueS { MOZ_ASSERT(aStream); - nsresult rv; - nsCOMPtr byteStream; if (aBodyInit.IsArrayBuffer()) { const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer(); - buf.ComputeLengthAndData(); - //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. - rv = NS_NewByteInputStream(getter_AddRefs(byteStream), - reinterpret_cast(buf.Data()), - buf.Length(), NS_ASSIGNMENT_COPY); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + return ExtractFromArrayBuffer(buf, aStream); } else if (aBodyInit.IsArrayBufferView()) { const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView(); - buf.ComputeLengthAndData(); - //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok. - rv = NS_NewByteInputStream(getter_AddRefs(byteStream), - reinterpret_cast(buf.Data()), - buf.Length(), NS_ASSIGNMENT_COPY); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + return ExtractFromArrayBufferView(buf, aStream); } else if (aBodyInit.IsScalarValueString()) { - nsString str = aBodyInit.GetAsScalarValueString(); - - nsCOMPtr encoder = EncodingUtils::EncoderForEncoding("UTF-8"); - if (!encoder) { - return NS_ERROR_OUT_OF_MEMORY; - } - - int32_t destBufferLen; - rv = encoder->GetMaxLength(str.get(), str.Length(), &destBufferLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsCString encoded; - if (!encoded.SetCapacity(destBufferLen, fallible_t())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - char* destBuffer = encoded.BeginWriting(); - int32_t srcLen = (int32_t) str.Length(); - int32_t outLen = destBufferLen; - rv = encoder->Convert(str.get(), &srcLen, destBuffer, &outLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(outLen <= destBufferLen); - encoded.SetLength(outLen); - rv = NS_NewCStringInputStream(getter_AddRefs(byteStream), encoded); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8"); + nsAutoString str; + str.Assign(aBodyInit.GetAsScalarValueString()); + return ExtractFromScalarValueString(str, aStream, aContentType); } else if (aBodyInit.IsURLSearchParams()) { URLSearchParams& params = aBodyInit.GetAsURLSearchParams(); - nsString serialized; - params.Stringify(serialized); - rv = NS_NewStringInputStream(getter_AddRefs(byteStream), serialized); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8"); + return ExtractFromURLSearchParams(params, aStream, aContentType); } - MOZ_ASSERT(byteStream); - byteStream.forget(aStream); - return NS_OK; + NS_NOTREACHED("Should never reach here"); + return NS_ERROR_FAILURE; } +nsresult +ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit, + nsIInputStream** aStream, + nsCString& aContentType) +{ + MOZ_ASSERT(aStream); + + if (aBodyInit.IsArrayBuffer()) { + const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer(); + return ExtractFromArrayBuffer(buf, aStream); + } else if (aBodyInit.IsArrayBufferView()) { + const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView(); + return ExtractFromArrayBufferView(buf, aStream); + } else if (aBodyInit.IsScalarValueString()) { + nsAutoString str; + str.Assign(aBodyInit.GetAsScalarValueString()); + return ExtractFromScalarValueString(str, aStream, aContentType); + } else if (aBodyInit.IsURLSearchParams()) { + URLSearchParams& params = aBodyInit.GetAsURLSearchParams(); + return ExtractFromURLSearchParams(params, aStream, aContentType); + } + + NS_NOTREACHED("Should never reach here"); + return NS_ERROR_FAILURE; +} + +namespace { +nsresult +DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded) +{ + nsCOMPtr decoder = + EncodingUtils::DecoderForEncoding("UTF-8"); + if (!decoder) { + return NS_ERROR_FAILURE; + } + + int32_t destBufferLen; + nsresult rv = + decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char16_t* destBuffer = aDecoded.BeginWriting(); + int32_t srcLen = (int32_t) aBuffer.Length(); + int32_t outLen = destBufferLen; + rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(outLen <= destBufferLen); + aDecoded.SetLength(outLen); + return NS_OK; +} +} + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv) +{ + nsRefPtr promise = Promise::Create(DerivedClass()->GetParentObject(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + if (BodyUsed()) { + aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR); + return nullptr; + } + + SetBodyUsed(); + + // While the spec says to do this asynchronously, all the body constructors + // right now only accept bodies whose streams are backed by an in-memory + // buffer that can be read without blocking. So I think this is fine. + nsCOMPtr stream; + DerivedClass()->GetBody(getter_AddRefs(stream)); + + if (!stream) { + aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0, + NS_ASSIGNMENT_COPY); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + AutoJSAPI api; + api.Init(DerivedClass()->GetParentObject()); + JSContext* cx = api.cx(); + + // We can make this assertion because for now we only support memory backed + // structures for the body argument for a Request. + MOZ_ASSERT(NS_InputStreamIsBuffered(stream)); + nsCString buffer; + uint64_t len; + aRv = stream->Available(&len); + if (aRv.Failed()) { + return nullptr; + } + + aRv = NS_ReadInputStreamToString(stream, buffer, len); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + buffer.SetLength(len); + + switch (aType) { + case CONSUME_ARRAYBUFFER: { + JS::Rooted arrayBuffer(cx); + arrayBuffer = + ArrayBuffer::Create(cx, buffer.Length(), + reinterpret_cast(buffer.get())); + JS::Rooted val(cx); + val.setObjectOrNull(arrayBuffer); + promise->MaybeResolve(cx, val); + return promise.forget(); + } + case CONSUME_BLOB: { + // XXXnsm it is actually possible to avoid these duplicate allocations + // for the Blob case by having the Blob adopt the stream's memory + // directly, but I've not added a special case for now. + // + // FIXME(nsm): Use nsContentUtils::CreateBlobBuffer once blobs have been fixed on + // workers. + uint32_t blobLen = buffer.Length(); + void* blobData = moz_malloc(blobLen); + nsRefPtr blob; + if (blobData) { + memcpy(blobData, buffer.BeginReading(), blobLen); + blob = File::CreateMemoryFile(DerivedClass()->GetParentObject(), blobData, blobLen, + NS_ConvertUTF8toUTF16(mMimeType)); + } else { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } + + promise->MaybeResolve(blob); + return promise.forget(); + } + case CONSUME_JSON: { + nsAutoString decoded; + aRv = DecodeUTF8(buffer, decoded); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + JS::Rooted json(cx); + if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) { + JS::Rooted exn(cx); + if (JS_GetPendingException(cx, &exn)) { + JS_ClearPendingException(cx); + promise->MaybeReject(cx, exn); + } + } + promise->MaybeResolve(cx, json); + return promise.forget(); + } + case CONSUME_TEXT: { + nsAutoString decoded; + aRv = DecodeUTF8(buffer, decoded); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + promise->MaybeResolve(decoded); + return promise.forget(); + } + } + + NS_NOTREACHED("Unexpected consume body type"); + // Silence warnings. + return nullptr; +} + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv); + +template +already_AddRefed +FetchBody::ConsumeBody(ConsumeType aType, ErrorResult& aRv); + +template +void +FetchBody::SetMimeType(ErrorResult& aRv) +{ + // Extract mime type. + nsTArray contentTypeValues; + MOZ_ASSERT(DerivedClass()->Headers_()); + DerivedClass()->Headers_()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + // HTTP ABNF states Content-Type may have only one value. + // This is from the "parse a header value" of the fetch spec. + if (contentTypeValues.Length() == 1) { + mMimeType = contentTypeValues[0]; + ToLowerCase(mMimeType); + } +} + +template +void +FetchBody::SetMimeType(ErrorResult& aRv); + +template +void +FetchBody::SetMimeType(ErrorResult& aRv); } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Fetch.h b/dom/fetch/Fetch.h index 86ba71c2b3b6..9911edf983dd 100644 --- a/dom/fetch/Fetch.h +++ b/dom/fetch/Fetch.h @@ -13,6 +13,8 @@ class nsIInputStream; namespace mozilla { namespace dom { +class Promise; + /* * Creates an nsIInputStream based on the fetch specifications 'extract a byte * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract. @@ -23,6 +25,81 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueS nsIInputStream** aStream, nsCString& aContentType); +/* + * Non-owning version. + */ +nsresult +ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit, + nsIInputStream** aStream, + nsCString& aContentType); + +template +class FetchBody { +public: + bool + BodyUsed() { return mBodyUsed; } + + already_AddRefed + ArrayBuffer(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_ARRAYBUFFER, aRv); + } + + already_AddRefed + Blob(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_BLOB, aRv); + } + + already_AddRefed + Json(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_JSON, aRv); + } + + already_AddRefed + Text(ErrorResult& aRv) + { + return ConsumeBody(CONSUME_TEXT, aRv); + } + +protected: + FetchBody() + : mBodyUsed(false) + { + } + + void + SetBodyUsed() + { + mBodyUsed = true; + } + + void + SetMimeType(ErrorResult& aRv); + +private: + enum ConsumeType + { + CONSUME_ARRAYBUFFER, + CONSUME_BLOB, + // FormData not supported right now, + CONSUME_JSON, + CONSUME_TEXT, + }; + + Derived* + DerivedClass() const + { + return static_cast(const_cast(this)); + } + + already_AddRefed + ConsumeBody(ConsumeType aType, ErrorResult& aRv); + + bool mBodyUsed; + nsCString mMimeType; +}; } // namespace dom } // namespace mozilla diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp new file mode 100644 index 000000000000..ef8d47e40a50 --- /dev/null +++ b/dom/fetch/InternalResponse.cpp @@ -0,0 +1,24 @@ +/* -*- 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/. */ + +#include "InternalResponse.h" + +#include "nsIDOMFile.h" + +#include "mozilla/dom/Headers.h" + +namespace mozilla { +namespace dom { + +InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) + : mType(ResponseType::Default) + , mStatus(aStatus) + , mStatusText(aStatusText) + , mHeaders(new Headers(nullptr, HeadersGuardEnum::Response)) +{ +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h new file mode 100644 index 000000000000..f965202f26ac --- /dev/null +++ b/dom/fetch/InternalResponse.h @@ -0,0 +1,102 @@ +/* -*- 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 mozilla_dom_InternalResponse_h +#define mozilla_dom_InternalResponse_h + +#include "nsISupportsImpl.h" + +#include "mozilla/dom/ResponseBinding.h" + +namespace mozilla { +namespace dom { + +class InternalResponse MOZ_FINAL +{ + friend class FetchDriver; + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse) + + InternalResponse(uint16_t aStatus, const nsACString& aStatusText); + + explicit InternalResponse(const InternalResponse& aOther) MOZ_DELETE; + + static already_AddRefed + NetworkError() + { + nsRefPtr response = new InternalResponse(0, EmptyCString()); + response->mType = ResponseType::Error; + return response.forget(); + } + + ResponseType + Type() const + { + return mType; + } + + bool + IsError() const + { + return Type() == ResponseType::Error; + } + + // FIXME(nsm): Return with exclude fragment. + nsCString& + GetUrl() + { + return mURL; + } + + uint16_t + GetStatus() const + { + return mStatus; + } + + const nsCString& + GetStatusText() const + { + return mStatusText; + } + + Headers* + Headers_() + { + return mHeaders; + } + + void + GetBody(nsIInputStream** aStream) + { + nsCOMPtr stream = mBody; + stream.forget(aStream); + } + + void + SetBody(nsIInputStream* aBody) + { + mBody = aBody; + } + +private: + ~InternalResponse() + { } + + ResponseType mType; + nsCString mTerminationReason; + nsCString mURL; + const uint16_t mStatus; + const nsCString mStatusText; + nsRefPtr mHeaders; + nsCOMPtr mBody; + nsCString mContentType; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_InternalResponse_h diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index 092c271bc557..582e1fd73726 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -5,25 +5,16 @@ #include "Request.h" -#include "nsIUnicodeDecoder.h" #include "nsIURI.h" - -#include "nsDOMString.h" -#include "nsNetUtil.h" #include "nsPIDOMWindow.h" -#include "nsStreamUtils.h" -#include "nsStringStream.h" #include "mozilla/ErrorResult.h" -#include "mozilla/dom/EncodingUtils.h" -#include "mozilla/dom/File.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Fetch.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/URL.h" #include "mozilla/dom/workers/bindings/URL.h" -// dom/workers #include "WorkerPrivate.h" namespace mozilla { @@ -39,9 +30,9 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request) NS_INTERFACE_MAP_END Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest) - : mOwner(aOwner) + : FetchBody() + , mOwner(aOwner) , mRequest(aRequest) - , mBodyUsed(false) { } @@ -224,21 +215,7 @@ Request::Constructor(const GlobalObject& aGlobal, } } - // Extract mime type. - nsTArray contentTypeValues; - domRequestHeaders->GetAll(NS_LITERAL_CSTRING("Content-Type"), - contentTypeValues, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // HTTP ABNF states Content-Type may have only one value. - // This is from the "parse a header value" of the fetch spec. - if (contentTypeValues.Length() == 1) { - domRequest->mMimeType = contentTypeValues[0]; - ToLowerCase(domRequest->mMimeType); - } - + domRequest->SetMimeType(aRv); return domRequest.forget(); } @@ -251,182 +228,5 @@ Request::Clone() const new InternalRequest(*mRequest)); return request.forget(); } - -namespace { -nsresult -DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded) -{ - nsCOMPtr decoder = - EncodingUtils::DecoderForEncoding("UTF-8"); - if (!decoder) { - return NS_ERROR_FAILURE; - } - - int32_t destBufferLen; - nsresult rv = - decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - char16_t* destBuffer = aDecoded.BeginWriting(); - int32_t srcLen = (int32_t) aBuffer.Length(); - int32_t outLen = destBufferLen; - rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(outLen <= destBufferLen); - aDecoded.SetLength(outLen); - return NS_OK; -} -} - -already_AddRefed -Request::ConsumeBody(ConsumeType aType, ErrorResult& aRv) -{ - nsRefPtr promise = Promise::Create(mOwner, aRv); - if (aRv.Failed()) { - return nullptr; - } - - if (BodyUsed()) { - aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR); - return nullptr; - } - - SetBodyUsed(); - - // While the spec says to do this asynchronously, all the body constructors - // right now only accept bodies whose streams are backed by an in-memory - // buffer that can be read without blocking. So I think this is fine. - nsCOMPtr stream; - mRequest->GetBody(getter_AddRefs(stream)); - - if (!stream) { - aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0, - NS_ASSIGNMENT_COPY); - if (aRv.Failed()) { - return nullptr; - } - } - - AutoJSAPI api; - api.Init(mOwner); - JSContext* cx = api.cx(); - - // We can make this assertion because for now we only support memory backed - // structures for the body argument for a Request. - MOZ_ASSERT(NS_InputStreamIsBuffered(stream)); - nsCString buffer; - uint64_t len; - aRv = stream->Available(&len); - if (aRv.Failed()) { - return nullptr; - } - - aRv = NS_ReadInputStreamToString(stream, buffer, len); - if (aRv.Failed()) { - return nullptr; - } - - buffer.SetLength(len); - - switch (aType) { - case CONSUME_ARRAYBUFFER: { - JS::Rooted arrayBuffer(cx); - arrayBuffer = - ArrayBuffer::Create(cx, buffer.Length(), - reinterpret_cast(buffer.get())); - JS::Rooted val(cx); - val.setObjectOrNull(arrayBuffer); - promise->MaybeResolve(cx, val); - return promise.forget(); - } - case CONSUME_BLOB: { - // XXXnsm it is actually possible to avoid these duplicate allocations - // for the Blob case by having the Blob adopt the stream's memory - // directly, but I've not added a special case for now. - // - // This is similar to nsContentUtils::CreateBlobBuffer, but also deals - // with worker wrapping. - uint32_t blobLen = buffer.Length(); - void* blobData = moz_malloc(blobLen); - nsRefPtr blob; - if (blobData) { - memcpy(blobData, buffer.BeginReading(), blobLen); - blob = File::CreateMemoryFile(GetParentObject(), blobData, blobLen, - NS_ConvertUTF8toUTF16(mMimeType)); - } else { - aRv = NS_ERROR_OUT_OF_MEMORY; - return nullptr; - } - - promise->MaybeResolve(blob); - return promise.forget(); - } - case CONSUME_JSON: { - nsString decoded; - aRv = DecodeUTF8(buffer, decoded); - if (aRv.Failed()) { - return nullptr; - } - - JS::Rooted json(cx); - if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) { - JS::Rooted exn(cx); - if (JS_GetPendingException(cx, &exn)) { - JS_ClearPendingException(cx); - promise->MaybeReject(cx, exn); - } - } - promise->MaybeResolve(cx, json); - return promise.forget(); - } - case CONSUME_TEXT: { - nsString decoded; - aRv = DecodeUTF8(buffer, decoded); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeResolve(decoded); - return promise.forget(); - } - } - - NS_NOTREACHED("Unexpected consume body type"); - // Silence warnings. - return nullptr; -} - -already_AddRefed -Request::ArrayBuffer(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_ARRAYBUFFER, aRv); -} - -already_AddRefed -Request::Blob(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_BLOB, aRv); -} - -already_AddRefed -Request::Json(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_JSON, aRv); -} - -already_AddRefed -Request::Text(ErrorResult& aRv) -{ - return ConsumeBody(CONSUME_TEXT, aRv); -} } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h index 7d78891b7fa8..938ed03cf25f 100644 --- a/dom/fetch/Request.h +++ b/dom/fetch/Request.h @@ -9,6 +9,7 @@ #include "nsISupportsImpl.h" #include "nsWrapperCache.h" +#include "mozilla/dom/Fetch.h" #include "mozilla/dom/InternalRequest.h" // Required here due to certain WebIDL enums/classes being declared in both // files. @@ -25,6 +26,7 @@ class Promise; class Request MOZ_FINAL : public nsISupports , public nsWrapperCache + , public FetchBody { NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request) @@ -76,11 +78,14 @@ public: Headers* Headers_() const { return mRequest->Headers_(); } + void + GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); } + static already_AddRefed Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput, const RequestInit& aInit, ErrorResult& rv); - nsISupports* GetParentObject() const + nsIGlobalObject* GetParentObject() const { return mOwner; } @@ -88,51 +93,13 @@ public: already_AddRefed Clone() const; - already_AddRefed - ArrayBuffer(ErrorResult& aRv); - - already_AddRefed - Blob(ErrorResult& aRv); - - already_AddRefed - Json(ErrorResult& aRv); - - already_AddRefed - Text(ErrorResult& aRv); - - bool - BodyUsed() const - { - return mBodyUsed; - } - already_AddRefed GetInternalRequest(); private: - enum ConsumeType - { - CONSUME_ARRAYBUFFER, - CONSUME_BLOB, - // FormData not supported right now, - CONSUME_JSON, - CONSUME_TEXT, - }; - ~Request(); - already_AddRefed - ConsumeBody(ConsumeType aType, ErrorResult& aRv); - - void - SetBodyUsed() - { - mBodyUsed = true; - } - nsCOMPtr mOwner; nsRefPtr mRequest; - bool mBodyUsed; - nsCString mMimeType; }; } // namespace dom diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp index 385553de7083..9c3c18d38e49 100644 --- a/dom/fetch/Response.cpp +++ b/dom/fetch/Response.cpp @@ -4,15 +4,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Response.h" -#include "nsDOMString.h" -#include "nsPIDOMWindow.h" -#include "nsIURI.h" + #include "nsISupportsImpl.h" +#include "nsIURI.h" +#include "nsPIDOMWindow.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Promise.h" +#include "nsDOMString.h" + +#include "InternalResponse.h" + namespace mozilla { namespace dom { @@ -25,9 +29,10 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -Response::Response(nsISupports* aOwner) - : mOwner(aOwner) - , mHeaders(new Headers(aOwner)) +Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse) + : FetchBody() + , mOwner(aGlobal) + , mInternalResponse(aInternalResponse) { } @@ -38,11 +43,9 @@ Response::~Response() /* static */ already_AddRefed Response::Error(const GlobalObject& aGlobal) { - ErrorResult result; - ResponseInit init; - init.mStatus = 0; - Optional body; - nsRefPtr r = Response::Constructor(aGlobal, body, init, result); + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + nsRefPtr error = InternalResponse::NetworkError(); + nsRefPtr r = new Response(global, error); return r.forget(); } @@ -58,81 +61,93 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, } /*static*/ already_AddRefed -Response::Constructor(const GlobalObject& global, +Response::Constructor(const GlobalObject& aGlobal, const Optional& aBody, - const ResponseInit& aInit, ErrorResult& rv) + const ResponseInit& aInit, ErrorResult& aRv) { - nsRefPtr response = new Response(global.GetAsSupports()); - return response.forget(); + if (aInit.mStatus < 200 || aInit.mStatus > 599) { + aRv.Throw(NS_ERROR_RANGE_ERR); + return nullptr; + } + + nsCString statusText; + if (aInit.mStatusText.WasPassed()) { + statusText = aInit.mStatusText.Value(); + nsACString::const_iterator start, end; + statusText.BeginReading(start); + statusText.EndReading(end); + if (FindCharInReadable('\r', start, end)) { + aRv.ThrowTypeError(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR); + return nullptr; + } + // Reset iterator since FindCharInReadable advances it. + statusText.BeginReading(start); + if (FindCharInReadable('\n', start, end)) { + aRv.ThrowTypeError(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR); + return nullptr; + } + } else { + // Since we don't support default values for ByteString. + statusText = NS_LITERAL_CSTRING("OK"); + } + + nsRefPtr internalResponse = + new InternalResponse(aInit.mStatus, statusText); + + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + nsRefPtr r = new Response(global, internalResponse); + + if (aInit.mHeaders.WasPassed()) { + internalResponse->Headers_()->Clear(); + + // Instead of using Fill, create an object to allow the constructor to + // unwrap the HeadersInit. + nsRefPtr headers = + Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + internalResponse->Headers_()->Fill(*headers, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + if (aBody.WasPassed()) { + nsCOMPtr bodyStream; + nsCString contentType; + aRv = ExtractByteStreamFromBody(aBody.Value(), getter_AddRefs(bodyStream), contentType); + internalResponse->SetBody(bodyStream); + + if (!contentType.IsVoid() && + !internalResponse->Headers_()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { + internalResponse->Headers_()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv); + } + + if (aRv.Failed()) { + return nullptr; + } + } + + r->SetMimeType(aRv); + return r.forget(); } +// FIXME(nsm): Bug 1073231: This is currently unspecced! already_AddRefed Response::Clone() { - nsRefPtr response = new Response(mOwner); + nsCOMPtr global = do_QueryInterface(mOwner); + nsRefPtr response = new Response(global, mInternalResponse); return response.forget(); } -already_AddRefed -Response::ArrayBuffer(ErrorResult& aRv) +void +Response::SetBody(nsIInputStream* aBody) { - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -already_AddRefed -Response::Blob(ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -already_AddRefed -Response::Json(ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -already_AddRefed -Response::Text(ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(GetParentObject()); - MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, aRv); - if (aRv.Failed()) { - return nullptr; - } - - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); - return promise.forget(); -} - -bool -Response::BodyUsed() -{ - return false; + // FIXME(nsm): Do we flip bodyUsed here? + mInternalResponse->SetBody(aBody); } } // namespace dom } // namespace mozilla diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h index dfaea9b1f68b..1b2b92d2946c 100644 --- a/dom/fetch/Response.h +++ b/dom/fetch/Response.h @@ -9,9 +9,12 @@ #include "nsWrapperCache.h" #include "nsISupportsImpl.h" +#include "mozilla/dom/Fetch.h" #include "mozilla/dom/ResponseBinding.h" #include "mozilla/dom/UnionTypes.h" +#include "InternalResponse.h" + class nsPIDOMWindow; namespace mozilla { @@ -22,12 +25,15 @@ class Promise; class Response MOZ_FINAL : public nsISupports , public nsWrapperCache + , public FetchBody { NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response) public: - explicit Response(nsISupports* aOwner); + Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse); + + Response(const Response& aOther) MOZ_DELETE; JSObject* WrapObject(JSContext* aCx) @@ -38,29 +44,32 @@ public: ResponseType Type() const { - return ResponseType::Error; + return mInternalResponse->Type(); } void GetUrl(DOMString& aUrl) const { - aUrl.AsAString() = EmptyString(); + aUrl.AsAString() = NS_ConvertUTF8toUTF16(mInternalResponse->GetUrl()); } uint16_t Status() const { - return 400; + return mInternalResponse->GetStatus(); } void GetStatusText(nsCString& aStatusText) const { - aStatusText = EmptyCString(); + aStatusText = mInternalResponse->GetStatusText(); } Headers* - Headers_() const { return mHeaders; } + Headers_() const { return mInternalResponse->Headers_(); } + + void + GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); } static already_AddRefed Error(const GlobalObject& aGlobal); @@ -73,7 +82,7 @@ public: const Optional& aBody, const ResponseInit& aInit, ErrorResult& rv); - nsISupports* GetParentObject() const + nsIGlobalObject* GetParentObject() const { return mOwner; } @@ -81,25 +90,13 @@ public: already_AddRefed Clone(); - already_AddRefed - ArrayBuffer(ErrorResult& aRv); - - already_AddRefed - Blob(ErrorResult& aRv); - - already_AddRefed - Json(ErrorResult& aRv); - - already_AddRefed - Text(ErrorResult& aRv); - - bool - BodyUsed(); + void + SetBody(nsIInputStream* aBody); private: ~Response(); - nsCOMPtr mOwner; - nsRefPtr mHeaders; + nsCOMPtr mOwner; + nsRefPtr mInternalResponse; }; } // namespace dom diff --git a/dom/fetch/moz.build b/dom/fetch/moz.build index c5491304cf5a..ceb99d173537 100644 --- a/dom/fetch/moz.build +++ b/dom/fetch/moz.build @@ -8,6 +8,7 @@ EXPORTS.mozilla.dom += [ 'Fetch.h', 'Headers.h', 'InternalRequest.h', + 'InternalResponse.h', 'Request.h', 'Response.h', ] @@ -16,6 +17,7 @@ UNIFIED_SOURCES += [ 'Fetch.cpp', 'Headers.cpp', 'InternalRequest.cpp', + 'InternalResponse.cpp', 'Request.cpp', 'Response.cpp', ] diff --git a/dom/workers/test/fetch/mochitest.ini b/dom/workers/test/fetch/mochitest.ini index ded2d970f35c..84492fca80ac 100644 --- a/dom/workers/test/fetch/mochitest.ini +++ b/dom/workers/test/fetch/mochitest.ini @@ -2,6 +2,8 @@ support-files = worker_interfaces.js worker_test_request.js + worker_test_response.js [test_interfaces.html] [test_request.html] +[test_response.html] diff --git a/dom/workers/test/fetch/test_response.html b/dom/workers/test/fetch/test_response.html new file mode 100644 index 000000000000..e1bbd399ed65 --- /dev/null +++ b/dom/workers/test/fetch/test_response.html @@ -0,0 +1,48 @@ + + + + + Bug 1039846 - Test Response object in worker + + + + +

+ +

+
+
+
+
+
diff --git a/dom/workers/test/fetch/worker_test_response.js b/dom/workers/test/fetch/worker_test_response.js
new file mode 100644
index 000000000000..5111967e607e
--- /dev/null
+++ b/dom/workers/test/fetch/worker_test_response.js
@@ -0,0 +1,124 @@
+function ok(a, msg) {
+  dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
+  postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
+}
+
+function is(a, b, msg) {
+  dump("IS: " + (a===b) + "  =>  " + a + " | " + b + " " + msg + "\n");
+  postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
+}
+
+function testDefaultCtor() {
+  var res = new Response();
+  is(res.type, "default", "Default Response type is default");
+  ok(res.headers instanceof Headers, "Response should have non-null Headers object");
+  is(res.url, "", "URL should be empty string");
+  is(res.status, 200, "Default status is 200");
+  is(res.statusText, "OK", "Default statusText is OK");
+}
+
+function testClone() {
+  var res = (new Response("This is a body", {
+              status: 404,
+              statusText: "Not Found",
+              headers: { "Content-Length": 5 },
+            })).clone();
+  is(res.status, 404, "Response status is 404");
+  is(res.statusText, "Not Found", "Response statusText is POST");
+  ok(res.headers instanceof Headers, "Response should have non-null Headers object");
+  is(res.headers.get('content-length'), "5", "Response content-length should be 5.");
+}
+
+function testBodyUsed() {
+  var res = new Response("Sample body");
+  ok(!res.bodyUsed, "bodyUsed is initially false.");
+  return res.text().then((v) => {
+    is(v, "Sample body", "Body should match");
+    ok(res.bodyUsed, "After reading body, bodyUsed should be true.");
+  }).then(() => {
+    return res.blob().then((v) => {
+      ok(false, "Attempting to read body again should fail.");
+    }, (e) => {
+      ok(true, "Attempting to read body again should fail.");
+    })
+  });
+}
+
+// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
+function testBodyCreation() {
+  var text = "κόσμε";
+  var res1 = new Response(text);
+  var p1 = res1.text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  });
+
+  var res2 = new Response(new Uint8Array([72, 101, 108, 108, 111]));
+  var p2 = res2.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var res2b = new Response((new Uint8Array([72, 101, 108, 108, 111])).buffer);
+  var p2b = res2b.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var params = new URLSearchParams();
+  params.append("item", "Geckos");
+  params.append("feature", "stickyfeet");
+  params.append("quantity", "700");
+  var res3 = new Response(params);
+  var p3 = res3.text().then(function(v) {
+    var extracted = new URLSearchParams(v);
+    is(extracted.get("item"), "Geckos", "Param should match");
+    is(extracted.get("feature"), "stickyfeet", "Param should match");
+    is(extracted.get("quantity"), "700", "Param should match");
+  });
+
+  return Promise.all([p1, p2, p2b, p3]);
+}
+
+function testBodyExtraction() {
+  var text = "κόσμε";
+  var newRes = function() { return new Response(text); }
+  return newRes().text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  }).then(function() {
+    return newRes().blob().then(function(v) {
+      ok(v instanceof Blob, "Should resolve to Blob");
+      var fs = new FileReaderSync();
+      is(fs.readAsText(v), text, "Decoded Blob should match original");
+    });
+  }).then(function() {
+    return newRes().json().then(function(v) {
+      ok(false, "Invalid json should reject");
+    }, function(e) {
+      ok(true, "Invalid json should reject");
+    })
+  }).then(function() {
+    return newRes().arrayBuffer().then(function(v) {
+      ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
+      var dec = new TextDecoder();
+      is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
+    });
+  })
+}
+
+onmessage = function() {
+  var done = function() { postMessage({ type: 'finish' }) }
+
+  testDefaultCtor();
+  testClone();
+
+  Promise.resolve()
+    .then(testBodyCreation)
+    .then(testBodyUsed)
+    .then(testBodyExtraction)
+    // Put more promise based tests here.
+    .then(done)
+    .catch(function(e) {
+      ok(false, "Some Response tests failed " + e);
+      done();
+    })
+}

From e1bbdf4cc1ccb7b40c26a422e957a5a8780840ba Mon Sep 17 00:00:00 2001
From: Nikhil Marathe 
Date: Thu, 2 Oct 2014 10:59:20 -0700
Subject: [PATCH 056/100] Bug 1039846 - Split Headers into InternalHeaders.
 r=baku

--HG--
extra : rebase_source : 1b7e0a27e44f1e11ed84de7be18a19155d6750d5
---
 dom/fetch/Fetch.cpp            |   4 +-
 dom/fetch/Headers.cpp          | 276 ++-------------------------------
 dom/fetch/Headers.h            | 113 +++++++-------
 dom/fetch/InternalHeaders.cpp  | 272 ++++++++++++++++++++++++++++++++
 dom/fetch/InternalHeaders.h    | 116 ++++++++++++++
 dom/fetch/InternalRequest.cpp  |   2 +-
 dom/fetch/InternalRequest.h    |  17 +-
 dom/fetch/InternalResponse.cpp |   4 +-
 dom/fetch/InternalResponse.h   |   9 +-
 dom/fetch/Request.cpp          |  40 +++--
 dom/fetch/Request.h            |  11 +-
 dom/fetch/Response.cpp         |  20 ++-
 dom/fetch/Response.h           |  12 +-
 dom/fetch/moz.build            |   2 +
 14 files changed, 541 insertions(+), 357 deletions(-)
 create mode 100644 dom/fetch/InternalHeaders.cpp
 create mode 100644 dom/fetch/InternalHeaders.h

diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp
index 3ba6e1c59816..1df46c2e62cf 100644
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -318,8 +318,8 @@ FetchBody::SetMimeType(ErrorResult& aRv)
 {
   // Extract mime type.
   nsTArray contentTypeValues;
-  MOZ_ASSERT(DerivedClass()->Headers_());
-  DerivedClass()->Headers_()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
+  MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
+  DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
diff --git a/dom/fetch/Headers.cpp b/dom/fetch/Headers.cpp
index ee7ad0c09ea7..a56f62934a68 100644
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -10,13 +10,6 @@
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/Preferences.h"
 
-#include "nsCharSeparatedTokenizer.h"
-#include "nsContentUtils.h"
-#include "nsDOMString.h"
-#include "nsNetUtil.h"
-#include "nsPIDOMWindow.h"
-#include "nsReadableUtils.h"
-
 namespace mozilla {
 namespace dom {
 
@@ -61,18 +54,19 @@ Headers::Constructor(const GlobalObject& aGlobal,
                      const Optional& aInit,
                      ErrorResult& aRv)
 {
-  nsRefPtr headers = new Headers(aGlobal.GetAsSupports());
+  nsRefPtr ih = new InternalHeaders();
+  nsRefPtr headers = new Headers(aGlobal.GetAsSupports(), ih);
 
   if (!aInit.WasPassed()) {
     return headers.forget();
   }
 
   if (aInit.Value().IsHeaders()) {
-    headers->Fill(aInit.Value().GetAsHeaders(), aRv);
+    ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
   } else if (aInit.Value().IsByteStringSequenceSequence()) {
-    headers->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
+    ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
   } else if (aInit.Value().IsByteStringMozMap()) {
-    headers->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
+    ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
   }
 
   if (aRv.Failed()) {
@@ -88,14 +82,15 @@ Headers::Constructor(const GlobalObject& aGlobal,
                      const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
                      ErrorResult& aRv)
 {
-  nsRefPtr headers = new Headers(aGlobal.GetAsSupports());
+  nsRefPtr ih = new InternalHeaders();
+  nsRefPtr headers = new Headers(aGlobal.GetAsSupports(), ih);
 
   if (aInit.IsHeaders()) {
-    headers->Fill(aInit.GetAsHeaders(), aRv);
+    ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
   } else if (aInit.IsByteStringSequenceSequence()) {
-    headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
+    ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
   } else if (aInit.IsByteStringMozMap()) {
-    headers->Fill(aInit.GetAsByteStringMozMap(), aRv);
+    ih->Fill(aInit.GetAsByteStringMozMap(), aRv);
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
@@ -105,153 +100,6 @@ Headers::Constructor(const GlobalObject& aGlobal,
   return headers.forget();
 }
 
-Headers::Headers(const Headers& aOther)
-  : mOwner(aOther.mOwner)
-  , mGuard(aOther.mGuard)
-{
-  ErrorResult result;
-  Fill(aOther, result);
-  MOZ_ASSERT(!result.Failed());
-}
-
-void
-Headers::Append(const nsACString& aName, const nsACString& aValue,
-                ErrorResult& aRv)
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
-    return;
-  }
-
-  mList.AppendElement(Entry(lowerName, aValue));
-}
-
-void
-Headers::Delete(const nsACString& aName, ErrorResult& aRv)
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidMutableHeader(lowerName, nullptr, aRv)) {
-    return;
-  }
-
-  // remove in reverse order to minimize copying
-  for (int32_t i = mList.Length() - 1; i >= 0; --i) {
-    if (lowerName == mList[i].mName) {
-      mList.RemoveElementAt(i);
-    }
-  }
-}
-
-void
-Headers::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidName(lowerName, aRv)) {
-    return;
-  }
-
-  for (uint32_t i = 0; i < mList.Length(); ++i) {
-    if (lowerName == mList[i].mName) {
-      aValue = mList[i].mValue;
-      return;
-    }
-  }
-
-  // No value found, so return null to content
-  aValue.SetIsVoid(true);
-}
-
-void
-Headers::GetAll(const nsACString& aName, nsTArray& aResults,
-                ErrorResult& aRv) const
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidName(lowerName, aRv)) {
-    return;
-  }
-
-  aResults.SetLength(0);
-  for (uint32_t i = 0; i < mList.Length(); ++i) {
-    if (lowerName == mList[i].mName) {
-      aResults.AppendElement(mList[i].mValue);
-    }
-  }
-}
-
-bool
-Headers::Has(const nsACString& aName, ErrorResult& aRv) const
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidName(lowerName, aRv)) {
-    return false;
-  }
-
-  for (uint32_t i = 0; i < mList.Length(); ++i) {
-    if (lowerName == mList[i].mName) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void
-Headers::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
-{
-  nsAutoCString lowerName;
-  ToLowerCase(aName, lowerName);
-
-  if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
-    return;
-  }
-
-  int32_t firstIndex = INT32_MAX;
-
-  // remove in reverse order to minimize copying
-  for (int32_t i = mList.Length() - 1; i >= 0; --i) {
-    if (lowerName == mList[i].mName) {
-      firstIndex = std::min(firstIndex, i);
-      mList.RemoveElementAt(i);
-    }
-  }
-
-  if (firstIndex < INT32_MAX) {
-    Entry* entry = mList.InsertElementAt(firstIndex);
-    entry->mName = lowerName;
-    entry->mValue = aValue;
-  } else {
-    mList.AppendElement(Entry(lowerName, aValue));
-  }
-}
-
-void
-Headers::Clear()
-{
-  mList.Clear();
-}
-
-void
-Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
-{
-  // Rather than re-validate all current headers, just require code to set
-  // this prior to populating the Headers object.  Allow setting immutable
-  // late, though, as that is pretty much required to have a  useful, immutable
-  // headers object.
-  if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
-  mGuard = aGuard;
-}
-
 JSObject*
 Headers::WrapObject(JSContext* aCx)
 {
@@ -261,109 +109,5 @@ Headers::WrapObject(JSContext* aCx)
 Headers::~Headers()
 {
 }
-
-// static
-bool
-Headers::IsSimpleHeader(const nsACString& aName, const nsACString* aValue)
-{
-  // Note, we must allow a null content-type value here to support
-  // get("content-type"), but the IsInvalidValue() check will prevent null
-  // from being set or appended.
-  return aName.EqualsLiteral("accept") ||
-         aName.EqualsLiteral("accept-language") ||
-         aName.EqualsLiteral("content-language") ||
-         (aName.EqualsLiteral("content-type") &&
-          (!aValue || nsContentUtils::IsAllowedNonCorsContentType(*aValue)));
-}
-
-//static
-bool
-Headers::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
-{
-  if (!NS_IsValidHTTPToken(aName)) {
-    NS_ConvertUTF8toUTF16 label(aName);
-    aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
-    return true;
-  }
-
-  return false;
-}
-
-// static
-bool
-Headers::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
-{
-  if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
-    NS_ConvertUTF8toUTF16 label(aValue);
-    aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
-    return true;
-  }
-  return false;
-}
-
-bool
-Headers::IsImmutable(ErrorResult& aRv) const
-{
-  if (mGuard == HeadersGuardEnum::Immutable) {
-    aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
-    return true;
-  }
-  return false;
-}
-
-bool
-Headers::IsForbiddenRequestHeader(const nsACString& aName) const
-{
-  return mGuard == HeadersGuardEnum::Request &&
-         nsContentUtils::IsForbiddenRequestHeader(aName);
-}
-
-bool
-Headers::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
-                                        const nsACString* aValue) const
-{
-  return mGuard == HeadersGuardEnum::Request_no_cors &&
-         !IsSimpleHeader(aName, aValue);
-}
-
-bool
-Headers::IsForbiddenResponseHeader(const nsACString& aName) const
-{
-  return mGuard == HeadersGuardEnum::Response &&
-         nsContentUtils::IsForbiddenResponseHeader(aName);
-}
-
-void
-Headers::Fill(const Headers& aInit, ErrorResult& aRv)
-{
-  const nsTArray& list = aInit.mList;
-  for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
-    const Entry& entry = list[i];
-    Append(entry.mName, entry.mValue, aRv);
-  }
-}
-
-void
-Headers::Fill(const Sequence>& aInit, ErrorResult& aRv)
-{
-  for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
-    const Sequence& tuple = aInit[i];
-    if (tuple.Length() != 2) {
-      aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
-      return;
-    }
-    Append(tuple[0], tuple[1], aRv);
-  }
-}
-
-void
-Headers::Fill(const MozMap& aInit, ErrorResult& aRv)
-{
-  nsTArray keys;
-  aInit.GetKeys(keys);
-  for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
-    Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
-  }
-}
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/fetch/Headers.h b/dom/fetch/Headers.h
index aa945581ae1d..6cd6140d1c16 100644
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -13,6 +13,8 @@
 #include "nsClassHashtable.h"
 #include "nsWrapperCache.h"
 
+#include "InternalHeaders.h"
+
 class nsPIDOMWindow;
 
 namespace mozilla {
@@ -24,38 +26,34 @@ namespace dom {
 template class MozMap;
 class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
 
+/**
+ * This Headers class is only used to represent the content facing Headers
+ * object. It is actually backed by an InternalHeaders implementation. Gecko
+ * code should NEVER use this, except in the Request and Response
+ * implementations, where they must always be created from the backing
+ * InternalHeaders object.
+ */
 class Headers MOZ_FINAL : public nsISupports
                         , public nsWrapperCache
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Headers)
 
+  friend class Request;
+  friend class Response;
+
 private:
-  struct Entry
-  {
-    Entry(const nsACString& aName, const nsACString& aValue)
-      : mName(aName)
-      , mValue(aValue)
-    { }
-
-    Entry() { }
-
-    nsCString mName;
-    nsCString mValue;
-  };
-
   nsCOMPtr mOwner;
-  HeadersGuardEnum mGuard;
-  nsTArray mList;
+  nsRefPtr mInternalHeaders;
 
 public:
-  explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None)
+  explicit Headers(nsISupports* aOwner, InternalHeaders* aInternalHeaders)
     : mOwner(aOwner)
-    , mGuard(aGuard)
+    , mInternalHeaders(aInternalHeaders)
   {
   }
 
-  explicit Headers(const Headers& aOther);
+  explicit Headers(const Headers& aOther) MOZ_DELETE;
 
   static bool PrefEnabled(JSContext* cx, JSObject* obj);
 
@@ -70,56 +68,59 @@ public:
               ErrorResult& aRv);
 
   void Append(const nsACString& aName, const nsACString& aValue,
-              ErrorResult& aRv);
-  void Delete(const nsACString& aName, ErrorResult& aRv);
-  void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
-  void GetAll(const nsACString& aName, nsTArray& aResults,
-              ErrorResult& aRv) const;
-  bool Has(const nsACString& aName, ErrorResult& aRv) const;
-  void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
+              ErrorResult& aRv)
+  {
+    mInternalHeaders->Append(aName, aValue, aRv);
+  }
 
-  void Clear();
+  void Delete(const nsACString& aName, ErrorResult& aRv)
+  {
+    mInternalHeaders->Delete(aName, aRv);
+  }
+
+  void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
+  {
+    mInternalHeaders->Get(aName, aValue, aRv);
+  }
+
+  void GetAll(const nsACString& aName, nsTArray& aResults,
+              ErrorResult& aRv) const
+  {
+    mInternalHeaders->GetAll(aName, aResults, aRv);
+  }
+
+  bool Has(const nsACString& aName, ErrorResult& aRv) const
+  {
+    return mInternalHeaders->Has(aName, aRv);
+  }
+
+  void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
+  {
+    mInternalHeaders->Set(aName, aValue, aRv);
+  }
 
   // ChromeOnly
-  HeadersGuardEnum Guard() const { return mGuard; }
-  void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
+  HeadersGuardEnum Guard() const
+  {
+    return mInternalHeaders->Guard();
+  }
+
+  void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
+  {
+    mInternalHeaders->SetGuard(aGuard, aRv);
+  }
 
   virtual JSObject* WrapObject(JSContext* aCx);
   nsISupports* GetParentObject() const { return mOwner; }
 
-  void Fill(const Headers& aInit, ErrorResult& aRv);
 private:
-  // Since Headers is also an nsISupports, the above constructor can
-  // accidentally be invoked as new Headers(Headers*[, implied None guard]) when
-  // the intention is to use the copy constructor. Explicitly disallow it.
-  Headers(Headers* aOther) MOZ_DELETE;
-
   virtual ~Headers();
 
-  static bool IsSimpleHeader(const nsACString& aName,
-                             const nsACString* aValue = nullptr);
-  static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
-  static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
-  bool IsImmutable(ErrorResult& aRv) const;
-  bool IsForbiddenRequestHeader(const nsACString& aName) const;
-  bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
-                                      const nsACString* aValue = nullptr) const;
-  bool IsForbiddenResponseHeader(const nsACString& aName) const;
-
-  bool IsInvalidMutableHeader(const nsACString& aName,
-                              const nsACString* aValue,
-                              ErrorResult& aRv) const
+  InternalHeaders*
+  GetInternalHeaders() const
   {
-    return IsInvalidName(aName, aRv) ||
-           (aValue && IsInvalidValue(*aValue, aRv)) ||
-           IsImmutable(aRv) ||
-           IsForbiddenRequestHeader(aName) ||
-           IsForbiddenRequestNoCorsHeader(aName, aValue) ||
-           IsForbiddenResponseHeader(aName);
+    return mInternalHeaders;
   }
-
-  void Fill(const Sequence>& aInit, ErrorResult& aRv);
-  void Fill(const MozMap& aInit, ErrorResult& aRv);
 };
 
 } // namespace dom
diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp
new file mode 100644
index 000000000000..5fe681037f48
--- /dev/null
+++ b/dom/fetch/InternalHeaders.cpp
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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/InternalHeaders.h"
+
+#include "mozilla/ErrorResult.h"
+
+#include "nsCharSeparatedTokenizer.h"
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+#include "nsReadableUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+void
+InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
+                        ErrorResult& aRv)
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
+    return;
+  }
+
+  mList.AppendElement(Entry(lowerName, aValue));
+}
+
+void
+InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidMutableHeader(lowerName, aRv)) {
+    return;
+  }
+
+  // remove in reverse order to minimize copying
+  for (int32_t i = mList.Length() - 1; i >= 0; --i) {
+    if (lowerName == mList[i].mName) {
+      mList.RemoveElementAt(i);
+    }
+  }
+}
+
+void
+InternalHeaders::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidName(lowerName, aRv)) {
+    return;
+  }
+
+  for (uint32_t i = 0; i < mList.Length(); ++i) {
+    if (lowerName == mList[i].mName) {
+      aValue = mList[i].mValue;
+      return;
+    }
+  }
+
+  // No value found, so return null to content
+  aValue.SetIsVoid(true);
+}
+
+void
+InternalHeaders::GetAll(const nsACString& aName, nsTArray& aResults,
+                        ErrorResult& aRv) const
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidName(lowerName, aRv)) {
+    return;
+  }
+
+  aResults.SetLength(0);
+  for (uint32_t i = 0; i < mList.Length(); ++i) {
+    if (lowerName == mList[i].mName) {
+      aResults.AppendElement(mList[i].mValue);
+    }
+  }
+}
+
+bool
+InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidName(lowerName, aRv)) {
+    return false;
+  }
+
+  for (uint32_t i = 0; i < mList.Length(); ++i) {
+    if (lowerName == mList[i].mName) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void
+InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
+{
+  nsAutoCString lowerName;
+  ToLowerCase(aName, lowerName);
+
+  if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
+    return;
+  }
+
+  int32_t firstIndex = INT32_MAX;
+
+  // remove in reverse order to minimize copying
+  for (int32_t i = mList.Length() - 1; i >= 0; --i) {
+    if (lowerName == mList[i].mName) {
+      firstIndex = std::min(firstIndex, i);
+      mList.RemoveElementAt(i);
+    }
+  }
+
+  if (firstIndex < INT32_MAX) {
+    Entry* entry = mList.InsertElementAt(firstIndex);
+    entry->mName = lowerName;
+    entry->mValue = aValue;
+  } else {
+    mList.AppendElement(Entry(lowerName, aValue));
+  }
+}
+
+void
+InternalHeaders::Clear()
+{
+  mList.Clear();
+}
+
+void
+InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
+{
+  // Rather than re-validate all current headers, just require code to set
+  // this prior to populating the InternalHeaders object.  Allow setting immutable
+  // late, though, as that is pretty much required to have a  useful, immutable
+  // headers object.
+  if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+  mGuard = aGuard;
+}
+
+InternalHeaders::~InternalHeaders()
+{
+}
+
+// static
+bool
+InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
+{
+  // Note, we must allow a null content-type value here to support
+  // get("content-type"), but the IsInvalidValue() check will prevent null
+  // from being set or appended.
+  return aName.EqualsLiteral("accept") ||
+         aName.EqualsLiteral("accept-language") ||
+         aName.EqualsLiteral("content-language") ||
+         (aName.EqualsLiteral("content-type") &&
+          nsContentUtils::IsAllowedNonCorsContentType(aValue));
+}
+
+//static
+bool
+InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
+{
+  if (!NS_IsValidHTTPToken(aName)) {
+    NS_ConvertUTF8toUTF16 label(aName);
+    aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
+    return true;
+  }
+
+  return false;
+}
+
+// static
+bool
+InternalHeaders::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
+{
+  if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
+    NS_ConvertUTF8toUTF16 label(aValue);
+    aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
+    return true;
+  }
+  return false;
+}
+
+bool
+InternalHeaders::IsImmutable(ErrorResult& aRv) const
+{
+  if (mGuard == HeadersGuardEnum::Immutable) {
+    aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
+    return true;
+  }
+  return false;
+}
+
+bool
+InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const
+{
+  return mGuard == HeadersGuardEnum::Request &&
+         nsContentUtils::IsForbiddenRequestHeader(aName);
+}
+
+bool
+InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName) const
+{
+  return mGuard == HeadersGuardEnum::Request_no_cors &&
+         !IsSimpleHeader(aName, EmptyCString());
+}
+
+bool
+InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
+                                                const nsACString& aValue) const
+{
+  return mGuard == HeadersGuardEnum::Request_no_cors &&
+         !IsSimpleHeader(aName, aValue);
+}
+
+bool
+InternalHeaders::IsForbiddenResponseHeader(const nsACString& aName) const
+{
+  return mGuard == HeadersGuardEnum::Response &&
+         nsContentUtils::IsForbiddenResponseHeader(aName);
+}
+
+void
+InternalHeaders::Fill(const InternalHeaders& aInit, ErrorResult& aRv)
+{
+  const nsTArray& list = aInit.mList;
+  for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
+    const Entry& entry = list[i];
+    Append(entry.mName, entry.mValue, aRv);
+  }
+}
+
+void
+InternalHeaders::Fill(const Sequence>& aInit, ErrorResult& aRv)
+{
+  for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
+    const Sequence& tuple = aInit[i];
+    if (tuple.Length() != 2) {
+      aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
+      return;
+    }
+    Append(tuple[0], tuple[1], aRv);
+  }
+}
+
+void
+InternalHeaders::Fill(const MozMap& aInit, ErrorResult& aRv)
+{
+  nsTArray keys;
+  aInit.GetKeys(keys);
+  for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
+    Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
+  }
+}
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h
new file mode 100644
index 000000000000..9d046585ef87
--- /dev/null
+++ b/dom/fetch/InternalHeaders.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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_InternalHeaders_h
+#define mozilla_dom_InternalHeaders_h
+
+// needed for HeadersGuardEnum.
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+
+#include "nsClassHashtable.h"
+#include "nsWrapperCache.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+template class MozMap;
+class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
+
+class InternalHeaders MOZ_FINAL
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders)
+
+private:
+  struct Entry
+  {
+    Entry(const nsACString& aName, const nsACString& aValue)
+      : mName(aName)
+      , mValue(aValue)
+    { }
+
+    Entry() { }
+
+    nsCString mName;
+    nsCString mValue;
+  };
+
+  HeadersGuardEnum mGuard;
+  nsTArray mList;
+
+public:
+  explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
+    : mGuard(aGuard)
+  {
+  }
+
+  explicit InternalHeaders(const InternalHeaders& aOther)
+    : mGuard(aOther.mGuard)
+  {
+    ErrorResult result;
+    Fill(aOther, result);
+    MOZ_ASSERT(!result.Failed());
+  }
+
+  void Append(const nsACString& aName, const nsACString& aValue,
+              ErrorResult& aRv);
+  void Delete(const nsACString& aName, ErrorResult& aRv);
+  void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
+  void GetAll(const nsACString& aName, nsTArray& aResults,
+              ErrorResult& aRv) const;
+  bool Has(const nsACString& aName, ErrorResult& aRv) const;
+  void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
+
+  void Clear();
+
+  HeadersGuardEnum Guard() const { return mGuard; }
+  void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
+
+  void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
+  void Fill(const Sequence>& aInit, ErrorResult& aRv);
+  void Fill(const MozMap& aInit, ErrorResult& aRv);
+private:
+  virtual ~InternalHeaders();
+
+  static bool IsSimpleHeader(const nsACString& aName,
+                             const nsACString& aValue);
+  static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
+  static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
+  bool IsImmutable(ErrorResult& aRv) const;
+  bool IsForbiddenRequestHeader(const nsACString& aName) const;
+  bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const;
+  bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
+                                      const nsACString& aValue) const;
+  bool IsForbiddenResponseHeader(const nsACString& aName) const;
+
+  bool IsInvalidMutableHeader(const nsACString& aName,
+                              ErrorResult& aRv) const
+  {
+    return IsInvalidMutableHeader(aName, EmptyCString(), aRv);
+  }
+
+  bool IsInvalidMutableHeader(const nsACString& aName,
+                              const nsACString& aValue,
+                              ErrorResult& aRv) const
+  {
+    return IsInvalidName(aName, aRv) ||
+           IsInvalidValue(aValue, aRv) ||
+           IsImmutable(aRv) ||
+           IsForbiddenRequestHeader(aName) ||
+           IsForbiddenRequestNoCorsHeader(aName, aValue) ||
+           IsForbiddenResponseHeader(aName);
+  }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InternalHeaders_h
diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp
index 207869fa0a5c..077f7f8e23b1 100644
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -24,7 +24,7 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
   nsRefPtr copy = new InternalRequest();
   copy->mURL.Assign(mURL);
   copy->SetMethod(mMethod);
-  copy->mHeaders = new Headers(*mHeaders);
+  copy->mHeaders = new InternalHeaders(*mHeaders);
 
   copy->mBodyStream = mBodyStream;
   copy->mPreserveContentCodings = true;
diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h
index 5b3e75d195fc..664e64ae0b3e 100644
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -6,7 +6,8 @@
 #ifndef mozilla_dom_InternalRequest_h
 #define mozilla_dom_InternalRequest_h
 
-#include "mozilla/dom/Headers.h"
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 
@@ -55,7 +56,7 @@ public:
 
   explicit InternalRequest()
     : mMethod("GET")
-    , mHeaders(new Headers(nullptr, HeadersGuardEnum::None))
+    , mHeaders(new InternalHeaders(HeadersGuardEnum::None))
     , mContextFrameType(FRAMETYPE_NONE)
     , mReferrerType(REFERRER_CLIENT)
     , mMode(RequestMode::No_cors)
@@ -159,6 +160,12 @@ public:
     return mSynchronous;
   }
 
+  RequestMode
+  Mode() const
+  {
+    return mMode;
+  }
+
   void
   SetMode(RequestMode aMode)
   {
@@ -177,8 +184,8 @@ public:
     return mContext;
   }
 
-  Headers*
-  Headers_()
+  InternalHeaders*
+  Headers()
   {
     return mHeaders;
   }
@@ -225,7 +232,7 @@ private:
 
   nsCString mMethod;
   nsCString mURL;
-  nsRefPtr mHeaders;
+  nsRefPtr mHeaders;
   nsCOMPtr mBodyStream;
 
   // nsContentPolicyType does not cover the complete set defined in the spec,
diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp
index ef8d47e40a50..ceaf131ce3f0 100644
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -7,7 +7,7 @@
 
 #include "nsIDOMFile.h"
 
-#include "mozilla/dom/Headers.h"
+#include "mozilla/dom/InternalHeaders.h"
 
 namespace mozilla {
 namespace dom {
@@ -16,7 +16,7 @@ InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusTe
   : mType(ResponseType::Default)
   , mStatus(aStatus)
   , mStatusText(aStatusText)
-  , mHeaders(new Headers(nullptr, HeadersGuardEnum::Response))
+  , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
 {
 }
 
diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h
index f965202f26ac..e9c7f1b81830 100644
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -6,6 +6,7 @@
 #ifndef mozilla_dom_InternalResponse_h
 #define mozilla_dom_InternalResponse_h
 
+#include "nsIInputStream.h"
 #include "nsISupportsImpl.h"
 
 #include "mozilla/dom/ResponseBinding.h"
@@ -13,6 +14,8 @@
 namespace mozilla {
 namespace dom {
 
+class InternalHeaders;
+
 class InternalResponse MOZ_FINAL
 {
   friend class FetchDriver;
@@ -63,8 +66,8 @@ public:
     return mStatusText;
   }
 
-  Headers*
-  Headers_()
+  InternalHeaders*
+  Headers()
   {
     return mHeaders;
   }
@@ -91,7 +94,7 @@ private:
   nsCString mURL;
   const uint16_t mStatus;
   const nsCString mStatusText;
-  nsRefPtr mHeaders;
+  nsRefPtr mHeaders;
   nsCOMPtr mBody;
   nsCString mContentType;
 };
diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp
index 582e1fd73726..a8e4cf3d9016 100644
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -22,7 +22,7 @@ namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -155,24 +155,24 @@ Request::Constructor(const GlobalObject& aGlobal,
     request->SetMethod(method);
   }
 
-  nsRefPtr domRequest = new Request(global, request);
-  nsRefPtr domRequestHeaders = domRequest->Headers_();
+  nsRefPtr requestHeaders = request->Headers();
 
-  nsRefPtr headers;
+  nsRefPtr headers;
   if (aInit.mHeaders.WasPassed()) {
-    headers = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
+    nsRefPtr h = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
+    headers = h->GetInternalHeaders();
   } else {
-    headers = new Headers(*domRequestHeaders);
+    headers = new InternalHeaders(*requestHeaders);
   }
 
-  domRequestHeaders->Clear();
+  requestHeaders->Clear();
 
-  if (domRequest->Mode() == RequestMode::No_cors) {
+  if (request->Mode() == RequestMode::No_cors) {
     nsCString method;
-    domRequest->GetMethod(method);
+    request->GetMethod(method);
     ToLowerCase(method);
     if (!method.EqualsASCII("get") &&
         !method.EqualsASCII("head") &&
@@ -182,13 +182,13 @@ Request::Constructor(const GlobalObject& aGlobal,
       return nullptr;
     }
 
-    domRequestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
+    requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
-  domRequestHeaders->Fill(*headers, aRv);
+  requestHeaders->Fill(*headers, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
@@ -205,9 +205,9 @@ Request::Constructor(const GlobalObject& aGlobal,
     request->SetBody(stream);
 
     if (!contentType.IsVoid() &&
-        !domRequestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
-      domRequestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
-                                contentType, aRv);
+        !requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
+      requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
+                             contentType, aRv);
     }
 
     if (aRv.Failed()) {
@@ -215,6 +215,7 @@ Request::Constructor(const GlobalObject& aGlobal,
     }
   }
 
+  nsRefPtr domRequest = new Request(global, request);
   domRequest->SetMimeType(aRv);
   return domRequest.forget();
 }
@@ -228,5 +229,16 @@ Request::Clone() const
                                           new InternalRequest(*mRequest));
   return request.forget();
 }
+
+Headers*
+Request::Headers_()
+{
+  if (!mHeaders) {
+    mHeaders = new Headers(mOwner, mRequest->Headers());
+  }
+
+  return mHeaders;
+}
+
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h
index 938ed03cf25f..01417a04a485 100644
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -22,6 +22,7 @@ namespace mozilla {
 namespace dom {
 
 class Headers;
+class InternalHeaders;
 class Promise;
 
 class Request MOZ_FINAL : public nsISupports
@@ -76,7 +77,13 @@ public:
     aReferrer.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mReferrerURL);
   }
 
-  Headers* Headers_() const { return mRequest->Headers_(); }
+  InternalHeaders*
+  GetInternalHeaders() const
+  {
+    return mRequest->Headers();
+  }
+
+  Headers* Headers_();
 
   void
   GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
@@ -100,6 +107,8 @@ private:
 
   nsCOMPtr mOwner;
   nsRefPtr mRequest;
+  // Lazily created.
+  nsRefPtr mHeaders;
 };
 
 } // namespace dom
diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp
index 9c3c18d38e49..1bed597667f1 100644
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -22,7 +22,7 @@ namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner, mHeaders)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -98,7 +98,7 @@ Response::Constructor(const GlobalObject& aGlobal,
   nsRefPtr r = new Response(global, internalResponse);
 
   if (aInit.mHeaders.WasPassed()) {
-    internalResponse->Headers_()->Clear();
+    internalResponse->Headers()->Clear();
 
     // Instead of using Fill, create an object to allow the constructor to
     // unwrap the HeadersInit.
@@ -108,7 +108,7 @@ Response::Constructor(const GlobalObject& aGlobal,
       return nullptr;
     }
 
-    internalResponse->Headers_()->Fill(*headers, aRv);
+    internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
@@ -121,8 +121,8 @@ Response::Constructor(const GlobalObject& aGlobal,
     internalResponse->SetBody(bodyStream);
 
     if (!contentType.IsVoid() &&
-        !internalResponse->Headers_()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
-      internalResponse->Headers_()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv);
+        !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
+      internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv);
     }
 
     if (aRv.Failed()) {
@@ -149,5 +149,15 @@ Response::SetBody(nsIInputStream* aBody)
   // FIXME(nsm): Do we flip bodyUsed here?
   mInternalResponse->SetBody(aBody);
 }
+
+Headers*
+Response::Headers_()
+{
+  if (!mHeaders) {
+    mHeaders = new Headers(mOwner, mInternalResponse->Headers());
+  }
+
+  return mHeaders;
+}
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h
index 1b2b92d2946c..5c75c72ad2a7 100644
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -21,6 +21,7 @@ namespace mozilla {
 namespace dom {
 
 class Headers;
+class InternalHeaders;
 class Promise;
 
 class Response MOZ_FINAL : public nsISupports
@@ -65,8 +66,13 @@ public:
     aStatusText = mInternalResponse->GetStatusText();
   }
 
-  Headers*
-  Headers_() const { return mInternalResponse->Headers_(); }
+  InternalHeaders*
+  GetInternalHeaders() const
+  {
+    return mInternalResponse->Headers();
+  }
+
+  Headers* Headers_();
 
   void
   GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); }
@@ -97,6 +103,8 @@ private:
 
   nsCOMPtr mOwner;
   nsRefPtr mInternalResponse;
+  // Lazily created
+  nsRefPtr mHeaders;
 };
 
 } // namespace dom
diff --git a/dom/fetch/moz.build b/dom/fetch/moz.build
index ceb99d173537..9d6b9474d298 100644
--- a/dom/fetch/moz.build
+++ b/dom/fetch/moz.build
@@ -7,6 +7,7 @@
 EXPORTS.mozilla.dom += [
     'Fetch.h',
     'Headers.h',
+    'InternalHeaders.h',
     'InternalRequest.h',
     'InternalResponse.h',
     'Request.h',
@@ -16,6 +17,7 @@ EXPORTS.mozilla.dom += [
 UNIFIED_SOURCES += [
     'Fetch.cpp',
     'Headers.cpp',
+    'InternalHeaders.cpp',
     'InternalRequest.cpp',
     'InternalResponse.cpp',
     'Request.cpp',

From 9771d67d26901e3d0396cc7606448dad8b0ddb39 Mon Sep 17 00:00:00 2001
From: Nikhil Marathe 
Date: Thu, 9 Oct 2014 10:52:10 -0700
Subject: [PATCH 057/100] Bug 1071290 - Allow Blobs in Fetch BodyInit. r=baku

--HG--
extra : rebase_source : 412dffd78d5b0c4cddad58374bbe1dd051877c47
---
 dom/fetch/Fetch.cpp                           | 26 +++++++++++++++++--
 dom/fetch/Fetch.h                             |  4 +--
 dom/fetch/Request.cpp                         |  2 +-
 dom/fetch/Response.cpp                        |  4 +--
 dom/fetch/Response.h                          |  2 +-
 dom/webidl/Fetch.webidl                       |  3 +--
 dom/workers/test/fetch/worker_test_request.js |  8 ++++--
 .../test/fetch/worker_test_response.js        |  8 ++++--
 8 files changed, 43 insertions(+), 14 deletions(-)

diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp
index 1df46c2e62cf..bd76394859c8 100644
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -49,6 +49,22 @@ ExtractFromArrayBufferView(const ArrayBufferView& aBuffer,
                                aBuffer.Length(), NS_ASSIGNMENT_COPY);
 }
 
+nsresult
+ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
+                nsCString& aContentType)
+{
+  nsRefPtr impl = aFile.Impl();
+  nsresult rv = impl->GetInternalStream(aStream);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsString type;
+  impl->GetType(type);
+  aContentType = NS_ConvertUTF16toUTF8(type);
+  return NS_OK;
+}
+
 nsresult
 ExtractFromScalarValueString(const nsString& aStr,
                              nsIInputStream** aStream,
@@ -99,7 +115,7 @@ ExtractFromURLSearchParams(const URLSearchParams& aParams,
 }
 
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
@@ -111,6 +127,9 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueS
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
+  } else if (aBodyInit.IsBlob()) {
+    const File& blob = aBodyInit.GetAsBlob();
+    return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsScalarValueString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsScalarValueString());
@@ -125,7 +144,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueS
 }
 
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
@@ -137,6 +156,9 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrScalarValueStringO
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
+  } else if (aBodyInit.IsBlob()) {
+    const File& blob = aBodyInit.GetAsBlob();
+    return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsScalarValueString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsScalarValueString());
diff --git a/dom/fetch/Fetch.h b/dom/fetch/Fetch.h
index 9911edf983dd..5c0eac3e30ac 100644
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -21,7 +21,7 @@ class Promise;
  * Stores content type in out param aContentType.
  */
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
@@ -29,7 +29,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueS
  * Non-owning version.
  */
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp
index a8e4cf3d9016..c151073ce818 100644
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -194,7 +194,7 @@ Request::Constructor(const GlobalObject& aGlobal,
   }
 
   if (aInit.mBody.WasPassed()) {
-    const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
+    const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
     nsCOMPtr stream;
     nsCString contentType;
     aRv = ExtractByteStreamFromBody(bodyInit,
diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp
index 1bed597667f1..f22337930ee8 100644
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -55,14 +55,14 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
 {
   ErrorResult result;
   ResponseInit init;
-  Optional body;
+  Optional body;
   nsRefPtr r = Response::Constructor(aGlobal, body, init, result);
   return r.forget();
 }
 
 /*static*/ already_AddRefed
 Response::Constructor(const GlobalObject& aGlobal,
-                      const Optional& aBody,
+                      const Optional& aBody,
                       const ResponseInit& aInit, ErrorResult& aRv)
 {
   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h
index 5c75c72ad2a7..85711ced5ff7 100644
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -85,7 +85,7 @@ public:
 
   static already_AddRefed
   Constructor(const GlobalObject& aGlobal,
-              const Optional& aBody,
+              const Optional& aBody,
               const ResponseInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
diff --git a/dom/webidl/Fetch.webidl b/dom/webidl/Fetch.webidl
index a1c66f3579d8..1c7de5efe9af 100644
--- a/dom/webidl/Fetch.webidl
+++ b/dom/webidl/Fetch.webidl
@@ -8,10 +8,9 @@
  */
 
 typedef object JSON;
-// FIXME(nsm): Bug 1071290: Blobs can't be passed as unions in workers.
 // FIXME(nsm): Bug 739173: FormData is not available in workers.
 // typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or ScalarValueString or URLSearchParams) BodyInit;
-typedef (ArrayBuffer or ArrayBufferView or ScalarValueString or URLSearchParams) BodyInit;
+typedef (ArrayBuffer or ArrayBufferView or Blob or ScalarValueString or URLSearchParams) BodyInit;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface Body {
diff --git a/dom/workers/test/fetch/worker_test_request.js b/dom/workers/test/fetch/worker_test_request.js
index fde748e4b997..a3504dd56a5a 100644
--- a/dom/workers/test/fetch/worker_test_request.js
+++ b/dom/workers/test/fetch/worker_test_request.js
@@ -131,7 +131,6 @@ function testBodyUsed() {
   });
 }
 
-// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
 function testBodyCreation() {
   var text = "κόσμε";
   var req1 = new Request("", { body: text });
@@ -150,6 +149,11 @@ function testBodyCreation() {
     is("Hello", v, "Extracted string should match");
   });
 
+  var reqblob = new Request("", { body: new Blob([text]) });
+  var pblob = reqblob.text().then(function(v) {
+    is(v, text, "Extracted string should match");
+  });
+
   var params = new URLSearchParams();
   params.append("item", "Geckos");
   params.append("feature", "stickyfeet");
@@ -162,7 +166,7 @@ function testBodyCreation() {
     is(extracted.get("quantity"), "700", "Param should match");
   });
 
-  return Promise.all([p1, p2, p2b, p3]);
+  return Promise.all([p1, p2, p2b, pblob, p3]);
 }
 
 function testBodyExtraction() {
diff --git a/dom/workers/test/fetch/worker_test_response.js b/dom/workers/test/fetch/worker_test_response.js
index 5111967e607e..ce11ca318f36 100644
--- a/dom/workers/test/fetch/worker_test_response.js
+++ b/dom/workers/test/fetch/worker_test_response.js
@@ -44,7 +44,6 @@ function testBodyUsed() {
   });
 }
 
-// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
 function testBodyCreation() {
   var text = "κόσμε";
   var res1 = new Response(text);
@@ -63,6 +62,11 @@ function testBodyCreation() {
     is("Hello", v, "Extracted string should match");
   });
 
+  var resblob = new Response(new Blob([text]));
+  var pblob = resblob.text().then(function(v) {
+    is(v, text, "Extracted string should match");
+  });
+
   var params = new URLSearchParams();
   params.append("item", "Geckos");
   params.append("feature", "stickyfeet");
@@ -75,7 +79,7 @@ function testBodyCreation() {
     is(extracted.get("quantity"), "700", "Param should match");
   });
 
-  return Promise.all([p1, p2, p2b, p3]);
+  return Promise.all([p1, p2, p2b, pblob, p3]);
 }
 
 function testBodyExtraction() {

From 2bcb359d40f15a3b07b4b253e14a52e789556ed7 Mon Sep 17 00:00:00 2001
From: Masayuki Nakano 
Date: Thu, 16 Oct 2014 10:02:29 +0900
Subject: [PATCH 058/100] Bug 1081993 WinIMEHandler should notify
 nsIMM32Handler of some notifications even in TSF mode when IMM IME is active
 r=emk

---
 widget/windows/WinIMEHandler.cpp | 44 ++++++++++++++++++++++++++++----
 widget/windows/WinIMEHandler.h   |  1 +
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/widget/windows/WinIMEHandler.cpp b/widget/windows/WinIMEHandler.cpp
index 35bbced25fb8..554a390388dd 100644
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -129,13 +129,22 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage,
                                         aResult);
 }
 
+#ifdef NS_ENABLE_TSF
+// static
+bool
+IMEHandler::IsIMMActive()
+{
+  return nsTextStore::IsIMM_IME();
+}
+#endif // #ifdef NS_ENABLE_TSF
+
 // static
 bool
 IMEHandler::IsComposing()
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
-    return nsTextStore::IsComposing();
+    return nsTextStore::IsComposing() || nsIMM32Handler::IsComposing();
   }
 #endif // #ifdef NS_ENABLE_TSF
 
@@ -148,7 +157,8 @@ IMEHandler::IsComposingOn(nsWindow* aWindow)
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
-    return nsTextStore::IsComposingOn(aWindow);
+    return nsTextStore::IsComposingOn(aWindow) ||
+           nsIMM32Handler::IsComposingOn(aWindow);
   }
 #endif // #ifdef NS_ENABLE_TSF
 
@@ -163,8 +173,24 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
     switch (aIMENotification.mMessage) {
-      case NOTIFY_IME_OF_SELECTION_CHANGE:
-        return nsTextStore::OnSelectionChange();
+      case NOTIFY_IME_OF_SELECTION_CHANGE: {
+        nsresult rv = nsTextStore::OnSelectionChange();
+        // If IMM IME is active, we need to notify nsIMM32Handler of updating
+        // composition change.  It will adjust candidate window position or
+        // composition window position.
+        if (IsIMMActive()) {
+          nsIMM32Handler::OnUpdateComposition(aWindow);
+        }
+        return rv;
+      }
+      case NOTIFY_IME_OF_COMPOSITION_UPDATE:
+        // If IMM IME is active, we need to notify nsIMM32Handler of updating
+        // composition change.  It will adjust candidate window position or
+        // composition window position.
+        if (IsIMMActive()) {
+          nsIMM32Handler::OnUpdateComposition(aWindow);
+        }
+        return NS_OK;
       case NOTIFY_IME_OF_TEXT_CHANGE:
         return nsTextStore::OnTextChange(aIMENotification);
       case NOTIFY_IME_OF_FOCUS:
@@ -174,15 +200,23 @@ IMEHandler::NotifyIME(nsWindow* aWindow,
         return nsTextStore::OnFocusChange(false, aWindow,
                                           aWindow->GetInputContext());
       case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
+        // If IMM IME is active, we should send a mouse button event via IMM.
+        if (IsIMMActive()) {
+          return nsIMM32Handler::OnMouseButtonEvent(aWindow, aIMENotification);
+        }
         return nsTextStore::OnMouseButtonEvent(aIMENotification);
       case REQUEST_TO_COMMIT_COMPOSITION:
         if (nsTextStore::IsComposingOn(aWindow)) {
           nsTextStore::CommitComposition(false);
+        } else if (IsIMMActive()) {
+          nsIMM32Handler::CommitComposition(aWindow);
         }
         return NS_OK;
       case REQUEST_TO_CANCEL_COMPOSITION:
         if (nsTextStore::IsComposingOn(aWindow)) {
           nsTextStore::CommitComposition(true);
+        } else if (IsIMMActive()) {
+          nsIMM32Handler::CancelComposition(aWindow);
         }
         return NS_OK;
       case NOTIFY_IME_OF_POSITION_CHANGE:
@@ -239,7 +273,7 @@ bool
 IMEHandler::GetOpenState(nsWindow* aWindow)
 {
 #ifdef NS_ENABLE_TSF
-  if (IsTSFAvailable()) {
+  if (IsTSFAvailable() && !IsIMMActive()) {
     return nsTextStore::GetIMEOpenState();
   }
 #endif //NS_ENABLE_TSF
diff --git a/widget/windows/WinIMEHandler.h b/widget/windows/WinIMEHandler.h
index e630bab34ed8..c2ea9e5466f5 100644
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -122,6 +122,7 @@ private:
   static bool sPluginHasFocus;
 
   static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
+  static bool IsIMMActive();
 #endif // #ifdef NS_ENABLE_TSF
 };
 

From 0945f9f3100690258e5295420c772ee63f405cc6 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo 
Date: Wed, 15 Oct 2014 18:06:49 -0700
Subject: [PATCH 059/100] Bug 1076026 - Don't consider uninitialized lexicals
 when initializing a singleton object property type. (r=bhackett)

---
 js/src/jit-test/tests/ion/bug1076026.js | 9 +++++++++
 js/src/jsinfer.cpp                      | 8 +++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 js/src/jit-test/tests/ion/bug1076026.js

diff --git a/js/src/jit-test/tests/ion/bug1076026.js b/js/src/jit-test/tests/ion/bug1076026.js
new file mode 100644
index 000000000000..b5e90a93e0c6
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1076026.js
@@ -0,0 +1,9 @@
+(function f() {
+    let x = (new function() {})
+    __defineGetter__("x", function() {
+        ({
+            e: x
+        })
+    })
+})();
+print(x)
diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp
index 2cf9fe046b25..a03038b65d15 100644
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2931,8 +2931,14 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, NativeObject *obj,
          * Don't add initial undefined types for properties of global objects
          * that are not collated into the JSID_VOID property (see propertySet
          * comment).
+         *
+         * Also don't add initial uninitialized lexical magic values as
+         * appearing in CallObjects.
          */
-        if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
+        MOZ_ASSERT_IF(value.isMagic(JS_UNINITIALIZED_LEXICAL), obj->is());
+        if ((indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) &&
+            !value.isMagic(JS_UNINITIALIZED_LEXICAL))
+        {
             Type type = GetValueType(value);
             types->TypeSet::addType(type, &cx->typeLifoAlloc());
         }

From ee2ad83c86bef3f503f3356e861a5847609cbd77 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo 
Date: Wed, 15 Oct 2014 18:06:50 -0700
Subject: [PATCH 060/100] Bug 1077949 - Fix TDZ checks when closing over
 non-dominating lexical declarations in switches. (r=Waldo)

---
 js/src/frontend/Parser.cpp                    | 32 +++++++++-
 .../tests/basic/letTDZSwitchClosure.js        | 60 +++++++++++++++++++
 2 files changed, 89 insertions(+), 3 deletions(-)
 create mode 100644 js/src/jit-test/tests/basic/letTDZSwitchClosure.js

diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index da4ee15c22c2..327c84c1fab4 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1254,6 +1254,17 @@ ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext *pc, HandleAtom name,
+                              Definition *dn)
+{
+    MOZ_ASSERT(dn->isLet());
+    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, nullptr);
+    if (stmt && stmt->type == STMT_SWITCH)
+        return dn->pn_cookie.slot() < stmt->firstDominatingLexicalInCase;
+    return false;
+}
+
 /*
  * Beware: this function is called for functions nested in other functions or
  * global scripts but not for functions compiled through the Function
@@ -1338,7 +1349,7 @@ Parser::leaveFunction(ParseNode *fn, ParseContext::leaveFunction(ParseNode *fn, ParseContextisLet()) {
+                    //
+                    // Similarly, if we are closing over a lexical binding
+                    // from another case in a switch, those uses also need to
+                    // be marked as needing dead zone checks.
+                    RootedAtom name(context, atom);
+                    if (outer_dn->isLet() &&
+                        (bodyLevelHoistedUse ||
+                         IsNonDominatingInScopedSwitch(outerpc, name, outer_dn)))
+                    {
                         while (true) {
                             pnu->pn_dflags |= PND_LET;
                             if (!pnu->pn_link)
@@ -1872,6 +1891,13 @@ Parser::addFreeVariablesFromLazyFunction(JSFunction *fun,
         // Note that body-level function declaration statements are always
         // hoisted to the top, so all accesses to free let variables need the
         // dead zone check.
+        //
+        // Subtlety: we don't need to check for closing over a non-dominating
+        // lexical binding in a switch, as lexical declarations currently
+        // disable syntax parsing. So a non-dominating but textually preceding
+        // lexical declaration would have aborted syntax parsing, and a
+        // textually following declaration would return true for
+        // handler.isPlaceholderDefinition(dn) below.
         if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse)
             freeVariables[i].setIsHoistedUse();
 
@@ -3142,7 +3168,7 @@ Parser::noteNameUse(HandlePropertyName name, Node pn)
             handler.setFlag(pn, PND_DEOPTIMIZED);
         } else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) {
             // See comments above StmtInfoPC and switchStatement for how
-            // firstDominatingLetInCase is computed.
+            // firstDominatingLexicalInCase is computed.
             MOZ_ASSERT(stmt->firstDominatingLexicalInCase <= stmt->staticBlock().numVariables());
             handler.markMaybeUninitializedLexicalUseInSwitch(pn, dn,
                                                              stmt->firstDominatingLexicalInCase);
diff --git a/js/src/jit-test/tests/basic/letTDZSwitchClosure.js b/js/src/jit-test/tests/basic/letTDZSwitchClosure.js
new file mode 100644
index 000000000000..c601f9858dd0
--- /dev/null
+++ b/js/src/jit-test/tests/basic/letTDZSwitchClosure.js
@@ -0,0 +1,60 @@
+function assertThrowsReferenceError(f) {
+  var err;
+  try {
+    f();
+  } catch (e) {
+    err = e;
+  }
+  assertEq(err instanceof ReferenceError, true);
+}
+
+function f() {
+    switch (0) {
+        case 1:
+            let x
+        case function() {
+            print(x)
+        }():
+    }
+}
+assertThrowsReferenceError(f);
+
+function g() {
+  switch (0) {
+    case 1:
+      let x;
+    case 0:
+      var inner = function () {
+        print(x);
+      }
+      inner();
+      break;
+  }
+}
+assertThrowsReferenceError(g);
+
+function h() {
+  switch (0) {
+    case 0:
+      var inner = function () {
+        print(x);
+      }
+      inner();
+    case 1:
+      let x;
+  }
+}
+assertThrowsReferenceError(h);
+
+// Tests that a dominating lexical doesn't throw.
+function F() {
+  switch (0) {
+    case 0:
+      let x = 42;
+      var inner = function () {
+        assertEq(x, 42);
+      }
+      inner();
+  }
+}
+F();

From 529d32060080e2af746dad3d184d3217ebf80669 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo 
Date: Wed, 15 Oct 2014 18:06:50 -0700
Subject: [PATCH 061/100] Bug 1077949 - Followup: refactor
 Parser::leaveFunction a bit. (rs=Waldo)

---
 js/src/frontend/Parser.cpp | 43 +++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 327c84c1fab4..29e67c375e87 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1265,6 +1265,23 @@ IsNonDominatingInScopedSwitch(ParseContext *pc, HandleAtom nam
     return false;
 }
 
+static void
+AssociateUsesWithOuterDefinition(ParseNode *pnu, Definition *dn, Definition *outer_dn,
+                                 bool markUsesAsLet)
+{
+    uint32_t dflags = markUsesAsLet ? PND_LET : 0;
+    while (true) {
+        pnu->pn_lexdef = outer_dn;
+        pnu->pn_dflags |= dflags;
+        if (!pnu->pn_link)
+            break;
+        pnu = pnu->pn_link;
+    }
+    pnu->pn_link = outer_dn->dn_uses;
+    outer_dn->dn_uses = dn->dn_uses;
+    dn->dn_uses = nullptr;
+}
+
 /*
  * Beware: this function is called for functions nested in other functions or
  * global scripts but not for functions compiled through the Function
@@ -1364,28 +1381,10 @@ Parser::leaveFunction(ParseNode *fn, ParseContextisLet() &&
-                        (bodyLevelHoistedUse ||
-                         IsNonDominatingInScopedSwitch(outerpc, name, outer_dn)))
-                    {
-                        while (true) {
-                            pnu->pn_dflags |= PND_LET;
-                            if (!pnu->pn_link)
-                                break;
-                            pnu = pnu->pn_link;
-                        }
-                        pnu = dn->dn_uses;
-                    }
-
-                    while (true) {
-                        pnu->pn_lexdef = outer_dn;
-                        if (!pnu->pn_link)
-                            break;
-                        pnu = pnu->pn_link;
-                    }
-                    pnu->pn_link = outer_dn->dn_uses;
-                    outer_dn->dn_uses = dn->dn_uses;
-                    dn->dn_uses = nullptr;
+                    bool markUsesAsLet = outer_dn->isLet() &&
+                                         (bodyLevelHoistedUse ||
+                                          IsNonDominatingInScopedSwitch(outerpc, name, outer_dn));
+                    AssociateUsesWithOuterDefinition(pnu, dn, outer_dn, markUsesAsLet);
                 }
 
                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;

From 6829088302c1fcf43a4139bd2c77d7e4d92b5d6e Mon Sep 17 00:00:00 2001
From: Shu-yu Guo 
Date: Wed, 15 Oct 2014 18:33:48 -0700
Subject: [PATCH 062/100] Bug 1077949 - Followup: explicitly cast nullptr to
 work around GCC. (r=bustage)

---
 js/src/frontend/Parser.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 29e67c375e87..0bdc72b83eb0 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1259,7 +1259,7 @@ IsNonDominatingInScopedSwitch(ParseContext *pc, HandleAtom nam
                               Definition *dn)
 {
     MOZ_ASSERT(dn->isLet());
-    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, nullptr);
+    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
     if (stmt && stmt->type == STMT_SWITCH)
         return dn->pn_cookie.slot() < stmt->firstDominatingLexicalInCase;
     return false;

From 29facae35b9b2853affb08753526a27b51aa6197 Mon Sep 17 00:00:00 2001
From: Christoph Kerschbaumer 
Date: Wed, 15 Oct 2014 19:11:45 -0700
Subject: [PATCH 063/100] Bug 1041180: Remove deprecated nsIChannelPolicy
 (r=sstamm,jduell,jst)

---
 content/base/src/EventSource.cpp              | 15 +-----
 content/base/src/ImportManager.cpp            | 12 -----
 content/base/src/moz.build                    |  1 -
 content/base/src/nsCSPContext.cpp             |  3 --
 content/base/src/nsCSPService.cpp             |  5 --
 content/base/src/nsChannelPolicy.cpp          | 46 ------------------
 content/base/src/nsChannelPolicy.h            | 37 --------------
 content/base/src/nsContentUtils.cpp           | 17 -------
 content/base/src/nsCrossSiteListenerProxy.cpp |  2 -
 content/base/src/nsDocument.cpp               |  1 -
 content/base/src/nsObjectLoadingContent.cpp   | 12 -----
 content/base/src/nsScriptLoader.cpp           | 15 ------
 content/base/src/nsSyncLoadService.cpp        |  1 -
 content/base/src/nsXMLHttpRequest.cpp         | 15 ------
 content/html/content/src/HTMLMediaElement.cpp | 15 ------
 content/html/content/src/HTMLTrackElement.cpp | 16 -------
 content/html/document/src/nsHTMLDocument.cpp  |  1 -
 content/media/MediaResource.cpp               |  2 -
 content/xul/document/src/XULDocument.cpp      |  1 -
 docshell/base/nsDocShell.cpp                  | 22 ---------
 dom/base/Navigator.cpp                        | 18 +------
 dom/plugins/base/nsPluginHost.cpp             |  1 -
 .../base/nsPluginStreamListenerPeer.cpp       |  1 -
 dom/workers/ScriptLoader.cpp                  | 21 --------
 dom/xbl/nsXBLService.cpp                      |  1 -
 dom/xml/XMLDocument.cpp                       |  1 -
 dom/xslt/base/txURIUtils.cpp                  |  1 -
 dom/xslt/xslt/txMozillaStylesheetCompiler.cpp |  1 -
 embedding/browser/nsContextMenuInfo.cpp       | 20 ++------
 .../webbrowserpersist/nsWebBrowserPersist.cpp |  1 -
 .../pref/autoconfig/src/nsAutoConfig.cpp      |  1 -
 image/public/imgILoader.idl                   |  6 +--
 image/src/imgLoader.cpp                       | 48 +++++++++----------
 image/src/imgLoader.h                         |  4 --
 image/test/unit/async_load_tests.js           |  6 +--
 image/test/unit/test_private_channel.js       |  2 +-
 js/xpconnect/loader/mozJSSubScriptLoader.cpp  |  1 -
 layout/build/nsLayoutModule.cpp               |  5 --
 layout/generic/nsImageFrame.cpp               |  1 -
 layout/style/FontFaceSet.cpp                  | 26 +---------
 layout/style/Loader.cpp                       | 12 -----
 modules/libjar/nsJARChannel.cpp               |  1 -
 netwerk/base/public/moz.build                 |  3 --
 netwerk/base/public/nsChannelProperties.h     | 35 --------------
 netwerk/base/public/nsIChannelPolicy.idl      | 29 -----------
 netwerk/base/public/nsNetStrings.h            | 24 ----------
 netwerk/base/public/nsNetUtil.h               | 20 --------
 netwerk/base/src/moz.build                    |  1 -
 netwerk/base/src/nsIncrementalDownload.cpp    |  1 -
 netwerk/base/src/nsNetStrings.cpp             | 14 ------
 netwerk/build/nsNetModule.cpp                 |  9 +---
 netwerk/protocol/ftp/FTPChannelParent.cpp     |  1 -
 netwerk/protocol/http/HttpChannelParent.cpp   |  1 -
 .../protocol/wyciwyg/WyciwygChannelParent.cpp |  1 -
 netwerk/test/TestPageLoad.cpp                 |  2 -
 netwerk/test/TestProtocols.cpp                |  2 -
 .../downloads/nsDownloadManager.cpp           |  1 -
 .../nsUrlClassifierStreamUpdater.cpp          |  1 -
 .../exthandler/nsExternalHelperAppService.cpp |  1 -
 uriloader/prefetch/nsOfflineCacheUpdate.cpp   |  2 -
 uriloader/prefetch/nsPrefetchService.cpp      |  1 -
 widget/cocoa/OSXNotificationCenter.mm         |  2 +-
 widget/cocoa/nsMenuItemIconX.mm               |  6 +--
 widget/windows/nsDataObj.cpp                  |  1 -
 .../directory/nsDirectoryViewer.cpp           |  1 -
 65 files changed, 38 insertions(+), 539 deletions(-)
 delete mode 100644 content/base/src/nsChannelPolicy.cpp
 delete mode 100644 content/base/src/nsChannelPolicy.h
 delete mode 100644 netwerk/base/public/nsChannelProperties.h
 delete mode 100644 netwerk/base/public/nsIChannelPolicy.idl
 delete mode 100644 netwerk/base/public/nsNetStrings.h
 delete mode 100644 netwerk/base/src/nsNetStrings.cpp

diff --git a/content/base/src/EventSource.cpp b/content/base/src/EventSource.cpp
index 47be79f75366..610b29be2780 100644
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -27,7 +27,6 @@
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIScriptError.h"
 #include "mozilla/dom/EncodingUtils.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
@@ -737,17 +736,7 @@ EventSource::InitChannelAndRequestEventSource()
   nsLoadFlags loadFlags;
   loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE;
 
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  nsresult rv = mPrincipal->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_DATAREQUEST);
-  }
-
+  nsresult rv;
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr doc =
     nsContentUtils::GetDocumentFromScriptContext(sc);
@@ -760,7 +749,6 @@ EventSource::InitChannelAndRequestEventSource()
                        doc,
                        nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                        nsIContentPolicy::TYPE_DATAREQUEST,
-                       channelPolicy,    // aChannelPolicy
                        mLoadGroup,       // loadGroup
                        nullptr,          // aCallbacks
                        loadFlags);       // aLoadFlags
@@ -771,7 +759,6 @@ EventSource::InitChannelAndRequestEventSource()
                        mPrincipal,
                        nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                        nsIContentPolicy::TYPE_DATAREQUEST,
-                       channelPolicy,    // aChannelPolicy
                        mLoadGroup,       // loadGroup
                        nullptr,          // aCallbacks
                        loadFlags);       // aLoadFlags
diff --git a/content/base/src/ImportManager.cpp b/content/base/src/ImportManager.cpp
index da7645d538cf..918bae5184a9 100644
--- a/content/base/src/ImportManager.cpp
+++ b/content/base/src/ImportManager.cpp
@@ -12,7 +12,6 @@
 #include "nsContentUtils.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsIChannel.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocument.h"
@@ -485,23 +484,12 @@ ImportLoader::Open()
   NS_ENSURE_SUCCESS_VOID(rv);
 
   nsCOMPtr loadGroup = master->GetDocumentLoadGroup();
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = principal->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS_VOID(rv);
-
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
-  }
   nsCOMPtr channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      mURI,
                      mImportParent,
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_SUBDOCUMENT,
-                     channelPolicy,
                      loadGroup,
                      nullptr,  // aCallbacks
                      nsIRequest::LOAD_BACKGROUND);
diff --git a/content/base/src/moz.build b/content/base/src/moz.build
index 7090ecf7b4da..849e9448b328 100644
--- a/content/base/src/moz.build
+++ b/content/base/src/moz.build
@@ -112,7 +112,6 @@ UNIFIED_SOURCES += [
     'nsAttrValue.cpp',
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
-    'nsChannelPolicy.cpp',
     'nsContentAreaDragDrop.cpp',
     'nsContentIterator.cpp',
     'nsContentList.cpp',
diff --git a/content/base/src/nsCSPContext.cpp b/content/base/src/nsCSPContext.cpp
index ccbb2fdd8464..657fe992012f 100644
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -11,7 +11,6 @@
 #include "nsCSPService.h"
 #include "nsError.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
-#include "nsIChannelPolicy.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
@@ -25,12 +24,10 @@
 #include "nsIObjectOutputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIPropertyBag2.h"
 #include "nsIStringStream.h"
 #include "nsIUploadChannel.h"
 #include "nsIScriptError.h"
 #include "nsIWebNavigation.h"
-#include "nsIWritablePropertyBag2.h"
 #include "nsNetUtil.h"
 #include "nsNullPrincipal.h"
 #include "nsIContentPolicy.h"
diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp
index d872851c23df..64e1a8dcd7ed 100644
--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -12,12 +12,7 @@
 #include "nsIContent.h"
 #include "nsCSPService.h"
 #include "nsIContentSecurityPolicy.h"
-#include "nsIChannelPolicy.h"
-#include "nsIChannelEventSink.h"
-#include "nsIPropertyBag2.h"
-#include "nsIWritablePropertyBag2.h"
 #include "nsError.h"
-#include "nsChannelProperties.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "mozilla/Preferences.h"
diff --git a/content/base/src/nsChannelPolicy.cpp b/content/base/src/nsChannelPolicy.cpp
deleted file mode 100644
index 7d647695bbe6..000000000000
--- a/content/base/src/nsChannelPolicy.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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 "nsChannelPolicy.h"
-
-nsChannelPolicy::nsChannelPolicy()
-  : mLoadType(0)
-{
-}
-
-nsChannelPolicy::~nsChannelPolicy()
-{
-}
-
-NS_IMPL_ISUPPORTS(nsChannelPolicy, nsIChannelPolicy)
-
-NS_IMETHODIMP
-nsChannelPolicy::GetLoadType(uint32_t *aLoadType)
-{
-    *aLoadType = mLoadType;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsChannelPolicy::SetLoadType(uint32_t aLoadType)
-{
-    mLoadType = aLoadType;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsChannelPolicy::GetContentSecurityPolicy(nsISupports **aCSP)
-{
-    *aCSP = mCSP;
-    NS_IF_ADDREF(*aCSP);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsChannelPolicy::SetContentSecurityPolicy(nsISupports *aCSP)
-{
-    mCSP = aCSP;
-    return NS_OK;
-}
diff --git a/content/base/src/nsChannelPolicy.h b/content/base/src/nsChannelPolicy.h
deleted file mode 100644
index f5a0ba29f0e0..000000000000
--- a/content/base/src/nsChannelPolicy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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 nsChannelPolicy_h___
-#define nsChannelPolicy_h___
-
-#include "nsCOMPtr.h"
-#include "nsIChannelPolicy.h"
-
-#define NSCHANNELPOLICY_CONTRACTID "@mozilla.org/nschannelpolicy;1"
-#define NSCHANNELPOLICY_CID \
-{ 0xd396b3cd, 0xf164, 0x4ce8, \
-  { 0x93, 0xa7, 0xe3, 0x85, 0xe1, 0x46, 0x56, 0x3c } }
-
-class nsChannelPolicy : public nsIChannelPolicy
-{
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICHANNELPOLICY
-
-    nsChannelPolicy();
-
-protected:
-    virtual ~nsChannelPolicy();
-
-    /* Represents the type of content being loaded in the channel per
-     * nsIContentPolicy, e.g. TYPE_IMAGE, TYPE_SCRIPT
-     */
-    unsigned long mLoadType;
-
-    /* pointer to a Content Security Policy object if available */
-    nsCOMPtr mCSP;
-};
-
-#endif /* nsChannelPolicy_h___ */
diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
index 63f541df96c4..38ec950eccf2 100644
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -59,7 +59,6 @@
 #include "nsAttrValueInlines.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
-#include "nsChannelPolicy.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsCOMPtr.h"
 #include "nsContentCreatorFunctions.h"
@@ -88,7 +87,6 @@
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsICategoryManager.h"
 #include "nsIChannelEventSink.h"
-#include "nsIChannelPolicy.h"
 #include "nsICharsetDetectionObserver.h"
 #include "nsIChromeRegistry.h"
 #include "nsIConsoleService.h"
@@ -3007,20 +3005,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
   NS_ASSERTION(loadGroup || IsFontTableURI(documentURI),
                "Could not get loadgroup; onload may fire too early");
 
-  // check for a Content Security Policy to pass down to the channel that
-  // will get created to load the image
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  if (aLoadingPrincipal) {
-    nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (csp) {
-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-      channelPolicy->SetContentSecurityPolicy(csp);
-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
-    }
-  }
-    
   // Make the URI immutable so people won't change it under us
   NS_TryToSetImmutable(aURI);
 
@@ -3035,7 +3019,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
                               aLoadingDocument,     /* uniquification key */
                               aLoadFlags,           /* load flags */
                               nullptr,               /* cache key */
-                              channelPolicy,        /* CSP info */
                               initiatorType,        /* the load initiator */
                               aRequest);
 }
diff --git a/content/base/src/nsCrossSiteListenerProxy.cpp b/content/base/src/nsCrossSiteListenerProxy.cpp
index 6a2ea5122a4c..582b6336c82d 100644
--- a/content/base/src/nsCrossSiteListenerProxy.cpp
+++ b/content/base/src/nsCrossSiteListenerProxy.cpp
@@ -1122,7 +1122,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
     rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel),
                                uri,
                                loadInfo,
-                               nullptr,   // aChannelPolicy
                                loadGroup,
                                nullptr,   // aCallbacks
                                loadFlags);
@@ -1134,7 +1133,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                                nsContentUtils::GetSystemPrincipal(),
                                nsILoadInfo::SEC_NORMAL,
                                nsIContentPolicy::TYPE_OTHER,
-                               nullptr,   // aChannelPolicy
                                loadGroup,
                                nullptr,   // aCallbacks
                                loadFlags);
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index 7962fc23da08..9d06af8500b4 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1330,7 +1330,6 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
                      aRequestingNode,
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr, // aChannelPolicy
                      loadGroup,
                      req); // aCallbacks
 
diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp
index 967592658350..781f53efe32f 100644
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -65,8 +65,6 @@
 #include "nsObjectLoadingContent.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIContentSecurityPolicy.h"
-#include "nsIChannelPolicy.h"
-#include "nsChannelPolicy.h"
 #include "GeckoProfiler.h"
 #include "nsPluginFrame.h"
 #include "nsDOMClassInfo.h"
@@ -2492,15 +2490,6 @@ nsObjectLoadingContent::OpenChannel()
 
   nsCOMPtr group = doc->GetDocumentLoadGroup();
   nsCOMPtr chan;
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT);
-  }
   nsRefPtr shim =
     new ObjectInterfaceRequestorShim(this);
 
@@ -2522,7 +2511,6 @@ nsObjectLoadingContent::OpenChannel()
                      thisContent,
                      securityFlags,
                      nsIContentPolicy::TYPE_OBJECT,
-                     channelPolicy,
                      group, // aLoadGroup
                      shim,  // aCallbacks
                      nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp
index 53cbbef24e22..7b730948be76 100644
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -41,8 +41,6 @@
 #include "nsDocShellCID.h"
 #include "nsIContentSecurityPolicy.h"
 #include "prlog.h"
-#include "nsIChannelPolicy.h"
-#include "nsChannelPolicy.h"
 #include "nsCRT.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsCrossSiteListenerProxy.h"
@@ -307,25 +305,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
     return NS_OK;
   }
 
-  // check for a Content Security Policy to pass down to the channel
-  // that will be created to load the script
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
-  }
-
   nsCOMPtr channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      aRequest->mURI,
                      mDocument,
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_SCRIPT,
-                     channelPolicy,
                      loadGroup,
                      prompter,
                      nsIRequest::LOAD_NORMAL |
diff --git a/content/base/src/nsSyncLoadService.cpp b/content/base/src/nsSyncLoadService.cpp
index 3a675e1a8d6e..6805aca44df9 100644
--- a/content/base/src/nsSyncLoadService.cpp
+++ b/content/base/src/nsSyncLoadService.cpp
@@ -315,7 +315,6 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal,
                                 aLoaderPrincipal,
                                 nsILoadInfo::SEC_NORMAL,
                                 nsIContentPolicy::TYPE_OTHER,
-                                nullptr,   // aChannelPolicy
                                 aLoadGroup);
     NS_ENSURE_SUCCESS(rv, rv);
 
diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp
index 3a8f39e018f1..6d1aa993538f 100644
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -52,8 +52,6 @@
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsIConsoleService.h"
-#include "nsIChannelPolicy.h"
-#include "nsChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsStringBuffer.h"
@@ -1732,17 +1730,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
   // will be automatically aborted if the user leaves the page.
   nsCOMPtr loadGroup = GetLoadGroup();
 
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = mPrincipal->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_XMLHTTPREQUEST);
-  }
-
   nsSecurityFlags secFlags = nsILoadInfo::SEC_NORMAL;
   if (IsSystemXHR()) {
     // Don't give this document the system principal.  We need to keep track of
@@ -1762,7 +1749,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
                        doc,
                        secFlags,
                        nsIContentPolicy::TYPE_XMLHTTPREQUEST,
-                       channelPolicy,
                        loadGroup,
                        nullptr,   // aCallbacks
                        nsIRequest::LOAD_BACKGROUND);
@@ -1773,7 +1759,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
                        mPrincipal,
                        secFlags,
                        nsIContentPolicy::TYPE_XMLHTTPREQUEST,
-                       channelPolicy,
                        loadGroup,
                        nullptr,   // aCallbacks
                        nsIRequest::LOAD_BACKGROUND);
diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp
index 9b916fbc202d..171861002c66 100755
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -99,8 +99,6 @@ static PRLogModuleInfo* gMediaElementEventsLog;
 #endif
 
 #include "nsIContentSecurityPolicy.h"
-#include "nsIChannelPolicy.h"
-#include "nsChannelPolicy.h"
 
 #include "mozilla/Preferences.h"
 
@@ -1170,25 +1168,12 @@ nsresult HTMLMediaElement::LoadResource()
   }
 
   nsCOMPtr loadGroup = GetDocumentLoadGroup();
-
-  // check for a Content Security Policy to pass down to the channel
-  // created to load the media content
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv,rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
-  }
   nsCOMPtr channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      mLoadingSrc,
                      static_cast(this),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_MEDIA,
-                     channelPolicy,
                      loadGroup,
                      nullptr,   // aCallbacks
                      nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
diff --git a/content/html/content/src/HTMLTrackElement.cpp b/content/html/content/src/HTMLTrackElement.cpp
index 5c21c4cc6f59..db01a4d5608c 100644
--- a/content/html/content/src/HTMLTrackElement.cpp
+++ b/content/html/content/src/HTMLTrackElement.cpp
@@ -21,7 +21,6 @@
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsICachingChannel.h"
 #include "nsIChannelEventSink.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocument.h"
@@ -237,20 +236,6 @@ HTMLTrackElement::LoadResource()
     CreateTextTrack();
   }
 
-  // Check for a Content Security Policy to pass down to the channel
-  // created to load the media content.
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    if (!channelPolicy) {
-      return;
-    }
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
-  }
   nsCOMPtr channel;
   nsCOMPtr loadGroup = OwnerDoc()->GetDocumentLoadGroup();
   rv = NS_NewChannel(getter_AddRefs(channel),
@@ -258,7 +243,6 @@ HTMLTrackElement::LoadResource()
                      static_cast(this),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_MEDIA,
-                     channelPolicy,
                      loadGroup);
 
   NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index d03ca06535f2..72d890366858 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1516,7 +1516,6 @@ nsHTMLDocument::Open(JSContext* cx,
                      callerDoc,
                      nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,   // aChannelPolicy
                      group);
 
   if (rv.Failed()) {
diff --git a/content/media/MediaResource.cpp b/content/media/MediaResource.cpp
index 194734fc68fa..b73fbddc4899 100644
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -924,7 +924,6 @@ ChannelMediaResource::RecreateChannel()
                               element,
                               nsILoadInfo::SEC_NORMAL,
                               nsIContentPolicy::TYPE_MEDIA,
-                              nullptr,   // aChannelPolicy
                               loadGroup,
                               nullptr,  // aCallbacks
                               loadFlags);
@@ -1442,7 +1441,6 @@ already_AddRefed FileMediaResource::CloneData(MediaDecoder* aDeco
                   element,
                   nsILoadInfo::SEC_NORMAL,
                   nsIContentPolicy::TYPE_MEDIA,
-                  nullptr,   // aChannelPolicy
                   loadGroup);
 
   if (NS_FAILED(rv))
diff --git a/content/xul/document/src/XULDocument.cpp b/content/xul/document/src/XULDocument.cpp
index 1c873a4c9f85..a31a93385c0d 100644
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -2702,7 +2702,6 @@ XULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
                            NodePrincipal(),
                            nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                            nsIContentPolicy::TYPE_OTHER,
-                           nullptr,    // aChannelPolicy
                            group);
 
         if (NS_SUCCEEDED(rv)) {
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 7cae031b1824..d218f4810825 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -168,7 +168,6 @@
 #endif
 
 #include "nsContentUtils.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsILoadInfo.h"
 #include "nsSandboxFlags.h"
@@ -10158,27 +10157,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
         loadFlags |= nsIChannel::LOAD_BACKGROUND;
     }
 
-    // check for Content Security Policy to pass along with the
-    // new channel we are creating
-    nsCOMPtr channelPolicy;
     if (IsFrame()) {
-        // check the parent docshell for a CSP
-        nsCOMPtr csp;
-        nsCOMPtr parentItem;
-        GetSameTypeParent(getter_AddRefs(parentItem));
-        if (parentItem) {
-          nsCOMPtr doc = parentItem->GetDocument();
-          if (doc) {
-            rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-            NS_ENSURE_SUCCESS(rv, rv);
-            if (csp) {
-              channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-              channelPolicy->SetContentSecurityPolicy(csp);
-              channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
-            }
-          }
-        }
-
         // Only allow view-source scheme in top-level docshells. view-source is
         // the only scheme to which this applies at the moment due to potential
         // timing attacks to read data from cross-origin iframes. If this widens
@@ -10247,7 +10226,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
                                    requestingPrincipal,
                                    securityFlags,
                                    aContentPolicyType,
-                                   channelPolicy,
                                    nullptr,   // loadGroup
                                    static_cast(this),
                                    loadFlags);
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index 1e1cfe7fedb6..3ef0cc9dc98b 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -67,7 +67,6 @@
 #include "mozIApplication.h"
 #include "WidgetUtils.h"
 #include "mozIThirdPartyUtil.h"
-#include "nsChannelPolicy.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "MediaManager.h"
@@ -1056,26 +1055,11 @@ Navigator::SendBeacon(const nsAString& aUrl,
   }
 
   nsCOMPtr channel;
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = principal->GetCsp(getter_AddRefs(csp));
-  if (NS_FAILED(rv)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return false;
-  }
-
-  if (csp) {
-    channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID);
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON);
-  }
-
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      doc,
                      nsILoadInfo::SEC_NORMAL,
-                     nsIContentPolicy::TYPE_BEACON,
-                     channelPolicy);
+                     nsIContentPolicy::TYPE_BEACON);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
index d8fc59477428..ec70c22afa0c 100644
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -2857,7 +2857,6 @@ nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
                              principal,
                              nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                              nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
-                             nullptr,  // aChannelPolicy
                              nullptr,  // aLoadGroup 
                              listenerPeer);
 
diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
index 54f2afb92a0a..ab00a1d97216 100644
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -662,7 +662,6 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
                              principal,
                              nsILoadInfo::SEC_NORMAL,
                              nsIContentPolicy::TYPE_OTHER,
-                             nullptr,   // aChannelPolicy
                              loadGroup,
                              callbacks);
 
diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp
index c4f6aa37c082..1f4b4b6841b8 100644
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -6,7 +6,6 @@
 #include "ScriptLoader.h"
 
 #include "nsIChannel.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIHttpChannel.h"
@@ -17,7 +16,6 @@
 #include "nsIURI.h"
 
 #include "jsapi.h"
-#include "nsChannelPolicy.h"
 #include "nsError.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
@@ -104,23 +102,6 @@ ChannelFromScriptURL(nsIPrincipal* principal,
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
   }
 
-  // Get Content Security Policy from parent document to pass into channel.
-  nsCOMPtr csp;
-  rv = principal->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr channelPolicy;
-  if (csp) {
-    channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = channelPolicy->SetContentSecurityPolicy(csp);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   uint32_t flags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
 
   nsCOMPtr channel;
@@ -131,7 +112,6 @@ ChannelFromScriptURL(nsIPrincipal* principal,
                        parentDoc,
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_SCRIPT,
-                       channelPolicy,
                        loadGroup,
                        nullptr, // aCallbacks
                        flags,
@@ -148,7 +128,6 @@ ChannelFromScriptURL(nsIPrincipal* principal,
                        nullPrincipal,
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_SCRIPT,
-                       channelPolicy,
                        loadGroup,
                        nullptr, // aCallbacks
                        flags,
diff --git a/dom/xbl/nsXBLService.cpp b/dom/xbl/nsXBLService.cpp
index 22d2b07d370b..eac4d6c9fa03 100644
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1076,7 +1076,6 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
                              requestingPrincipal,
                              nsILoadInfo::SEC_NORMAL,
                              nsIContentPolicy::TYPE_OTHER,
-                             nullptr,   // aChannelPolicy
                              loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
diff --git a/dom/xml/XMLDocument.cpp b/dom/xml/XMLDocument.cpp
index ebd093a5f548..2d1bc1d20974 100644
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -449,7 +449,6 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
                                   static_cast(this),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_XMLHTTPREQUEST,
-                     nullptr,   // aChannelPolicy
                      loadGroup,
                      req,
                      nsIRequest::LOAD_BACKGROUND);
diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp
index ebcc484d21d6..b2a78db2e47d 100644
--- a/dom/xslt/base/txURIUtils.cpp
+++ b/dom/xslt/base/txURIUtils.cpp
@@ -64,7 +64,6 @@ URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode)
                                     sourceDoc,
                                     nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                                     nsIContentPolicy::TYPE_OTHER,
-                                    nullptr,   // aChannelPolicy
                                     loadGroup);
 
         if (NS_FAILED(rv)) {
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
index ec313edf974f..30f9b1f68aa0 100644
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -465,7 +465,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
                                 aReferrerPrincipal,
                                 nsILoadInfo::SEC_NORMAL,
                                 nsIContentPolicy::TYPE_STYLESHEET,
-                                nullptr,
                                 loadGroup);
 
     NS_ENSURE_SUCCESS(rv, rv);
diff --git a/embedding/browser/nsContextMenuInfo.cpp b/embedding/browser/nsContextMenuInfo.cpp
index 6a15401444b2..0b4733071c0b 100644
--- a/embedding/browser/nsContextMenuInfo.cpp
+++ b/embedding/browser/nsContextMenuInfo.cpp
@@ -23,7 +23,6 @@
 #include "nsUnicharUtils.h"
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentPolicy.h"
 #include "nsAutoPtr.h"
@@ -268,22 +267,9 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRe
   nsCOMPtr primitiveValue;
   nsAutoString bgStringValue;
 
-  // get Content Security Policy to pass to LoadImage
   nsCOMPtr doc(do_QueryInterface(document));
-  nsCOMPtr principal;
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  if (doc) {
-    principal = doc->NodePrincipal();
-    nsresult rv = principal->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (csp) {
-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-      channelPolicy->SetContentSecurityPolicy(csp);
-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
-    }
-  }
-  
+  nsCOMPtr principal = doc ? doc->NodePrincipal() : nullptr;
+
   while (true) {
     nsCOMPtr domElement(do_QueryInterface(domNode));
     // bail for the parent node of the root element or null argument
@@ -310,7 +296,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRe
 
           return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,
                                nullptr, nullptr, nsIRequest::LOAD_NORMAL,
-                               nullptr, channelPolicy, EmptyString(), aRequest);
+                               nullptr, EmptyString(), aRequest);
         }
       }
 
diff --git a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
index cbfef03aa9fa..dad12ded7f69 100644
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1205,7 +1205,6 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // aLoadGroup
                        static_cast(this),
                        loadFlags);
diff --git a/extensions/pref/autoconfig/src/nsAutoConfig.cpp b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
index 0ee2e3fbc8b2..63368902dfc7 100644
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -281,7 +281,6 @@ nsresult nsAutoConfig::downloadAutoConfig()
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // loadGroup
                        nullptr,  // aCallbacks
                        nsIRequest::INHIBIT_PERSISTENT_CACHING |
diff --git a/image/public/imgILoader.idl b/image/public/imgILoader.idl
index cf751632aae7..491eda22ae63 100644
--- a/image/public/imgILoader.idl
+++ b/image/public/imgILoader.idl
@@ -16,7 +16,6 @@ interface nsIStreamListener;
 interface nsIURI;
 
 interface nsISimpleEnumerator;
-interface nsIChannelPolicy;
 
 #include "nsIRequest.idl" // for nsLoadFlags
 
@@ -27,7 +26,7 @@ interface nsIChannelPolicy;
  * @version 0.3
  * @see imagelib2
  */
-[scriptable, builtinclass, uuid(c8126129-8dac-43cd-b1ba-3896fba2dd01)]
+[scriptable, builtinclass, uuid(046d5fa6-ac59-489d-b51e-0ffe57e8df59)]
 interface imgILoader : nsISupports
 {
   // Extra flags to pass to loadImage if you want a load to use CORS
@@ -62,8 +61,7 @@ interface imgILoader : nsISupports
                              in imgINotificationObserver aObserver,
                              in nsISupports aCX,
                              in nsLoadFlags aLoadFlags,
-                             in nsISupports cacheKey,
-                             in nsIChannelPolicy channelPolicy);
+                             in nsISupports cacheKey);
 
   /**
    * Start the load and decode of an image.
diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
index 0ac8d497a9dc..a96e00796d4c 100644
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -635,7 +635,6 @@ static nsresult NewImageChannel(nsIChannel **aResult,
                                 nsILoadGroup *aLoadGroup,
                                 const nsCString& aAcceptHeader,
                                 nsLoadFlags aLoadFlags,
-                                nsIChannelPolicy *aPolicy,
                                 nsIPrincipal *aLoadingPrincipal,
                                 nsISupports *aRequestingContext)
 {
@@ -691,7 +690,6 @@ static nsresult NewImageChannel(nsIChannel **aResult,
                              requestingPrincipal,
                              securityFlags,
                              nsIContentPolicy::TYPE_IMAGE,
-                             aPolicy,
                              nullptr,   // loadGroup
                              callbacks,
                              aLoadFlags);
@@ -1445,7 +1443,6 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
                                                 nsISupports *aCX,
                                                 nsLoadFlags aLoadFlags,
                                                 imgRequestProxy **aProxyRequest,
-                                                nsIChannelPolicy *aPolicy,
                                                 nsIPrincipal* aLoadingPrincipal,
                                                 int32_t aCORSMode)
 {
@@ -1493,7 +1490,6 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
                          aLoadGroup,
                          mAcceptHeader,
                          aLoadFlags,
-                         aPolicy,
                          aLoadingPrincipal,
                          aCX);
     if (NS_FAILED(rv)) {
@@ -1573,7 +1569,6 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
                                 nsLoadFlags aLoadFlags,
                                 bool aCanMakeNewChannel,
                                 imgRequestProxy **aProxyRequest,
-                                nsIChannelPolicy *aPolicy,
                                 nsIPrincipal* aLoadingPrincipal,
                                 int32_t aCORSMode)
 {
@@ -1678,7 +1673,7 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
 
     return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
                                          aReferrerURI, aLoadGroup, aObserver,
-                                         aCX, aLoadFlags, aProxyRequest, aPolicy,
+                                         aCX, aLoadFlags, aProxyRequest,
                                          aLoadingPrincipal, aCORSMode);
   }
 
@@ -1853,7 +1848,6 @@ NS_IMETHODIMP imgLoader::LoadImageXPCOM(nsIURI *aURI,
                                    nsISupports *aCX,
                                    nsLoadFlags aLoadFlags,
                                    nsISupports *aCacheKey,
-                                   nsIChannelPolicy *aPolicy,
                                    imgIRequest **_retval)
 {
     imgRequestProxy *proxy;
@@ -1866,29 +1860,32 @@ NS_IMETHODIMP imgLoader::LoadImageXPCOM(nsIURI *aURI,
                                 aCX,
                                 aLoadFlags,
                                 aCacheKey,
-                                aPolicy,
                                 EmptyString(),
                                 &proxy);
     *_retval = proxy;
     return result;
 }
 
-
-
-/* imgIRequest loadImage(in nsIURI aURI, in nsIURI aInitialDocumentURL, in nsIURI aReferrerURI, in nsIPrincipal aLoadingPrincipal, in nsILoadGroup aLoadGroup, in imgINotificationObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in nsIChannelPolicy channelPolicy); */
-
+// imgIRequest loadImage(in nsIURI aURI,
+//                       in nsIURI aInitialDocumentURL,
+//                       in nsIURI aReferrerURI,
+//                       in nsIPrincipal aLoadingPrincipal,
+//                       in nsILoadGroup aLoadGroup,
+//                       in imgINotificationObserver aObserver,
+//                       in nsISupports aCX,
+//                       in nsLoadFlags aLoadFlags,
+//                       in nsISupports cacheKey);
 nsresult imgLoader::LoadImage(nsIURI *aURI,
-			      nsIURI *aInitialDocumentURI,
-			      nsIURI *aReferrerURI,
-			      nsIPrincipal* aLoadingPrincipal,
-			      nsILoadGroup *aLoadGroup,
-			      imgINotificationObserver *aObserver,
-			      nsISupports *aCX,
-			      nsLoadFlags aLoadFlags,
-			      nsISupports *aCacheKey,
-			      nsIChannelPolicy *aPolicy,
-			      const nsAString& initiatorType,
-			      imgRequestProxy **_retval)
+                              nsIURI *aInitialDocumentURI,
+                              nsIURI *aReferrerURI,
+                              nsIPrincipal* aLoadingPrincipal,
+                              nsILoadGroup *aLoadGroup,
+                              imgINotificationObserver *aObserver,
+                              nsISupports *aCX,
+                              nsLoadFlags aLoadFlags,
+                              nsISupports *aCacheKey,
+                              const nsAString& initiatorType,
+                              imgRequestProxy **_retval)
 {
 	VerifyCacheSizes();
 
@@ -1966,7 +1963,7 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
   if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
     if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
                       aLoadGroup, aObserver, aCX, requestFlags, true,
-                      _retval, aPolicy, aLoadingPrincipal, corsmode)) {
+                      _retval, aLoadingPrincipal, corsmode)) {
       request = entry->GetRequest();
 
       // If this entry has no proxies, its request has no reference to the entry.
@@ -2008,7 +2005,6 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
                          aLoadGroup,
                          mAcceptHeader,
                          requestFlags,
-                         aPolicy,
                          aLoadingPrincipal,
                          aCX);
     if (NS_FAILED(rv))
@@ -2192,7 +2188,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel *channel, imgINotificationOb
       // XXX -- should this be changed? it's pretty much verbatim from the old
       // code, but seems nonsensical.
       if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver, aCX,
-                        requestFlags, false, nullptr, nullptr, nullptr,
+                        requestFlags, false, nullptr, nullptr,
                         imgIRequest::CORS_NONE)) {
         request = entry->GetRequest();
       } else {
diff --git a/image/src/imgLoader.h b/image/src/imgLoader.h
index 334a3a16b260..620457651086 100644
--- a/image/src/imgLoader.h
+++ b/image/src/imgLoader.h
@@ -29,7 +29,6 @@ class imgINotificationObserver;
 class nsILoadGroup;
 class imgCacheExpirationTracker;
 class imgMemoryReporter;
-class nsIChannelPolicy;
 
 namespace mozilla {
 namespace image {
@@ -258,7 +257,6 @@ public:
                      nsISupports *aCX,
                      nsLoadFlags aLoadFlags,
                      nsISupports *aCacheKey,
-                     nsIChannelPolicy *aPolicy,
                      const nsAString& initiatorType,
                      imgRequestProxy **_retval);
   nsresult LoadImageWithChannel(nsIChannel *channel,
@@ -340,7 +338,6 @@ private: // methods
                        imgINotificationObserver *aObserver, nsISupports *aCX,
                        nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
                        imgRequestProxy **aProxyRequest,
-                       nsIChannelPolicy *aPolicy,
                        nsIPrincipal* aLoadingPrincipal,
                        int32_t aCORSMode);
 
@@ -351,7 +348,6 @@ private: // methods
                                        imgINotificationObserver *aObserver,
                                        nsISupports *aCX, nsLoadFlags aLoadFlags,
                                        imgRequestProxy **aProxyRequest,
-                                       nsIChannelPolicy *aPolicy,
                                        nsIPrincipal* aLoadingPrincipal,
                                        int32_t aCORSMode);
 
diff --git a/image/test/unit/async_load_tests.js b/image/test/unit/async_load_tests.js
index 970ae812ee86..c4cdcd0730c0 100644
--- a/image/test/unit/async_load_tests.js
+++ b/image/test/unit/async_load_tests.js
@@ -96,7 +96,7 @@ function checkSecondLoad()
   var listener = new ImageListener(checkClone, secondLoadDone);
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                 .createScriptedObserver(listener);
-  requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null));
+  requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null));
   listener.synchronous = false;
 }
 
@@ -194,7 +194,7 @@ function startImageCallback(otherCb)
     var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); });
     var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                   .createScriptedObserver(listener2);
-    requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null));
+    requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null));
     listener2.synchronous = false;
 
     // Now that we've started another load, chain to the callback.
@@ -221,7 +221,7 @@ function run_test()
   var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone);
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                 .createScriptedObserver(listener);
-  var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null);
+  var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null);
   requests.push(req);
 
   // Ensure that we don't cause any mayhem when we lock an image.
diff --git a/image/test/unit/test_private_channel.js b/image/test/unit/test_private_channel.js
index 36aa8ee784c5..318dece2afa1 100644
--- a/image/test/unit/test_private_channel.js
+++ b/image/test/unit/test_private_channel.js
@@ -77,7 +77,7 @@ function loadImage(isPrivate, callback) {
   var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
   loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate);
   var loader = isPrivate ? gPrivateLoader : gPublicLoader;
-  requests.push(loader.loadImageXPCOM(uri, null, null, null, loadGroup, outer, null, 0, null, null));
+  requests.push(loader.loadImageXPCOM(uri, null, null, null, loadGroup, outer, null, 0, null));
   listener.synchronous = false;
 }
 
diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
index 2303fdaba857..2ec843d450ab 100644
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -112,7 +112,6 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // aLoadGroup
                        nullptr,  // aCallbacks
                        nsIRequest::LOAD_NORMAL,
diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp
index b5752093f264..6f9d7b6a2f33 100644
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -61,7 +61,6 @@
 #include "mozilla/dom/DOMParser.h"
 #include "nsDOMSerializer.h"
 #include "nsXMLHttpRequest.h"
-#include "nsChannelPolicy.h"
 
 // view stuff
 #include "nsContentCreatorFunctions.h"
@@ -282,7 +281,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser)
 NS_GENERIC_FACTORY_CONSTRUCTOR(Exception)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService,
                                          DOMRequestService::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManager,
@@ -748,7 +746,6 @@ NS_DEFINE_NAMED_CID(NS_EVENTLISTENERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_GLOBALMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_PARENTPROCESSMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_CHILDPROCESSMESSAGEMANAGER_CID);
-NS_DEFINE_NAMED_CID(NSCHANNELPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_SCRIPTSECURITYMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_PRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_SYSTEMPRINCIPAL_CID);
@@ -1041,7 +1038,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
   { &kNS_GLOBALMESSAGEMANAGER_CID, false, nullptr, CreateGlobalMessageManager },
   { &kNS_PARENTPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateParentMessageManager },
   { &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateChildMessageManager },
-  { &kNSCHANNELPOLICY_CID, false, nullptr, nsChannelPolicyConstructor },
   { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager },
   { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor },
   { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, nsSystemPrincipalConstructor },
@@ -1197,7 +1193,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   { NS_GLOBALMESSAGEMANAGER_CONTRACTID, &kNS_GLOBALMESSAGEMANAGER_CID },
   { NS_PARENTPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_PARENTPROCESSMESSAGEMANAGER_CID },
   { NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_CHILDPROCESSMESSAGEMANAGER_CID },
-  { NSCHANNELPOLICY_CONTRACTID, &kNSCHANNELPOLICY_CID },
   { NS_SCRIPTSECURITYMANAGER_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
   { NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
   { NS_PRINCIPAL_CONTRACTID, &kNS_PRINCIPAL_CID },
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c742c78225b0..6b67ee2d55f9 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1931,7 +1931,6 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
                        nullptr,      /* Not associated with any particular document */
                        loadFlags,
                        nullptr,
-                       nullptr,      /* channel policy not needed */
                        EmptyString(),
                        aRequest);
 }
diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp
index 1dfeb22d1fc3..8b5493ae8007 100644
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -17,7 +17,6 @@
 #include "mozilla/Preferences.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsFontFaceLoader.h"
-#include "nsIChannelPolicy.h"
 #include "nsIConsoleService.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
@@ -395,16 +394,6 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
   nsCOMPtr loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
 
   nsCOMPtr channel;
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = aUserFontEntry->GetPrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
-  }
   // Note we are calling NS_NewChannelInternal() with both a node and a
   // principal.  This is because the document where the font is being loaded
   // might have a different origin from the principal of the stylesheet
@@ -415,7 +404,6 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
                              aUserFontEntry->GetPrincipal(),
                              nsILoadInfo::SEC_NORMAL,
                              nsIContentPolicy::TYPE_FONT,
-                             channelPolicy,
                              loadGroup);
 
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1172,17 +1160,6 @@ FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
   nsresult rv;
 
   nsCOMPtr channel;
-  // get Content Security Policy from principal to pass into channel
-  nsCOMPtr channelPolicy;
-  nsCOMPtr csp;
-  rv = aFontToLoad->GetPrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
-    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-    channelPolicy->SetContentSecurityPolicy(csp);
-    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
-  }
-
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps) {
     return NS_ERROR_FAILURE;
@@ -1196,8 +1173,7 @@ FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
                              ps->GetDocument(),
                              aFontToLoad->GetPrincipal(),
                              nsILoadInfo::SEC_NORMAL,
-                             nsIContentPolicy::TYPE_FONT,
-                             channelPolicy);
+                             nsIContentPolicy::TYPE_FONT);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 5cf983df3db2..c0773ebc3555 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -60,7 +60,6 @@
 #include "nsIDOMStyleSheet.h"
 #include "nsError.h"
 
-#include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 
 #include "mozilla/dom/EncodingUtils.h"
@@ -1549,20 +1548,10 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
   mSyncCallback = true;
 #endif
   nsCOMPtr loadGroup;
-  // Content Security Policy information to pass into channel
-  nsCOMPtr channelPolicy;
   if (mDocument) {
     loadGroup = mDocument->GetDocumentLoadGroup();
     NS_ASSERTION(loadGroup,
                  "No loadgroup for stylesheet; onload will fire early");
-    nsCOMPtr csp;
-    rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (csp) {
-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
-      channelPolicy->SetContentSecurityPolicy(csp);
-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_STYLESHEET);
-    }
   }
 
   nsLoadFlags securityFlags = nsILoadInfo::SEC_NORMAL;
@@ -1581,7 +1570,6 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
                              requestingPrincipal,
                              securityFlags,
                              nsIContentPolicy::TYPE_STYLESHEET,
-                             channelPolicy,
                              loadGroup,
                              nullptr,   // aCallbacks
                              nsIChannel::LOAD_NORMAL |
diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp
index 99230e006793..c712544f2d5c 100644
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -13,7 +13,6 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIViewSourceChannel.h"
-#include "nsChannelProperties.h"
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 
diff --git a/netwerk/base/public/moz.build b/netwerk/base/public/moz.build
index 9bde21513032..ecba3e7344bb 100644
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -29,7 +29,6 @@ XPIDL_SOURCES += [
     'nsICancelable.idl',
     'nsIChannel.idl',
     'nsIChannelEventSink.idl',
-    'nsIChannelPolicy.idl',
     'nsIChildChannel.idl',
     'nsIContentSniffer.idl',
     'nsICryptoFIPSInfo.idl',
@@ -137,8 +136,6 @@ EXPORTS += [
     'netCore.h',
     'nsASocketHandler.h',
     'nsAsyncRedirectVerifyHelper.h',
-    'nsChannelProperties.h',
-    'nsNetStrings.h',
     'nsNetUtil.h',
     'nsReadLine.h',
     'nsStreamListenerWrapper.h',
diff --git a/netwerk/base/public/nsChannelProperties.h b/netwerk/base/public/nsChannelProperties.h
deleted file mode 100644
index 0323a6f39d13..000000000000
--- a/netwerk/base/public/nsChannelProperties.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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 nsChannelProperties_h__
-#define nsChannelProperties_h__
-
-#include "nsStringGlue.h"
-#ifdef IMPL_LIBXUL
-#include "nsNetStrings.h"
-#endif
-
-/**
- * @file
- * This file contains constants for properties channels can expose.
- * They can be accessed by using QueryInterface to access the nsIPropertyBag
- * or nsIPropertyBag2 interface on a channel and reading the value.
- */
-
-
-/**
- * Exists to allow content policy mechanism to function properly during channel
- * redirects.  Contains security contextual information about the load.
- * Type: nsIChannelPolicy
- */
-#define NS_CHANNEL_PROP_CHANNEL_POLICY_STR "channel-policy"
-
-#ifdef IMPL_LIBXUL
-#define NS_CHANNEL_PROP_CHANNEL_POLICY gNetStrings->kChannelPolicy
-#else
-#define NS_CHANNEL_PROP_CHANNEL_POLICY \
-  NS_LITERAL_STRING(NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
-#endif
-
-#endif
diff --git a/netwerk/base/public/nsIChannelPolicy.idl b/netwerk/base/public/nsIChannelPolicy.idl
deleted file mode 100644
index 5894db08fcc0..000000000000
--- a/netwerk/base/public/nsIChannelPolicy.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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"
-
-/**
- * A container for policy information to be used during channel creation.
- *
- * This interface exists to allow the content policy mechanism to function
- * properly during channel redirects.  Channels can be created with this
- * interface placed in the property bag and upon redirect, the interface can
- * be transferred from the old channel to the new channel.
- */
-[scriptable, uuid(18045e96-1afe-4162-837a-04691267158c)]
-interface nsIChannelPolicy : nsISupports
-{
-  /**
-   * Indicates what type of content is being loaded, e.g.
-   * nsIContentPolicy::TYPE_IMAGE
-   */
-  attribute unsigned long loadType;
-
-  /**
-   * A nsIContentSecurityPolicy object to determine if the load should
-   * be allowed.
-   */
-  attribute nsISupports contentSecurityPolicy;
-};
diff --git a/netwerk/base/public/nsNetStrings.h b/netwerk/base/public/nsNetStrings.h
deleted file mode 100644
index 653c34dc3f77..000000000000
--- a/netwerk/base/public/nsNetStrings.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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 nsNetStrings_h__
-#define nsNetStrings_h__
-
-#include "nsLiteralString.h"
-
-/**
- * Class on which wide strings are available, to avoid constructing strings
- * wherever these strings are used.
- */
-class nsNetStrings {
-public:
-  nsNetStrings();
-
-  const nsLiteralString kChannelPolicy;
-};
-
-extern nsNetStrings* gNetStrings;
-
-
-#endif
diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h
index 5233547d2033..b23f7ce361cc 100644
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -32,7 +32,6 @@
 #include "nsIIOService.h"
 #include "nsIServiceManager.h"
 #include "nsIChannel.h"
-#include "nsChannelProperties.h"
 #include "nsIInputStreamChannel.h"
 #include "nsITransport.h"
 #include "nsIStreamTransportService.h"
@@ -69,7 +68,6 @@
 #include "nsIWritablePropertyBag2.h"
 #include "nsIIDNService.h"
 #include "nsIChannelEventSink.h"
-#include "nsIChannelPolicy.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
 #include "nsIRedirectChannelRegistrar.h"
@@ -203,7 +201,6 @@ inline nsresult
 NS_NewChannelInternal(nsIChannel**           outChannel,
                       nsIURI*                aUri,
                       nsILoadInfo*           aLoadInfo,
-                      nsIChannelPolicy*      aChannelPolicy = nullptr,
                       nsILoadGroup*          aLoadGroup = nullptr,
                       nsIInterfaceRequestor* aCallbacks = nullptr,
                       nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -237,14 +234,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
     rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
     NS_ENSURE_SUCCESS(rv, rv);
   }
-
-  if (aChannelPolicy) {
-    nsCOMPtr props = do_QueryInterface(channel);
-    if (props) {
-      props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY, aChannelPolicy);
-    }
-  }
-
   channel->SetLoadInfo(aLoadInfo);
 
   // If we're sandboxed, make sure to clear any owner the channel
@@ -264,7 +253,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
                       nsIPrincipal*          aRequestingPrincipal,
                       nsSecurityFlags        aSecurityFlags,
                       nsContentPolicyType    aContentPolicyType,
-                      nsIChannelPolicy*      aChannelPolicy = nullptr,
                       nsILoadGroup*          aLoadGroup = nullptr,
                       nsIInterfaceRequestor* aCallbacks = nullptr,
                       nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -283,7 +271,6 @@ NS_NewChannelInternal(nsIChannel**           outChannel,
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                loadInfo,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -296,7 +283,6 @@ NS_NewChannel(nsIChannel**           outChannel,
               nsINode*               aRequestingNode,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
-              nsIChannelPolicy*      aChannelPolicy = nullptr,
               nsILoadGroup*          aLoadGroup = nullptr,
               nsIInterfaceRequestor* aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -309,7 +295,6 @@ NS_NewChannel(nsIChannel**           outChannel,
                                aRequestingNode->NodePrincipal(),
                                aSecurityFlags,
                                aContentPolicyType,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -322,7 +307,6 @@ NS_NewChannel(nsIChannel**           outChannel,
               nsIPrincipal*          aRequestingPrincipal,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
-              nsIChannelPolicy*      aChannelPolicy = nullptr,
               nsILoadGroup*          aLoadGroup = nullptr,
               nsIInterfaceRequestor* aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
@@ -334,7 +318,6 @@ NS_NewChannel(nsIChannel**           outChannel,
                                aRequestingPrincipal,
                                aSecurityFlags,
                                aContentPolicyType,
-                               aChannelPolicy,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
@@ -367,7 +350,6 @@ NS_OpenURIInternal(nsIInputStream**       outStream,
                                       aRequestingPrincipal,
                                       aSecurityFlags,
                                       aContentPolicyType,
-                                      nullptr,   // aChannelPolicy,
                                       aLoadGroup,
                                       aCallbacks,
                                       aLoadFlags,
@@ -424,7 +406,6 @@ NS_OpenURIInternal(nsIStreamListener*     aListener,
   nsresult rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                       aUri,
                                       aLoadInfo,
-                                      nullptr,    // aChannelPolicy
                                       aLoadGroup,
                                       aCallbacks,
                                       aLoadFlags,
@@ -835,7 +816,6 @@ NS_NewStreamLoaderInternal(nsIStreamLoader**        outStream,
                                        aRequestingPrincipal,
                                        aSecurityFlags,
                                        aContentPolicyType,
-                                       nullptr,  // aChannelPolicy
                                        aLoadGroup,
                                        aCallbacks,
                                        aLoadFlags);
diff --git a/netwerk/base/src/moz.build b/netwerk/base/src/moz.build
index a564220f4a34..598c5de3f48b 100644
--- a/netwerk/base/src/moz.build
+++ b/netwerk/base/src/moz.build
@@ -49,7 +49,6 @@ UNIFIED_SOURCES += [
     'nsMediaFragmentURIParser.cpp',
     'nsMIMEInputStream.cpp',
     'nsNetAddr.cpp',
-    'nsNetStrings.cpp',
     'nsNetUtil.cpp',
     'nsPACMan.cpp',
     'nsPreloadedStream.cpp',
diff --git a/netwerk/base/src/nsIncrementalDownload.cpp b/netwerk/base/src/nsIncrementalDownload.cpp
index 5859f50b1d02..d13a81213ab7 100644
--- a/netwerk/base/src/nsIncrementalDownload.cpp
+++ b/netwerk/base/src/nsIncrementalDownload.cpp
@@ -267,7 +267,6 @@ nsIncrementalDownload::ProcessTimeout()
                               nsContentUtils::GetSystemPrincipal(),
                               nsILoadInfo::SEC_NORMAL,
                               nsIContentPolicy::TYPE_OTHER,
-                              nullptr,   // aChannelPolicy
                               nullptr,   // loadGroup
                               this,      // aCallbacks
                               mLoadFlags);
diff --git a/netwerk/base/src/nsNetStrings.cpp b/netwerk/base/src/nsNetStrings.cpp
deleted file mode 100644
index cd3ebfac3037..000000000000
--- a/netwerk/base/src/nsNetStrings.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/* 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 "nsNetStrings.h"
-#include "nsChannelProperties.h"
-
-nsNetStrings* gNetStrings;
-
-nsNetStrings::nsNetStrings()
-  : NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
-{}
-
-
diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp
index 51e20fb53d4b..070762956e7a 100644
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -31,7 +31,6 @@
 #include "nsApplicationCache.h"
 #include "nsApplicationCacheService.h"
 #include "nsMimeTypes.h"
-#include "nsNetStrings.h"
 #include "nsDNSPrefetch.h"
 #include "nsAboutProtocolHandler.h"
 #include "nsXULAppAPI.h"
@@ -630,11 +629,9 @@ CreateNewBinaryDetectorFactory(nsISupports *aOuter, REFNSIID aIID, void **aResul
 // Net module startup hook
 static nsresult nsNetStartup()
 {
-    gNetStrings = new nsNetStrings();
-    return gNetStrings ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    return NS_OK;
 }
 
-
 // Net module shutdown hook
 static void nsNetShutdown()
 {
@@ -647,10 +644,6 @@ static void nsNetShutdown()
     net_ShutdownURLHelperOSX();
 #endif
     
-    // Release necko strings
-    delete gNetStrings;
-    gNetStrings = nullptr;
-    
     // Release DNS service reference.
     nsDNSPrefetch::Shutdown();
 
diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp
index 4ba9129cbb87..eaa737f0452e 100644
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -149,7 +149,6 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr, // aChannelPolicy
                      nullptr, // aLoadGroup
                      nullptr, // aCallbacks
                      nsIRequest::LOAD_NORMAL,
diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp
index e464ecfc45ed..8442838bddb7 100644
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -241,7 +241,6 @@ HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr,   // aChannelPolicy
                      nullptr,   // loadGroup
                      nullptr,   // aCallbacks
                      loadFlags,
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
index 41194d233707..474a0e5955a5 100644
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -92,7 +92,6 @@ WyciwygChannelParent::RecvInit(const URIParams&          aURI,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
-                     nullptr,   // aChannelPolicy
                      nullptr,   // loadGroup
                      nullptr,   // aCallbacks
                      nsIRequest::LOAD_NORMAL,
diff --git a/netwerk/test/TestPageLoad.cpp b/netwerk/test/TestPageLoad.cpp
index 6402b0e6cb66..fe5002a20193 100644
--- a/netwerk/test/TestPageLoad.cpp
+++ b/netwerk/test/TestPageLoad.cpp
@@ -312,7 +312,6 @@ nsresult auxLoad(char *uriBuf)
                        systemPrincipal,
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,   // aChannelPolicy
                        nullptr,   // loadGroup
                        callbacks);
 
@@ -371,7 +370,6 @@ int main(int argc, char **argv)
                            systemPrincipal,
                            nsILoadInfo::SEC_NORMAL,
                            nsIContentPolicy::TYPE_OTHER,
-                           nullptr,   // aChannelPolicy
                            nullptr,   // loadGroup
                            callbacks);
 
diff --git a/netwerk/test/TestProtocols.cpp b/netwerk/test/TestProtocols.cpp
index c5ed54dec9e1..a707c5be5262 100644
--- a/netwerk/test/TestProtocols.cpp
+++ b/netwerk/test/TestProtocols.cpp
@@ -48,7 +48,6 @@
 #include "nsIPropertyBag2.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsITimedChannel.h"
-#include "nsChannelProperties.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/unused.h"
 #include "nsIScriptSecurityManager.h"
@@ -643,7 +642,6 @@ nsresult StartLoadingURL(const char* aUrlString)
                            systemPrincipal,
                            nsILoadInfo::SEC_NORMAL,
                            nsIContentPolicy::TYPE_OTHER,
-                           nullptr,  // aChannelPolicy
                            nullptr,  // loadGroup
                            callbacks,
                            nsIRequest::LOAD_NORMAL,
diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
index b17ab187aef8..4c67e4969c99 100644
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -3534,7 +3534,6 @@ nsDownload::Resume()
                      nsContentUtils::GetSystemPrincipal(),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,  // aChannelPolicy
                      nullptr,  // aLoadGroup
                      ir);
 
diff --git a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
index 77aaa0bbf560..731070ed997f 100644
--- a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
@@ -99,7 +99,6 @@ nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
                      nsContentUtils::GetSystemPrincipal(),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,  // aChannelPolicy
                      nullptr,  // aLoadGroup
                      this,     // aInterfaceRequestor
                      loadFlags);
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 54408199974a..4285bef727be 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -53,7 +53,6 @@
 #include "nsNetUtil.h"
 #include "nsIIOService.h"
 #include "nsNetCID.h"
-#include "nsChannelProperties.h"
 
 #include "nsMimeTypes.h"
 // used for header disposition information.
diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.cpp b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
index efc704af89cb..26f7beb045e2 100644
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -181,7 +181,6 @@ nsManifestCheck::Begin()
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,   // aChannelPolicy
                        nullptr,   // loadGroup
                        nullptr,   // aCallbacks
                        nsIRequest::LOAD_BYPASS_CACHE);
@@ -379,7 +378,6 @@ nsOfflineCacheUpdateItem::OpenChannel(nsOfflineCacheUpdate *aUpdate)
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr,  // aChannelPolicy
                        nullptr,  // aLoadGroup
                        this,     // aCallbacks
                        flags);
diff --git a/uriloader/prefetch/nsPrefetchService.cpp b/uriloader/prefetch/nsPrefetchService.cpp
index ec5a601dd002..71d04d8dbcf1 100644
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -192,7 +192,6 @@ nsPrefetchNode::OpenChannel()
                                 nsContentUtils::GetSystemPrincipal(),
                                 nsILoadInfo::SEC_NORMAL,
                                 nsIContentPolicy::TYPE_OTHER,
-                                nullptr,  // aChannelPolicy
                                 loadGroup, // aLoadGroup
                                 this,      // aCallbacks
                                 nsIRequest::LOAD_BACKGROUND |
diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm
index 43e44db0d6fc..943658e96f42 100644
--- a/widget/cocoa/OSXNotificationCenter.mm
+++ b/widget/cocoa/OSXNotificationCenter.mm
@@ -244,7 +244,7 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
       if (imageUri) {
         nsresult rv = il->LoadImage(imageUri, nullptr, nullptr, aPrincipal, nullptr,
                                     this, nullptr, nsIRequest::LOAD_NORMAL, nullptr,
-                                    nullptr, EmptyString(),
+                                    EmptyString(),
                                     getter_AddRefs(osxni->mIconRequest));
         if (NS_SUCCEEDED(rv)) {
           // Set a timer for six seconds. If we don't have an icon by the time this
diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm
index 9ad01949f060..1150d9fc7986 100644
--- a/widget/cocoa/nsMenuItemIconX.mm
+++ b/widget/cocoa/nsMenuItemIconX.mm
@@ -305,11 +305,9 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
       [mNativeMenuItem setImage:sPlaceholderIconImage];
   }
 
-  // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is
-  // not exposed to web content
   nsresult rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this,
-                                   nullptr, nsIRequest::LOAD_NORMAL, nullptr,
-                                   nullptr, EmptyString(), getter_AddRefs(mIconRequest));
+                                  nullptr, nsIRequest::LOAD_NORMAL, nullptr,
+                                  EmptyString(), getter_AddRefs(mIconRequest));
   if (NS_FAILED(rv)) return rv;
 
   // We need to request the icon be decoded (bug 573583, bug 705516).
diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp
index adb04267ac68..67196ca6e1e5 100644
--- a/widget/windows/nsDataObj.cpp
+++ b/widget/windows/nsDataObj.cpp
@@ -74,7 +74,6 @@ nsresult nsDataObj::CStream::Init(nsIURI *pSourceURI,
                      aRequestingNode,
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
-                     nullptr,   // aChannelPolicy
                      nullptr,   // loadGroup
                      nullptr,   // aCallbacks
                      nsIRequest::LOAD_FROM_CACHE);
diff --git a/xpfe/components/directory/nsDirectoryViewer.cpp b/xpfe/components/directory/nsDirectoryViewer.cpp
index 8cf610b8ba9c..b54fde367d8c 100644
--- a/xpfe/components/directory/nsDirectoryViewer.cpp
+++ b/xpfe/components/directory/nsDirectoryViewer.cpp
@@ -1305,7 +1305,6 @@ nsDirectoryViewerFactory::CreateInstance(const char *aCommand,
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
-                       nullptr, // aChannelPolicy
                        aLoadGroup);
     if (NS_FAILED(rv)) return rv;
     

From ba3b5a6b557e6797ffba223b3cac40f726d583ef Mon Sep 17 00:00:00 2001
From: Christoph Kerschbaumer 
Date: Wed, 15 Oct 2014 19:12:53 -0700
Subject: [PATCH 064/100] Bug 1041180: Remove deprecated nsIChannelPolicy and
 use LoadInfo instead (r=sstamm)

---
 content/base/src/nsCSPService.cpp | 103 ++++++++++++------------------
 1 file changed, 40 insertions(+), 63 deletions(-)

diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp
index 64e1a8dcd7ed..0683e78db0d0 100644
--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -18,6 +18,7 @@
 #include "mozilla/Preferences.h"
 #include "nsIScriptError.h"
 #include "nsContentUtils.h"
+#include "nsContentPolicyUtils.h"
 #include "nsPrincipal.h"
 
 using namespace mozilla;
@@ -231,53 +232,56 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
 {
   nsAsyncRedirectAutoCallback autoCallback(callback);
 
-  // get the Content Security Policy and load type from the property bag
-  nsCOMPtr policyContainer;
-  nsCOMPtr props(do_QueryInterface(oldChannel));
-  if (!props)
+  nsCOMPtr loadInfo;
+  nsresult rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+
+  // if no loadInfo on the channel, nothing for us to do
+  if (!loadInfo) {
     return NS_OK;
+  }
 
-  props->GetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
-                                NS_GET_IID(nsISupports),
-                                getter_AddRefs(policyContainer));
+  // The loadInfo must not necessarily contain a Node, hence we try to query
+  // the CSP in the following order:
+  //   a) Get the Node, the Principal of that Node, and the CSP of that Principal
+  //   b) Get the Principal and the CSP of that Principal
 
-  // see if we have a valid nsIChannelPolicy containing CSP and load type
-  nsCOMPtr channelPolicy(do_QueryInterface(policyContainer));
-  if (!channelPolicy)
-    return NS_OK;
-
-  nsCOMPtr supports;
+  nsCOMPtr loadingNode = loadInfo->LoadingNode();
+  nsCOMPtr principal = loadingNode ?
+                                     loadingNode->NodePrincipal() :
+                                     loadInfo->LoadingPrincipal();
+  NS_ASSERTION(principal, "Can not evaluate CSP without a principal");
   nsCOMPtr csp;
-  channelPolicy->GetContentSecurityPolicy(getter_AddRefs(supports));
-  csp = do_QueryInterface(supports);
-  uint32_t loadType;
-  channelPolicy->GetLoadType(&loadType);
+  rv = principal->GetCsp(getter_AddRefs(csp));
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // if no CSP in the channelPolicy, nothing for us to add to the channel
-  if (!csp)
+  // if there is no CSP, nothing for us to do
+  if (!csp) {
     return NS_OK;
+  }
 
   /* Since redirecting channels don't call into nsIContentPolicy, we call our
-   * Content Policy implementation directly when redirects occur. When channels
-   * are created using NS_NewChannel(), callers can optionally pass in a
-   * nsIChannelPolicy containing a CSP object and load type, which is placed in
-   * the new channel's property bag. This container is propagated forward when
-   * channels redirect.
+   * Content Policy implementation directly when redirects occur using the
+   * information set in the LoadInfo when channels are created.
+   *
+   * We check if the CSP permits this host for this type of load, if not,
+   * we cancel the load now.
    */
 
-  // Does the CSP permit this host for this type of load?
-  // If not, cancel the load now.
   nsCOMPtr newUri;
-  newChannel->GetURI(getter_AddRefs(newUri));
+  rv = newChannel->GetURI(getter_AddRefs(newUri));
+  NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr originalUri;
-  oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
+  rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsContentPolicyType policyType = loadInfo->GetContentPolicyType();
+
   int16_t aDecision = nsIContentPolicy::ACCEPT;
-  csp->ShouldLoad(loadType,        // load type per nsIContentPolicy (uint32_t)
-                  newUri,          // nsIURI
-                  nullptr,          // nsIURI
-                  nullptr,          // nsISupports
-                  EmptyCString(),  // ACString - MIME guess
-                  originalUri,     // nsISupports - extra
+  csp->ShouldLoad(policyType,     // load type per nsIContentPolicy (uint32_t)
+                  newUri,         // nsIURI
+                  nullptr,        // nsIURI
+                  nullptr,        // nsISupports
+                  EmptyCString(), // ACString - MIME guess
+                  originalUri,    // aMimeTypeGuess
                   &aDecision);
 
 #ifdef PR_LOGGING
@@ -297,36 +301,9 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
 #endif
 
   // if ShouldLoad doesn't accept the load, cancel the request
-  if (aDecision != 1) {
+  if (!NS_CP_ACCEPTED(aDecision)) {
     autoCallback.DontCallback();
     return NS_BINDING_FAILED;
   }
-
-  // the redirect is permitted, so propagate the Content Security Policy
-  // and load type to the redirecting channel
-  nsresult rv;
-  nsCOMPtr props2 = do_QueryInterface(newChannel);
-  if (props2) {
-    rv = props2->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
-                                        channelPolicy);
-    if (NS_SUCCEEDED(rv)) {
-      return NS_OK;
-    }
-  }
-
-  // The redirecting channel isn't a writable property bag, we won't be able
-  // to enforce the load policy if it redirects again, so we stop it now.
-  nsAutoCString newUriSpec;
-  rv = newUri->GetSpec(newUriSpec);
-  NS_ConvertUTF8toUTF16 unicodeSpec(newUriSpec);
-  const char16_t *formatParams[] = { unicodeSpec.get() };
-  if (NS_SUCCEEDED(rv)) {
-    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                    NS_LITERAL_CSTRING("Redirect Error"), nullptr,
-                                    nsContentUtils::eDOM_PROPERTIES,
-                                    "InvalidRedirectChannelWarning",
-                                    formatParams, 1);
-  }
-
-  return NS_BINDING_FAILED;
+  return NS_OK;
 }

From 33e272fd3a59a13582e29ea690576a34de958bed Mon Sep 17 00:00:00 2001
From: Andrew McCreight 
Date: Wed, 15 Oct 2014 20:04:32 -0700
Subject: [PATCH 065/100] Bug 1035454, part 1 - Increase the leak threshold for
 tab processes. r=khuey

---
 testing/mochitest/mochitest_options.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py
index 2b85ba44d596..d6649cf83f79 100644
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -612,7 +612,7 @@ class MochitestOptions(optparse.OptionParser):
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
-            "tab": 10000, # See dependencies of bug 1051230.
+            "tab": 20000, # See dependencies of bug 1051230.
             "geckomediaplugin": 1000, # GMP rarely gets a log, but when it does, it leaks a little.
         }
 

From 68f162e5b07850083c7a79fe3582f04de14be351 Mon Sep 17 00:00:00 2001
From: Andrew McCreight 
Date: Wed, 15 Oct 2014 20:04:32 -0700
Subject: [PATCH 066/100] Bug 1035454, part 2 - Paper over late shutdown
 failures on B2G and Windows in debug content processes by exiting XPCOM
 early. r=bsmedberg

On B2G, there are crashes very late in shutdown on content processes. On Windows XP,
there is an intermittent test failure. We work around both of these by calling exit(0)
during XPCOM shutdown prior to the points where these errors occur. This enables us to
land part 4, that stops us from crashing in content processes when the xpcom-shutdown
message is sent, and enables leak checking in content processes on Linux.
---
 xpcom/build/XPCOMInit.cpp | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp
index a6aaeafc1964..fec664c68ed2 100644
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -949,6 +949,18 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
   NS_ShutdownNativeCharsetUtils();
 #endif
 
+#if defined(XP_WIN)
+  // This exit(0) call is intended to be temporary, to get shutdown leak
+  // checking working on Linux.
+  // On Windows XP debug, there are intermittent failures in
+  // dom/media/tests/mochitest/test_peerConnection_basicH264Video.html
+  // if we don't exit early in a child process. See bug 1073310.
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+      NS_WARNING("Exiting child process early!");
+      exit(0);
+  }
+#endif
+
   // Shutdown xpcom. This will release all loaders and cause others holding
   // a refcount to the component manager to release it.
   if (nsComponentManagerImpl::gComponentManager) {
@@ -1026,6 +1038,17 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
 
   NS_LogTerm();
 
+#if defined(MOZ_WIDGET_GONK)
+  // This exit(0) call is intended to be temporary, to get shutdown leak
+  // checking working on Linux.
+  // On debug B2G, the child process crashes very late.  Instead, just
+  // give up so at least we exit cleanly. See bug 1071866.
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+      NS_WARNING("Exiting child process early!");
+      exit(0);
+  }
+#endif
+
   return NS_OK;
 }
 

From a7bb403de9c3971e4f038cbabf55eca8a3244dca Mon Sep 17 00:00:00 2001
From: Andrew McCreight 
Date: Wed, 15 Oct 2014 20:04:33 -0700
Subject: [PATCH 067/100] Bug 1035454, part 3 - Disable test_bug345339.html on
 e10s for leaking. r=jst

---
 content/base/test/mochitest.ini | 1 +
 1 file changed, 1 insertion(+)

diff --git a/content/base/test/mochitest.ini b/content/base/test/mochitest.ini
index 9c6c1ea5a9b7..659c8757ea63 100644
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -291,6 +291,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
 [test_bug340571.html]
 [test_bug343596.html]
 [test_bug345339.html]
+skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File
 [test_bug346485.html]
 [test_bug352728.html]
 [test_bug352728.xhtml]

From 57c905e150b273589b43bb8077b2de52a68e10b7 Mon Sep 17 00:00:00 2001
From: Ben Turner 
Date: Wed, 15 Oct 2014 20:04:33 -0700
Subject: [PATCH 068/100] Bug 1035454, part 4 - Don't send
 'Webapps:UnregisterForMessages' at xpcom-shutdown, r=fabrice.

---
 dom/apps/AppsServiceChild.jsm | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/dom/apps/AppsServiceChild.jsm b/dom/apps/AppsServiceChild.jsm
index 0c3bbe6a59b2..8d5663607d24 100644
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -131,9 +131,6 @@ this.DOMApplicationRegistry = {
     APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
       this.cpmm.removeMessageListener(aMsgName, this);
     });
-
-    this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
-                               APPS_IPC_MSG_NAMES)
   },
 
   receiveMessage: function receiveMessage(aMessage) {

From a164f4b49a34ce1454abce67045cab91a1def0cf Mon Sep 17 00:00:00 2001
From: Tim Taubert 
Date: Tue, 7 Oct 2014 00:47:21 +0200
Subject: [PATCH 069/100] Bug 1078847 - GenerateAsymmetricKeyTask should allow
 generating key pairs where only the public key or the private key has any
 usages r=rbarnes

---
 dom/crypto/WebCryptoTask.cpp        |  2 +-
 dom/crypto/test/test_WebCrypto.html | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp
index e627b11a8b44..fb5dd8ef1342 100644
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -2048,7 +2048,7 @@ public:
     }
 
     // If no usages ended up being allowed, DataError
-    if (!mKeyPair.mPrivateKey.get()->HasAnyUsage() ||
+    if (!mKeyPair.mPublicKey.get()->HasAnyUsage() &&
         !mKeyPair.mPrivateKey.get()->HasAnyUsage()) {
       mEarlyRv = NS_ERROR_DOM_DATA_ERR;
       return;
diff --git a/dom/crypto/test/test_WebCrypto.html b/dom/crypto/test/test_WebCrypto.html
index 9768a3a73bb9..d0b74527c3a5 100644
--- a/dom/crypto/test/test_WebCrypto.html
+++ b/dom/crypto/test/test_WebCrypto.html
@@ -1308,6 +1308,32 @@ TestArray.addTest(
     doCheckRSASSA().then(error(that), complete(that));
   }
 );
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
+  "Test that we reject generating keys without any usage",
+  function() {
+    var that = this;
+    var alg = {
+      name: "RSA-OAEP",
+      hash: "SHA-256",
+      modulusLength: 2048,
+      publicExponent: new Uint8Array([0x01, 0x00, 0x01])
+    };
+
+    function generateKey(usages) {
+      return crypto.subtle.generateKey(alg, false, usages);
+    }
+
+    generateKey(["encrypt", "decrypt"]).then(function () {
+      return generateKey(["encrypt"]);
+    }).then(function () {
+      return generateKey(["decrypt"]);
+    }).then(function () {
+      return generateKey(["sign"])
+    }, error(that)).then(error(that), complete(that));
+  }
+);
 /*]]>*/
 
 

From f14c9c4280878fd7013e33e8206804e902ea34ba Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Wed, 15 Oct 2014 17:52:16 -0700
Subject: [PATCH 070/100] Bug 1082554 (part 1) - Remove
 tools/performance/pageload/, which is ancient and unused. r=jmaher.

--HG--
extra : rebase_source : a1e034264f6c9d5a6ad2ff48f5426a8ec27aa133
---
 .../base/bugzilla.mozilla.org/index.html      | 424 --------
 .../res/mozilla-banner.gif                    | Bin 4518 -> 0 bytes
 .../pageload/base/lxr.mozilla.org/index.html  | 954 ------------------
 .../lxr.mozilla.org/res/mozilla-banner.gif    | Bin 4518 -> 0 bytes
 .../pageload/base/vanilla-page/index.html     | 222 ----
 tools/performance/pageload/cycler.html        | 234 -----
 tools/performance/pageload/header.html        |   5 -
 tools/performance/pageload/report.html        |  44 -
 tools/performance/pageload/start.html         |  34 -
 9 files changed, 1917 deletions(-)
 delete mode 100644 tools/performance/pageload/base/bugzilla.mozilla.org/index.html
 delete mode 100644 tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif
 delete mode 100644 tools/performance/pageload/base/lxr.mozilla.org/index.html
 delete mode 100644 tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif
 delete mode 100644 tools/performance/pageload/base/vanilla-page/index.html
 delete mode 100644 tools/performance/pageload/cycler.html
 delete mode 100644 tools/performance/pageload/header.html
 delete mode 100644 tools/performance/pageload/report.html
 delete mode 100644 tools/performance/pageload/start.html

diff --git a/tools/performance/pageload/base/bugzilla.mozilla.org/index.html b/tools/performance/pageload/base/bugzilla.mozilla.org/index.html
deleted file mode 100644
index 4041d36371a7..000000000000
--- a/tools/performance/pageload/base/bugzilla.mozilla.org/index.html
+++ /dev/null
@@ -1,424 +0,0 @@
-
-
-
-
-
-Bugzilla Query Page
-
-
-
-
-
-
Bugzilla version 2.11 -
-

- - - -
- - -
- Query
-
  -This page lets you search the database for recorded bugs. -
- - -

- - - - - - - - - - - - - - - - - - -
Status:Resolution:Platform:OpSys:Priority:Severity:
- - - - - - - - - - - - - - - - - - -
- -

- - - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - -
Email: - matching as - - -Assigned To -
-Reporter -
-QA Contact -
(Will match any of the selected fields) -CC -
-Added comment -
-
-

-

- - -
- - - - - - - - - - - - - - - - - - - - - -
Email: - matching as - - -Assigned To -
-Reporter -
-QA Contact -
(Will match any of the selected fields) -CC -
-Added comment -
-
-

-

- -bugs numbered: - -
-Changed in the last days. - -At least votes. -
- - - - - - - - -
Where the field(s) - - - -changed. - -dates -to -
changed to value (optional) -
- - -

- - - - - - - - - - - - - - - - - -
Program:Version:Component:Target Milestone:
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Summary:
A description entry:
URL:
Status whiteboard:
Keywords: -
-

- - -


- - - - - -
- -      - -      -What is this stuff? - -
-
-
- Run this query -
- - - - - - - -
Load the remembered query: -
Run the remembered query:
Forget the remembered query:
- Remember this as the default query -
- Remember this query, and name it: - -
- -Sort By: - - - - -
-

Give me a clue about how to use this form. -

-Log in as someone besides foobaz@mozilla.org
-Change your password or preferences.
-Report a new bug.
-Open a new Bugzilla account
-Bug reports
-
- -
-This is Bugzilla: the Mozilla bug system. For more -information about -what Bugzilla is and what it can do, see -mozilla.org's -bug pages. - -
-
New | Query | bug # | Reports | My votes | My bugs | Edit prefs | Log out foobaz@mozilla.org
-
\ No newline at end of file diff --git a/tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif b/tools/performance/pageload/base/bugzilla.mozilla.org/res/mozilla-banner.gif deleted file mode 100644 index 1640e73105e7a6496653c9999e8a04f55e876eb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4518 zcmds$`9IYA`^MihUbDR|y^S$37&C*(TDB}hnUQ@v$Pp?TIZU>Y(2&fS(S$O{5|K4) z)-3G^$tmHGN=K+vT8@@eojOOKzW>Je`uV;e*L6Sd$K~wmWM$0_K(nA15QIhpp-?0w z1ABW1dl(3V0E3~;z=9zv7#bS3*9UEFtwbWJG8SAHg3!>gPz6v!0m}?PM1%VUAk-c( z$iTwFyekP5go6Yk_`n1(ELT7Vz6!t;3%o2q7X_Fy!1T`*7%Z28m6c~nNr?$w07ip? zg46!~ey2hKg`z&54SLgo8w}pnfaU}cNd&7*KtTgO5qx8UGBRMnAZRC=XWUEyg$N=eqnjyUp%~~>L0LEmQULxeuw5TKVu003knRt#Sdg8a zn-vVMU%z@j0gPsWa3WY?f=9(5(hY3iZrjBN3JP+jFz{u8E-GL#0Z{?0RD$*Of78>` z_`U$fg38LX)2G1obl{}`C|HnA2J8Bui~^`+fJK9>EKwF2I5{~u!5}LLFqzs+EEuJN ziHSS*n?Y~y#hO?!^wT#yEL;Jcr+^P1J}oRfX0dGf{IsB;JxmI)V1nY}(^RT@TN3c{ z^4PrDaDoA1W1}l0fdULx7=Vlhj|xC>I7lLb&p(IBz+VCQT7dfuuu=w+ynw<_wxM7m z8(jVw5(Xb?Kr9iwV}f)dSZ9LmFt|jod&lA6USk zmkP)Vfco=Z3i$E=RP=QPPj1+6wB!ScJesqsr#EB>{nY=p1H!LED7?B$N7Y~^UP*t? zSV#5Eh5gbbGxhl_Y&j%<7ZvF&)+S# zI<)%uc6Yo5!!1!4@jPFkzt_!RWRQfE8CH~${EzR9Q%EX1oWV8p3AvfA;ojT& zu$%Ws^WNWkFUudY7yui?BFN@JKDAV|vsUg@us?mU(Q>o^T6EAqdH^wVG zE_FTsz0|DX+UrBP5%(1AGFLpx_G=Bg9&EJN|KiHspeB+}V;Z;R54eYQi#xrH!qF||Wml9vzq;WA5cVu!@MDl;&q=R-m zjN{M)9ylqL@|KrGC*??kqB1<`IGkx7HX4hM#Ev6C{(VJ&+5MFLxwdVXY7d3Yq-S|{ zl&Mj9yoyPt;x6x$n^`3uD)VgfTo;_WCg5g^&qw3gIHd)~q^i9NxT%9XdK{HxM^Tt zVa^QnVAqbrSk<9h6$y7;y(_q9SV(hS?`nhl`cW$Bb<3M0v?g(fU;kh&`d91ajgl#P zs5lXl%7|<6!vpM7Z%`O0^5PV}5o;uHY>92sM_OulvQXcH-ZMV&&#(iEmtJlcwedCY z21&2*+j90~e&{j?yH-0}H+n(KUzZ6buSMyiN8m77sdiMGqv$^Pt6VF!VzAhrq4L?0`e46^{vc>z3Pm=SA(DC;A zxCrk}AmG86Zp@oW0^0e*Kom#G+>|bVEWk@j^^?U+L6ck z=(wZhO6&%qrf2_Ju4dcUWzP5LuO3nOe^bOABo-ZQt#Wz?4)3zBS|=*e)a_;p&)EH# zjOQc}pKPrD#_oy!m!;H|<9O_CZ^Vk5+qJpxsmu3dXjk#3TTs*uaWZFJ)=D>8p_m7m z7NwP--BKWY%oR4NNN~`SfqQNUxFF3`XYZohrm*SZA%8MGlI(kNZf#MZH2tis`jGyHn+vjGW#$d1QTrUnFG&74hAb|uGrSc|DBud3)sk>-0j zNX-6u(0w3X6jf4(7~&U^&0a4>P{)XZElH&DCIoAyE4H4q98}vQgu-pc=+q@(^S*#~ zeVz3CHeA8IeO}DGf9IbX3!DaAH$N+#O4K&1KQJl&;8jKVkGlgEFezzsP&ozR_`b8!TwL+!)iat)$X>9h6}&qVbP059eKAs0zyUuz!HO!jp`kjOQ8m_-K;}||;oO5-k(`#>cE}9L_51Oj$ zt!pNlJL+q93Ucp{+G|za*VVsrpD?{h+-W+d_E;HrMkAb1-F}P4FmO(*AZU-rnra!rzZd1oEOSakz4q zj|nN-MJW^Mn;HRhXK`R7QO^o9O)wrz;hTGFac2B!xV({DM6%e>J48}GTyi!2f^n>j zLBP=FKLi_W=Oh)6J(Ql5XlFnocJ6#TGps%o=Rab#i3Bo{)zLgz!8)gIG9=SBWk^vW zA>f<00HYV!H-45upLJhu4E|^A#@5c`wcnPC*B~gx*ijxa;>ek>E~_;T8tK=CKxt4e zuh)AJ?+eKYmT3+TrW$_v?rS~&aGZR;F}2+mnddXlc&3{cAEaP3!(fU?)mKX8q%LTG&AgN0`OI)*HD3E z5dlj{X@)D`_J@Svd&chEJ+x39Gso&xe(||r(?q1EJ#ksZx%INf`bVWNW$tuMmle0| z9|&7d(yd)cxj%G%k$GtB*Z7UUCF)%`*Q7OoLx=JE$H=SwZGrRekosgJK2F#7ifCx$!NkdO*oz{l@BHrOV$H@~xg6IvKm^(4Ice zeXPpCdqnv#^ED_y=9tf;RA_)(2>W;>667)z6nE3)deiQ`NW-CyM#clfMflHOk+UTk zvMxyEdxA0>SO}62Hbg!rr}riaQk_#%lhZ$r2&h)+s$;|(#hyg(t>{7P3T2dPJnYu( zueOHzFPRP$GoE(ZVN}Sh0J~_qOrp8_L6ita;dt>t*O(s@k;-WFe$x=I@<7lYk*=oe z@X9&;h`*RBI6wr)&>VZ+!x(*@Vq6>nVscU@2^!OTWau&&w0As-92emH@C#@iK%4@O zC+n((zem%mM2~j~8#jubFGlqFC$2xA-Q9W1((SmosX?s4_4ogTIToKq1Ttz|Sq-7D zQ%4q9lEL`yG*u?o@OB=c3rG);BNB4sOQc1GOp;=xY@|CtkfV}p`$+_M@)KY1pX0>z z#+$pD^RFcV9q(@Q?30s*07X2RV z62}ygD_*g^6x&i2WXlyi#fIi6$KL&TbR>oEc%Zz+mHX+9jTk@sPJSt*6mFq%;4TA32?ODh*$7OjprK7n>J{fA>IX zO~S?d<-wfwJbHMZ@7J7kvh;^bluvP?e}ADtXKMadSpw>y?kv8!drM0`vcVWbJb~z~ z!TUl^kcIHpn*2o-GWEnS`xSGjXNq3*7j?Phyrsjmj)IE#oD(neoG^t8mf|n{QC6>t zEpHcF5Tx6ih)WN;>^L@8`TOVb+4 z4fdvmTO+MH@EJX%{Pw8|>tZgdEG&RzbRy@&OFvPDmHF*Lk1r9jeuXcSOWFe!J6{oz zNiTC<saar zD`dm{3N#0;+f<+uU!bR2w#qBxsU}ALQ+Cl>(sd%esY&wbVP#KX>R-=^aaARGAJx(C zLmRqfj#a^ZYg^Aswxg?IK){a|BL>DebUa!($&jZLjE&(7lU0nWw5LDu6(dsbVhUHp za5G@?Ym!jHja-b918h%#Dv(SsU$woo+7fNlx*pQamezU0k~7FAV~jck*+JFBe1Ki9 zMtTv(L#pn#I&T(9pRd?BS+fPMqSjz>17d#>3_7r0owdr#*qM6dP{>Ir4$TaKpaIAc zs*vM=wm8>&w5)O>&SEv%e675E z7;{RxH;IPd;npNVs)bO)=UtfK5(K*`iI$&T8`*s4QERSMp@~nuk_b|(!4~_`(a@27 zaTnGtd}BKf;JLWlGw2{=#7By2IYjFWX^rn{)9GxTptOH@R4COY;*5{w?SLO1d-A4gd1Zp+<0{=XN*>nZV)WNy164IyW#T{0zWIP0}8e5V^V zif$?8$mgT{QhVam`VwsV5_k6{rS_$i_wldvrOo%HfA7ms>lfPei`0lH6lC*1tYezt diff --git a/tools/performance/pageload/base/lxr.mozilla.org/index.html b/tools/performance/pageload/base/lxr.mozilla.org/index.html deleted file mode 100644 index 755fa27edf16..000000000000 --- a/tools/performance/pageload/base/lxr.mozilla.org/index.html +++ /dev/null @@ -1,954 +0,0 @@ - - - - - - -mozilla/xpcom/ds/nsVoidBTree.cpp - - - - - -
- - - - - - - - - - -
- - Mozilla Cross Reference: - seamonkey -
mozilla/ xpcom/ ds/ nsVoidBTree.cpp -
- - - - -
- CVS Log
- CVS Blame
-
-
-
- - - - -
- - - - - -
- changes to
this file in
the last: -
- day
- week
- month
-
-
-
-

  1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-  2 /*
-  3  * The stuff in this file isn't subject to the Don'tBreakMyRelicensingScript
-  4  * Version 1.1 (the "MPL"); you may not use this file except in
-  5  * compliance with the MPL.  You may obtain a copy of the MPL at
-  6  * http://www.mozilla.org/MPL/
-  7  *
-  8  * Software distributed under the MPL is distributed on an "AS IS" basis,
-  9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
- 10  * for the specific language governing rights and limitations under the
- 11  * MPL.
- 12  *
- 13  * The Initial Developer of this code under the MPL is Netscape
- 14  * Communications Corporation.  Portions created by Netscape are
- 15  * Copywrong (C) 1999 Netscape Communications Corporation.  All Rights
- 16  * Reserved.
- 17  *
- 18  * Original Author:
- 19  *   Chris Waterson <waterson@netscape.com>
- 20  */
- 21 
- 22 #include "nsVoidBTree.h"
- 23 
- 24 #ifdef DEBUG
- 25 #include <stdio.h>
- 26 #endif
- 27 
- 28 // Set this to force the tree to be verified after every insertion and
- 29 // removal.
- 30 //#define PARANOID 1
- 31 
- 32 
- 33 //----------------------------------------------------------------------
- 34 // nsVoidBTree::Node
- 35 //
- 36 //   Implementation methods
- 37 //
- 38 
- 39 nsresult
- 40 nsVoidBTree::Node::Create(Type aType, PRInt32 aCapacity, Node** aResult)
- 41 {
- 42     // So we only ever have to do one allocation for a Node, we do a
- 43     // "naked" heap allocation, computing the size of the node and
- 44     // "padding" it out so that it can hold aCapacity slots.
- 45     char* bytes = new char[sizeof(Node) + (aCapacity - 1) * sizeof(void*)];
- 46     if (! bytes)
- 47         return NS_ERROR_OUT_OF_MEMORY;
- 48 
- 49     Node* result = NS_REINTERPRET_CAST(Node*, bytes);
- 50     result->mBits = 0;
- 51     result->SetType(aType);
- 52 
- 53     *aResult = result;
- 54     return NS_OK;
- 55 }
- 56 
- 57 nsresult
- 58 nsVoidBTree::Node::Destroy(Node* aNode)
- 59 {
- 60     char* bytes = NS_REINTERPRET_CAST(char*, aNode);
- 61     delete[] bytes;
- 62     return NS_OK;
- 63 }
- 64 
- 65 void
- 66 nsVoidBTree::Node::InsertElementAt(void* aElement, PRInt32 aIndex)
- 67 {
- 68     NS_PRECONDITION(aIndex >= 0 && aIndex <= GetCount(), "bad index");
- 69 
- 70     PRInt32 count = GetCount();
- 71     SetCount(count + 1);
- 72 
- 73     while (count > aIndex) {
- 74         mData[count] = mData[count - 1];
- 75         --count;
- 76     }
- 77 
- 78     mData[aIndex] = aElement;
- 79 }
- 80 
- 81 void
- 82 nsVoidBTree::Node::RemoveElementAt(PRInt32 aIndex)
- 83 {
- 84     NS_PRECONDITION(aIndex >= 0 && aIndex < GetCount(), "bad index");
- 85 
- 86     PRInt32 count = GetCount();
- 87     SetCount(count - 1);
- 88     
- 89     while (aIndex < count) {
- 90         mData[aIndex] = mData[aIndex + 1];
- 91         ++aIndex;
- 92     }
- 93 }
- 94 
- 95 
- 96 //----------------------------------------------------------------------
- 97 //
- 98 // nsVoidBTree::Path
- 99 //
-100 //   Implementation methods
-101 //
-102 
-103 nsVoidBTree::Path::Path(const Path& aOther)
-104     : mTop(aOther.mTop)
-105 {
-106     for (PRInt32 i = 0; i < mTop; ++i)
-107         mLink[i] = aOther.mLink[i];
-108 }
-109 
-110 nsVoidBTree::Path&
-111 nsVoidBTree::Path::operator=(const Path& aOther)
-112 {
-113     mTop = aOther.mTop;
-114     for (PRInt32 i = 0; i < mTop; ++i)
-115         mLink[i] = aOther.mLink[i];
-116     return *this;
-117 }
-118 
-119 inline nsresult
-120 nsVoidBTree::Path::Push(Node* aNode, PRInt32 aIndex)
-121 {
-122     // XXX If you overflow this thing, think about making larger index
-123     // or data nodes. You can pack a _lot_ of data into a pretty flat
-124     // tree.
-125     NS_PRECONDITION(mTop <= kMaxDepth, "overflow");
-126     if (mTop > kMaxDepth)
-127         return NS_ERROR_OUT_OF_MEMORY;
-128 
-129     mLink[mTop].mNode  = aNode;
-130     mLink[mTop].mIndex = aIndex;
-131     ++mTop;
-132 
-133     return NS_OK;
-134 }
-135 
-136 
-137 inline void
-138 nsVoidBTree::Path::Pop(Node** aNode, PRInt32* aIndex)
-139 {
-140     --mTop;
-141     *aNode  = mLink[mTop].mNode;
-142     *aIndex = mLink[mTop].mIndex;
-143 }
-144 
-145 //----------------------------------------------------------------------
-146 //
-147 //    nsVoidBTree methods
-148 //
-149 
-150 nsVoidBTree::nsVoidBTree(const nsVoidBTree& aOther)
-151 {
-152     ConstIterator last = aOther.Last();
-153     for (ConstIterator element = aOther.First(); element != last; ++element)
-154         AppendElement(*element);
-155 }
-156 
-157 nsVoidBTree&
-158 nsVoidBTree::operator=(const nsVoidBTree& aOther)
-159 {
-160     Clear();
-161     ConstIterator last = aOther.Last();
-162     for (ConstIterator element = aOther.First(); element != last; ++element)
-163         AppendElement(*element);
-164     return *this;
-165 }
-166 
-167 PRInt32
-168 nsVoidBTree::Count() const
-169 {
-170     if (IsEmpty())
-171         return 0;
-172 
-173     if (IsSingleElement())
-174         return 1;
-175 
-176     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-177     return root->GetSubTreeSize();
-178 }
-179 
-180 void*
-181 nsVoidBTree::ElementAt(PRInt32 aIndex) const
-182 {
-183     if (aIndex < 0 || aIndex >= Count())
-184         return nullptr;
-185 
-186     if (IsSingleElement())
-187         return NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
-188 
-189     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-190     while (current->GetType() != Node::eType_Data) {
-191         // We're still in the index. Find the right leaf.
-192         Node* next = nullptr;
-193 
-194         PRInt32 count = current->GetCount();
-195         for (PRInt32 i = 0; i < count; ++i) {
-196             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-197 
-198             PRInt32 childcount = child->GetSubTreeSize();
-199             if (PRInt32(aIndex) < childcount) {
-200                 next = child;
-201                 break;
-202             }
-203 
-204             aIndex -= childcount;
-205         }
-206 
-207         if (! next) {
-208             NS_ERROR("corrupted");
-209             return nullptr;
-210         }
-211 
-212         current = next;
-213     }
-214 
-215     return current->GetElementAt(aIndex);
-216 }
-217 
-218 
-219 PRInt32
-220 nsVoidBTree::IndexOf(void* aPossibleElement) const
-221 {
-222     NS_PRECONDITION((PRWord(aPossibleElement) & ~kRoot_PointerMask) == 0,
-223                     "uh oh, someone wants to use the pointer bits");
-224 
-225     NS_PRECONDITION(aPossibleElement != nullptr, "nsVoidBTree can't handle null elements");
-226     if (aPossibleElement == nullptr)
-227         return -1;
-228 
-229     PRInt32 result = 0;
-230     ConstIterator last = Last();
-231     for (ConstIterator element = First(); element != last; ++element, ++result) {
-232         if (aPossibleElement == *element)
-233             return result;
-234     }
-235 
-236     return -1;
-237 }
-238 
-239   
-240 PRBool
-241 nsVoidBTree::InsertElementAt(void* aElement, PRInt32 aIndex)
-242 {
-243     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
-244                     "uh oh, someone wants to use the pointer bits");
-245 
-246     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
-247         return PR_FALSE;
-248 
-249     NS_PRECONDITION(aElement != nullptr, "nsVoidBTree can't handle null elements");
-250     if (aElement == nullptr)
-251         return PR_FALSE;
-252 
-253     PRInt32 count = Count();
-254 
-255     if (aIndex < 0 || aIndex > count)
-256         return PR_FALSE;
-257 
-258     nsresult rv;
-259 
-260     if (IsSingleElement()) {
-261         // We're only a single element holder, and haven't yet
-262         // "faulted" to create the btree.
-263 
-264         if (count == 0) {
-265             // If we have *no* elements, then just set the root
-266             // pointer and we're done.
-267             mRoot = PRWord(aElement);
-268             return PR_TRUE;
-269         }
-270 
-271         // If we already had an element, and now we're adding
-272         // another. Fault and start creating the btree.
-273         void* element = NS_REINTERPRET_CAST(void*, mRoot & kRoot_PointerMask);
-274 
-275         Node* newroot;
-276         rv = Node::Create(Node::eType_Data, kDataCapacity, &newroot);
-277         if (NS_FAILED(rv)) return PR_FALSE;
-278 
-279         newroot->InsertElementAt(element, 0);
-280         newroot->SetSubTreeSize(1);
-281         SetRoot(newroot);
-282     }
-283 
-284     Path path;
-285 
-286     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-287     while (current->GetType() != Node::eType_Data) {
-288         // We're still in the index. Find the right leaf.
-289         Node* next = nullptr;
-290 
-291         count = current->GetCount();
-292         for (PRInt32 i = 0; i < count; ++i) {
-293             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-294 
-295             PRInt32 childcount = child->GetSubTreeSize();
-296             if (PRInt32(aIndex) <= childcount) {
-297                 rv = path.Push(current, i + 1);
-298                 if (NS_FAILED(rv)) return PR_FALSE;
-299 
-300                 next = child;
-301                 break;
-302             }
-303 
-304             aIndex -= childcount;
-305         }
-306 
-307         if (! next) {
-308             NS_ERROR("corrupted");
-309             return PR_FALSE;
-310         }
-311 
-312         current = next;
-313     }
-314 
-315     if (current->GetCount() >= kDataCapacity) {
-316         // We just blew the data node's buffer. Create another
-317         // datanode and split.
-318         rv = Split(path, current, aElement, aIndex);
-319         if (NS_FAILED(rv)) return PR_FALSE;
-320     }
-321     else {
-322         current->InsertElementAt(aElement, aIndex);
-323         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
-324     }
-325 
-326     while (path.Length() > 0) {
-327         PRInt32 index;
-328         path.Pop(&current, &index);
-329         current->SetSubTreeSize(current->GetSubTreeSize() + 1);
-330     }
-331 
-332 #ifdef PARANOID
-333     Verify(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask));
-334 #endif
-335 
-336     return PR_TRUE;
-337 }
-338 
-339 PRBool
-340 nsVoidBTree::ReplaceElementAt(void* aElement, PRInt32 aIndex)
-341 {
-342     NS_PRECONDITION((PRWord(aElement) & ~kRoot_PointerMask) == 0,
-343                     "uh oh, someone wants to use the pointer bits");
-344 
-345     if ((PRWord(aElement) & ~kRoot_PointerMask) != 0)
-346         return PR_FALSE;
-347 
-348     NS_PRECONDITION(aElement != nullptr, "nsVoidBTree can't handle null elements");
-349     if (aElement == nullptr)
-350         return PR_FALSE;
-351 
-352     if (aIndex < 0 || aIndex >= Count())
-353         return PR_FALSE;
-354 
-355     if (IsSingleElement()) {
-356         mRoot = PRWord(aElement);
-357         return PR_TRUE;
-358     }
-359 
-360     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-361     while (current->GetType() != Node::eType_Data) {
-362         // We're still in the index. Find the right leaf.
-363         Node* next = nullptr;
-364 
-365         PRInt32 count = current->GetCount();
-366         for (PRInt32 i = 0; i < count; ++i) {
-367             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-368 
-369             PRInt32 childcount = child->GetSubTreeSize();
-370             if (PRInt32(aIndex) < childcount) {
-371                 next = child;
-372                 break;
-373             }
-374 
-375             aIndex -= childcount;
-376         }
-377 
-378         if (! next) {
-379             NS_ERROR("corrupted");
-380             return PR_FALSE;
-381         }
-382 
-383         current = next;
-384     }
-385 
-386     current->SetElementAt(aElement, aIndex);
-387     return PR_TRUE;
-388 }
-389 
-390 PRBool
-391 nsVoidBTree::RemoveElement(void* aElement)
-392 {
-393     PRInt32 index = IndexOf(aElement);
-394     return (index >= 0) ? RemoveElementAt(index) : PR_FALSE;
-395 }
-396 
-397 PRBool
-398 nsVoidBTree::RemoveElementAt(PRInt32 aIndex)
-399 {
-400     PRInt32 count = Count();
-401 
-402     if (aIndex < 0 || aIndex >= count)
-403         return PR_FALSE;
-404 
-405     if (IsSingleElement()) {
-406         // We're removing the one and only element
-407         mRoot = 0;
-408         return PR_TRUE;
-409     }
-410 
-411     // We've got more than one element, and we're removing it.
-412     nsresult rv;
-413     Path path;
-414 
-415     Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-416 
-417     Node* current = root;
-418     while (current->GetType() != Node::eType_Data) {
-419         // We're still in the index. Find the right leaf.
-420         Node* next = nullptr;
-421 
-422         count = current->GetCount();
-423         for (PRInt32 i = 0; i < count; ++i) {
-424             Node* child = NS_REINTERPRET_CAST(Node*, current->GetElementAt(i));
-425 
-426             PRInt32 childcount = child->GetSubTreeSize();
-427             if (PRInt32(aIndex) < childcount) {
-428                 rv = path.Push(current, i);
-429                 if (NS_FAILED(rv)) return PR_FALSE;
-430 
-431                 next = child;
-432                 break;
-433             }
-434             
-435             aIndex -= childcount;
-436         }
-437 
-438         if (! next) {
-439             NS_ERROR("corrupted");
-440             return PR_FALSE;
-441         }
-442 
-443         current = next;
-444     }
-445 
-446     current->RemoveElementAt(aIndex);
-447 
-448     while ((current->GetCount() == 0) && (current != root)) {
-449         Node* doomed = current;
-450 
-451         PRInt32 index;
-452         path.Pop(&current, &index);
-453         current->RemoveElementAt(index);
-454 
-455         Node::Destroy(doomed);
-456     }
-457 
-458     current->SetSubTreeSize(current->GetSubTreeSize() - 1);
-459 
-460     while (path.Length() > 0) {
-461         PRInt32 index;
-462         path.Pop(&current, &index);
-463         current->SetSubTreeSize(current->GetSubTreeSize() - 1);
-464     }
-465 
-466     while ((root->GetType() == Node::eType_Index) && (root->GetCount() == 1)) {
-467         Node* doomed = root;
-468         root = NS_REINTERPRET_CAST(Node*, root->GetElementAt(0));
-469         SetRoot(root);
-470         Node::Destroy(doomed);
-471     }
-472 
-473 #ifdef PARANOID
-474     Verify(root);
-475 #endif
-476 
-477     return PR_TRUE;
-478 }
-479 
-480 void
-481 nsVoidBTree::Clear(void)
-482 {
-483     if (IsEmpty())
-484         return;
-485 
-486     if (! IsSingleElement()) {
-487         Node* root = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-488 
-489 #ifdef PARANOID
-490         Dump(root, 0);
-491 #endif
-492 
-493         DestroySubtree(root);
-494     }
-495 
-496     mRoot = 0;
-497 }
-498 
-499 
-500 void
-501 nsVoidBTree::Compact(void)
-502 {
-503     // XXX We could go through and try to merge datanodes.
-504 }
-505 
-506 PRBool
-507 nsVoidBTree::EnumerateForwards(EnumFunc aFunc, void* aData) const
-508 {
-509     PRBool running = PR_TRUE;
-510 
-511     ConstIterator last = Last();
-512     for (ConstIterator element = First(); running && element != last; ++element)
-513         running = (*aFunc)(*element, aData);
-514 
-515     return running;
-516 }
-517 
-518 PRBool
-519 nsVoidBTree::EnumerateBackwards(EnumFunc aFunc, void* aData) const
-520 {
-521     PRBool running = PR_TRUE;
-522 
-523     ConstIterator element = Last();
-524     ConstIterator first = First();
-525 
-526     if (element != first) {
-527         do {
-528             running = (*aFunc)(*--element, aData);
-529         } while (running && element != first);
-530     }
-531 
-532     return running;
-533 }
-534 
-535 
-536 void
-537 nsVoidBTree::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
-538 {
-539     if (! aResult)
-540         return;
-541 
-542     *aResult = sizeof(*this);
-543 
-544     if (IsSingleElement())
-545         return;
-546 
-547     Path path;
-548     path.Push(NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask), 0);
-549 
-550     while (path.Length()) {
-551         Node* current;
-552         PRInt32 index;
-553         path.Pop(&current, &index);
-554 
-555         if (current->GetType() == Node::eType_Data) {
-556             *aResult += sizeof(Node) + (sizeof(void*) * (kDataCapacity - 1));
-557         }
-558         else {
-559             *aResult += sizeof(Node) + (sizeof(void*) * (kIndexCapacity - 1));
-560 
-561             // If we're in an index node, and there are still kids to
-562             // traverse, well, traverse 'em.
-563             if (index < current->GetCount()) {
-564                 path.Push(current, index + 1);
-565                 path.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), 0);
-566             }
-567         }
-568     }
-569 }
-570 
-571 //----------------------------------------------------------------------
-572 
-573 nsresult
-574 nsVoidBTree::Split(Path& path, Node* aOldNode, void* aElementToInsert, PRInt32 aSplitIndex)
-575 {
-576     nsresult rv;
-577 
-578     PRInt32 capacity = (aOldNode->GetType() == Node::eType_Data) ? kDataCapacity : kIndexCapacity;
-579     PRInt32 delta = 0;
-580 
-581 
-582     Node* newnode;
-583     rv = Node::Create(aOldNode->GetType(), capacity, &newnode);
-584     if (NS_FAILED(rv)) return rv;
-585 
-586     if (aSplitIndex == capacity) {
-587         // If aSplitIndex is the same as the capacity of the node,
-588         // then there'll be nothing to copy from the old node to the
-589         // new node, and the element is really meant to be inserted in
-590         // the newnode. In that case, do it _now_ so that newnode's
-591         // subtree size will be correct.
-592         newnode->InsertElementAt(aElementToInsert, 0);
-593 
-594         if (newnode->GetType() == Node::eType_Data) {
-595             newnode->SetSubTreeSize(1);
-596         }
-597         else {
-598             Node* child = NS_REINTERPRET_CAST(Node*, aElementToInsert);
-599             newnode->SetSubTreeSize(child->GetSubTreeSize());
-600         }
-601     }
-602     else {
-603         // We're meant to insert the element into the oldnode at
-604         // aSplitIndex. Copy data from aOldNode to the newnode but
-605         // _don't_ insert newnode yet. We may need to recursively
-606         // split parents, an operation that allocs, and hence, may
-607         // fail. If it does fail, we wan't to not screw up the
-608         // existing datastructure.
-609         //
-610         // Note that it should be the case that count == capacity, but
-611         // who knows, we may decide at some point to prematurely split
-612         // nodes for some reason or another.
-613         PRInt32 count = aOldNode->GetCount();
-614         PRInt32 i = aSplitIndex;
-615         PRInt32 j = 0;
-616 
-617         newnode->SetCount(count - aSplitIndex);
-618         while (i < count) {
-619             if (aOldNode->GetType() == Node::eType_Data) {
-620                 ++delta;
-621             }
-622             else {
-623                 Node* migrating = NS_REINTERPRET_CAST(Node*, aOldNode->GetElementAt(i));
-624                 delta += migrating->GetSubTreeSize();
-625             }
-626 
-627             newnode->SetElementAt(aOldNode->GetElementAt(i), j);
-628             ++i;
-629             ++j;
-630         }
-631         newnode->SetSubTreeSize(delta);
-632     }
-633 
-634     // Now we split the node.
-635 
-636     if (path.Length() == 0) {
-637         // We made it all the way up to the root! Ok, so, create a new
-638         // root
-639         Node* newroot;
-640         rv = Node::Create(Node::eType_Index, kIndexCapacity, &newroot);
-641         if (NS_FAILED(rv)) return rv;
-642 
-643         newroot->SetCount(2);
-644         newroot->SetElementAt(aOldNode, 0);
-645         newroot->SetElementAt(newnode, 1);
-646         newroot->SetSubTreeSize(aOldNode->GetSubTreeSize() + 1);
-647         SetRoot(newroot);
-648     }
-649     else {
-650         // Otherwise, use the "path" to pop off the next thing above us.
-651         Node* parent;
-652         PRInt32 indx;
-653         path.Pop(&parent, &indx);
-654 
-655         if (parent->GetCount() >= kIndexCapacity) {
-656             // Parent is full, too. Recursively split it.
-657             rv = Split(path, parent, newnode, indx);
-658             if (NS_FAILED(rv)) {
-659                 Node::Destroy(newnode);
-660                 return rv;
-661             }
-662         }
-663         else {
-664             // Room in the parent, so just smack it on up there.
-665             parent->InsertElementAt(newnode, indx);
-666             parent->SetSubTreeSize(parent->GetSubTreeSize() + 1);
-667         }
-668     }
-669 
-670     // Now, since all our operations that might fail have finished, we
-671     // can go ahead and monkey with the old node.
-672 
-673     if (aSplitIndex == capacity) {
-674         PRInt32 nodeslost = newnode->GetSubTreeSize() - 1;
-675         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - nodeslost;
-676         aOldNode->SetSubTreeSize(subtreesize);
-677     }
-678     else {
-679         aOldNode->SetCount(aSplitIndex);
-680         aOldNode->InsertElementAt(aElementToInsert, aSplitIndex);
-681         PRInt32 subtreesize = aOldNode->GetSubTreeSize() - delta + 1;
-682         aOldNode->SetSubTreeSize(subtreesize);
-683     }
-684 
-685     return NS_OK;
-686 }
-687 
-688 
-689 PRInt32
-690 nsVoidBTree::Verify(Node* aNode)
-691 {
-692     // Sanity check the tree by verifying that the subtree sizes all
-693     // add up correctly.
-694     if (aNode->GetType() == Node::eType_Data) {
-695         NS_ASSERTION(aNode->GetCount() == aNode->GetSubTreeSize(), "corrupted");
-696         return aNode->GetCount();
-697     }
-698 
-699     PRInt32 childcount = 0;
-700     for (PRInt32 i = 0; i < aNode->GetCount(); ++i) {
-701         Node* child = NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(i));
-702         childcount += Verify(child);
-703     }
-704 
-705     NS_ASSERTION(childcount == aNode->GetSubTreeSize(), "corrupted");
-706     return childcount;
-707 }
-708 
-709 
-710 void
-711 nsVoidBTree::DestroySubtree(Node* aNode)
-712 {
-713     PRInt32 count = aNode->GetCount() - 1;
-714     while (count >= 0) {
-715         if (aNode->GetType() == Node::eType_Index)
-716             DestroySubtree(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(count)));
-717         
-718         --count;
-719     }
-720 
-721     Node::Destroy(aNode);
-722 }
-723 
-724 #ifdef DEBUG
-725 void
-726 nsVoidBTree::Dump(Node* aNode, PRInt32 aIndent)
-727 {
-728     for (PRInt32 i = 0; i < aIndent; ++i)
-729         printf("  ");
-730 
-731     if (aNode->GetType() == Node::eType_Data) {
-732         printf("data(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
-733     }
-734     else {
-735         printf("index(%d/%d)\n", aNode->GetCount(), aNode->GetSubTreeSize());
-736         for (PRInt32 j = 0; j < aNode->GetCount(); ++j)
-737             Dump(NS_REINTERPRET_CAST(Node*, aNode->GetElementAt(j)), aIndent + 1);
-738     }
-739 }
-740 #endif
-741 
-742 //----------------------------------------------------------------------
-743 //
-744 // nsVoidBTree::ConstIterator and Iterator methods
-745 //
-746 
-747 void* nsVoidBTree::kDummyLast;
-748 
-749 void
-750 nsVoidBTree::ConstIterator::Next()
-751 {
-752     if (mIsSingleton) {
-753         mIsExhausted = PR_TRUE;
-754         return;
-755     }
-756 
-757     // Otherwise we're a real b-tree iterator, and we need to pull and
-758     // pop our path stack appropriately to gyrate into the right
-759     // position.
-760     while (1) {
-761         Node* current;
-762         PRInt32 index;
-763         mPath.Pop(&current, &index);
-764 
-765         PRInt32 count = current->GetCount();
-766 
-767         NS_ASSERTION(index < count, "ran off the end, pal");
-768 
-769         if (++index >= count) {
-770             // XXXwaterson Oh, this is so ugly. I wish I was smart
-771             // enough to figure out a prettier way to do it.
-772             //
-773             // See if we've just iterated past the last element in the
-774             // b-tree, and now need to leave ourselves in the magical
-775             // state that is equal to nsVoidBTree::Last().
-776             if (current->GetType() == Node::eType_Data) {
-777                 PRBool rightmost = PR_TRUE;
-778                 for (PRInt32 slot = mPath.mTop - 1; slot >= 0; --slot) {
-779                     const Link& link = mPath.mLink[slot];
-780                     if (link.mIndex != link.mNode->GetCount() - 1) {
-781                         rightmost = PR_FALSE;
-782                         break;
-783                     }
-784                 }
-785 
-786                 if (rightmost) {
-787                     // It's the last one. Make the path look exactly
-788                     // like nsVoidBTree::Last().
-789                     mPath.Push(current, index);
-790                     return;
-791                 }
-792             }
-793 
-794             // Otherwise, we just ran off the end of a "middling"
-795             // node. Loop around, to pop back up the b-tree to its
-796             // parent.
-797             continue;
-798         }
-799 
-800         // We're somewhere in the middle. Push the new location onto
-801         // the stack.
-802         mPath.Push(current, index);
-803 
-804         // If we're in a data node, we're done: break out of the loop
-805         // here leaving the top of the stack pointing to the next data
-806         // element in the b-tree.
-807         if (current->GetType() == Node::eType_Data)
-808             break;
-809 
-810         // Otherwise, we're still in an index node. Push next node
-811         // down onto the stack, starting "one off" to the left, and
-812         // continue around.
-813         mPath.Push(NS_STATIC_CAST(Node*, current->GetElementAt(index)), -1);
-814     }
-815 }
-816 
-817 void
-818 nsVoidBTree::ConstIterator::Prev()
-819 {
-820     if (mIsSingleton) {
-821         mIsExhausted = PR_FALSE;
-822         return;
-823     }
-824 
-825     // Otherwise we're a real b-tree iterator, and we need to pull and
-826     // pop our path stack appropriately to gyrate into the right
-827     // position. This is just like nsVoidBTree::ConstIterator::Next(),
-828     // but in reverse.
-829     while (1) {
-830         Node* current;
-831         PRInt32 index;
-832         mPath.Pop(&current, &index);
-833 
-834         NS_ASSERTION(index >= 0, "ran off the front, pal");
-835 
-836         if (--index < 0)
-837             continue;
-838 
-839         mPath.Push(current, index);
-840 
-841         if (current->GetType() == Node::eType_Data)
-842             break;
-843 
-844         current = NS_STATIC_CAST(Node*, current->GetElementAt(index));
-845         mPath.Push(current, current->GetCount());
-846     }
-847 }
-848 
-849 const nsVoidBTree::Path
-850 nsVoidBTree::LeftMostPath() const
-851 {
-852     Path path;
-853     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-854 
-855     while (1) {
-856         path.Push(current, 0);
-857 
-858         if (current->GetType() == Node::eType_Data)
-859             break;
-860 
-861         current = NS_STATIC_CAST(Node*, current->GetElementAt(0));
-862     }
-863 
-864     return path;
-865 }
-866 
-867 
-868 const nsVoidBTree::Path
-869 nsVoidBTree::RightMostPath() const
-870 {
-871     Path path;
-872     Node* current = NS_REINTERPRET_CAST(Node*, mRoot & kRoot_PointerMask);
-873 
-874     while (1) {
-875         PRInt32 count = current->GetCount();
-876 
-877         if (current->GetType() == Node::eType_Data) {
-878             path.Push(current, count);
-879             break;
-880         }
-881 
-882         path.Push(current, count - 1);
-883         current = NS_STATIC_CAST(Node*, current->GetElementAt(count - 1));
-884     }
-885 
-886     return path;
-887 }
-888 

- This page was automatically generated by - LXR. - diff --git a/tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif b/tools/performance/pageload/base/lxr.mozilla.org/res/mozilla-banner.gif deleted file mode 100644 index 1640e73105e7a6496653c9999e8a04f55e876eb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4518 zcmds$`9IYA`^MihUbDR|y^S$37&C*(TDB}hnUQ@v$Pp?TIZU>Y(2&fS(S$O{5|K4) z)-3G^$tmHGN=K+vT8@@eojOOKzW>Je`uV;e*L6Sd$K~wmWM$0_K(nA15QIhpp-?0w z1ABW1dl(3V0E3~;z=9zv7#bS3*9UEFtwbWJG8SAHg3!>gPz6v!0m}?PM1%VUAk-c( z$iTwFyekP5go6Yk_`n1(ELT7Vz6!t;3%o2q7X_Fy!1T`*7%Z28m6c~nNr?$w07ip? zg46!~ey2hKg`z&54SLgo8w}pnfaU}cNd&7*KtTgO5qx8UGBRMnAZRC=XWUEyg$N=eqnjyUp%~~>L0LEmQULxeuw5TKVu003knRt#Sdg8a zn-vVMU%z@j0gPsWa3WY?f=9(5(hY3iZrjBN3JP+jFz{u8E-GL#0Z{?0RD$*Of78>` z_`U$fg38LX)2G1obl{}`C|HnA2J8Bui~^`+fJK9>EKwF2I5{~u!5}LLFqzs+EEuJN ziHSS*n?Y~y#hO?!^wT#yEL;Jcr+^P1J}oRfX0dGf{IsB;JxmI)V1nY}(^RT@TN3c{ z^4PrDaDoA1W1}l0fdULx7=Vlhj|xC>I7lLb&p(IBz+VCQT7dfuuu=w+ynw<_wxM7m z8(jVw5(Xb?Kr9iwV}f)dSZ9LmFt|jod&lA6USk zmkP)Vfco=Z3i$E=RP=QPPj1+6wB!ScJesqsr#EB>{nY=p1H!LED7?B$N7Y~^UP*t? zSV#5Eh5gbbGxhl_Y&j%<7ZvF&)+S# zI<)%uc6Yo5!!1!4@jPFkzt_!RWRQfE8CH~${EzR9Q%EX1oWV8p3AvfA;ojT& zu$%Ws^WNWkFUudY7yui?BFN@JKDAV|vsUg@us?mU(Q>o^T6EAqdH^wVG zE_FTsz0|DX+UrBP5%(1AGFLpx_G=Bg9&EJN|KiHspeB+}V;Z;R54eYQi#xrH!qF||Wml9vzq;WA5cVu!@MDl;&q=R-m zjN{M)9ylqL@|KrGC*??kqB1<`IGkx7HX4hM#Ev6C{(VJ&+5MFLxwdVXY7d3Yq-S|{ zl&Mj9yoyPt;x6x$n^`3uD)VgfTo;_WCg5g^&qw3gIHd)~q^i9NxT%9XdK{HxM^Tt zVa^QnVAqbrSk<9h6$y7;y(_q9SV(hS?`nhl`cW$Bb<3M0v?g(fU;kh&`d91ajgl#P zs5lXl%7|<6!vpM7Z%`O0^5PV}5o;uHY>92sM_OulvQXcH-ZMV&&#(iEmtJlcwedCY z21&2*+j90~e&{j?yH-0}H+n(KUzZ6buSMyiN8m77sdiMGqv$^Pt6VF!VzAhrq4L?0`e46^{vc>z3Pm=SA(DC;A zxCrk}AmG86Zp@oW0^0e*Kom#G+>|bVEWk@j^^?U+L6ck z=(wZhO6&%qrf2_Ju4dcUWzP5LuO3nOe^bOABo-ZQt#Wz?4)3zBS|=*e)a_;p&)EH# zjOQc}pKPrD#_oy!m!;H|<9O_CZ^Vk5+qJpxsmu3dXjk#3TTs*uaWZFJ)=D>8p_m7m z7NwP--BKWY%oR4NNN~`SfqQNUxFF3`XYZohrm*SZA%8MGlI(kNZf#MZH2tis`jGyHn+vjGW#$d1QTrUnFG&74hAb|uGrSc|DBud3)sk>-0j zNX-6u(0w3X6jf4(7~&U^&0a4>P{)XZElH&DCIoAyE4H4q98}vQgu-pc=+q@(^S*#~ zeVz3CHeA8IeO}DGf9IbX3!DaAH$N+#O4K&1KQJl&;8jKVkGlgEFezzsP&ozR_`b8!TwL+!)iat)$X>9h6}&qVbP059eKAs0zyUuz!HO!jp`kjOQ8m_-K;}||;oO5-k(`#>cE}9L_51Oj$ zt!pNlJL+q93Ucp{+G|za*VVsrpD?{h+-W+d_E;HrMkAb1-F}P4FmO(*AZU-rnra!rzZd1oEOSakz4q zj|nN-MJW^Mn;HRhXK`R7QO^o9O)wrz;hTGFac2B!xV({DM6%e>J48}GTyi!2f^n>j zLBP=FKLi_W=Oh)6J(Ql5XlFnocJ6#TGps%o=Rab#i3Bo{)zLgz!8)gIG9=SBWk^vW zA>f<00HYV!H-45upLJhu4E|^A#@5c`wcnPC*B~gx*ijxa;>ek>E~_;T8tK=CKxt4e zuh)AJ?+eKYmT3+TrW$_v?rS~&aGZR;F}2+mnddXlc&3{cAEaP3!(fU?)mKX8q%LTG&AgN0`OI)*HD3E z5dlj{X@)D`_J@Svd&chEJ+x39Gso&xe(||r(?q1EJ#ksZx%INf`bVWNW$tuMmle0| z9|&7d(yd)cxj%G%k$GtB*Z7UUCF)%`*Q7OoLx=JE$H=SwZGrRekosgJK2F#7ifCx$!NkdO*oz{l@BHrOV$H@~xg6IvKm^(4Ice zeXPpCdqnv#^ED_y=9tf;RA_)(2>W;>667)z6nE3)deiQ`NW-CyM#clfMflHOk+UTk zvMxyEdxA0>SO}62Hbg!rr}riaQk_#%lhZ$r2&h)+s$;|(#hyg(t>{7P3T2dPJnYu( zueOHzFPRP$GoE(ZVN}Sh0J~_qOrp8_L6ita;dt>t*O(s@k;-WFe$x=I@<7lYk*=oe z@X9&;h`*RBI6wr)&>VZ+!x(*@Vq6>nVscU@2^!OTWau&&w0As-92emH@C#@iK%4@O zC+n((zem%mM2~j~8#jubFGlqFC$2xA-Q9W1((SmosX?s4_4ogTIToKq1Ttz|Sq-7D zQ%4q9lEL`yG*u?o@OB=c3rG);BNB4sOQc1GOp;=xY@|CtkfV}p`$+_M@)KY1pX0>z z#+$pD^RFcV9q(@Q?30s*07X2RV z62}ygD_*g^6x&i2WXlyi#fIi6$KL&TbR>oEc%Zz+mHX+9jTk@sPJSt*6mFq%;4TA32?ODh*$7OjprK7n>J{fA>IX zO~S?d<-wfwJbHMZ@7J7kvh;^bluvP?e}ADtXKMadSpw>y?kv8!drM0`vcVWbJb~z~ z!TUl^kcIHpn*2o-GWEnS`xSGjXNq3*7j?Phyrsjmj)IE#oD(neoG^t8mf|n{QC6>t zEpHcF5Tx6ih)WN;>^L@8`TOVb+4 z4fdvmTO+MH@EJX%{Pw8|>tZgdEG&RzbRy@&OFvPDmHF*Lk1r9jeuXcSOWFe!J6{oz zNiTC<saar zD`dm{3N#0;+f<+uU!bR2w#qBxsU}ALQ+Cl>(sd%esY&wbVP#KX>R-=^aaARGAJx(C zLmRqfj#a^ZYg^Aswxg?IK){a|BL>DebUa!($&jZLjE&(7lU0nWw5LDu6(dsbVhUHp za5G@?Ym!jHja-b918h%#Dv(SsU$woo+7fNlx*pQamezU0k~7FAV~jck*+JFBe1Ki9 zMtTv(L#pn#I&T(9pRd?BS+fPMqSjz>17d#>3_7r0owdr#*qM6dP{>Ir4$TaKpaIAc zs*vM=wm8>&w5)O>&SEv%e675E z7;{RxH;IPd;npNVs)bO)=UtfK5(K*`iI$&T8`*s4QERSMp@~nuk_b|(!4~_`(a@27 zaTnGtd}BKf;JLWlGw2{=#7By2IYjFWX^rn{)9GxTptOH@R4COY;*5{w?SLO1d-A4gd1Zp+<0{=XN*>nZV)WNy164IyW#T{0zWIP0}8e5V^V zif$?8$mgT{QhVam`VwsV5_k6{rS_$i_wldvrOo%HfA7ms>lfPei`0lH6lC*1tYezt diff --git a/tools/performance/pageload/base/vanilla-page/index.html b/tools/performance/pageload/base/vanilla-page/index.html deleted file mode 100644 index 425626127203..000000000000 --- a/tools/performance/pageload/base/vanilla-page/index.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - -

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

-

-Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -Just some very plain HTML. Just some very plain HTML. Just some very plain HTML. -

- - - diff --git a/tools/performance/pageload/cycler.html b/tools/performance/pageload/cycler.html deleted file mode 100644 index 9d42415300c1..000000000000 --- a/tools/performance/pageload/cycler.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - diff --git a/tools/performance/pageload/header.html b/tools/performance/pageload/header.html deleted file mode 100644 index ee7490858fab..000000000000 --- a/tools/performance/pageload/header.html +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/tools/performance/pageload/report.html b/tools/performance/pageload/report.html deleted file mode 100644 index a820be42bfd4..000000000000 --- a/tools/performance/pageload/report.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - -
PageMinMaxMeanStdMedianTimes...
- - diff --git a/tools/performance/pageload/start.html b/tools/performance/pageload/start.html deleted file mode 100644 index de11eed404be..000000000000 --- a/tools/performance/pageload/start.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - -
- - - - -
Cycles: (number of times to loop over the pages)
Pages: (only loop over the first N pages; leave blank to loop over all pages)
I18N: (set to "1" to include i18n pages)
- -
- - From 9b028957ffd2b8d3d27f268fbad46f00b381d600 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 Oct 2014 17:52:24 -0700 Subject: [PATCH 071/100] Bug 1082554 (part 2) - Remove tools/performance/startup/, which is ancient and unused. r=jmaher. --HG-- extra : rebase_source : e5236f362fc4829a3586789a85d02b994a80b4e5 --- tools/performance/startup/gettime.pl | 77 ------------- tools/performance/startup/quit.html | 5 - tools/performance/startup/quit.js | 120 -------------------- tools/performance/startup/quitForMac.html | 15 --- tools/performance/startup/startup-test.html | 21 ---- tools/performance/startup/startup-unix.pl | 55 --------- 6 files changed, 293 deletions(-) delete mode 100644 tools/performance/startup/gettime.pl delete mode 100644 tools/performance/startup/quit.html delete mode 100644 tools/performance/startup/quit.js delete mode 100644 tools/performance/startup/quitForMac.html delete mode 100644 tools/performance/startup/startup-test.html delete mode 100755 tools/performance/startup/startup-unix.pl diff --git a/tools/performance/startup/gettime.pl b/tools/performance/startup/gettime.pl deleted file mode 100644 index 946f6020a654..000000000000 --- a/tools/performance/startup/gettime.pl +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/perl -# 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/. - -# -# Use high resolution routines if installed (on win32 or linux), using -# eval as try/catch block around import of modules. Otherwise, just use 'time()'. -# -# 'Win32::API' -# 'Time::HiRes' -# (also: http://rpmfind.net/linux/rpm2html/search.php?query=perl-Time-HiRes) -# -package Time::PossiblyHiRes; - -use strict; - -#use Time::HiRes qw(gettimeofday); - -my $getLocalTime; # for win32 -my $lpSystemTime = pack("SSSSSSSS"); # for win32 -my $timesub; # code ref - -# returns 12 char string "'s'x9.'m'x3" which is milliseconds since epoch, -# although resolution may vary depending on OS and installed packages - -sub getTime () { - - return &$timesub - if $timesub; - - $timesub = sub { time() . "000"; }; # default - - return &$timesub - if $^O eq "MacOS"; # don't know a better way on Mac - - if ($^O eq "MSWin32") { - eval "use Win32::API;"; - $timesub = sub { - # pass pointer to struct, void return - $getLocalTime = - eval "new Win32::API('kernel32', 'GetLocalTime', [qw{P}], qw{V});" - unless $getLocalTime; - $getLocalTime->Call($lpSystemTime); - my @t = unpack("SSSSSSSS", $lpSystemTime); - sprintf("%9s%03s", time(), pop @t); - } if !$@; - } - - # ass-u-me if not mac/win32, then we're on a unix flavour - else { - eval "use Time::HiRes qw(gettimeofday);"; - $timesub = sub { - my @t = gettimeofday(); - $t[0]*1000 + int($t[1]/1000); - } if !$@; - } - - return &$timesub; - -} - -# -# -# Test script to compare with low-res time: -# -# require "gettime.pl"; -# -# use POSIX qw(strftime); -# -# print "hires time = " . Time::PossiblyHiRes::getTime() . "\n"; -# print "lowres time = " . time() . "\n"; -# - - -# end package -1; diff --git a/tools/performance/startup/quit.html b/tools/performance/startup/quit.html deleted file mode 100644 index b6e5eb573e01..000000000000 --- a/tools/performance/startup/quit.html +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/tools/performance/startup/quit.js b/tools/performance/startup/quit.js deleted file mode 100644 index 39258141625b..000000000000 --- a/tools/performance/startup/quit.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- indent-tabs-mode: nil -*- */ -/* 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/. */ - -/* - From mozilla/toolkit/content - These files did not have a license -*/ - -function quitHook() -{ - var xhr = new XMLHttpRequest(); - xhr.open("GET", "http://" + location.host + "/server/shutdown", true); - xhr.onreadystatechange = function (event) - { - if (xhr.readyState == 4) - goQuitApplication(); - }; - xhr.send(null); -} - -function canQuitApplication() -{ - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - if (!os) - { - return true; - } - - try - { - var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] - .createInstance(Components.interfaces.nsISupportsPRBool); - os.notifyObservers(cancelQuit, "quit-application-requested", null); - - // Something aborted the quit process. - if (cancelQuit.data) - { - return false; - } - } - catch (ex) - { - } - os.notifyObservers(null, "quit-application-granted", null); - return true; -} - -function goQuitApplication() -{ - const privs = 'UniversalXPConnect'; - - try - { - netscape.security.PrivilegeManager.enablePrivilege(privs); - } - catch(ex) - { - throw('goQuitApplication: privilege failure ' + ex); - } - - if (!canQuitApplication()) - { - return false; - } - - const kAppStartup = '@mozilla.org/toolkit/app-startup;1'; - const kAppShell = '@mozilla.org/appshell/appShellService;1'; - var appService; - var forceQuit; - - if (kAppStartup in Components.classes) - { - appService = Components.classes[kAppStartup]. - getService(Components.interfaces.nsIAppStartup); - forceQuit = Components.interfaces.nsIAppStartup.eForceQuit; - - } - else if (kAppShell in Components.classes) - { - appService = Components.classes[kAppShell]. - getService(Components.interfaces.nsIAppShellService); - forceQuit = Components.interfaces.nsIAppShellService.eForceQuit; - } - else - { - throw 'goQuitApplication: no AppStartup/appShell'; - } - - var windowManager = Components. - classes['@mozilla.org/appshell/window-mediator;1'].getService(); - - var windowManagerInterface = windowManager. - QueryInterface(Components.interfaces.nsIWindowMediator); - - var enumerator = windowManagerInterface.getEnumerator(null); - - while (enumerator.hasMoreElements()) - { - var domWindow = enumerator.getNext(); - if (("tryToClose" in domWindow) && !domWindow.tryToClose()) - { - return false; - } - domWindow.close(); - } - - try - { - appService.quit(forceQuit); - } - catch(ex) - { - throw('goQuitApplication: ' + ex); - } - - return true; -} diff --git a/tools/performance/startup/quitForMac.html b/tools/performance/startup/quitForMac.html deleted file mode 100644 index 22a4de33a248..000000000000 --- a/tools/performance/startup/quitForMac.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - -Use JS to quit the browser on Mac OS X - - - - -

This page uses netscape.security.PrivilegeManager JS calls to cleanly and completely exit the browser under Mac OSX.

- - - diff --git a/tools/performance/startup/startup-test.html b/tools/performance/startup/startup-test.html deleted file mode 100644 index 20da3e1637fa..000000000000 --- a/tools/performance/startup/startup-test.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/tools/performance/startup/startup-unix.pl b/tools/performance/startup/startup-unix.pl deleted file mode 100755 index fc7f7c575419..000000000000 --- a/tools/performance/startup/startup-unix.pl +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/perl -# 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/. - - -# -# Script to time mozilla startup. -# Feeds in start time as url argument, startup-test.html -# takes this arg and computes the time difference. -# So something like this happens: -# -# mozilla file:/foo/startup-test.html?begin=T -# where T = ms since 1970, e.g.: -# mozilla file:/foo/startup-test.html?begin=999456977124 -# -# NOTE: You will get much better results if you install the -# Time::HiRes perl module (urls in gettime.pl) and test -# an optimized build. -# -# For optimized builds, startup-test.html will also dump -# the time out to stdout if you set: -# user_pref("browser.dom.window.dump.enabled", true); -# - -require 5.003; - -require "gettime.pl"; - -use strict; -use Cwd; - -sub PrintUsage { - die < [] - e.g - startup-unix.pl ../../../dist/bin/mozilla - startup-unix.pl ../../../dist/bin/mozilla -P \"Default User\" -END_USAGE -} - -{ - PrintUsage() unless $#ARGV >= 0; - # Build up command string. - my $cwd = Cwd::getcwd(); - - my $cmd = join(' ', map {/\s/ ? qq("$_") : $_} @ARGV); - my $time = Time::PossiblyHiRes::getTime(); - $cmd .= qq( -url "file:$cwd/startup-test.html?begin=$time"); - print "cmd = $cmd\n"; - - # Run the command. - exec $cmd; -} - From 99cb35f533366310e211f9dc28a6d87b98f094b5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 Oct 2014 17:52:41 -0700 Subject: [PATCH 072/100] Bug 1082554 (part 3) - Move diff-talos.py from tools/performance/ to testing/talos/. r=jmaher. DONTBUILD because NPOTB. --HG-- rename : tools/performance/diff-talos.py => testing/talos/diff-talos.py --- {tools/performance => testing/talos}/diff-talos.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tools/performance => testing/talos}/diff-talos.py (100%) diff --git a/tools/performance/diff-talos.py b/testing/talos/diff-talos.py similarity index 100% rename from tools/performance/diff-talos.py rename to testing/talos/diff-talos.py From b160becb9fb95367a1afb3ec10b31ac64d4993ac Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Wed, 15 Oct 2014 17:34:26 -0400 Subject: [PATCH 073/100] Bug 1081409: Fix forwarding of captured MediaStreams to PeerConnections r=jib --- .../src/mediapipeline/MediaPipeline.cpp | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index 16ad7089ae4f..bf7df1c89eb9 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -1195,22 +1195,29 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( const layers::PlanarYCbCrData *data = yuv->GetData(); uint8_t *y = data->mYChannel; -#ifdef DEBUG uint8_t *cb = data->mCbChannel; uint8_t *cr = data->mCrChannel; -#endif uint32_t width = yuv->GetSize().width; uint32_t height = yuv->GetSize().height; uint32_t length = yuv->GetDataSize(); + // NOTE: length may be rounded up or include 'other' data (see + // YCbCrImageDataDeserializerBase::ComputeMinBufferSize()) // SendVideoFrame only supports contiguous YCrCb 4:2:0 buffers // Verify it's contiguous and in the right order - MOZ_ASSERT(cb == (y + YSIZE(width, height)) && - cr == (cb + CRSIZE(width, height)) && - length == I420SIZE(width, height)); - // XXX Consider making this a non-debug-only check if we ever implement + if (cb != (y + YSIZE(width, height)) || + cr != (cb + CRSIZE(width, height))) { + MOZ_ASSERT(false, "Incorrect cb/cr pointers in ProcessVideoChunk()!"); + return; + } + if (length < I420SIZE(width, height)) { + MOZ_ASSERT(false, "Invalid length for ProcessVideoChunk()"); + return; + } + // XXX Consider modifying these checks if we ever implement // any subclasses of PlanarYCbCrImage that allow disjoint buffers such - // that y+3(width*height)/2 might go outside the allocation. + // that y+3(width*height)/2 might go outside the allocation or there are + // pads between y, cr and cb. // GrallocImage can have wider strides, and so in some cases // would encode as garbage. If we need to encode it we'll either want to // modify SendVideoFrame or copy/move the data in the buffer. @@ -1218,7 +1225,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( // OK, pass it on to the conduit MOZ_MTLOG(ML_DEBUG, "Sending a video frame"); // Not much for us to do with an error - conduit->SendVideoFrame(y, length, width, height, mozilla::kVideoI420, 0); + conduit->SendVideoFrame(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0); } else if(format == ImageFormat::CAIRO_SURFACE) { layers::CairoImage* rgb = const_cast( From e55e4364d5b92242b6ad539d8c10a0caca8a25e5 Mon Sep 17 00:00:00 2001 From: Randy Lin Date: Thu, 16 Oct 2014 12:40:09 +0800 Subject: [PATCH 074/100] Bug 1074177 - DTMF tone are not coming on Bluetooth headset. r=mwu. --- dom/system/gonk/AudioManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp index ae5bdcc70a3b..dbed18fce279 100644 --- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -835,6 +835,11 @@ AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) { static_cast(aStream), aIndex, AUDIO_DEVICE_OUT_EARPIECE); + status += AudioSystem::setStreamVolumeIndex( + static_cast(aStream), + aIndex, + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET); + return status ? NS_ERROR_FAILURE : NS_OK; #endif } From 94f92795a95304d06eb338d0179ef48db8af644d Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Oct 2014 18:42:00 +0200 Subject: [PATCH 075/100] Bug 583083 - Use the '//# sourceURL=display.js' directive's filename in Error.prototype.stack; r=shu --- .../tests/basic/display-url-in-stack-trace.js | 27 +++++++++++++++++++ js/src/jsexn.cpp | 16 +++++++---- js/src/vm/Stack.cpp | 7 +++++ js/src/vm/Stack.h | 5 +--- 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 js/src/jit-test/tests/basic/display-url-in-stack-trace.js diff --git a/js/src/jit-test/tests/basic/display-url-in-stack-trace.js b/js/src/jit-test/tests/basic/display-url-in-stack-trace.js new file mode 100644 index 000000000000..acab47ab61ee --- /dev/null +++ b/js/src/jit-test/tests/basic/display-url-in-stack-trace.js @@ -0,0 +1,27 @@ +eval(` + function a() { + return b(); + } + //# sourceURL=source-a.js +`); + +eval(` + function b() { + return c(); + } + //# sourceURL=source-b.js +`); + +eval(` + function c() { + return Error().stack; + } + //# sourceURL=source-c.js +`); + +let filenames = a().split(/\n/) + .map(f => f.slice(f.indexOf("@") + 1, f.indexOf(":"))); +print(filenames.join("\n")); +assertEq(filenames[0], "source-c.js"); +assertEq(filenames[1], "source-b.js"); +assertEq(filenames[2], "source-a.js"); diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index ed570ca781d1..1b5baaffdae9 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -289,11 +289,17 @@ js::ComputeStackString(JSContext *cx) return nullptr; /* Now the filename. */ - const char *cfilename = i.scriptFilename(); - if (!cfilename) - cfilename = ""; - if (!sb.append(cfilename, strlen(cfilename))) - return nullptr; + + /* First, try the `//# sourceURL=some-display-url.js` directive. */ + if (const char16_t *display = i.scriptDisplayURL()) { + if (!sb.append(display, js_strlen(display))) + return nullptr; + } + /* Second, try the actual filename. */ + else if (const char *filename = i.scriptFilename()) { + if (!sb.append(filename, strlen(filename))) + return nullptr; + } uint32_t column = 0; uint32_t line = i.computeLine(&column); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 6047ed43cfa8..05d232b613db 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -957,6 +957,13 @@ FrameIter::scriptFilename() const MOZ_CRASH("Unexpected state"); } +const char16_t * +FrameIter::scriptDisplayURL() const +{ + ScriptSource *ss = scriptSource(); + return ss->hasDisplayURL() ? ss->displayURL() : nullptr; +} + unsigned FrameIter::computeLine(uint32_t *column) const { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 9d7e297ee031..e09ba468f75c 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1644,12 +1644,9 @@ class FrameIter bool isGeneratorFrame() const; bool hasArgs() const { return isNonEvalFunctionFrame(); } - /* - * Get an abstract frame pointer dispatching to either an interpreter, - * baseline, or rematerialized optimized frame. - */ ScriptSource *scriptSource() const; const char *scriptFilename() const; + const char16_t *scriptDisplayURL() const; unsigned computeLine(uint32_t *column = nullptr) const; JSAtom *functionDisplayAtom() const; bool mutedErrors() const; From 7ee3b3105e03644adb1489f233bc5bf1765b1761 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Oct 2014 18:42:00 +0200 Subject: [PATCH 076/100] Bug 583083 - Use the '//# sourceURL=display.js' directive's filename in js::SavedStacks; r=shu --- .../tests/saved-stacks/display-url.js | 26 +++++++++++++++++++ js/src/vm/SavedStacks.cpp | 19 +++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 js/src/jit-test/tests/saved-stacks/display-url.js diff --git a/js/src/jit-test/tests/saved-stacks/display-url.js b/js/src/jit-test/tests/saved-stacks/display-url.js new file mode 100644 index 000000000000..4688fefe013e --- /dev/null +++ b/js/src/jit-test/tests/saved-stacks/display-url.js @@ -0,0 +1,26 @@ +eval(` + function a() { + return b(); + } + //# sourceURL=source-a.js +`); + +eval(` + function b() { + return c(); + } + //# sourceURL=source-b.js +`); + +eval(` + function c() { + return saveStack(); + } + //# sourceURL=source-c.js +`); + +let stack = a(); +print(stack); +assertEq(stack.source, "source-c.js"); +assertEq(stack.parent.source, "source-b.js"); +assertEq(stack.parent.parent.source, "source-a.js"); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 70dcbdea5931..96a4981ff9f6 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -676,10 +676,12 @@ SavedStacks::getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLoca // that doesn't employ memoization, and update |locationp|'s slots directly. if (!iter.hasScript()) { - const char *filename = iter.scriptFilename(); - if (!filename) - filename = ""; - locationp->source = Atomize(cx, filename, strlen(filename)); + if (const char16_t *displayURL = iter.scriptDisplayURL()) { + locationp->source = AtomizeChars(cx, displayURL, js_strlen(displayURL)); + } else { + const char *filename = iter.scriptFilename() ? iter.scriptFilename() : ""; + locationp->source = Atomize(cx, filename, strlen(filename)); + } if (!locationp->source) return false; @@ -694,8 +696,13 @@ SavedStacks::getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLoca PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key); if (!p) { - const char *filename = script->filename() ? script->filename() : ""; - RootedAtom source(cx, Atomize(cx, filename, strlen(filename))); + RootedAtom source(cx); + if (const char16_t *displayURL = iter.scriptDisplayURL()) { + source = AtomizeChars(cx, displayURL, js_strlen(displayURL)); + } else { + const char *filename = script->filename() ? script->filename() : ""; + source = Atomize(cx, filename, strlen(filename)); + } if (!source) return false; From 1d2292d6973173795c2a743f2bc93fcc50e41a2e Mon Sep 17 00:00:00 2001 From: JW Wang Date: Tue, 14 Oct 2014 23:28:00 +0200 Subject: [PATCH 077/100] Bug 760770 - allow 'progress' and 'suspend' events after 'ended'. r=roc --- .../test/test_timeupdate_small_files.html | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/content/media/test/test_timeupdate_small_files.html b/content/media/test/test_timeupdate_small_files.html index b6d51800bdbe..9eac499e2536 100644 --- a/content/media/test/test_timeupdate_small_files.html +++ b/content/media/test/test_timeupdate_small_files.html @@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495319 var manager = new MediaTestManager; -function timeupdate(e) { - var v = e.target; - v._timeupdateCount++; - ok(v.gotEnded == 0, v._name + " - shouldn't get timeupdate after ended"); -} - function ended(e) { var v = e.target; - ++v.gotEnded; - ok(v._timeupdateCount > 0, v._name + " - should see at least one timeupdate: " + v.currentTime); - v._finished = true; + ++v.counter["ended"]; + is(v.counter["ended"], 1, v._name + " should see ended only once"); + ok(v.counter["timeupdate"] > 0, v._name + " should see at least one timeupdate: " + v.currentTime); + + // Rest event counters for we don't allow events after ended. + eventsToLog.forEach(function(e) { + v.counter[e] = 0; + }); + // Finish the test after 500ms. We shouldn't receive any timeupdate events // after the ended event, so this gives time for any pending timeupdate events // to fire so we can ensure we don't regress behaviour. @@ -39,10 +39,9 @@ function ended(e) { // invoked when it's removed from a document), and we don't want those // confusing the test results. v.removeEventListener("ended", ended, false); - v.removeEventListener("timeupdate", timeupdate, false); - for (var i = 0; i < eventsToLog.length; ++i) { - v.removeEventListener(eventsToLog[i], logEvent, false); - } + eventsToLog.forEach(function(e) { + v.removeEventListener(e, logEvent, false); + }); removeNodeAndSource(v); manager.finished(v.token); }, @@ -50,17 +49,14 @@ function ended(e) { } var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmetadata", - "loadeddata", "playing", "progress", "timeupdate", "ended", "suspend", "error", "stalled", "emptied", "abort", + "loadeddata", "playing", "timeupdate", "error", "stalled", "emptied", "abort", "waiting", "pause"]; + function logEvent(event) { - if (event.target.gotEnded > (event.type == "ended" ? 1 : 0)) { - if (event.target.currentSrc.slice(-9) == "seek.webm" && event.type == "stalled") { - todo(false, event.target.currentSrc + " got unexpected stalled after ended (bug 760770)"); - } else { - ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended"); - } - } else { - info(event.target.currentSrc + " got " + event.type); + var v = event.target; + ++v.counter[event.type]; + if (v.counter["ended"] > 0) { + is(v.counter[event.type], 0, v._name + " got unexpected " + event.type + " after ended"); } } @@ -71,14 +67,15 @@ function startTest(test, token) { manager.started(token); v.src = test.name; v._name = test.name; - v._timeupdateCount = 0; - v._finished = false; - v.gotEnded = 0; + + // Keep how many events received for each event type. + v.counter = {}; + eventsToLog.forEach(function(e) { + v.addEventListener(e, logEvent, false); + v.counter[e] = 0; + }); v.addEventListener("ended", ended, false); - v.addEventListener("timeupdate", timeupdate, false); - for (var i = 0; i < eventsToLog.length; ++i) { - v.addEventListener(eventsToLog[i], logEvent, false); - } + v.counter["ended"] = 0; document.body.appendChild(v); v.play(); } From f5092e255eb4be7e724400d4a4480ca83e3146be Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 13 Oct 2014 23:19:00 +0200 Subject: [PATCH 078/100] Bug 1034854 - Add support for ECDSA to WebCrypto API r=ttaubert,dkeeler r=bz --- config/external/nss/nss.def | 5 + dom/crypto/CryptoKey.cpp | 31 +++- dom/crypto/CryptoKey.h | 2 + dom/crypto/WebCryptoCommon.h | 6 + dom/crypto/WebCryptoTask.cpp | 216 +++++++++++++++------- dom/crypto/test/test-vectors.js | 50 +++++ dom/crypto/test/test_WebCrypto_ECDSA.html | 162 ++++++++++++++++ dom/webidl/SubtleCrypto.webidl | 3 + 8 files changed, 403 insertions(+), 72 deletions(-) create mode 100644 dom/crypto/test/test_WebCrypto_ECDSA.html diff --git a/config/external/nss/nss.def b/config/external/nss/nss.def index 1c71dccd51dd..9480229e9f62 100644 --- a/config/external/nss/nss.def +++ b/config/external/nss/nss.def @@ -160,6 +160,8 @@ DER_GetInteger_Util DER_Lengths DER_SetUInteger DER_UTCTimeToTime_Util +DSAU_DecodeDerSigToLen +DSAU_EncodeDerSigWithLen DTLS_GetHandshakeTimeout DTLS_ImportFD HASH_Begin @@ -308,6 +310,7 @@ PK11_DeriveWithTemplate PK11_DestroyContext PK11_DestroyGenericObject PK11_DestroyMergeLog +PK11_DestroyObject PK11_DestroyTokenObject PK11_DigestBegin PK11_DigestFinal @@ -369,6 +372,7 @@ PK11_ImportCert PK11_ImportCertForKey PK11_ImportCRL PK11_ImportDERPrivateKeyInfoAndReturnKey +PK11_ImportPublicKey PK11_ImportSymKey PK11_InitPin PK11_IsDisabled @@ -672,6 +676,7 @@ VFY_CreateContext VFY_DestroyContext VFY_End VFY_Update +VFY_VerifyData VFY_VerifyDataDirect VFY_VerifyDataWithAlgorithmID _SGN_VerifyPKCS1DigestInfo diff --git a/dom/crypto/CryptoKey.cpp b/dom/crypto/CryptoKey.cpp index 002fdf9521df..13ab8f932ebe 100644 --- a/dom/crypto/CryptoKey.cpp +++ b/dom/crypto/CryptoKey.cpp @@ -395,7 +395,12 @@ CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData, } } - return SECKEY_ExtractPublicKey(spki.get()); + ScopedSECKEYPublicKey tmp(SECKEY_ExtractPublicKey(spki.get())); + if (!tmp.get() || !PublicKeyValid(tmp.get())) { + return nullptr; + } + + return SECKEY_CopyPublicKey(tmp); } nsresult @@ -843,6 +848,10 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk, } key->u.ec.publicValue = *point; + if (!PublicKeyValid(key)) { + return nullptr; + } + return SECKEY_CopyPublicKey(key); } @@ -881,6 +890,26 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKey* aPubKey, } } +bool +CryptoKey::PublicKeyValid(SECKEYPublicKey* aPubKey) +{ + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot.get()) { + return false; + } + + // This assumes that NSS checks the validity of a public key when + // it is imported into a PKCS#11 module, and returns CK_INVALID_HANDLE + // if it is invalid. + CK_OBJECT_HANDLE id = PK11_ImportPublicKey(slot, aPubKey, PR_FALSE); + if (id == CK_INVALID_HANDLE) { + return false; + } + + SECStatus rv = PK11_DestroyObject(slot, id); + return (rv == SECSuccess); +} + bool CryptoKey::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const { diff --git a/dom/crypto/CryptoKey.h b/dom/crypto/CryptoKey.h index d1f6f71d2f18..966151b5388f 100644 --- a/dom/crypto/CryptoKey.h +++ b/dom/crypto/CryptoKey.h @@ -171,6 +171,8 @@ public: JsonWebKey& aRetVal, const nsNSSShutDownPreventionLock& /*proofOfLock*/); + static bool PublicKeyValid(SECKEYPublicKey* aPubKey); + // Structured clone methods use these to clone keys bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; bool ReadStructuredClone(JSStructuredCloneReader* aReader); diff --git a/dom/crypto/WebCryptoCommon.h b/dom/crypto/WebCryptoCommon.h index 891c4c981105..9b548d534f00 100644 --- a/dom/crypto/WebCryptoCommon.h +++ b/dom/crypto/WebCryptoCommon.h @@ -27,6 +27,7 @@ #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5" #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP" #define WEBCRYPTO_ALG_ECDH "ECDH" +#define WEBCRYPTO_ALG_ECDSA "ECDSA" // WebCrypto key formats #define WEBCRYPTO_KEY_FORMAT_RAW "raw" @@ -84,6 +85,9 @@ #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256" #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384" #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512" +#define JWK_ALG_ECDSA_P_256 "ES256" +#define JWK_ALG_ECDSA_P_384 "ES384" +#define JWK_ALG_ECDSA_P_521 "ES521" // JWK usages #define JWK_USE_ENC "enc" @@ -225,6 +229,8 @@ NormalizeToken(const nsString& aName, nsString& aDest) aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP); } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) { aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA); // Named curve values } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) { aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256); diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index fb5dd8ef1342..a05104997fff 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -66,7 +66,8 @@ enum TelemetryAlgorithm { // Later additions TA_AES_KW = 19, TA_ECDH = 20, - TA_PBKDF2 = 21 + TA_PBKDF2 = 21, + TA_ECDSA = 22, }; // Convenience functions for extracting / converting information @@ -782,10 +783,9 @@ public: mMgfMechanism = CKG_MGF1_SHA384; break; case CKM_SHA512: mMgfMechanism = CKG_MGF1_SHA512; break; - default: { + default: mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; - } } } @@ -955,49 +955,97 @@ private: } }; -class RsassaPkcs1Task : public WebCryptoTask +class AsymmetricSignVerifyTask : public WebCryptoTask { public: - RsassaPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm, - CryptoKey& aKey, - const CryptoOperationData& aSignature, - const CryptoOperationData& aData, - bool aSign) + AsymmetricSignVerifyTask(JSContext* aCx, + const ObjectOrString& aAlgorithm, + CryptoKey& aKey, + const CryptoOperationData& aSignature, + const CryptoOperationData& aData, + bool aSign) : mOidTag(SEC_OID_UNKNOWN) , mPrivKey(aKey.GetPrivateKey()) , mPubKey(aKey.GetPublicKey()) , mSign(aSign) , mVerified(false) + , mEcdsa(false) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); - - CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); - ATTEMPT_BUFFER_INIT(mData, aData); if (!aSign) { ATTEMPT_BUFFER_INIT(mSignature, aSignature); } - // Look up the SECOidTag based on the KeyAlgorithm - // static_cast is safe because we only get here if the algorithm name - // is RSASSA-PKCS1-v1_5, and that only happens if we've constructed - // an RsaHashedKeyAlgorithm - CK_MECHANISM_TYPE mech; - mech = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash); + nsString algName; + mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); + if (NS_FAILED(mEarlyRv)) { + return; + } - switch (mech) { - case CKM_SHA_1: - mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; - case CKM_SHA256: - mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; - case CKM_SHA384: - mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; - case CKM_SHA512: - mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; - default: { - mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + // Look up the SECOidTag + if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + mEcdsa = false; + Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); + CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); + + // For RSA, the hash name comes from the key algorithm + nsString hashName = aKey.Algorithm().mRsa.mHash.mName; + switch (MapAlgorithmNameToMechanism(hashName)) { + case CKM_SHA_1: + mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; + case CKM_SHA256: + mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; + case CKM_SHA384: + mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; + case CKM_SHA512: + mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; + default: + mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return; + } + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + mEcdsa = true; + Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA); + CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA); + + // For ECDSA, the hash name comes from the algorithm parameter + RootedDictionary params(aCx); + mEarlyRv = Coerce(aCx, params, aAlgorithm); + if (NS_FAILED(mEarlyRv)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } + + nsString hashName; + mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); + if (NS_FAILED(mEarlyRv)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } + + CK_MECHANISM_TYPE hashMechanism = MapAlgorithmNameToMechanism(hashName); + if (hashMechanism == UNKNOWN_CK_MECHANISM) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } + + switch (hashMechanism) { + case CKM_SHA_1: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; + case CKM_SHA256: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; + case CKM_SHA384: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; + case CKM_SHA512: + mOidTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; + default: + mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return; + } + } else { + // This shouldn't happen; CreateSignVerifyTask shouldn't create + // one of these unless it's for the above algorithms. + MOZ_ASSERT(false); } // Check that we have the appropriate key @@ -1015,6 +1063,7 @@ private: CryptoBuffer mData; bool mSign; bool mVerified; + bool mEcdsa; virtual nsresult DoCrypto() MOZ_OVERRIDE { @@ -1022,44 +1071,53 @@ private: if (mSign) { ScopedSECItem signature((SECItem*) PORT_Alloc(sizeof(SECItem))); ScopedSGNContext ctx(SGN_NewContext(mOidTag, mPrivKey)); - if (!ctx) { + if (!signature.get() || !ctx.get()) { return NS_ERROR_DOM_OPERATION_ERR; } - rv = MapSECStatus(SGN_Begin(ctx)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + rv = MapSECStatus(SEC_SignData(signature, mData.Elements(), + mData.Length(), mPrivKey, mOidTag)); - rv = MapSECStatus(SGN_Update(ctx, mData.Elements(), mData.Length())); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - - rv = MapSECStatus(SGN_End(ctx, signature)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - - ATTEMPT_BUFFER_ASSIGN(mSignature, signature); - } else { - ScopedSECItem signature(mSignature.ToSECItem()); - if (!signature) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } - - ScopedVFYContext ctx(VFY_CreateContext(mPubKey, signature, - mOidTag, nullptr)); - if (!ctx) { - int err = PORT_GetError(); - if (err == SEC_ERROR_BAD_SIGNATURE) { - mVerified = false; - return NS_OK; + if (mEcdsa) { + // DER-decode the signature + int signatureLength = PK11_SignatureLen(mPrivKey); + ScopedSECItem rawSignature(DSAU_DecodeDerSigToLen(signature.get(), + signatureLength)); + if (!rawSignature.get()) { + return NS_ERROR_DOM_OPERATION_ERR; } - return NS_ERROR_DOM_OPERATION_ERR; + + ATTEMPT_BUFFER_ASSIGN(mSignature, rawSignature); + } else { + ATTEMPT_BUFFER_ASSIGN(mSignature, signature); } - rv = MapSECStatus(VFY_Begin(ctx)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + } else { + ScopedSECItem signature; - rv = MapSECStatus(VFY_Update(ctx, mData.Elements(), mData.Length())); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + if (mEcdsa) { + // DER-encode the signature + ScopedSECItem rawSignature(mSignature.ToSECItem()); + if (!rawSignature.get()) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } - rv = MapSECStatus(VFY_End(ctx)); + signature = (SECItem*) PORT_Alloc(sizeof(SECItem)); + if (!signature.get()) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + rv = MapSECStatus(DSAU_EncodeDerSigWithLen(signature, rawSignature, + rawSignature->len)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); + } else { + signature = mSignature.ToSECItem(); + if (!signature) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + } + + rv = MapSECStatus(VFY_VerifyData(mData.Elements(), mData.Length(), + mPubKey, signature, mOidTag, nullptr)); mVerified = NS_SUCCEEDED(rv); } @@ -1661,12 +1719,23 @@ private: virtual nsresult AfterCrypto() MOZ_OVERRIDE { - // Check permissions for the requested operation - if (mKey->GetKeyType() == CryptoKey::PRIVATE && - mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) { - return NS_ERROR_DOM_DATA_ERR; + uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0; + if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + privateAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; + publicAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; + } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + privateAllowedUsages = CryptoKey::SIGN; + publicAllowedUsages = CryptoKey::VERIFY; } + // Check permissions for the requested operation + if ((mKey->GetKeyType() == CryptoKey::PRIVATE && + mKey->HasUsageOtherThan(privateAllowedUsages)) || + (mKey->GetKeyType() == CryptoKey::PUBLIC && + mKey->HasUsageOtherThan(publicAllowedUsages))) { + return NS_ERROR_DOM_DATA_ERR; + } + mKey->Algorithm().MakeEc(mAlgName, mNamedCurve); if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { @@ -1991,7 +2060,8 @@ public: mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; return; } - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); if (NS_FAILED(mEarlyRv)) { @@ -2014,7 +2084,8 @@ public: } // Set key usages. - if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { privateAllowedUsages = CryptoKey::SIGN; publicAllowedUsages = CryptoKey::VERIFY; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { @@ -2176,10 +2247,9 @@ public: case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break; case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break; case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break; - default: { + default: mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; - } } ATTEMPT_BUFFER_INIT(mSalt, params.mSalt) @@ -2544,8 +2614,10 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { - return new RsassaPkcs1Task(aCx, aAlgorithm, aKey, aSignature, aData, aSign); + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature, + aData, aSign); } return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); @@ -2618,7 +2690,8 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx, algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); } else { @@ -2694,7 +2767,8 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx, return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages); } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) || - algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { + algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) || + algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA)) { return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages); } else { return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); diff --git a/dom/crypto/test/test-vectors.js b/dom/crypto/test/test-vectors.js index e4dee263c54f..8d8c607d7137 100644 --- a/dom/crypto/test/test-vectors.js +++ b/dom/crypto/test/test-vectors.js @@ -608,4 +608,54 @@ tv = { x: "XOe4bjsyZgQD5jcS7wmY3q4QJ_rsPBvp92-TTf61jpg", } }, + + // NIST ECDSA test vectors + // http://csrc.nist.gov/groups/STM/cavp/index.html + ecdsa_verify: { + pub_jwk: { + "kty": "EC", + "crv": "P-521", + + // 0061387fd6b95914e885f912edfbb5fb274655027f216c4091ca83e19336740fd8 + // 1aedfe047f51b42bdf68161121013e0d55b117a14e4303f926c8debb77a7fdaad1 + "x": "AGE4f9a5WRTohfkS7fu1-ydGVQJ_IWxAkcqD4ZM2dA_Y" + + "Gu3-BH9RtCvfaBYRIQE-DVWxF6FOQwP5Jsjeu3en_arR", + // 00e7d0c75c38626e895ca21526b9f9fdf84dcecb93f2b233390550d2b1463b7ee3 + // f58df7346435ff0434199583c97c665a97f12f706f2357da4b40288def888e59e6 + "y": "AOfQx1w4Ym6JXKIVJrn5_fhNzsuT8rIzOQVQ0rFGO37j" + + "9Y33NGQ1_wQ0GZWDyXxmWpfxL3BvI1faS0Aoje-Ijlnm", + }, + + "data": util.hex2abv( + "9ecd500c60e701404922e58ab20cc002651fdee7cbc9336adda33e4c1088fab1" + + "964ecb7904dc6856865d6c8e15041ccf2d5ac302e99d346ff2f686531d255216" + + "78d4fd3f76bbf2c893d246cb4d7693792fe18172108146853103a51f824acc62" + + "1cb7311d2463c3361ea707254f2b052bc22cb8012873dcbb95bf1a5cc53ab89f" + ), + "sig": util.hex2abv( + "004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" + + "99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" + + "0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" + + "4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac566e8ee3b43" + ), + + // Same as "sig", but with the last few octets set to 0 + "sig_tampered": util.hex2abv( + "004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" + + "99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" + + "0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" + + "4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac56600000000" + ) + }, + + ecdsa_bad: { + pub_jwk: { + "kty": "EC", + "crv": "P-521", + "x": "BhOH_WuVkU6IX5Eu37tfsnRlUCfyFsQJHKg-GTNnQP2B" + + "rt_gR_UbQr32gWESEBPg1VsRehTkMD-SbI3rt3p_2q0B", + "y": "AUNouOdGgHsraPNhXNeNdhpGTd15GPyN9R0iWWL98ePc" + + "JD4mUQD/DsEzNZ4zLkTdSa/Y5fOP6GEzVzQy0zwC+goD" + } + } } diff --git a/dom/crypto/test/test_WebCrypto_ECDSA.html b/dom/crypto/test/test_WebCrypto_ECDSA.html new file mode 100644 index 000000000000..74d1845dd8a5 --- /dev/null +++ b/dom/crypto/test/test_WebCrypto_ECDSA.html @@ -0,0 +1,162 @@ + + + + +WebCrypto Test Suite + + + + + + + + + + + + + + + + + + + + + +
+ + +
RUN ALL
+ +
+ Summary: + 0 passed, + 0 failed, + 0 pending. +
+
+ + + + + + + +
TestResultTime
+ +
+ + +
+ + + diff --git a/dom/webidl/SubtleCrypto.webidl b/dom/webidl/SubtleCrypto.webidl index a4e1b07950cb..09bd3ac97ba3 100644 --- a/dom/webidl/SubtleCrypto.webidl +++ b/dom/webidl/SubtleCrypto.webidl @@ -87,6 +87,9 @@ dictionary EcdhKeyDeriveParams : Algorithm { required CryptoKey public; }; +dictionary EcdsaParams : Algorithm { + required AlgorithmIdentifier hash; +}; /***** JWK *****/ From cd19a8d6b01707549602d7ce0b68cc7874b5adbc Mon Sep 17 00:00:00 2001 From: Akshendra Pratap Singh Date: Wed, 15 Oct 2014 07:42:00 +0200 Subject: [PATCH 079/100] Bug 1037990 - AccessLabelKey is now accessible event if the element is detached. r=bzbarsky --- .../html/content/src/nsGenericHTMLElement.cpp | 15 ++--- dom/events/EventStateManager.cpp | 12 ++-- dom/events/EventStateManager.h | 3 +- dom/events/test/mochitest.ini | 1 + dom/events/test/test_bug1037990.html | 61 +++++++++++++++++++ 5 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 dom/events/test/test_bug1037990.html diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 8580903b4f9b..065f691625b0 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -291,16 +291,11 @@ static const nsAttrValue::EnumTable kDirTable[] = { void nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel) { - //XXXsmaug We shouldn't need PresContext for this. - nsPresContext *presContext = GetPresContext(eForComposedDoc); - - if (presContext) { - nsAutoString suffix; - GetAccessKey(suffix); - if (!suffix.IsEmpty() && - presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) { - aLabel.Append(suffix); - } + nsAutoString suffix; + GetAccessKey(suffix); + if (!suffix.IsEmpty()) { + EventStateManager::GetAccessKeyLabelPrefix(this, aLabel); + aLabel.Append(suffix); } } diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 373b60fe054a..a966c873ff63 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -944,16 +944,21 @@ EventStateManager::ExecuteAccessKey(nsTArray& aAccessCharCodes, return false; } -bool -EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix) +// static +void +EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix) { aPrefix.Truncate(); nsAutoString separator, modifierText; nsContentUtils::GetModifierSeparatorText(separator); - nsCOMPtr container = mPresContext->GetContainerWeak(); + nsCOMPtr container = aElement->OwnerDoc()->GetDocShell(); int32_t modifierMask = GetAccessModifierMaskFor(container); + if (modifierMask == -1) { + return; + } + if (modifierMask & NS_MODIFIER_CONTROL) { nsContentUtils::GetControlText(modifierText); aPrefix.Append(modifierText + separator); @@ -974,7 +979,6 @@ EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix) nsContentUtils::GetShiftText(modifierText); aPrefix.Append(modifierText + separator); } - return !aPrefix.IsEmpty(); } void diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index 20073f590c6c..68c0809853b3 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -40,6 +40,7 @@ class WheelTransaction; namespace dom { class DataTransfer; +class Element; class TabParent; } // namespace dom @@ -169,7 +170,7 @@ public: */ uint32_t GetRegisteredAccessKey(nsIContent* aContent); - bool GetAccessKeyLabelPrefix(nsAString& aPrefix); + static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix); nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer, bool aHaveHotspot, float aHotspotX, float aHotspotY, diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini index 081c141e47e1..ac452c415ab2 100644 --- a/dom/events/test/mochitest.ini +++ b/dom/events/test/mochitest.ini @@ -22,6 +22,7 @@ skip-if = buildapp == 'b2g' skip-if = buildapp == 'b2g' [test_bug288392.html] [test_bug299673-1.html] +[test_bug1037990.html] [test_bug299673-2.html] [test_bug322588.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage diff --git a/dom/events/test/test_bug1037990.html b/dom/events/test/test_bug1037990.html new file mode 100644 index 000000000000..025c8744b288 --- /dev/null +++ b/dom/events/test/test_bug1037990.html @@ -0,0 +1,61 @@ + + + + + + Test for Bug 1037990 + + + + +Mozilla Bug 1037990 +

+ +
+
+ + + From e22f96099007a2ec434f2060475a88e7ef3d6bd0 Mon Sep 17 00:00:00 2001 From: Benjamin Chen Date: Wed, 15 Oct 2014 17:34:30 +0800 Subject: [PATCH 080/100] Bug 1041362 - Modify testcases because during the oncanplaythrough callback function, the element might not ended but the mediastream is ended. r=roc --- ...t_mediarecorder_record_immediate_stop.html | 9 +++--- ...est_mediarecorder_record_no_timeslice.html | 28 ++++++++----------- .../test_mediarecorder_record_session.html | 8 ++++-- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/content/media/test/test_mediarecorder_record_immediate_stop.html b/content/media/test/test_mediarecorder_record_immediate_stop.html index 1327f1acd73c..0f51fe300ed0 100644 --- a/content/media/test/test_mediarecorder_record_immediate_stop.html +++ b/content/media/test/test_mediarecorder_record_immediate_stop.html @@ -97,9 +97,9 @@ function startTest(test, token) { // This handler completes a start and stop of recording and verifies // respective media recorder state. - var canPlayThrough = function() { - element.removeEventListener('canplaythrough', canPlayThrough, false); - + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + element.play(); mediaRecorder.start(); is(mediaRecorder.state, 'recording', 'Media recorder should be recording'); is(mediaRecorder.stream, element.stream, @@ -112,8 +112,7 @@ function startTest(test, token) { 'Media recorder stream = element stream post recording'); }; - element.addEventListener('canplaythrough', canPlayThrough, false); - element.play(); + element.preload = "metadata"; } manager.runTests(gMediaRecorderTests, startTest); diff --git a/content/media/test/test_mediarecorder_record_no_timeslice.html b/content/media/test/test_mediarecorder_record_no_timeslice.html index 5d0270e013de..67321ceb4efc 100644 --- a/content/media/test/test_mediarecorder_record_no_timeslice.html +++ b/content/media/test/test_mediarecorder_record_no_timeslice.html @@ -84,24 +84,18 @@ function startTest(test, token) { } }; - element.oncanplaythrough = function () { - element.oncanplaythrough = null; - // If content has ended, skip the test - if (element.ended) { - ok(true, 'ended fired before canplaythrough, skipping test'); - manager.finished(token); - } else { - // If content hasn't ended, start recording - mediaRecorder.start(); - is(mediaRecorder.state, 'recording', - 'Media recorder should be recording'); - is(mediaRecorder.stream, element.stream, - 'Media recorder stream = element stream at the start of recording'); - // Recording will automatically stop when the stream ends. - } - } + element.preload = "metadata"; - element.play(); + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + mediaRecorder.start(); + is(mediaRecorder.state, 'recording', + 'Media recorder should be recording'); + is(mediaRecorder.stream, element.stream, + 'Media recorder stream = element stream at the start of recording'); + + element.play(); + } } manager.runTests(gMediaRecorderTests, startTest); diff --git a/content/media/test/test_mediarecorder_record_session.html b/content/media/test/test_mediarecorder_record_session.html index a4b4a4b7a8ed..3c179ced020e 100644 --- a/content/media/test/test_mediarecorder_record_session.html +++ b/content/media/test/test_mediarecorder_record_session.html @@ -54,15 +54,17 @@ function startTest(test, token) { ok(false, 'Unexpected warning fired'); } - element.oncanplaythrough = function () { - element.oncanplaythrough = null; + element.preload = "metadata"; + + element.onloadedmetadata = function () { + element.onloadedmetadata = null; + element.play(); for (var i = 0; i < mExpectStopCount; i++) { mediaRecorder.start(1000); mediaRecorder.stop(); } } - element.play(); } manager.runTests(gMediaRecorderTests, startTest); From 51b2436fc189cc419203eff96ab8d3a285a2f949 Mon Sep 17 00:00:00 2001 From: David Parks Date: Sun, 12 Oct 2014 16:23:20 -0700 Subject: [PATCH 081/100] Bug 1065881 - [e10s] Crash on child process shutdown in ShadowLayerForwarder::InWorkerThread. r=nical Had caused a crash in the test_streams_element_capture mochitest on Windows. The issue was that the audio decoder thread was destroying stale media frames by releasing a reference to them. This was causing the release of an Image on that thread, but that thread does not process a MessageLoop so the current MessageLoop is null. This is not a problem. Obviously, any thread that has no MessageLoop can't be the worker thread. --- content/media/test/mochitest.ini | 1 - gfx/layers/ipc/ShadowLayers.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/content/media/test/mochitest.ini b/content/media/test/mochitest.ini index 94787bd9120e..139a859f6923 100644 --- a/content/media/test/mochitest.ini +++ b/content/media/test/mochitest.ini @@ -460,7 +460,6 @@ skip-if = true # bug 1021673 [test_standalone.html] [test_streams_autoplay.html] [test_streams_element_capture.html] -skip-if = e10s && os == 'win' # Bug 1065881 - Crash on child process shutdown in ShadowLayerForwarder::InWorkerThread [test_streams_element_capture_createObjectURL.html] [test_streams_element_capture_playback.html] [test_streams_element_capture_reset.html] diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 116b8fc15672..07b349024fc6 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -494,7 +494,7 @@ ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker bool ShadowLayerForwarder::InWorkerThread() { - return GetMessageLoop()->id() == MessageLoop::current()->id(); + return MessageLoop::current() && (GetMessageLoop()->id() == MessageLoop::current()->id()); } static void RemoveTextureWorker(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone) From 120fb11ce323eb155049eff83b68b805e1803141 Mon Sep 17 00:00:00 2001 From: pchang Date: Fri, 26 Sep 2014 15:14:35 +0800 Subject: [PATCH 082/100] Bug 1067243 - Refine the selection reason matching logic to toggle the visibility of selection carets. r=roc --- layout/base/SelectionCarets.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/layout/base/SelectionCarets.cpp b/layout/base/SelectionCarets.cpp index 9243db0f3b32..276601a318c4 100644 --- a/layout/base/SelectionCarets.cpp +++ b/layout/base/SelectionCarets.cpp @@ -856,7 +856,9 @@ SelectionCarets::NotifySelectionChanged(nsIDOMDocument* aDoc, SetVisibility(false); return NS_OK; } - if (aReason & nsISelectionListener::KEYPRESS_REASON) { + if (!aReason || (aReason & (nsISelectionListener::DRAG_REASON | + nsISelectionListener::KEYPRESS_REASON | + nsISelectionListener::MOUSEDOWN_REASON))) { SetVisibility(false); } else { UpdateSelectionCarets(); @@ -905,7 +907,7 @@ SelectionCarets::AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos) void SelectionCarets::ScrollPositionChanged() { - if (!mAPZenabled) { + if (!mAPZenabled && mVisible) { SetVisibility(false); //TODO: handling scrolling for selection bubble when APZ is off LaunchScrollEndDetector(); From 4a4253aa97a6d7e8ace69986a494f19367f03cc7 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Tue, 14 Oct 2014 20:57:00 +0200 Subject: [PATCH 083/100] Bug 1073134 - Be more permissive on OSX 10.9.5 when parental control is on. r=jdm --- .../parentalcontrols/nsParentalControlsServiceCocoa.mm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm index 09da2c89d47f..0eb018400186 100644 --- a/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm +++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm @@ -32,13 +32,15 @@ nsParentalControlsService::GetParentalControlsEnabled(bool *aResult) NS_IMETHODIMP nsParentalControlsService::GetBlockFileDownloadsEnabled(bool *aResult) { - return NS_ERROR_NOT_AVAILABLE; + *aResult = false; + return NS_OK; } NS_IMETHODIMP nsParentalControlsService::GetLoggingEnabled(bool *aResult) { - return NS_ERROR_NOT_AVAILABLE; + *aResult = false; + return NS_OK; } NS_IMETHODIMP @@ -47,7 +49,8 @@ nsParentalControlsService::Log(int16_t aEntryType, nsIURI *aSource, nsIFile *aTarget) { - return NS_ERROR_NOT_AVAILABLE; + // silently drop on the floor + return NS_OK; } NS_IMETHODIMP From b1db9690ab951ee58bbef6b9ffe1cca861da3682 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Oct 2014 19:21:00 +0200 Subject: [PATCH 084/100] Bug 1082761 - Add Debugger.prototype.findObjects; r=jimb --- js/public/UbiNodeTraverse.h | 9 + js/src/doc/Debugger/Debugger.md | 26 +++ .../tests/debug/Debugger-findObjects-01.js | 4 + .../tests/debug/Debugger-findObjects-02.js | 18 ++ .../tests/debug/Debugger-findObjects-03.js | 12 ++ .../tests/debug/Debugger-findObjects-04.js | 16 ++ .../tests/debug/Debugger-findObjects-05.js | 10 + .../tests/debug/Debugger-findObjects-06.js | 14 ++ .../tests/debug/Debugger-findObjects-07.js | 22 ++ .../tests/debug/Debugger-findObjects-08.js | 12 ++ .../tests/debug/Debugger-findObjects-09.js | 9 + js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/Debugger.cpp | 198 ++++++++++++++++++ js/src/vm/Debugger.h | 2 + 14 files changed, 353 insertions(+) create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-01.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-02.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-03.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-04.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-05.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-06.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-07.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-08.js create mode 100644 js/src/jit-test/tests/debug/Debugger-findObjects-09.js diff --git a/js/public/UbiNodeTraverse.h b/js/public/UbiNodeTraverse.h index d64e02726951..e5a2a33b233e 100644 --- a/js/public/UbiNodeTraverse.h +++ b/js/public/UbiNodeTraverse.h @@ -95,6 +95,15 @@ struct BreadthFirst { // as many starting points as you like. Return false on OOM. bool addStart(Node node) { return pending.append(node); } + // Add |node| as a starting point for the traversal (see addStart) and also + // add it to the |visited| set. Return false on OOM. + bool addStartVisited(Node node) { + typename NodeMap::AddPtr ptr = visited.lookupForAdd(node); + if (!ptr && !visited.add(ptr, node, typename Handler::NodeData())) + return false; + return addStart(node); + } + // True if the handler wants us to compute edge names; doing so can be // expensive in time and memory. True by default. bool wantNames; diff --git a/js/src/doc/Debugger/Debugger.md b/js/src/doc/Debugger/Debugger.md index 029d6ab659e9..97efdfd30d1e 100644 --- a/js/src/doc/Debugger/Debugger.md +++ b/js/src/doc/Debugger/Debugger.md @@ -378,6 +378,32 @@ other kinds of objects. such scripts appear can be affected by the garbage collector's behavior, so this function's behavior is not entirely deterministic. +findObjects([query]) +: Return an array of [`Debugger.Object`][object] instances referring to each + live object allocated in the scope of the debuggee globals that matches + *query*. Each instance appears only once in the array. *Query* is an object + whose properties restrict which objects are returned; an object must meet + all the criteria given by *query* to be returned. If *query* is omitted, we + return the [`Debugger.Object`][object] instances for all objects allocated + in the scope of debuggee globals. + + The *query* object may have the following properties: + + `class` + : If present, only return objects whose internal `[[Class]]`'s name + matches the given string. Note that in some cases, the prototype object + for a given constructor has the same `[[Class]]` as the instances that + refer to it, but cannot itself be used as a valid instance of the + class. Code gathering objects by class name may need to examine them + further before trying to use them. + + All properties of *query* are optional. Passing an empty object returns all + objects in debuggee globals. + + Unlike `findScripts`, this function is deterministic and will never return + [`Debugger.Object`s][object] referring to previously unreachable objects + that had not been collected yet. + clearBreakpoint(handler) : Remove all breakpoints set in this `Debugger` instance that use handler as their handler. Note that, if breakpoints using other diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-01.js b/js/src/jit-test/tests/debug/Debugger-findObjects-01.js new file mode 100644 index 000000000000..4ed43310a92b --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-01.js @@ -0,0 +1,4 @@ +// In a debugger with no debuggees, findObjects should return no objects. + +var dbg = new Debugger; +assertEq(dbg.findObjects().length, 0); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-02.js b/js/src/jit-test/tests/debug/Debugger-findObjects-02.js new file mode 100644 index 000000000000..bfb33391f922 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-02.js @@ -0,0 +1,18 @@ +// In a debuggee with live objects, findObjects finds those objects. + +var g = newGlobal(); + +let defObject = v => g.eval(`this.${v} = { toString: () => "[object ${v}]" }`); +defObject("a"); +defObject("b"); +defObject("c"); + +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); +var aw = gw.makeDebuggeeValue(g.a); +var bw = gw.makeDebuggeeValue(g.b); +var cw = gw.makeDebuggeeValue(g.c); + +assertEq(dbg.findObjects().indexOf(aw) != -1, true); +assertEq(dbg.findObjects().indexOf(bw) != -1, true); +assertEq(dbg.findObjects().indexOf(cw) != -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-03.js b/js/src/jit-test/tests/debug/Debugger-findObjects-03.js new file mode 100644 index 000000000000..d391415cc28d --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-03.js @@ -0,0 +1,12 @@ +// findObjects' result includes objects referenced by other objects. + +var g = newGlobal(); +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); + +g.eval('this.a = { b: {} };'); + +var bw = gw.makeDebuggeeValue(g.a.b); + +var objects = dbg.findObjects(); +assertEq(objects.indexOf(bw) != -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-04.js b/js/src/jit-test/tests/debug/Debugger-findObjects-04.js new file mode 100644 index 000000000000..a01378e35fa6 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-04.js @@ -0,0 +1,16 @@ +// findObjects' result includes objects captured by closures. + +var g = newGlobal(); +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); + +g.eval(` + this.f = (function () { + let a = { foo: () => {} }; + return () => a; + }()); +`); + +let objects = dbg.findObjects(); +let aw = gw.makeDebuggeeValue(g.f()); +assertEq(objects.indexOf(aw) != -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-05.js b/js/src/jit-test/tests/debug/Debugger-findObjects-05.js new file mode 100644 index 000000000000..05120919640f --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-05.js @@ -0,0 +1,10 @@ +// findObjects' result doesn't include any duplicates. + +var g = newGlobal(); +var dbg = new Debugger(); +dbg.addDebuggee(g); + +let objects = dbg.findObjects(); +let set = new Set(objects); + +assertEq(objects.length, set.size); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-06.js b/js/src/jit-test/tests/debug/Debugger-findObjects-06.js new file mode 100644 index 000000000000..8bdedab03a44 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-06.js @@ -0,0 +1,14 @@ +// In a debugger with multiple debuggees, findObjects finds objects from all debuggees. + +var g1 = newGlobal(); +var g2 = newGlobal(); +var dbg = new Debugger(); +var g1w = dbg.addDebuggee(g1); +var g2w = dbg.addDebuggee(g2); + +g1.eval('this.a = {};'); +g2.eval('this.b = {};'); + +var objects = dbg.findObjects(); +assertEq(objects.indexOf(g1w.makeDebuggeeValue(g1.a)) != -1, true); +assertEq(objects.indexOf(g2w.makeDebuggeeValue(g2.b)) != -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-07.js b/js/src/jit-test/tests/debug/Debugger-findObjects-07.js new file mode 100644 index 000000000000..3e306a86c6d6 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-07.js @@ -0,0 +1,22 @@ +// findObjects can filter objects by class name. + +var g = newGlobal(); + +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); + +g.eval('this.re = /foo/;'); +g.eval('this.d = new Date();'); + +var rew = gw.makeDebuggeeValue(g.re); +var dw = gw.makeDebuggeeValue(g.d); + +var objects; + +objects = dbg.findObjects({ class: "RegExp" }); +assertEq(objects.indexOf(rew) != -1, true); +assertEq(objects.indexOf(dw) == -1, true); + +objects = dbg.findObjects({ class: "Date" }); +assertEq(objects.indexOf(dw) != -1, true); +assertEq(objects.indexOf(rew) == -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-08.js b/js/src/jit-test/tests/debug/Debugger-findObjects-08.js new file mode 100644 index 000000000000..fd6ceb1031d7 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-08.js @@ -0,0 +1,12 @@ +// Passing bad query properties to Debugger.prototype.findScripts throws. + +load(libdir + 'asserts.js'); + +var dbg = new Debugger(); +var g = newGlobal(); + +assertThrowsInstanceOf(() => dbg.findObjects({ class: null }), TypeError); +assertThrowsInstanceOf(() => dbg.findObjects({ class: true }), TypeError); +assertThrowsInstanceOf(() => dbg.findObjects({ class: 1337 }), TypeError); +assertThrowsInstanceOf(() => dbg.findObjects({ class: /re/ }), TypeError); +assertThrowsInstanceOf(() => dbg.findObjects({ class: {} }), TypeError); diff --git a/js/src/jit-test/tests/debug/Debugger-findObjects-09.js b/js/src/jit-test/tests/debug/Debugger-findObjects-09.js new file mode 100644 index 000000000000..a50f2be08895 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findObjects-09.js @@ -0,0 +1,9 @@ +// We don't return objects where our query's class name is the prefix of the +// object's class name and vice versa. + +var dbg = new Debugger(); +var g = newGlobal(); +var gw = dbg.addDebuggee(g); + +assertEq(dbg.findObjects({ class: "Objec" }).length, 0); +assertEq(dbg.findObjects({ class: "Objectttttt" }).length, 0); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index a8dd532a2e4b..75db592e55ae 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -32,6 +32,7 @@ macro(caller, caller, "caller") \ macro(callFunction, callFunction, "callFunction") \ macro(caseFirst, caseFirst, "caseFirst") \ + macro(class_, class_, "class") \ macro(Collator, Collator, "Collator") \ macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \ macro(columnNumber, columnNumber, "columnNumber") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 352ef71ce5d4..87f801175800 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -20,6 +20,7 @@ #include "jit/BaselineJIT.h" #include "js/Debug.h" #include "js/GCAPI.h" +#include "js/UbiNodeTraverse.h" #include "js/Vector.h" #include "vm/ArgumentsObject.h" #include "vm/DebuggerMemory.h" @@ -2982,6 +2983,202 @@ Debugger::findScripts(JSContext *cx, unsigned argc, Value *vp) return true; } +/* + * A class for parsing 'findObjects' query arguments and searching for objects + * that match the criteria they represent. + */ +class MOZ_STACK_CLASS Debugger::ObjectQuery +{ + public: + /* Construct an ObjectQuery to use matching scripts for |dbg|. */ + ObjectQuery(JSContext *cx, Debugger *dbg) : + cx(cx), dbg(dbg), className(cx) + {} + + /* + * Parse the query object |query|, and prepare to match only the objects it + * specifies. + */ + bool parseQuery(HandleObject query) { + /* Check for the 'class' property */ + RootedValue cls(cx); + if (!JSObject::getProperty(cx, query, query, cx->names().class_, &cls)) + return false; + if (!cls.isUndefined()) { + if (!cls.isString()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, + "query object's 'class' property", + "neither undefined nor a string"); + return false; + } + className = cls; + } + return true; + } + + /* Set up this ObjectQuery appropriately for a missing query argument. */ + void omittedQuery() { + className.setUndefined(); + } + + /* + * Traverse the heap to find all relevant objects and add them to the + * provided vector. + */ + bool findObjects(AutoObjectVector &objs) { + if (!prepareQuery()) + return false; + + { + /* + * We can't tolerate the GC moving things around while we're + * searching the heap. Check that nothing we do causes a GC. + */ + JS::AutoCheckCannotGC autoCannotGC; + + Traversal traversal(cx, *this, autoCannotGC); + if (!traversal.init()) + return false; + + /* Add each debuggee global as a start point of our traversal. */ + for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) { + if (!traversal.addStartVisited(JS::ubi::Node(static_cast(r.front())))) + return false; + } + + /* + * Iterate over all compartments and add traversal start points at + * objects that have CCWs in other compartments keeping them alive. + */ + for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) { + JSCompartment *comp = c.get(); + if (!comp) + continue; + for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { + const CrossCompartmentKey &key = e.front().key(); + if (key.kind != CrossCompartmentKey::ObjectWrapper) + continue; + JSObject *obj = static_cast(key.wrapped); + if (!traversal.addStartVisited(JS::ubi::Node(obj))) + return false; + } + } + + if (!traversal.traverse()) + return false; + + /* + * Iterate over the visited set of nodes and accumulate all + * |JSObject|s matching our criteria in the given vector. + */ + for (Traversal::NodeMap::Range r = traversal.visited.all(); !r.empty(); r.popFront()) { + JS::ubi::Node node = r.front().key(); + if (!node.is()) + continue; + + JSObject *obj = node.as(); + + if (!className.isUndefined()) { + const char *objClassName = obj->getClass()->name; + if (strcmp(objClassName, classNameCString.ptr()) != 0) + continue; + } + + if (!objs.append(obj)) + return false; + } + + return true; + } + } + + /* + * |ubi::Node::BreadthFirst| interface. + * + * We use an empty traversal function and just iterate over the traversal's + * visited set post-facto in |findObjects|. + */ + + class NodeData {}; + typedef JS::ubi::BreadthFirst Traversal; + bool operator() (Traversal &, JS::ubi::Node, const JS::ubi::Edge &, NodeData *, bool) + { + return true; + } + + private: + /* The context in which we should do our work. */ + JSContext *cx; + + /* The debugger for which we conduct queries. */ + Debugger *dbg; + + /* + * If this is non-null, matching objects will have a class whose name is + * this property. + */ + RootedValue className; + + /* The className member, as a C string. */ + JSAutoByteString classNameCString; + + /* + * Given that either omittedQuery or parseQuery has been called, prepare the + * query for matching objects. + */ + bool prepareQuery() { + if (className.isString()) { + if (!classNameCString.encodeLatin1(cx, className.toString())) + return false; + } + + return true; + } +}; + +bool +Debugger::findObjects(JSContext *cx, unsigned argc, Value *vp) +{ + THIS_DEBUGGER(cx, argc, vp, "findObjects", args, dbg); + + ObjectQuery query(cx, dbg); + + if (args.length() >= 1) { + RootedObject queryObject(cx, NonNullObject(cx, args[0])); + if (!queryObject || !query.parseQuery(queryObject)) + return false; + } else { + query.omittedQuery(); + } + + /* + * Accumulate the objects in an AutoObjectVector, instead of creating the JS + * array as we go, because we mustn't allocate JS objects or GC while we + * traverse the heap graph. + */ + AutoObjectVector objects(cx); + + if (!query.findObjects(objects)) + return false; + + size_t length = objects.length(); + RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); + if (!result) + return false; + + result->ensureDenseInitializedLength(cx, 0, length); + + for (size_t i = 0; i < length; i++) { + RootedValue debuggeeVal(cx, ObjectValue(*objects[i])); + if (!dbg->wrapDebuggeeValue(cx, &debuggeeVal)) + return false; + result->setDenseElement(i, debuggeeVal); + } + + args.rval().setObject(*result); + return true; +} + bool Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp) { @@ -3061,6 +3258,7 @@ const JSFunctionSpec Debugger::methods[] = { JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0), JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 0, 0), JS_FN("findScripts", Debugger::findScripts, 1, 0), + JS_FN("findObjects", Debugger::findObjects, 1, 0), JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0), JS_FN("makeGlobalObjectReference", Debugger::makeGlobalObjectReference, 1, 0), JS_FS_END diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 47b43b1dd0a1..ad8d4f987d8d 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -271,6 +271,7 @@ class Debugger : private mozilla::LinkedListElement class FrameRange; class ScriptQuery; + class ObjectQuery; bool addDebuggeeGlobal(JSContext *cx, Handle obj); bool addDebuggeeGlobal(JSContext *cx, Handle obj, @@ -369,6 +370,7 @@ class Debugger : private mozilla::LinkedListElement static bool getNewestFrame(JSContext *cx, unsigned argc, Value *vp); static bool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp); static bool findScripts(JSContext *cx, unsigned argc, Value *vp); + static bool findObjects(JSContext *cx, unsigned argc, Value *vp); static bool findAllGlobals(JSContext *cx, unsigned argc, Value *vp); static bool makeGlobalObjectReference(JSContext *cx, unsigned argc, Value *vp); static bool construct(JSContext *cx, unsigned argc, Value *vp); From 73f77307944dbe4f024c168542e2d4021297b491 Mon Sep 17 00:00:00 2001 From: Mike Taylor Date: Wed, 15 Oct 2014 20:16:00 +0200 Subject: [PATCH 085/100] Bug 1083536 - Remove max-width/height on radio & checkbox inputs. r=bz --- b2g/chrome/content/content.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css index c28f2fa32e70..645ab3d384ac 100644 --- a/b2g/chrome/content/content.css +++ b/b2g/chrome/content/content.css @@ -178,8 +178,6 @@ button { input[type="radio"], input[type="checkbox"] { - max-width: 14px; - max-height: 14px; border: 1px solid #a7a7a7 !important; padding: 2px 1px 2px 1px; } From 14285121937ded91e91bab46c6c37be6e2c73652 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 16 Oct 2014 09:40:19 +0100 Subject: [PATCH 086/100] Bug 1081867 - Convert textrun metrics to physical coordinates before merging with visual-overflow region. r=smontagu --- gfx/thebes/gfxFont.cpp | 8 +++++--- gfx/thebes/gfxFont.h | 2 +- gfx/thebes/gfxMacFont.cpp | 6 ++++-- gfx/thebes/gfxMacFont.h | 2 +- gfx/thebes/gfxTextRun.cpp | 16 ++++++++++------ gfx/thebes/gfxTextRun.h | 2 ++ layout/generic/nsTextFrame.cpp | 21 +++++++++++++++++++-- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 28f059d41ba3..0e802851188f 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2103,7 +2103,8 @@ gfxFont::Measure(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - Spacing *aSpacing) + Spacing *aSpacing, + uint16_t aOrientation) { // If aBoundingBoxType is TIGHT_HINTED_OUTLINE_EXTENTS // and the underlying cairo font may be antialiased, @@ -2119,14 +2120,15 @@ gfxFont::Measure(gfxTextRun *aTextRun, if (mNonAAFont) { return mNonAAFont->Measure(aTextRun, aStart, aEnd, TIGHT_HINTED_OUTLINE_EXTENTS, - aRefContext, aSpacing); + aRefContext, aSpacing, aOrientation); } } const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit(); // Current position in appunits gfxFont::Orientation orientation = - aTextRun->IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal; + aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT + ? gfxFont::eVertical : gfxFont::eHorizontal; const gfxFont::Metrics& fontMetrics = GetMetrics(orientation); RunMetrics metrics; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 3c783372b35a..588b5ba255a9 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1556,7 +1556,7 @@ public: uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aContextForTightBoundingBox, - Spacing *aSpacing); + Spacing *aSpacing, uint16_t aOrientation); /** * Line breaks have been changed at the beginning and/or end of a substring * of the text. Reshaping may be required; glyph updating is permitted. diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 44608b9470c7..43976596f96e 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -167,11 +167,13 @@ gfxMacFont::Measure(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - Spacing *aSpacing) + Spacing *aSpacing, + uint16_t aOrientation) { gfxFont::RunMetrics metrics = gfxFont::Measure(aTextRun, aStart, aEnd, - aBoundingBoxType, aRefContext, aSpacing); + aBoundingBoxType, aRefContext, aSpacing, + aOrientation); // if aBoundingBoxType is not TIGHT_HINTED_OUTLINE_EXTENTS then we need to add // a pixel column each side of the bounding box in case of antialiasing "bleed" diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index 36ec9de140f8..b61ea55a2be3 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -35,7 +35,7 @@ public: uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aContextForTightBoundingBox, - Spacing *aSpacing); + Spacing *aSpacing, uint16_t aOrientation); virtual mozilla::TemporaryRef GetScaledFont(mozilla::gfx::DrawTarget *aTarget); diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index e9d8762a74fd..a2cb3bb8919d 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -690,13 +690,15 @@ gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, gfxContext *aRefContext, PropertyProvider *aProvider, uint32_t aSpacingStart, uint32_t aSpacingEnd, + uint16_t aOrientation, Metrics *aMetrics) { nsAutoTArray spacingBuffer; bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider, aSpacingStart, aSpacingEnd, &spacingBuffer); Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType, aRefContext, - haveSpacing ? spacingBuffer.Elements() : nullptr); + haveSpacing ? spacingBuffer.Elements() : nullptr, + aOrientation); aMetrics->CombineWith(metrics, IsRightToLeft()); } @@ -704,7 +706,7 @@ void gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, gfxFont::BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - PropertyProvider *aProvider, Metrics *aMetrics) + PropertyProvider *aProvider, uint16_t aOrientation, Metrics *aMetrics) { if (aStart >= aEnd) return; @@ -717,7 +719,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Metrics metrics; AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd, aBoundingBoxType, aRefContext, - aProvider, aStart, aEnd, &metrics); + aProvider, aStart, aEnd, aOrientation, &metrics); // Clip the bounding box to the ligature part gfxFloat bboxLeft = metrics.mBoundingBox.X(); @@ -757,7 +759,8 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); AccumulatePartialLigatureMetrics(font, start, ligatureRunStart, - aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics); + aBoundingBoxType, aRefContext, aProvider, + iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); // XXX This sucks. We have to get glyph extents just so we can detect // glyphs outside the font box, even when aBoundingBoxType is LOOSE, @@ -767,10 +770,11 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, AccumulateMetricsForRun(font, ligatureRunStart, ligatureRunEnd, aBoundingBoxType, aRefContext, aProvider, ligatureRunStart, ligatureRunEnd, - &accumulatedMetrics); + iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end, - aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics); + aBoundingBoxType, aRefContext, aProvider, + iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); } return accumulatedMetrics; diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index b4472f5e7a35..6b80c799b991 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -684,6 +684,7 @@ private: gfxFont::BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, PropertyProvider *aProvider, + uint16_t aOrientation, Metrics *aMetrics); // **** measurement helper **** @@ -692,6 +693,7 @@ private: gfxContext *aRefContext, PropertyProvider *aProvider, uint32_t aSpacingStart, uint32_t aSpacingEnd, + uint16_t aOrientation, Metrics *aMetrics); // **** drawing helper **** diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 008fd089d3de..f60e91971244 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -7578,7 +7578,13 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const aContext, &provider); // mAscent should be the same as metrics.mAscent, but it's what we use to // paint so that's the one we'll use. - return RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent); + nsRect boundingBox = RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent); + if (mTextRun->IsVertical()) { + // Swap line-relative textMetrics dimensions to physical coordinates. + Swap(boundingBox.x, boundingBox.y); + Swap(boundingBox.width, boundingBox.height); + } + return boundingBox; } /* virtual */ nsresult @@ -8284,6 +8290,11 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // Handle text that runs outside its normal bounds. nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); aMetrics.SetOverflowAreasToDesiredBounds(); + if (mTextRun->IsVertical()) { + // Swap line-relative textMetrics dimensions to physical coordinates. + Swap(boundingBox.x, boundingBox.y); + Swap(boundingBox.width, boundingBox.height); + } aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox); // When we have text decorations, we don't need to compute their overflow now @@ -8530,7 +8541,13 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); nsRect &vis = result.VisualOverflow(); - vis.UnionRect(vis, RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent)); + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); + if (mTextRun->IsVertical()) { + // Swap line-relative textMetrics dimensions to physical coordinates. + Swap(boundingBox.x, boundingBox.y); + Swap(boundingBox.width, boundingBox.height); + } + vis.UnionRect(vis, boundingBox); UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, &vis, true); return result; From 4778df83d17ba2df572bef00b556b1dd711ea8a3 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 16 Oct 2014 09:40:20 +0100 Subject: [PATCH 087/100] Bug 1080621 - Don't pass nscoord in-params by reference in nsBidiPresUtils methods. r=smontagu --- layout/base/nsBidiPresUtils.cpp | 8 ++++---- layout/base/nsBidiPresUtils.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 1a3dc7042dce..60136cb2a4b1 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1224,7 +1224,7 @@ void nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine, int32_t aNumFramesOnLine, WritingMode aLineWM, - nscoord& aLineWidth, + nscoord aLineWidth, nscoord aStart) { // If this line consists of a line frame, reorder the line frame's children. @@ -1399,7 +1399,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame, nscoord& aStart, nsContinuationStates* aContinuationStates, WritingMode aContainerWM, - nscoord& aContainerWidth) + nscoord aContainerWidth) { if (!aFrame) return; @@ -1509,8 +1509,8 @@ void nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld, nsIFrame* aFirstChild, WritingMode aLineWM, - nscoord& aLineWidth, - nscoord& aStart) + nscoord aLineWidth, + nscoord aStart) { nscoord start = aStart; nsIFrame* frame; diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index 3377ab6de57a..7a39a2dda164 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -160,7 +160,7 @@ public: static void ReorderFrames(nsIFrame* aFirstFrameOnLine, int32_t aNumFramesOnLine, mozilla::WritingMode aLineWM, - nscoord& aLineWidth, + nscoord aLineWidth, nscoord aStart); /** @@ -399,7 +399,7 @@ private: nscoord& aStart, nsContinuationStates* aContinuationStates, mozilla::WritingMode aContainerWM, - nscoord& aContainerWidth); + nscoord aContainerWidth); /* * Initialize the continuation state(nsFrameContinuationState) to @@ -452,8 +452,8 @@ private: static void RepositionInlineFrames(BidiLineData* aBld, nsIFrame* aFirstChild, mozilla::WritingMode aLineWM, - nscoord& aLineWidth, - nscoord& aStart); + nscoord aLineWidth, + nscoord aStart); /** * Helper method for Resolve() From 75e3fc9c57de10910b3cb9ecb06f7464ea1f32d3 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 16 Oct 2014 09:40:20 +0100 Subject: [PATCH 088/100] Bug 1083104 - Fix misuse of physical instead of logical dimension for line breaking. r=smontagu --- layout/generic/nsLineLayout.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index b78e012d9e70..bb9ca9afc989 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -313,8 +313,8 @@ nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace, #ifdef NOISY_REFLOW nsFrame::ListTag(stdout, mBlockReflowState->frame); printf(": UpdateBand: %d,%d,%d,%d deltaISize=%d deltaICoord=%d\n", - aNewAvailSpace.x, aNewAvailSpace.y, - aNewAvailSpace.width, aNewAvailSpace.height, deltaISize, deltaICoord); + aNewAvailSpace.IStart(lineWM), aNewAvailSpace.BStart(lineWM), + aNewAvailSpace.ISize(lineWM), aNewAvailSpace.BSize(lineWM), deltaISize, deltaICoord); #endif // Update the root span position @@ -795,8 +795,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsHTMLReflowState& reflowState = *reflowStateHolder; reflowState.mLineLayout = this; reflowState.mFlags.mIsTopOfPage = mIsTopOfPage; - if (reflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE) - reflowState.AvailableWidth() = availableSpaceOnLine; + if (reflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE) { + reflowState.AvailableISize() = availableSpaceOnLine; + } WritingMode stateWM = reflowState.GetWritingMode(); pfd->mMargin = reflowState.ComputedLogicalMargin().ConvertTo(frameWM, stateWM); From 94663d65c1acc30e26da5c4c7e0dd2b5c7ae7ea5 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Thu, 16 Oct 2014 05:05:11 -0400 Subject: [PATCH 089/100] Bug 1083369 - update talos.json to include fixes for mainthreadio whitelist and other goodness. r=dminor --- testing/talos/talos.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/talos/talos.json b/testing/talos/talos.json index 93eda5620ff3..017c4b1566da 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -1,11 +1,11 @@ { "talos.zip": { - "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.49b74c08dad4.zip", + "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.04081c46ff03.zip", "path": "" }, "global": { "talos_repo": "https://hg.mozilla.org/build/talos", - "talos_revision": "ced1b2d1c400" + "talos_revision": "04081c46ff03" }, "suites": { "chromez": { @@ -54,7 +54,7 @@ } }, "xperf": { - "tests": ["tp5n"], + "tests": ["tp5n", "ts_paint_cold"], "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip", "pagesets_parent_dir_path": "talos/page_load_test/", "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5n.manifest", From a20685ff2b564771b5841eec97df6a956d8f1a7b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 16 Oct 2014 11:42:11 +0200 Subject: [PATCH 090/100] Backed out changeset 1abddb50ed34 (bug 1081867) for bustage on a CLOSED TREE --- gfx/thebes/gfxFont.cpp | 8 +++----- gfx/thebes/gfxFont.h | 2 +- gfx/thebes/gfxMacFont.cpp | 6 ++---- gfx/thebes/gfxMacFont.h | 2 +- gfx/thebes/gfxTextRun.cpp | 16 ++++++---------- gfx/thebes/gfxTextRun.h | 2 -- layout/generic/nsTextFrame.cpp | 21 ++------------------- 7 files changed, 15 insertions(+), 42 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 0e802851188f..28f059d41ba3 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2103,8 +2103,7 @@ gfxFont::Measure(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - Spacing *aSpacing, - uint16_t aOrientation) + Spacing *aSpacing) { // If aBoundingBoxType is TIGHT_HINTED_OUTLINE_EXTENTS // and the underlying cairo font may be antialiased, @@ -2120,15 +2119,14 @@ gfxFont::Measure(gfxTextRun *aTextRun, if (mNonAAFont) { return mNonAAFont->Measure(aTextRun, aStart, aEnd, TIGHT_HINTED_OUTLINE_EXTENTS, - aRefContext, aSpacing, aOrientation); + aRefContext, aSpacing); } } const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit(); // Current position in appunits gfxFont::Orientation orientation = - aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT - ? gfxFont::eVertical : gfxFont::eHorizontal; + aTextRun->IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal; const gfxFont::Metrics& fontMetrics = GetMetrics(orientation); RunMetrics metrics; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 588b5ba255a9..3c783372b35a 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1556,7 +1556,7 @@ public: uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aContextForTightBoundingBox, - Spacing *aSpacing, uint16_t aOrientation); + Spacing *aSpacing); /** * Line breaks have been changed at the beginning and/or end of a substring * of the text. Reshaping may be required; glyph updating is permitted. diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 43976596f96e..44608b9470c7 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -167,13 +167,11 @@ gfxMacFont::Measure(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - Spacing *aSpacing, - uint16_t aOrientation) + Spacing *aSpacing) { gfxFont::RunMetrics metrics = gfxFont::Measure(aTextRun, aStart, aEnd, - aBoundingBoxType, aRefContext, aSpacing, - aOrientation); + aBoundingBoxType, aRefContext, aSpacing); // if aBoundingBoxType is not TIGHT_HINTED_OUTLINE_EXTENTS then we need to add // a pixel column each side of the bounding box in case of antialiasing "bleed" diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index b61ea55a2be3..36ec9de140f8 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -35,7 +35,7 @@ public: uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, gfxContext *aContextForTightBoundingBox, - Spacing *aSpacing, uint16_t aOrientation); + Spacing *aSpacing); virtual mozilla::TemporaryRef GetScaledFont(mozilla::gfx::DrawTarget *aTarget); diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index a2cb3bb8919d..e9d8762a74fd 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -690,15 +690,13 @@ gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, gfxContext *aRefContext, PropertyProvider *aProvider, uint32_t aSpacingStart, uint32_t aSpacingEnd, - uint16_t aOrientation, Metrics *aMetrics) { nsAutoTArray spacingBuffer; bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider, aSpacingStart, aSpacingEnd, &spacingBuffer); Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType, aRefContext, - haveSpacing ? spacingBuffer.Elements() : nullptr, - aOrientation); + haveSpacing ? spacingBuffer.Elements() : nullptr); aMetrics->CombineWith(metrics, IsRightToLeft()); } @@ -706,7 +704,7 @@ void gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, gfxFont::BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, - PropertyProvider *aProvider, uint16_t aOrientation, Metrics *aMetrics) + PropertyProvider *aProvider, Metrics *aMetrics) { if (aStart >= aEnd) return; @@ -719,7 +717,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Metrics metrics; AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd, aBoundingBoxType, aRefContext, - aProvider, aStart, aEnd, aOrientation, &metrics); + aProvider, aStart, aEnd, &metrics); // Clip the bounding box to the ligature part gfxFloat bboxLeft = metrics.mBoundingBox.X(); @@ -759,8 +757,7 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); AccumulatePartialLigatureMetrics(font, start, ligatureRunStart, - aBoundingBoxType, aRefContext, aProvider, - iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); + aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics); // XXX This sucks. We have to get glyph extents just so we can detect // glyphs outside the font box, even when aBoundingBoxType is LOOSE, @@ -770,11 +767,10 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, AccumulateMetricsForRun(font, ligatureRunStart, ligatureRunEnd, aBoundingBoxType, aRefContext, aProvider, ligatureRunStart, ligatureRunEnd, - iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); + &accumulatedMetrics); AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end, - aBoundingBoxType, aRefContext, aProvider, - iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); + aBoundingBoxType, aRefContext, aProvider, &accumulatedMetrics); } return accumulatedMetrics; diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 6b80c799b991..b4472f5e7a35 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -684,7 +684,6 @@ private: gfxFont::BoundingBoxType aBoundingBoxType, gfxContext *aRefContext, PropertyProvider *aProvider, - uint16_t aOrientation, Metrics *aMetrics); // **** measurement helper **** @@ -693,7 +692,6 @@ private: gfxContext *aRefContext, PropertyProvider *aProvider, uint32_t aSpacingStart, uint32_t aSpacingEnd, - uint16_t aOrientation, Metrics *aMetrics); // **** drawing helper **** diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index f60e91971244..008fd089d3de 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -7578,13 +7578,7 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const aContext, &provider); // mAscent should be the same as metrics.mAscent, but it's what we use to // paint so that's the one we'll use. - nsRect boundingBox = RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent); - if (mTextRun->IsVertical()) { - // Swap line-relative textMetrics dimensions to physical coordinates. - Swap(boundingBox.x, boundingBox.y); - Swap(boundingBox.width, boundingBox.height); - } - return boundingBox; + return RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent); } /* virtual */ nsresult @@ -8290,11 +8284,6 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // Handle text that runs outside its normal bounds. nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); aMetrics.SetOverflowAreasToDesiredBounds(); - if (mTextRun->IsVertical()) { - // Swap line-relative textMetrics dimensions to physical coordinates. - Swap(boundingBox.x, boundingBox.y); - Swap(boundingBox.width, boundingBox.height); - } aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox); // When we have text decorations, we don't need to compute their overflow now @@ -8541,13 +8530,7 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); nsRect &vis = result.VisualOverflow(); - nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); - if (mTextRun->IsVertical()) { - // Swap line-relative textMetrics dimensions to physical coordinates. - Swap(boundingBox.x, boundingBox.y); - Swap(boundingBox.width, boundingBox.height); - } - vis.UnionRect(vis, boundingBox); + vis.UnionRect(vis, RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent)); UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, &vis, true); return result; From c1c0f335cea02ceb9b75d066c10ad92fbbfed82f Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:12 +0100 Subject: [PATCH 091/100] Bug 1082477, part 1 - Convert Matrix4x4::TranslatePost/ScalePost callers to Matrix4x4::PostTranslate/PostScale. r=Bas --- gfx/layers/LayerTreeInvalidation.cpp | 2 +- gfx/layers/composite/AsyncCompositionManager.cpp | 2 +- gfx/layers/composite/LayerManagerComposite.cpp | 2 +- gfx/layers/ipc/LayerTransactionParent.cpp | 2 +- gfx/tests/gtest/TestAsyncPanZoomController.cpp | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index bf5e26b516e3..5c5179401319 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -467,7 +467,7 @@ LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFu void LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset) { - mTransform.TranslatePost(aOffset.x, aOffset.y, 0); + mTransform.PostTranslate(aOffset.x, aOffset.y, 0); } } // namespace layers diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 2d46e60fe797..efe641b17446 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -918,7 +918,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) 1.0f/container->GetPreYScale(), 1); } - computedTransform.ScalePost(1.0f/aLayer->GetPostXScale(), + computedTransform.PostScale(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), 1); layerComposite->SetShadowTransform(computedTransform); diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 541e82051363..caed637c50dd 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -855,7 +855,7 @@ LayerManagerComposite::ComputeRenderIntegrity() Layer* rootScrollable = rootScrollableLayers[0]; const FrameMetrics& metrics = LayerMetricsWrapper::TopmostScrollableMetrics(rootScrollable); Matrix4x4 transform = rootScrollable->GetEffectiveTransform(); - transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1); + transform.PostScale(metrics.mResolution.scale, metrics.mResolution.scale, 1); // Clip the screen rect to the document bounds Rect documentBounds = diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 1768203afca5..95d202ce532e 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -670,7 +670,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent, Matrix4x4 transform = layer->AsLayerComposite()->GetShadowTransform(); if (ContainerLayer* c = layer->AsContainerLayer()) { // Undo the scale transform applied by AsyncCompositionManager::SampleValue - transform.ScalePost(1.0f/c->GetInheritedXScale(), + transform.PostScale(1.0f/c->GetInheritedXScale(), 1.0f/c->GetInheritedYScale(), 1.0f); } diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 690e935f5df4..09faa68b8ca7 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -698,8 +698,8 @@ TEST_F(APZCBasicTester, ComplexTransform) { Matrix4x4(), Matrix4x4(), }; - transforms[0].ScalePost(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer - transforms[1].ScalePost(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer + transforms[0].PostScale(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer + transforms[1].PostScale(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer nsTArray > layers; nsRefPtr lm; From b841266ac1238dfe91ba3e9959ac909dbe288fd8 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:12 +0100 Subject: [PATCH 092/100] Bug 1082477, part 2 - Remove the Matrix4x4::TranslatePost/ScalePost methods. r=Bas --- gfx/2d/Matrix.h | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index 1318ed95a3ab..5b68f1d898c4 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -777,42 +777,6 @@ public: } } - void ScalePost(Float aX, Float aY, Float aZ) - { - _11 *= aX; - _21 *= aX; - _31 *= aX; - _41 *= aX; - - _12 *= aY; - _22 *= aY; - _32 *= aY; - _42 *= aY; - - _13 *= aZ; - _23 *= aZ; - _33 *= aZ; - _43 *= aZ; - } - - void TranslatePost(Float aX, Float aY, Float aZ) - { - _11 += _14 * aX; - _21 += _24 * aX; - _31 += _34 * aX; - _41 += _44 * aX; - - _12 += _14 * aY; - _22 += _24 * aY; - _32 += _34 * aY; - _42 += _44 * aY; - - _13 += _14 * aZ; - _23 += _24 * aZ; - _33 += _34 * aZ; - _43 += _44 * aZ; - } - bool FuzzyEqual(const Matrix4x4& o) const { return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) && From a47a426fe57b1d1792aa32d70facf205b8efde34 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:12 +0100 Subject: [PATCH 093/100] Bug 1082483, part 1 - Rename Matrix4x4::Translate/Scale to Matrix4x4::PreTranslate/PreScale, leaving temporary inlines for the old names. r=Bas --- gfx/2d/Matrix.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index 5b68f1d898c4..d86473fc80c6 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -558,7 +558,7 @@ public: * this method would be preferred since it only involves 12 floating-point * multiplications.) */ - Matrix4x4 &Translate(Float aX, Float aY, Float aZ) + Matrix4x4 &PreTranslate(Float aX, Float aY, Float aZ) { _41 += aX * _11 + aY * _21 + aZ * _31; _42 += aX * _12 + aY * _22 + aZ * _32; @@ -567,6 +567,10 @@ public: return *this; } + Matrix4x4 &Translate(Float aX, Float aY, Float aZ) + { + return PreTranslate(aX, aY, aZ); + } /** * Similar to PreTranslate, but the translation is applied -after- this @@ -609,7 +613,7 @@ public: /** * Similar to PreTranslate, but applies a scale instead of a translation. */ - Matrix4x4 &Scale(Float aX, Float aY, Float aZ) + Matrix4x4 &PreScale(Float aX, Float aY, Float aZ) { _11 *= aX; _12 *= aX; @@ -623,6 +627,10 @@ public: return *this; } + Matrix4x4 &Scale(Float aX, Float aY, Float aZ) + { + return PreScale(aX, aY, aZ); + } /** * Similar to PostTranslate, but applies a scale instead of a translation. @@ -663,7 +671,7 @@ public: Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ) { // Translate to the origin before applying this matrix - Translate(-aX, -aY, -aZ); + PreTranslate(-aX, -aY, -aZ); // Translate back into position after applying this matrix PostTranslate(aX, aY, aZ); From 08d7dd3f8f0cfe9eb6acccd3431e5a5ae13d1e38 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:12 +0100 Subject: [PATCH 094/100] Bug 1082483, part 2 - Convert Mozilla code to use the new Matrix4x4::PreTranslate/PreScale method names. r=Bas --- content/base/src/DOMMatrix.cpp | 2 +- gfx/layers/ImageLayers.cpp | 4 +-- gfx/layers/Layers.cpp | 4 +-- .../composite/AsyncCompositionManager.cpp | 36 +++++++++---------- gfx/layers/composite/FPSCounter.cpp | 2 +- gfx/layers/composite/ImageLayerComposite.cpp | 4 +-- gfx/layers/composite/TextRenderer.cpp | 2 +- gfx/layers/composite/TiledContentHost.cpp | 4 +-- gfx/layers/ipc/LayerTransactionParent.cpp | 2 +- layout/base/FrameLayerBuilder.cpp | 2 +- layout/ipc/RenderFrameParent.cpp | 5 ++- layout/style/StyleAnimationValue.cpp | 4 +-- 12 files changed, 35 insertions(+), 36 deletions(-) diff --git a/content/base/src/DOMMatrix.cpp b/content/base/src/DOMMatrix.cpp index 4c98f6dec536..462b8225cfc3 100644 --- a/content/base/src/DOMMatrix.cpp +++ b/content/base/src/DOMMatrix.cpp @@ -435,7 +435,7 @@ DOMMatrix::TranslateSelf(double aTx, if (mMatrix3D || aTz != 0) { Ensure3DMatrix(); - mMatrix3D->Translate(aTx, aTy, aTz); + mMatrix3D->PreTranslate(aTx, aTy, aTz); } else { mMatrix2D->PreTranslate(aTx, aTy); } diff --git a/gfx/layers/ImageLayers.cpp b/gfx/layers/ImageLayers.cpp index daabe084543d..0b699fbb7085 100644 --- a/gfx/layers/ImageLayers.cpp +++ b/gfx/layers/ImageLayers.cpp @@ -38,8 +38,8 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSu sourceRect.width != 0.0 && sourceRect.height != 0.0) { NS_ASSERTION(mScaleMode == ScaleMode::STRETCH, "No other scalemodes than stretch and none supported yet."); - local.Scale(mScaleToSize.width / sourceRect.width, - mScaleToSize.height / sourceRect.height, 1.0); + local.PreScale(mScaleToSize.width / sourceRect.width, + mScaleToSize.height / sourceRect.height, 1.0); } } // Snap our local transform first, and snap the inherited transform as well. diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 364f2daf31ab..67ea78c9c403 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -717,7 +717,7 @@ Layer::GetTransform() const Matrix4x4 transform = mTransform; transform.PostScale(mPostXScale, mPostYScale, 1.0f); if (const ContainerLayer* c = AsContainerLayer()) { - transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f); + transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f); } return transform; } @@ -733,7 +733,7 @@ Layer::GetLocalTransform() transform.PostScale(mPostXScale, mPostYScale, 1.0f); if (ContainerLayer* c = AsContainerLayer()) { - transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f); + transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f); } return transform; diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index efe641b17446..a79acb42089c 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -174,9 +174,9 @@ TranslateShadowLayer2D(Layer* aLayer, // transform, we must apply the inverse resolution scale here. Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform); if (ContainerLayer* c = aLayer->AsContainerLayer()) { - layerTransform3D.Scale(1.0f/c->GetPreXScale(), - 1.0f/c->GetPreYScale(), - 1); + layerTransform3D.PreScale(1.0f/c->GetPreXScale(), + 1.0f/c->GetPreYScale(), + 1); } layerTransform3D.PostScale(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), @@ -620,9 +620,9 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) // will apply the pre- and post-scale again when computing the effective // transform, we must apply the inverses here. if (ContainerLayer* container = aLayer->AsContainerLayer()) { - transform.Scale(1.0f/container->GetPreXScale(), - 1.0f/container->GetPreYScale(), - 1); + transform.PreScale(1.0f/container->GetPreXScale(), + 1.0f/container->GetPreYScale(), + 1); } transform.PostScale(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), @@ -639,7 +639,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) // bottom-most scrollable metrics because that should have the most accurate // cumulative resolution for aLayer. LayoutDeviceToLayerScale resolution = bottom.mCumulativeResolution; - oldTransform.Scale(resolution.scale, resolution.scale, 1); + oldTransform.PreScale(resolution.scale, resolution.scale, 1); // For the purpose of aligning fixed and sticky layers, we disregard // the overscroll transform when computing the 'aCurrentTransformForRoot' @@ -767,9 +767,9 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, // will apply the pre- and post-scale again when computing the effective // transform, we must apply the inverses here. if (ContainerLayer* container = aScrollbar->AsContainerLayer()) { - transform.Scale(1.0f/container->GetPreXScale(), - 1.0f/container->GetPreYScale(), - 1); + transform.PreScale(1.0f/container->GetPreXScale(), + 1.0f/container->GetPreYScale(), + 1); } transform.PostScale(1.0f/aScrollbar->GetPostXScale(), 1.0f/aScrollbar->GetPostYScale(), @@ -914,9 +914,9 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) // transform, we must apply the inverse resolution scale here. Matrix4x4 computedTransform = oldTransform * treeTransform; if (ContainerLayer* container = aLayer->AsContainerLayer()) { - computedTransform.Scale(1.0f/container->GetPreXScale(), - 1.0f/container->GetPreYScale(), - 1); + computedTransform.PreScale(1.0f/container->GetPreXScale(), + 1.0f/container->GetPreYScale(), + 1); } computedTransform.PostScale(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), @@ -927,7 +927,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) // Apply resolution scaling to the old transform - the layer tree as it is // doesn't have the necessary transform to display correctly. - oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1); + oldTransform.PreScale(metrics.mResolution.scale, metrics.mResolution.scale, 1); // Make sure that overscroll and under-zoom are represented in the old // transform so that fixed position content moves and scales accordingly. @@ -948,9 +948,9 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) overscrollTranslation.y = contentScreenRect.YMost() - (userScroll.y + metrics.mCompositionBounds.height); } - oldTransform.Translate(overscrollTranslation.x, - overscrollTranslation.y, - overscrollTranslation.z); + oldTransform.PreTranslate(overscrollTranslation.x, + overscrollTranslation.y, + overscrollTranslation.z); gfx::Size underZoomScale(1.0f, 1.0f); if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) { @@ -961,7 +961,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) underZoomScale.height = (mContentRect.height * userZoom.scale) / metrics.mCompositionBounds.height; } - oldTransform.Scale(underZoomScale.width, underZoomScale.height, 1); + oldTransform.PreScale(underZoomScale.width, underZoomScale.height, 1); // Make sure fixed position layers don't move away from their anchor points // when we're asynchronously panning or zooming diff --git a/gfx/layers/composite/FPSCounter.cpp b/gfx/layers/composite/FPSCounter.cpp index 81c6ff8d124a..f03eb778b5a3 100644 --- a/gfx/layers/composite/FPSCounter.cpp +++ b/gfx/layers/composite/FPSCounter.cpp @@ -383,7 +383,7 @@ static void DrawDigits(unsigned int aValue, float textureWidth = FontWidth * 10; gfx::Float opacity = 1; gfx::Matrix4x4 transform; - transform.Scale(FontScaleX, FontScaleY, 1); + transform.PreScale(FontScaleX, FontScaleY, 1); for (size_t n = 0; n < 3; ++n) { unsigned int digit = aValue % (divisor * 10) / divisor; diff --git a/gfx/layers/composite/ImageLayerComposite.cpp b/gfx/layers/composite/ImageLayerComposite.cpp index 99d7b491b961..d91a49d1197d 100644 --- a/gfx/layers/composite/ImageLayerComposite.cpp +++ b/gfx/layers/composite/ImageLayerComposite.cpp @@ -129,8 +129,8 @@ ImageLayerComposite::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransform sourceRect.width != 0.0 && sourceRect.height != 0.0) { NS_ASSERTION(mScaleMode == ScaleMode::STRETCH, "No other scalemodes than stretch and none supported yet."); - local.Scale(mScaleToSize.width / sourceRect.width, - mScaleToSize.height / sourceRect.height, 1.0); + local.PreScale(mScaleToSize.width / sourceRect.width, + mScaleToSize.height / sourceRect.height, 1.0); } } // Snap our local transform first, and snap the inherited transform as well. diff --git a/gfx/layers/composite/TextRenderer.cpp b/gfx/layers/composite/TextRenderer.cpp index 873fcf039a11..99e007a82eab 100644 --- a/gfx/layers/composite/TextRenderer.cpp +++ b/gfx/layers/composite/TextRenderer.cpp @@ -134,7 +134,7 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin, chain.mPrimaryEffect = effect; Matrix4x4 transform = aTransform; - transform.Scale(scaleFactor, scaleFactor, 1.0f); + transform.PreScale(scaleFactor, scaleFactor, 1.0f); mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16), Rect(-10000, -10000, 20000, 20000), chain, 1.0f, transform); } diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 615ebabc14ea..0d7cdb400dd2 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -556,8 +556,8 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, // Make sure the resolution and difference in frame resolution are accounted // for in the layer transform. - aTransform.Scale(1/(resolution * layerScale.width), - 1/(resolution * layerScale.height), 1); + aTransform.PreScale(1/(resolution * layerScale.width), + 1/(resolution * layerScale.height), 1); uint32_t rowCount = 0; uint32_t tileX = 0; diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 95d202ce532e..590399be7bba 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -694,7 +694,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent, // Undo the translation to the origin of the reference frame applied by // AsyncCompositionManager::SampleValue - transform.Translate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z); + transform.PreTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z); // Undo the rebasing applied by // nsDisplayTransform::GetResultingTransformMatrixInternal diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 6926341d3fa4..2be834268832 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -4712,7 +4712,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, maskTransform.Invert(); Matrix4x4 matrix = Matrix4x4::From2D(maskTransform); - matrix.Translate(mParameters.mOffset.x, mParameters.mOffset.y, 0); + matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0); maskLayer->SetBaseTransform(matrix); // save the details of the clip in user data diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 2f21016e6b87..2ffb604613a4 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -387,11 +387,10 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, // container, but our display item is LAYER_ACTIVE_FORCE which // forces all layers above to be active. MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint()); - gfx::Matrix4x4 m; - m.Translate(offset.x, offset.y, 0.0); + gfx::Matrix4x4 m = gfx::Matrix4x4::Translation(offset.x, offset.y, 0.0); // Remote content can't be repainted by us, so we multiply down // the resolution that our container expects onto our container. - m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0); + m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0); layer->SetBaseTransform(m); return layer.forget(); diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index bc98acfee780..40bc8bfa0954 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -1556,7 +1556,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, Point3D translate = InterpolateNumerically(translate1, translate2, aProgress); - result.Translate(translate.x, translate.y, translate.z); + result.PreTranslate(translate.x, translate.y, translate.z); gfxQuaternion q3 = rotate1.Slerp(rotate2, aProgress); Matrix4x4 rotate = q3.ToMatrix(); @@ -1586,7 +1586,7 @@ StyleAnimationValue::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1, Point3D scale = InterpolateNumerically(scale1, scale2, aProgress); if (scale != Point3D(1.0, 1.0, 1.0)) { - result.Scale(scale.x, scale.y, scale.z); + result.PreScale(scale.x, scale.y, scale.z); } return To3DMatrix(result); From 370a10c692eb5be8704c6927cd19329d2c405a90 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:13 +0100 Subject: [PATCH 095/100] Bug 1082483, part 3 - Remove the temporary Matrix4x4::Translate/Scale methods. r=Bas --- gfx/2d/Matrix.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index d86473fc80c6..cdcaf7e4fea0 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -567,10 +567,6 @@ public: return *this; } - Matrix4x4 &Translate(Float aX, Float aY, Float aZ) - { - return PreTranslate(aX, aY, aZ); - } /** * Similar to PreTranslate, but the translation is applied -after- this @@ -627,10 +623,6 @@ public: return *this; } - Matrix4x4 &Scale(Float aX, Float aY, Float aZ) - { - return PreScale(aX, aY, aZ); - } /** * Similar to PostTranslate, but applies a scale instead of a translation. From c5b87ba504b36af6b4e8323b2878ac369bad4601 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:13 +0100 Subject: [PATCH 096/100] Bug 1082518 - Get rid of some unused gfxContext flags. r=Bas --- gfx/thebes/gfxContext.h | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index ce4653e5d22d..208c1f992415 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -517,10 +517,6 @@ public: * how drawing something will modify the destination. For example, the * OVER operator will do alpha blending of source and destination, while * SOURCE will replace the destination with the source. - * - * Note that if the flag FLAG_SIMPLIFY_OPERATORS is set on this - * gfxContext, the actual operator set might change for optimization - * purposes. Check the comments below around that flag. */ void SetOperator(GraphicsOperator op); GraphicsOperator CurrentOperator() const; @@ -593,32 +589,12 @@ public: mozilla::gfx::Point GetDeviceOffset() const; - /** - ** Flags - **/ - enum { - /* If this flag is set, operators other than CLEAR, SOURCE, or - * OVER will be converted to OVER before being sent to cairo. - * - * This is most useful with a printing surface, where - * operators such as ADD are used to avoid seams for on-screen - * display, but where such errors aren't noticeable in print. - * This approach is currently used in border rendering. - * - * However, when printing complex renderings such as SVG, - * care should be taken to clear this flag. - */ - FLAG_SIMPLIFY_OPERATORS = (1 << 0), - /** + /** * When this flag is set, snapping to device pixels is disabled. * It simply never does anything. */ FLAG_DISABLE_SNAPPING = (1 << 1), - /** - * Disable copying of backgrounds in PushGroupAndCopyBackground. - */ - FLAG_DISABLE_COPY_BACKGROUND = (1 << 2) }; void SetFlag(int32_t aFlag) { mFlags |= aFlag; } From b4111658815f8ba8b99040fbaa454fb28362af32 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:13 +0100 Subject: [PATCH 097/100] Bug 1082553 - Remove gfxContext::OriginalSurface. r=Bas --- gfx/thebes/gfxContext.cpp | 19 ------------------- gfx/thebes/gfxContext.h | 11 +---------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 5be6e24ccd9c..a9de345e9535 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -88,7 +88,6 @@ gfxContext::gfxContext(DrawTarget *aTarget, const Point& aDeviceOffset) : mPathIsRect(false) , mTransformChanged(false) , mRefCairo(nullptr) - , mSurface(nullptr) , mFlags(0) , mDT(aTarget) , mOriginalDT(aTarget) @@ -130,24 +129,6 @@ gfxContext::~gfxContext() MOZ_COUNT_DTOR(gfxContext); } -gfxASurface * -gfxContext::OriginalSurface() -{ - if (mSurface) { - return mSurface; - } - - if (mOriginalDT && mOriginalDT->GetBackendType() == BackendType::CAIRO) { - cairo_surface_t *s = - (cairo_surface_t*)mOriginalDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE); - if (s) { - mSurface = gfxASurface::Wrap(s); - return mSurface; - } - } - return nullptr; -} - already_AddRefed gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy) { diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index 208c1f992415..e5a1bd690ed2 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -60,11 +60,6 @@ public: */ static already_AddRefed ContextForDrawTarget(mozilla::gfx::DrawTarget* aTarget); - /** - * Return the surface that this gfxContext was created with - */ - gfxASurface *OriginalSurface(); - /** * Return the current transparency group target, if any, along * with its device offsets from the top. If no group is @@ -708,7 +703,6 @@ private: const AzureState &CurrentState() const { return mStateStack[mStateStack.Length() - 1]; } cairo_t *mRefCairo; - nsRefPtr mSurface; int32_t mFlags; mozilla::RefPtr mDT; @@ -882,15 +876,12 @@ public: } ~gfxContextAutoDisableSubpixelAntialiasing() { - if (mSurface) { - mSurface->SetSubpixelAntialiasingEnabled(mSubpixelAntialiasingEnabled); - } else if (mDT) { + if (mDT) { mDT->SetPermitSubpixelAA(mSubpixelAntialiasingEnabled); } } private: - nsRefPtr mSurface; mozilla::RefPtr mDT; bool mSubpixelAntialiasingEnabled; }; From e3b677cbfd13f7edbd26eb88f4639827d8addc84 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:13 +0100 Subject: [PATCH 098/100] Bug 1082553 - Remove a few unnecessary nsRenderingContext includes and forward declarations. r=Bas --- layout/svg/nsSVGFilterFrame.cpp | 1 - layout/svg/nsSVGFilterFrame.h | 1 - layout/svg/nsSVGFilterInstance.cpp | 1 - widget/android/nsWindow.cpp | 1 - widget/nsIWidget.h | 1 - widget/qt/nsWindow.cpp | 1 - widget/windows/nsWindowGfx.cpp | 1 - 7 files changed, 7 deletions(-) diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp index c5d0f0b2283a..1fe8f3d2d479 100644 --- a/layout/svg/nsSVGFilterFrame.cpp +++ b/layout/svg/nsSVGFilterFrame.cpp @@ -9,7 +9,6 @@ // Keep others in (case-insensitive) order: #include "gfxUtils.h" #include "nsGkAtoms.h" -#include "nsRenderingContext.h" #include "nsSVGEffects.h" #include "nsSVGElement.h" #include "mozilla/dom/SVGFilterElement.h" diff --git a/layout/svg/nsSVGFilterFrame.h b/layout/svg/nsSVGFilterFrame.h index 47d3ea475b50..1fcc9eb88848 100644 --- a/layout/svg/nsSVGFilterFrame.h +++ b/layout/svg/nsSVGFilterFrame.h @@ -16,7 +16,6 @@ class nsIAtom; class nsIContent; class nsIFrame; class nsIPresShell; -class nsRenderingContext; class nsStyleContext; class nsSVGIntegerPair; class nsSVGLength2; diff --git a/layout/svg/nsSVGFilterInstance.cpp b/layout/svg/nsSVGFilterInstance.cpp index 39d1f10a4e4e..0a7e32593402 100644 --- a/layout/svg/nsSVGFilterInstance.cpp +++ b/layout/svg/nsSVGFilterInstance.cpp @@ -10,7 +10,6 @@ #include "gfxPlatform.h" #include "gfxUtils.h" #include "nsISVGChildFrame.h" -#include "nsRenderingContext.h" #include "mozilla/dom/SVGFilterElement.h" #include "nsReferencedElement.h" #include "nsSVGFilterFrame.h" diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index cb9443e48807..0e10c7ba633e 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -31,7 +31,6 @@ using mozilla::unused; #include "nsIWidgetListener.h" #include "nsViewManager.h" -#include "nsRenderingContext.h" #include "nsIDOMSimpleGestureEvent.h" #include "nsGkAtoms.h" diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 1d53b196fabd..0fae9b886b99 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -25,7 +25,6 @@ // forward declarations class nsFontMetrics; -class nsRenderingContext; class nsDeviceContext; struct nsFont; class nsIRollupListener; diff --git a/widget/qt/nsWindow.cpp b/widget/qt/nsWindow.cpp index 3e3f9a544b2a..323940dd0efa 100644 --- a/widget/qt/nsWindow.cpp +++ b/widget/qt/nsWindow.cpp @@ -40,7 +40,6 @@ #include "mozqwidget.h" #include "nsIdleService.h" -#include "nsRenderingContext.h" #include "nsIRollupListener.h" #include "nsWidgetsCID.h" #include "nsQtKeyUtils.h" diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 32fd41a4f793..9b46960e19d6 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -36,7 +36,6 @@ using mozilla::plugins::PluginInstanceParent; #include "mozilla/RefPtr.h" #include "nsGfxCIID.h" #include "gfxContext.h" -#include "nsRenderingContext.h" #include "prmem.h" #include "WinUtils.h" #include "nsIWidgetListener.h" From 57ce44320629bbe925beb1c0fb3a2013d990cf93 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:14 +0100 Subject: [PATCH 099/100] Bug 1083215, part 1 - Add a Moz2D helper for snapping lines to device pixels. r=mattwoodrow --- gfx/2d/PathHelpers.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++ gfx/2d/PathHelpers.h | 25 ++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/gfx/2d/PathHelpers.cpp b/gfx/2d/PathHelpers.cpp index 87379374f41a..e53ed3974989 100644 --- a/gfx/2d/PathHelpers.cpp +++ b/gfx/2d/PathHelpers.cpp @@ -162,6 +162,65 @@ AppendEllipseToPath(PathBuilder* aPathBuilder, AppendRoundedRectToPath(aPathBuilder, rect, radii); } +bool +SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2, + const DrawTarget& aDrawTarget) +{ + Matrix mat = aDrawTarget.GetTransform(); + if (mat.HasNonTranslation()) { + return false; + } + if (aP1.x != aP2.x && aP1.y != aP2.y) { + return false; // not a horizontal or vertical line + } + Point p1 = aP1 + mat.GetTranslation(); // into device space + Point p2 = aP2 + mat.GetTranslation(); + p1.Round(); + p2.Round(); + p1 -= mat.GetTranslation(); // back into user space + p2 -= mat.GetTranslation(); + if (aP1.x == aP2.x) { + // snap vertical line, adding 0.5 to align it to be mid-pixel: + aP1 = p1 + Point(0.5, 0); + aP2 = p2 + Point(0.5, 0); + } else { + // snap horizontal line, adding 0.5 to align it to be mid-pixel: + aP1 = p1 + Point(0, 0.5); + aP2 = p2 + Point(0, 0.5); + } + return true; +} + +void +StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) +{ + if (aRect.IsEmpty()) { + return; + } + + Point p1 = aRect.TopLeft(); + Point p2 = aRect.BottomLeft(); + SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); + aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); + + p1 = aRect.BottomLeft(); + p2 = aRect.BottomRight(); + SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); + aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); + + p1 = aRect.TopLeft(); + p2 = aRect.TopRight(); + SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); + aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); + + p1 = aRect.TopRight(); + p2 = aRect.BottomRight(); + SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget); + aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions); +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 80963cd1af4f..ea69d18fb433 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -156,6 +156,31 @@ GFX2D_API void AppendEllipseToPath(PathBuilder* aPathBuilder, const Point& aCenter, const Size& aDimensions); +/** + * If aDrawTarget's transform only contains a translation, and if this line is + * a horizontal or vertical line, this function will snap the line's vertices + * to align with the device pixel grid so that stroking the line with a one + * pixel wide stroke will result in a crisp line that is not antialiased over + * two pixels across its width. + * + * @return Returns true if this function snaps aRect's vertices, else returns + * false. + */ +GFX2D_API bool SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2, + const DrawTarget& aDrawTarget); + +/** + * This function paints each edge of aRect separately, snapping the edges using + * SnapLineToDevicePixelsForStroking. Stroking the edges as separate paths + * helps ensure not only that the stroke spans a single row of device pixels if + * possible, but also that the ends of stroke dashes start and end on device + * pixels too. + */ +GFX2D_API void StrokeSnappedEdgesOfRect(const Rect& aRect, + DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions); + static inline bool UserToDevicePixelSnapped(Rect& aRect, const Matrix& aTransform) { From 3a8b0e745ab927d74755cac33de7277e418bb981 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 16 Oct 2014 10:51:14 +0100 Subject: [PATCH 100/100] Bug 1083215, part 2 - Convert drawing of HTML image map area focus to Moz2D. r=mattwoodrow --- layout/base/nsLayoutUtils.h | 27 ++++++++ layout/generic/nsImageFrame.cpp | 46 +++++++----- layout/generic/nsImageMap.cpp | 119 ++++++++++++++++++++------------ layout/generic/nsImageMap.h | 9 ++- 4 files changed, 136 insertions(+), 65 deletions(-) diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 8cf4ce6a3fae..3c64492445a6 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -7,6 +7,7 @@ #define nsLayoutUtils_h__ #include "mozilla/MemoryReporting.h" +#include "mozilla/ArrayUtils.h" #include "nsChangeHint.h" #include "nsAutoPtr.h" #include "nsFrameList.h" @@ -118,9 +119,12 @@ class nsLayoutUtils typedef mozilla::layers::Layer Layer; typedef mozilla::ContainerLayerParameters ContainerLayerParameters; typedef mozilla::gfx::SourceSurface SourceSurface; + typedef mozilla::gfx::Color Color; typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::gfx::Float Float; typedef mozilla::gfx::Rect Rect; typedef mozilla::gfx::Matrix4x4 Matrix4x4; + typedef mozilla::gfx::StrokeOptions StrokeOptions; public: typedef mozilla::layers::FrameMetrics FrameMetrics; @@ -1480,6 +1484,29 @@ public: const nsRect& aDirty, uint32_t aImageFlags); + static inline Color NSColorToColor(nscolor aColor) { + return Color(NS_GET_R(aColor)/255.0, + NS_GET_G(aColor)/255.0, + NS_GET_B(aColor)/255.0, + NS_GET_A(aColor)/255.0); + } + + static inline void InitDashPattern(StrokeOptions& aStrokeOptions, + uint8_t aBorderStyle) { + if (aBorderStyle == NS_STYLE_BORDER_STYLE_DOTTED) { + static Float dot[] = { 1.f, 1.f }; + aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot); + aStrokeOptions.mDashPattern = dot; + } else if (aBorderStyle == NS_STYLE_BORDER_STYLE_DASHED) { + static Float dash[] = { 5.f, 5.f }; + aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash); + aStrokeOptions.mDashPattern = dash; + } else { + aStrokeOptions.mDashLength = 0; + aStrokeOptions.mDashPattern = nullptr; + } + } + /** * Convert an nsRect to a gfxRect. */ diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 6b67ee2d55f9..a767297974de 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -7,8 +7,11 @@ #include "nsImageFrame.h" +#include "gfx2DGlue.h" #include "mozilla/DebugOnly.h" #include "mozilla/EventStates.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Helpers.h" #include "mozilla/MouseEvents.h" #include "nsCOMPtr.h" @@ -70,6 +73,7 @@ #include "mozilla/dom/Link.h" using namespace mozilla; +using namespace mozilla::gfx; // sizes (pixels) for image icon, padding and border frame #define ICON_SIZE (16) @@ -1292,19 +1296,19 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, #ifdef DEBUG static void PaintDebugImageMap(nsIFrame* aFrame, nsRenderingContext* aCtx, - const nsRect& aDirtyRect, nsPoint aPt) { + const nsRect& aDirtyRect, nsPoint aPt) +{ nsImageFrame* f = static_cast(aFrame); nsRect inner = f->GetInnerArea() + aPt; - - aCtx->SetColor(NS_RGB(0, 0, 0)); - aCtx->ThebesContext()->Save(); gfxPoint devPixelOffset = nsLayoutUtils::PointToGfxPoint(inner.TopLeft(), aFrame->PresContext()->AppUnitsPerDevPixel()); - aCtx->ThebesContext()->SetMatrix( - aCtx->ThebesContext()->CurrentMatrix().Translate(devPixelOffset)); - f->GetImageMap()->Draw(aFrame, *aCtx); - aCtx->ThebesContext()->Restore(); + DrawTarget* drawTarget = aCtx->GetDrawTarget(); + AutoRestoreTransform autoRestoreTransform(drawTarget); + drawTarget->SetTransform( + drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); + f->GetImageMap()->Draw(aFrame, *drawTarget, + ColorPattern(Color(0.f, 0.f, 0.f, 1.f))); } #endif @@ -1458,6 +1462,8 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt, const nsRect& aDirtyRect, imgIContainer* aImage, uint32_t aFlags) { + DrawTarget* drawTarget = aRenderingContext.GetDrawTarget(); + // Render the image into our content area (the area inside // the borders and padding) NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width"); @@ -1470,20 +1476,22 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt, nullptr, aFlags); nsImageMap* map = GetImageMap(); - if (nullptr != map) { - aRenderingContext.ThebesContext()->Save(); + if (map) { gfxPoint devPixelOffset = nsLayoutUtils::PointToGfxPoint(inner.TopLeft(), PresContext()->AppUnitsPerDevPixel()); - aRenderingContext.ThebesContext()->SetMatrix( - aRenderingContext.ThebesContext()->CurrentMatrix().Translate(devPixelOffset)); - aRenderingContext.SetColor(NS_RGB(255, 255, 255)); - aRenderingContext.SetLineStyle(nsLineStyle_kSolid); - map->Draw(this, aRenderingContext); - aRenderingContext.SetColor(NS_RGB(0, 0, 0)); - aRenderingContext.SetLineStyle(nsLineStyle_kDotted); - map->Draw(this, aRenderingContext); - aRenderingContext.ThebesContext()->Restore(); + AutoRestoreTransform autoRestoreTransform(drawTarget); + drawTarget->SetTransform( + drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); + + // solid white stroke: + map->Draw(this, *drawTarget, ColorPattern(Color(1.f, 1.f, 1.f, 1.f))); + + // then dashed black stroke over the top: + StrokeOptions strokeOptions; + nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED); + map->Draw(this, *drawTarget, ColorPattern(Color(0.f, 0.f, 0.f, 1.f)), + strokeOptions); } } diff --git a/layout/generic/nsImageMap.cpp b/layout/generic/nsImageMap.cpp index d5baec7ea1d1..b078c6a836c0 100644 --- a/layout/generic/nsImageMap.cpp +++ b/layout/generic/nsImageMap.cpp @@ -9,6 +9,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() +#include "mozilla/gfx/PathHelpers.h" #include "nsString.h" #include "nsReadableUtils.h" #include "nsRenderingContext.h" @@ -26,6 +27,7 @@ #endif using namespace mozilla; +using namespace mozilla::gfx; class Area { public: @@ -35,7 +37,9 @@ public: virtual void ParseCoords(const nsAString& aSpec); virtual bool IsInside(nscoord x, nscoord y) const = 0; - virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) = 0; + virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) = 0; virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) = 0; void HasFocus(bool aHasFocus); @@ -267,7 +271,9 @@ public: explicit DefaultArea(nsIContent* aArea); virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE; - virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE; + virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE; virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE; }; @@ -281,21 +287,18 @@ bool DefaultArea::IsInside(nscoord x, nscoord y) const return true; } -void DefaultArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) +void DefaultArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) { if (mHasFocus) { - nsRect r = aFrame->GetRect(); - r.MoveTo(0, 0); - nscoord x1 = r.x; - nscoord y1 = r.y; + nsRect r(nsPoint(0, 0), aFrame->GetSize()); const nscoord kOnePixel = nsPresContext::CSSPixelsToAppUnits(1); - nscoord x2 = r.XMost() - kOnePixel; - nscoord y2 = r.YMost() - kOnePixel; - // XXX aRC.DrawRect(r) result is ugly, that's why we use DrawLine. - aRC.DrawLine(x1, y1, x1, y2); - aRC.DrawLine(x1, y2, x2, y2); - aRC.DrawLine(x1, y1, x2, y1); - aRC.DrawLine(x2, y1, x2, y2); + r.width -= kOnePixel; + r.height -= kOnePixel; + Rect rect = + ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel())); + StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions); } } @@ -313,7 +316,9 @@ public: virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE; virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE; - virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE; + virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE; virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE; }; @@ -375,7 +380,9 @@ bool RectArea::IsInside(nscoord x, nscoord y) const return false; } -void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) +void RectArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) { if (mHasFocus) { if (mNumCoords >= 4) { @@ -385,10 +392,10 @@ void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) nscoord y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[3]); NS_ASSERTION(x1 <= x2 && y1 <= y2, "Someone screwed up RectArea::ParseCoords"); - aRC.DrawLine(x1, y1, x1, y2); - aRC.DrawLine(x1, y2, x2, y2); - aRC.DrawLine(x1, y1, x2, y1); - aRC.DrawLine(x2, y1, x2, y2); + nsRect r(x1, y1, x2 - x1, y2 - y1); + Rect rect = + ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel())); + StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions); } } } @@ -415,7 +422,9 @@ public: virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE; virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE; - virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE; + virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE; virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE; }; @@ -507,23 +516,36 @@ bool PolyArea::IsInside(nscoord x, nscoord y) const return false; } -void PolyArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) +void PolyArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) { if (mHasFocus) { if (mNumCoords >= 6) { - nscoord x0 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]); - nscoord y0 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]); - nscoord x1, y1; + // Where possible, we want all horizontal and vertical lines to align on + // pixel rows or columns, and to start at pixel boundaries so that one + // pixel dashing neatly sits on pixels to give us neat lines. To achieve + // that we draw each line segment as a separate path, snapping it to + // device pixels if applicable. + nsPresContext* pc = aFrame->PresContext(); + Point p1(pc->CSSPixelsToDevPixels(mCoords[0]), + pc->CSSPixelsToDevPixels(mCoords[1])); + Point p2, p1snapped, p2snapped; for (int32_t i = 2; i < mNumCoords; i += 2) { - x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i]); - y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i+1]); - aRC.DrawLine(x0, y0, x1, y1); - x0 = x1; - y0 = y1; + p2.x = pc->CSSPixelsToDevPixels(mCoords[i]); + p2.y = pc->CSSPixelsToDevPixels(mCoords[i+1]); + p1snapped = p1; + p2snapped = p2; + SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget); + aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions); + p1 = p2; } - x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]); - y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]); - aRC.DrawLine(x0, y0, x1, y1); + p2.x = pc->CSSPixelsToDevPixels(mCoords[0]); + p2.y = pc->CSSPixelsToDevPixels(mCoords[1]); + p1snapped = p1; + p2snapped = p2; + SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget); + aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions); } } } @@ -555,7 +577,9 @@ public: virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE; virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE; - virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE; + virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE; virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE; }; @@ -614,20 +638,23 @@ bool CircleArea::IsInside(nscoord x, nscoord y) const return false; } -void CircleArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) +void CircleArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) { if (mHasFocus) { if (mNumCoords >= 3) { - nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]); - nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]); - nscoord radius = nsPresContext::CSSPixelsToAppUnits(mCoords[2]); - if (radius < 0) { + Point center(aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[0]), + aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[1])); + Float diameter = + 2 * aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[2]); + if (diameter <= 0) { return; } - nscoord x = x1 - radius; - nscoord y = y1 - radius; - nscoord w = 2 * radius; - aRC.DrawEllipse(x, y, w, w); + RefPtr builder = aDrawTarget.CreatePathBuilder(); + AppendEllipseToPath(builder, center, Size(diameter, diameter)); + RefPtr circle = builder->Finish(); + aDrawTarget.Stroke(circle, aColor, aStrokeOptions); } } } @@ -868,12 +895,14 @@ nsImageMap::GetAreaAt(uint32_t aIndex) const } void -nsImageMap::Draw(nsIFrame* aFrame, nsRenderingContext& aRC) +nsImageMap::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions) { uint32_t i, n = mAreas.Length(); for (i = 0; i < n; i++) { Area* area = mAreas.ElementAt(i); - area->Draw(aFrame, aRC); + area->Draw(aFrame, aDrawTarget, aColor, aStrokeOptions); } } diff --git a/layout/generic/nsImageMap.h b/layout/generic/nsImageMap.h index 239ffbbbd0e3..749f36cc0441 100644 --- a/layout/generic/nsImageMap.h +++ b/layout/generic/nsImageMap.h @@ -8,6 +8,7 @@ #ifndef nsImageMap_h #define nsImageMap_h +#include "mozilla/gfx/2D.h" #include "nsCOMPtr.h" #include "nsCoord.h" #include "nsTArray.h" @@ -24,6 +25,10 @@ struct nsRect; class nsImageMap MOZ_FINAL : public nsStubMutationObserver, public nsIDOMEventListener { + typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::gfx::ColorPattern ColorPattern; + typedef mozilla::gfx::StrokeOptions StrokeOptions; + public: nsImageMap(); @@ -45,7 +50,9 @@ public: */ nsIContent* GetAreaAt(uint32_t aIndex) const; - void Draw(nsIFrame* aFrame, nsRenderingContext& aRC); + void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget, + const ColorPattern& aColor, + const StrokeOptions& aStrokeOptions = StrokeOptions()); /** * Called just before the nsImageFrame releases us.