diff --git a/addon-sdk/source/test/test-clipboard.js b/addon-sdk/source/test/test-clipboard.js index 358d1b5e0f1..fd1efcaeeb7 100644 --- a/addon-sdk/source/test/test-clipboard.js +++ b/addon-sdk/source/test/test-clipboard.js @@ -20,6 +20,10 @@ const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" + const { base64jpeg } = require("./fixtures"); +const { platform } = require("sdk/system"); +// For Windows, Mac and Linux, platform returns the following: winnt, darwin and linux. +var isWindows = platform.toLowerCase().indexOf("win") == 0; + const canvasHTML = "data:text/html," + encodeURIComponent( "\ \ @@ -99,6 +103,13 @@ exports["test With No Flavor"] = function(assert) { exports["test With Flavor"] = function(assert) { var contents = "hello there"; var contentsText = "hello there"; + + // On windows, HTML clipboard includes extra data. + // The values are from widget/windows/nsDataObj.cpp. + var contentsWindowsHtml = "\n" + + contents + + "\n\n"; + var flavor = "html"; var fullFlavor = "text/html"; var unicodeFlavor = "text"; @@ -110,8 +121,8 @@ exports["test With Flavor"] = function(assert) { assert.equal(clip.currentFlavors[0], unicodeFlavor); assert.equal(clip.currentFlavors[1], flavor); assert.equal(clip.get(), contentsText); - assert.equal(clip.get(flavor), contents); - assert.equal(clip.get(fullFlavor), contents); + assert.equal(clip.get(flavor), isWindows ? contentsWindowsHtml : contents); + assert.equal(clip.get(fullFlavor), isWindows ? contentsWindowsHtml : contents); assert.equal(clip.get(unicodeFlavor), contentsText); assert.equal(clip.get(unicodeFullFlavor), contentsText); }; diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index fca1dc32c22..cab76273249 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index e904f8d1d70..377fd4b03d2 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index c015505fdac..7e0a8ec8a86 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -1,39 +1,48 @@ - - - - + + + + + + - - - + + + + - - - - - + + + + - + + + + + + + + + - - + @@ -42,8 +51,6 @@ - - @@ -53,6 +60,7 @@ + @@ -62,11 +70,9 @@ - - @@ -81,9 +87,8 @@ - - + @@ -91,21 +96,17 @@ + + + + - - + - - - - - - - diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 5dd2a854d7b..801fb2f5702 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,10 +17,10 @@ - + - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index ac880817d22..a0d798e5aab 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 9ae39f57799..4934635d19e 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index c015505fdac..7e0a8ec8a86 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -1,39 +1,48 @@ - - - - + + + + + + - - - + + + + - - - - - + + + + - + + + + + + + + + - - + @@ -42,8 +51,6 @@ - - @@ -53,6 +60,7 @@ + @@ -62,11 +70,9 @@ - - @@ -81,9 +87,8 @@ - - + @@ -91,21 +96,17 @@ + + + + - - + - - - - - - - diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index b6f2a22dbfb..39f8b7948eb 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 6e4912fe9d9..4759b67043f 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "ea673b5c4cc19c3daca072691a659c68e4c6937f", + "git_revision": "37250b125e0db6966875d3b37b117f6d9b76cbc0", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "f5fc1ed93387c0ff18811fb306e061b8ca77bd40", + "revision": "e094d698a05cd04c90815dd11579326f43f02a6b", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml index 6b3cfe596fe..c0aeb646672 100644 --- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 446c1f6d0b3..f92c433565b 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,10 +18,10 @@ - + - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 7f769a41885..85ab233b07e 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/installer/flash.bat b/b2g/installer/flash.bat new file mode 100755 index 00000000000..9b5093677de --- /dev/null +++ b/b2g/installer/flash.bat @@ -0,0 +1,73 @@ +@ECHO OFF + +REM read config file +setlocal ENABLEDELAYEDEXPANSION +set loop=0 +for /F "tokens=*" %%A in (.config) do ( + SET /A loop=!loop! + 1 + set %%A +) + +set DEVICE_FOUND=0 + +REM nexus has device instead of product name +IF [%PRODUCT_NAME%]==[] ( + set PRODUCT_NAME=%DEVICE% +) + +REM if nexus 4 assume you are in fastboot mode, can't seem to find drivers +IF [%DEVICE%]==[mako] ( +call :flash +) + +REM push device from adb to fastboot mode +win_adb kill-server +win_adb devices +win_adb get-state > devicestate.txt +set /p DEVICE_STATE= < devicestate.txt + +IF NOT "%DEVICE_STATE%"=="device" ( + ECHO Please check : + ECHO 1. to make sure that only one device is connected to the computer + ECHO 2. the device is turned on with the screen showing + ECHO 3. the device is set to debugging via USB : ADB Only or ADB and Devtools + ECHO 4. the device drivers are installed on the computer. + Del devicestate.txt + PAUSE + EXIT /b +) + +Del devicestate.txt +win_adb reboot bootloader + +TIMEOUT 5 + +:flash +win_fastboot devices 2> fastboot_state.txt +set /p FASTBOOT_STATE= < fastboot_state.txt + +IF NOT [%FASTBOOT_STATE%]==[] ( + ECHO Please check : + ECHO 1. to make sure that only one device is connected to the computer + ECHO 2. the device is turned on with an indication that the device is in fastboot mode + ECHO 3. the fastboot drivers are installed on the computer. + Del fastboot_state.txt + PAUSE + EXIT /b +) + +Del fastboot_state.txt + +ECHO "Flashing build. If nothing mentions that it flashed anything and it looks stuck, make sure you have the drivers installed." +win_fastboot flash boot out/target/product/%PRODUCT_NAME%/boot.img +win_fastboot flash system out/target/product/%PRODUCT_NAME%/system.img +win_fastboot flash persist out/target/product/%PRODUCT_NAME%/persist.img +win_fastboot flash recovery out/target/product/%PRODUCT_NAME%/recovery.img +win_fastboot flash cache out/target/product/%PRODUCT_NAME%/cache.img +win_fastboot flash userdata out/target/product/%PRODUCT_NAME%/userdata.img + +ECHO "Done..." + +win_fastboot reboot +echo "Just close the windows as you wish." +TIMEOUT 5 diff --git a/browser/app/jar.mn b/browser/app/jar.mn deleted file mode 100644 index cb6ebbfc780..00000000000 --- a/browser/app/jar.mn +++ /dev/null @@ -1,3 +0,0 @@ -browser.jar: -% resource app % - defaults/permissions (permissions) diff --git a/browser/app/moz.build b/browser/app/moz.build index 70b1453e7f5..e10ddf093af 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -21,6 +21,7 @@ SOURCES += [ FINAL_TARGET_FILES += ['blocklist.xml'] FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js'] +FINAL_TARGET_FILES.defaults += ['permissions'] DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] @@ -70,7 +71,5 @@ if CONFIG['MOZ_LINKER']: if CONFIG['HAVE_CLOCK_MONOTONIC']: OS_LIBS += CONFIG['REALTIME_LIBS'] -JAR_MANIFESTS += ['jar.mn'] - if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wshadow'] diff --git a/browser/base/content/blockedSite.xhtml b/browser/base/content/blockedSite.xhtml index cba04c007c6..8ab5f712258 100644 --- a/browser/base/content/blockedSite.xhtml +++ b/browser/base/content/blockedSite.xhtml @@ -22,8 +22,9 @@ + + + diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index edb54352afe..a8dcd51fa85 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -23,5 +23,6 @@ load 1099143-1.html load 1161277-1.html load 1183363.html load 1190705.html +load 1223740-1.html load 1225381-1.html load texImage2D.html diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 6eb119f9fe6..04c6b1c785c 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -161,6 +161,7 @@ skip-if = toolkit != 'cocoa' skip-if = toolkit != 'cocoa' [test_2d.drawImage.zerocanvas.html] [test_2d.fill.winding.html] +[test_2d.fill.pattern.imageSmoothingEnabled.html] # These tests do not pass on any platform; Quartz backend won't pass them # because we fall back to pixman when one circle doesn't contain the other. # See bug 512647. diff --git a/dom/canvas/test/test_2d.fill.pattern.imageSmoothingEnabled.html b/dom/canvas/test/test_2d.fill.pattern.imageSmoothingEnabled.html new file mode 100644 index 00000000000..8a675f8c0c1 --- /dev/null +++ b/dom/canvas/test/test_2d.fill.pattern.imageSmoothingEnabled.html @@ -0,0 +1,81 @@ + +Canvas test: 2d.fill.pattern.imageSmoothingEnabled + + + + +

FAIL (fallback content)

+ + + diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 5758ff864a2..76c75197afd 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -1237,7 +1237,7 @@ DataTransfer::CacheExternalDragFormats() // there isn't a way to get a list of the formats that might be available on // all platforms, so just check for the types that can actually be imported // XXXndeakin there are some other formats but those are platform specific. - const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime }; + const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime }; uint32_t count; dragSession->GetNumDropItems(&count); @@ -1279,7 +1279,7 @@ DataTransfer::CacheExternalClipboardFormats() // there isn't a way to get a list of the formats that might be available on // all platforms, so just check for the types that can actually be imported - const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime }; + const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime }; for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) { // check each format one at a time @@ -1361,7 +1361,14 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex) variant->SetAsAString(str); } else { - variant->SetAsISupports(data); + nsCOMPtr supportscstr = do_QueryInterface(data); + if (supportscstr) { + nsAutoCString str; + supportscstr->GetData(str); + variant->SetAsACString(str); + } else { + variant->SetAsISupports(data); + } } aItem.mData = variant; diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index cb18df98fbb..5199be81e1c 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -288,6 +288,7 @@ EventStateManager::DeltaAccumulator* EventStateManager::EventStateManager() : mLockCursor(0) + , mLastFrameConsumedSetCursor(false) , mPreLockPoint(0,0) , mCurrentTarget(nullptr) // init d&d gesture state machine variables @@ -3527,8 +3528,19 @@ EventStateManager::UpdateCursor(nsPresContext* aPresContext, nsIFrame::Cursor framecursor; nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aTargetFrame); - if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) - return; // don't update the cursor if we failed to get it from the frame see bug 118877 + // Avoid setting cursor when the mouse is over a windowless pluign. + if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) { + if (XRE_IsContentProcess()) { + mLastFrameConsumedSetCursor = true; + } + return; + } + // Make sure cursors get reset after the mouse leaves a + // windowless plugin frame. + if (mLastFrameConsumedSetCursor) { + ClearCachedWidgetCursor(aTargetFrame); + mLastFrameConsumedSetCursor = false; + } cursor = framecursor.mCursor; container = framecursor.mContainer; haveHotspot = framecursor.mHaveHotspot; diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index c6a83fbfbcf..0575233c05e 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -861,6 +861,7 @@ private: bool dispatchedToContentProcess); int32_t mLockCursor; + bool mLastFrameConsumedSetCursor; // Last mouse event refPoint (the offset from the widget's origin in // device pixels) when mouse was locked, used to restore mouse position diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index e744614cd11..9fa14f63878 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -40,7 +40,7 @@ namespace mozilla { using namespace widget; -PRLogModuleInfo* sIMECOLog = nullptr; +LazyLogModule sIMECOLog("IMEContentObserver"); static const char* ToChar(bool aBool) @@ -207,9 +207,6 @@ IMEContentObserver::IMEContentObserver() #ifdef DEBUG mTextChangeData.Test(); #endif - if (!sIMECOLog) { - sIMECOLog = PR_NewLogModule("IMEContentObserver"); - } } void diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 8fd2a47a9a6..acada04c2de 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -57,7 +57,7 @@ using namespace widget; * for debug, log the information with LogLevel::Debug. In this case, the log * should start with "ISM: (),". */ -PRLogModuleInfo* sISMLog = nullptr; +LazyLogModule sISMLog("IMEStateManager"); static const char* GetBoolName(bool aBool) @@ -175,10 +175,6 @@ bool IMEStateManager::sRemoteHasFocus = false; void IMEStateManager::Init() { - if (!sISMLog) { - sISMLog = PR_NewLogModule("IMEStateManager"); - } - Preferences::AddBoolVarCache( &sCheckForIMEUnawareWebApps, "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 3484a2b9d70..af11554ff94 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -976,8 +976,14 @@ FetchBody::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength // FetchBody on the main thread. RefPtr> r = new CancelPumpRunnable(this); - if (!r->Dispatch(mWorkerPrivate->GetJSContext())) { + ErrorResult rv; + r->Dispatch(rv); + if (rv.Failed()) { NS_WARNING("Could not dispatch CancelPumpRunnable. Nothing we can do here"); + // None of our callers are callled directly from JS, so there is no + // point in trying to propagate this failure out of here. And + // localPromise is already rejected. Just suppress the failure. + rv.SuppressException(); } } } diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 50c31bec433..6c1fa9e8a7d 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -29,6 +29,7 @@ #include "nsPrintfCString.h" #include "nsStreamUtils.h" #include "nsStringStream.h" +#include "nsHttpChannel.h" #include "mozilla/dom/File.h" #include "mozilla/dom/workers/Workers.h" @@ -51,7 +52,6 @@ FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal, , mLoadGroup(aLoadGroup) , mRequest(aRequest) , mHasBeenCrossSite(false) - , mFoundOpaqueRedirect(false) , mResponseAvailableCalled(false) , mFetchCalled(false) { @@ -236,6 +236,10 @@ FetchDriver::HttpFetch() return NS_ERROR_UNEXPECTED; } + if (mRequest->GetRedirectMode() != RequestRedirect::Follow) { + secFlags |= nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS; + } + // From here on we create a channel and set its properties with the // information from the InternalRequest. This is an implementation detail. MOZ_ASSERT(mLoadGroup); @@ -441,7 +445,9 @@ FetchDriver::IsUnsafeRequest() } already_AddRefed -FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI) +FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, + nsIURI* aFinalURI, + bool aFoundOpaqueRedirect) { MOZ_ASSERT(aResponse); nsAutoCString reqURL; @@ -454,7 +460,7 @@ FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aF MOZ_ASSERT(NS_SUCCEEDED(rv)); RefPtr filteredResponse; - if (mFoundOpaqueRedirect) { + if (aFoundOpaqueRedirect) { filteredResponse = aResponse->OpaqueRedirectResponse(); } else { switch (mRequest->GetResponseTainting()) { @@ -551,10 +557,22 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, nsCOMPtr httpChannel = do_QueryInterface(aRequest); nsCOMPtr jarChannel = do_QueryInterface(aRequest); + bool foundOpaqueRedirect = false; + if (httpChannel) { uint32_t responseStatus; httpChannel->GetResponseStatus(&responseStatus); + if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) { + if (mRequest->GetRedirectMode() == RequestRedirect::Error) { + FailWithNetworkError(); + return NS_BINDING_FAILED; + } + if (mRequest->GetRedirectMode() == RequestRedirect::Manual) { + foundOpaqueRedirect = true; + } + } + nsAutoCString statusText; httpChannel->GetResponseStatusText(statusText); @@ -660,7 +678,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, // Resolves fetch() promise which may trigger code running in a worker. Make // sure the Response is fully initialized before calling this. - mResponse = BeginAndGetFilteredResponse(response, channelURI); + mResponse = BeginAndGetFilteredResponse(response, channelURI, + foundOpaqueRedirect); nsCOMPtr sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -743,6 +762,12 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, return NS_OK; } + // We should only ever get here if we use a "follow" redirect policy, + // or if if we set an "error" policy as a result of a CORS policy. + MOZ_ASSERT(mRequest->GetRedirectMode() == RequestRedirect::Follow || + (mRequest->GetRedirectMode() == RequestRedirect::Error && + IsUnsafeRequest())); + // HTTP Fetch step 5, "redirect status", step 1 if (NS_WARN_IF(mRequest->GetRedirectMode() == RequestRedirect::Error)) { aOldChannel->Cancel(NS_BINDING_FAILED); @@ -763,33 +788,10 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, // HTTP Fetch step 5, "redirect status", step 10 requires us to halt the // redirect, but successfully return an opaqueredirect Response to the // initiating Fetch. - if (mRequest->GetRedirectMode() == RequestRedirect::Manual) { - // Ideally we would simply not cancel the old channel and allow it to - // be processed as normal. Unfortunately this is quite fragile and - // other redirect handlers can easily break it for certain use cases. - // - // For example, nsCORSListenerProxy cancels vetoed redirect channels. - // The HTTP cache will also error on vetoed redirects when the - // redirect has been previously cached. - // - // Therefore simulate the completion of the channel to produce the - // opaqueredirect Response and then cancel the original channel. This - // will result in OnStartRequest() getting called twice, but the second - // time will be with an error response (from the Cancel) which will - // be ignored. - MOZ_ASSERT(!mFoundOpaqueRedirect); - mFoundOpaqueRedirect = true; - Unused << OnStartRequest(aOldChannel, nullptr); - Unused << OnStopRequest(aOldChannel, nullptr, NS_OK); - - aOldChannel->Cancel(NS_BINDING_FAILED); - - return NS_BINDING_FAILED; - } // The following steps are from HTTP Fetch step 5, "redirect status", step 11 - // which requires the RequestRedirect to be "follow". - MOZ_ASSERT(mRequest->GetRedirectMode() == RequestRedirect::Follow); + // which requires the RequestRedirect to be "follow". We asserted that we're + // in either "follow" or "error" mode here. // HTTP Fetch step 5, "redirect status", steps 11.1 and 11.2 block redirecting // to a URL with credentials in CORS mode. This is implemented in diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h index ee8f2d0347a..8071316a6f8 100644 --- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -83,7 +83,6 @@ private: RefPtr mObserver; nsCOMPtr mDocument; bool mHasBeenCrossSite; - bool mFoundOpaqueRedirect; DebugOnly mResponseAvailableCalled; DebugOnly mFetchCalled; @@ -100,7 +99,8 @@ private: // Returns the filtered response sent to the observer. // Callers who don't have access to a channel can pass null for aFinalURI. already_AddRefed - BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI); + BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI, + bool aFoundOpaqueRedirect); // Utility since not all cases need to do any post processing of the filtered // response. nsresult FailWithNetworkError(); diff --git a/dom/html/HTMLAnchorElement.cpp b/dom/html/HTMLAnchorElement.cpp index 7115f14e678..91bbe3ad2a4 100644 --- a/dom/html/HTMLAnchorElement.cpp +++ b/dom/html/HTMLAnchorElement.cpp @@ -63,13 +63,11 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAnchorElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAnchorElement, nsGenericHTMLElement) - tmp->Link::Traverse(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLAnchorElement, nsGenericHTMLElement) - tmp->Link::Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -324,17 +322,13 @@ HTMLAnchorElement::RelList() NS_IMETHODIMP \ HTMLAnchorElement::Get##_part(nsAString& a##_part) \ { \ - ErrorResult rv; \ - Link::Get##_part(a##_part, rv); \ - MOZ_ASSERT(!rv.Failed()); \ + Link::Get##_part(a##_part); \ return NS_OK; \ } \ NS_IMETHODIMP \ HTMLAnchorElement::Set##_part(const nsAString& a##_part) \ { \ - ErrorResult rv; \ - Link::Set##_part(a##_part, rv); \ - MOZ_ASSERT(!rv.Failed()); \ + Link::Set##_part(a##_part); \ return NS_OK; \ } diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h index e3cf409c694..e29d6d8b1f9 100644 --- a/dom/html/HTMLAnchorElement.h +++ b/dom/html/HTMLAnchorElement.h @@ -89,10 +89,8 @@ public: virtual bool HasDeferredDNSPrefetchRequest() override; // WebIDL API - void GetHref(nsAString& aValue, ErrorResult& rv) - { - GetHTMLURIAttr(nsGkAtoms::href, aValue); - } + + // The XPCOM GetHref is OK for us void SetHref(const nsAString& aValue, mozilla::ErrorResult& rv) { SetHTMLAttr(nsGkAtoms::href, aValue, rv); @@ -156,8 +154,8 @@ public: // Link::GetOrigin is OK for us - using Link::GetProtocol; - using Link::SetProtocol; + // Link::GetProtocol is OK for us + // Link::SetProtocol is OK for us // Link::GetUsername is OK for us // Link::SetUsername is OK for us @@ -165,23 +163,23 @@ public: // Link::GetPassword is OK for us // Link::SetPassword is OK for us - using Link::GetHost; - using Link::SetHost; + // Link::Link::GetHost is OK for us + // Link::Link::SetHost is OK for us - using Link::GetHostname; - using Link::SetHostname; + // Link::Link::GetHostname is OK for us + // Link::Link::SetHostname is OK for us - using Link::GetPort; - using Link::SetPort; + // Link::Link::GetPort is OK for us + // Link::Link::SetPort is OK for us - using Link::GetPathname; - using Link::SetPathname; + // Link::Link::GetPathname is OK for us + // Link::Link::SetPathname is OK for us - using Link::GetSearch; - using Link::SetSearch; + // Link::Link::GetSearch is OK for us + // Link::Link::SetSearch is OK for us - using Link::GetHash; - using Link::SetHash; + // Link::Link::GetHash is OK for us + // Link::Link::SetHash is OK for us // The XPCOM URI decomposition attributes are fine for us void GetCoords(DOMString& aValue) @@ -224,9 +222,9 @@ public: { SetHTMLAttr(nsGkAtoms::shape, aValue, rv); } - void Stringify(nsAString& aResult, ErrorResult& aError) + void Stringify(nsAString& aResult) { - GetHref(aResult, aError); + GetHref(aResult); } protected: diff --git a/dom/html/HTMLAreaElement.cpp b/dom/html/HTMLAreaElement.cpp index b2f8a2a47b8..eecdf27317a 100644 --- a/dom/html/HTMLAreaElement.cpp +++ b/dom/html/HTMLAreaElement.cpp @@ -40,13 +40,11 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAreaElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLAreaElement, nsGenericHTMLElement) - tmp->Link::Traverse(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLAreaElement, nsGenericHTMLElement) - tmp->Link::Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -207,17 +205,13 @@ HTMLAreaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, NS_IMETHODIMP \ HTMLAreaElement::Get##_part(nsAString& a##_part) \ { \ - ErrorResult rv; \ - Link::Get##_part(a##_part, rv); \ - MOZ_ASSERT(!rv.Failed()); \ + Link::Get##_part(a##_part); \ return NS_OK; \ } \ NS_IMETHODIMP \ HTMLAreaElement::Set##_part(const nsAString& a##_part) \ { \ - ErrorResult rv; \ - Link::Set##_part(a##_part, rv); \ - MOZ_ASSERT(!rv.Failed()); \ + Link::Set##_part(a##_part); \ return NS_OK; \ } diff --git a/dom/html/HTMLAreaElement.h b/dom/html/HTMLAreaElement.h index bd876ec2afc..c8dadd6af70 100644 --- a/dom/html/HTMLAreaElement.h +++ b/dom/html/HTMLAreaElement.h @@ -90,10 +90,7 @@ public: SetHTMLAttr(nsGkAtoms::shape, aShape, aError); } - void GetHref(nsAString& aHref, ErrorResult& aError) - { - aError = GetHref(aHref); - } + // The XPCOM GetHref is OK for us void SetHref(const nsAString& aHref, ErrorResult& aError) { aError = SetHref(aHref); @@ -139,8 +136,8 @@ public: // The Link::GetOrigin is OK for us - using Link::GetProtocol; - using Link::SetProtocol; + // Link::Link::GetProtocol is OK for us + // Link::Link::SetProtocol is OK for us // The Link::GetUsername is OK for us // The Link::SetUsername is OK for us @@ -148,23 +145,23 @@ public: // The Link::GetPassword is OK for us // The Link::SetPassword is OK for us - using Link::GetHost; - using Link::SetHost; + // Link::Link::GetHost is OK for us + // Link::Link::SetHost is OK for us - using Link::GetHostname; - using Link::SetHostname; + // Link::Link::GetHostname is OK for us + // Link::Link::SetHostname is OK for us - using Link::GetPort; - using Link::SetPort; + // Link::Link::GetPort is OK for us + // Link::Link::SetPort is OK for us - using Link::GetPathname; - using Link::SetPathname; + // Link::Link::GetPathname is OK for us + // Link::Link::SetPathname is OK for us - using Link::GetSearch; - using Link::SetSearch; + // Link::Link::GetSearch is OK for us + // Link::Link::SetSearch is OK for us - using Link::GetHash; - using Link::SetHash; + // Link::Link::GetHash is OK for us + // Link::Link::SetHash is OK for us // The Link::GetSearchParams is OK for us @@ -178,9 +175,9 @@ public: SetHTMLBoolAttr(nsGkAtoms::nohref, aValue, aError); } - void Stringify(nsAString& aResult, ErrorResult& aError) + void Stringify(nsAString& aResult) { - GetHref(aResult, aError); + GetHref(aResult); } protected: diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index f3505766a67..b339eab749c 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -535,12 +535,6 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) { - // This is for dom.disable_image_src_set, which predates "srcset" - // as an attribute. See Bug 773429 - if (nsContentUtils::IsImageSrcSetDisabled()) { - return NS_OK; - } - if (InResponsiveMode()) { if (mResponsiveSelector && mResponsiveSelector->Content() == this) { diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index 97e7f83393f..ddaab02560b 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -48,7 +48,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLLinkElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLLinkElement, nsGenericHTMLElement) tmp->nsStyleLinkElement::Traverse(cb); - tmp->Link::Traverse(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportLoader) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -56,7 +55,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement, nsGenericHTMLElement) tmp->nsStyleLinkElement::Unlink(); - tmp->Link::Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportLoader) NS_IMPL_CYCLE_COLLECTION_UNLINK_END diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 06df311970e..15687b9a5e2 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -91,8 +91,9 @@ #include #include -static PRLogModuleInfo* gMediaElementLog; -static PRLogModuleInfo* gMediaElementEventsLog; +static mozilla::LazyLogModule gMediaElementLog("nsMediaElement"); +static mozilla::LazyLogModule gMediaElementEventsLog("nsMediaElementEvents"); + #define LOG(type, msg) MOZ_LOG(gMediaElementLog, type, msg) #define LOG_EVENT(type, msg) MOZ_LOG(gMediaElementEventsLog, type, msg) @@ -107,12 +108,6 @@ static PRLogModuleInfo* gMediaElementEventsLog; #include "mozilla/EventStateManager.h" -#if defined(MOZ_B2G) && !defined(MOZ_GRAPHENE) -// This controls the b2g specific of pausing the media element when the -// AudioChannel tells us to mute it. -#define PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL -#endif - using namespace mozilla::layers; using mozilla::net::nsMediaFragmentURIParser; @@ -578,6 +573,7 @@ void HTMLMediaElement::SetSrcObject(DOMMediaStream* aValue) { mSrcAttrStream = aValue; + UpdateAudioChannelPlayingState(); DoLoad(); } @@ -602,6 +598,7 @@ void HTMLMediaElement::SetMozSrcObject(DOMMediaStream* aValue) { mSrcAttrStream = aValue; + UpdateAudioChannelPlayingState(); DoLoad(); } @@ -768,6 +765,7 @@ void HTMLMediaElement::AbortExistingLoads() FireTimeUpdate(false); } DispatchAsyncEvent(NS_LITERAL_STRING("emptied")); + UpdateAudioChannelPlayingState(); } // We may have changed mPaused, mAutoplaying, and other @@ -1711,6 +1709,7 @@ HTMLMediaElement::Pause(ErrorResult& aRv) // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference AddRemoveSelfReference(); UpdateSrcMediaStreamPlaying(); + UpdateAudioChannelPlayingState(); if (!oldPaused) { FireTimeUpdate(false); @@ -2113,13 +2112,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo mFirstFrameLoaded(false), mDefaultPlaybackStartPosition(0.0) { - if (!gMediaElementLog) { - gMediaElementLog = PR_NewLogModule("nsMediaElement"); - } - if (!gMediaElementEventsLog) { - gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents"); - } - mAudioChannel = AudioChannelService::GetDefaultAudioChannel(); mPaused.SetOuter(this); @@ -2317,6 +2309,7 @@ HTMLMediaElement::PlayInternal(bool aCallerIsChrome) AddRemoveSelfReference(); UpdatePreloadAction(); UpdateSrcMediaStreamPlaying(); + UpdateAudioChannelPlayingState(); return NS_OK; } @@ -2897,6 +2890,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder, // We may want to suspend the new stream now. // This will also do an AddRemoveSelfReference. NotifyOwnerDocumentActivityChangedInternal(); + UpdateAudioChannelPlayingState(); if (!mPaused) { SetPlayedOrSeeked(true); @@ -3993,6 +3987,7 @@ void HTMLMediaElement::CheckAutoplayDataReady() // We changed mPaused which can affect AddRemoveSelfReference AddRemoveSelfReference(); UpdateSrcMediaStreamPlaying(); + UpdateAudioChannelPlayingState(); if (mDecoder) { SetPlayedOrSeeked(true); @@ -4007,13 +4002,13 @@ void HTMLMediaElement::CheckAutoplayDataReady() } -bool HTMLMediaElement::IsActive() +bool HTMLMediaElement::IsActive() const { nsIDocument* ownerDoc = OwnerDoc(); return ownerDoc && ownerDoc->IsActive() && ownerDoc->IsVisible(); } -bool HTMLMediaElement::IsHidden() +bool HTMLMediaElement::IsHidden() const { if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) { return true; @@ -4192,6 +4187,7 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE if (aPauseElement != mPausedForInactiveDocumentOrChannel) { mPausedForInactiveDocumentOrChannel = aPauseElement; UpdateSrcMediaStreamPlaying(); + UpdateAudioChannelPlayingState(); if (aPauseElement) { if (mMediaSource) { ReportMSETelemetry(); @@ -4251,15 +4247,12 @@ bool HTMLMediaElement::IsBeingDestroyed() void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() { bool pauseElement = NotifyOwnerDocumentActivityChangedInternal(); - if (pauseElement && mAudioChannelAgent -#ifdef PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL + if (pauseElement && mAudioChannelAgent && // On B2G, NotifyOwnerDocumentActivityChangedInternal may return true for // two reasons: the document no longer being active, or the element being // paused by the audio channel. However we are only interested in the // first case here, so we need to filter out the second case. - && !ComputedMuted() -#endif - ) { + (!UseAudioChannelAPI() || !ComputedMuted())) { // If the element is being paused since we are navigating away from the // document, notify the audio channel agent. // Be careful to ignore this event during a docshell frame swap. @@ -4283,15 +4276,13 @@ HTMLMediaElement::NotifyOwnerDocumentActivityChangedInternal() } bool pauseElement = !IsActive(); -#ifdef PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL // Only pause the element when we start playing. If we pause without playing // audio, the resource loading would be affected unexpectedly. For example, // the media element is muted by default, but we don't want this behavior // interrupting the loading process. - if (mAudioChannelAgent) { + if (UseAudioChannelAPI() && mAudioChannelAgent) { pauseElement |= ComputedMuted(); } -#endif SuspendOrResumeElement(pauseElement, !IsActive()); @@ -4725,9 +4716,10 @@ nsresult HTMLMediaElement::UpdateChannelMuteState(float aVolume, bool aMuted) } } -#ifdef PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL - SuspendOrResumeElement(ComputedMuted(), false); -#endif + if (UseAudioChannelAPI()) { + SuspendOrResumeElement(ComputedMuted(), false); + } + return NS_OK; } @@ -4761,6 +4753,11 @@ HTMLMediaElement::IsPlayingThroughTheAudioChannel() const return false; } + // We should consider any bfcached page or inactive document as non-playing. + if (!IsActive()) { + return false; + } + // A loop always is playing if (HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) { return true; @@ -4837,9 +4834,9 @@ NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted) UpdateChannelMuteState(aVolume, aMuted); -#ifdef PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL - mPaused.SetCanPlay(!aMuted); -#endif + if (UseAudioChannelAPI()) { + mPaused.SetCanPlay(!aMuted); + } return NS_OK; } diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index b9c376e108a..1935c949f13 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -214,9 +214,9 @@ public: // suspended the channel. virtual void NotifySuspendedByCache(bool aIsSuspended) final override; - virtual bool IsActive() final override; + virtual bool IsActive() const final override; - virtual bool IsHidden() final override; + virtual bool IsHidden() const final override; // In order to create overlayImageContainer to support DOMHwMediaStream. VideoFrameContainer* GetOverlayImageVideoFrameContainer(); diff --git a/dom/html/HTMLTrackElement.cpp b/dom/html/HTMLTrackElement.cpp index abdda2fa8c2..6a47128dfd0 100644 --- a/dom/html/HTMLTrackElement.cpp +++ b/dom/html/HTMLTrackElement.cpp @@ -40,7 +40,7 @@ #include "nsThreadUtils.h" #include "nsVideoFrame.h" -static PRLogModuleInfo* gTrackElementLog; +static mozilla::LazyLogModule gTrackElementLog("nsTrackElement"); #define LOG(type, msg) MOZ_LOG(gTrackElementLog, type, msg) // Replace the usual NS_IMPL_NS_NEW_HTML_ELEMENT(Track) so @@ -76,9 +76,6 @@ static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable[0].tag; HTMLTrackElement::HTMLTrackElement(already_AddRefed& aNodeInfo) : nsGenericHTMLElement(aNodeInfo) { - if (!gTrackElementLog) { - gTrackElementLog = PR_NewLogModule("nsTrackElement"); - } } HTMLTrackElement::~HTMLTrackElement() diff --git a/dom/html/nsHTMLDNSPrefetch.cpp b/dom/html/nsHTMLDNSPrefetch.cpp index 09d281b9bec..1c36218f51b 100644 --- a/dom/html/nsHTMLDNSPrefetch.cpp +++ b/dom/html/nsHTMLDNSPrefetch.cpp @@ -182,8 +182,7 @@ nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement, return NS_ERROR_NOT_AVAILABLE; nsAutoString hostname; - ErrorResult rv; - aElement->GetHostname(hostname, rv); + aElement->GetHostname(hostname); return CancelPrefetch(hostname, flags, aReason); } diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 53e42e034c9..8250c9b6d58 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -20994,80 +20994,33 @@ OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec) AssertIsOnOwningThread(); MOZ_ASSERT(mMetadata); - class MOZ_STACK_CLASS Helper final - { - DatabaseSpec& mSpec; - ObjectStoreSpec* mCurrentObjectStoreSpec; + aSpec.metadata() = mMetadata->mCommonMetadata; - public: - static void - CopyToSpec(const FullDatabaseMetadata* aMetadata, DatabaseSpec& aSpec) - { - AssertIsOnBackgroundThread(); - MOZ_ASSERT(aMetadata); + for (auto objectStoreIter = mMetadata->mObjectStores.ConstIter(); + !objectStoreIter.Done(); + objectStoreIter.Next()) { + FullObjectStoreMetadata* metadata = objectStoreIter.UserData(); + MOZ_ASSERT(objectStoreIter.Key()); + MOZ_ASSERT(metadata); - aSpec.metadata() = aMetadata->mCommonMetadata; + // XXX This should really be fallible... + ObjectStoreSpec* objectStoreSpec = aSpec.objectStores().AppendElement(); + objectStoreSpec->metadata() = metadata->mCommonMetadata; - Helper helper(aSpec); - aMetadata->mObjectStores.EnumerateRead(Enumerate, &helper); - } - - private: - explicit Helper(DatabaseSpec& aSpec) - : mSpec(aSpec) - , mCurrentObjectStoreSpec(nullptr) - { } - - static PLDHashOperator - Enumerate(const uint64_t& aKey, - FullObjectStoreMetadata* aValue, - void* aClosure) - { - MOZ_ASSERT(aKey); - MOZ_ASSERT(aValue); - MOZ_ASSERT(aClosure); - - auto* helper = static_cast(aClosure); - - MOZ_ASSERT(!helper->mCurrentObjectStoreSpec); + for (auto indexIter = metadata->mIndexes.Iter(); + !indexIter.Done(); + indexIter.Next()) { + FullIndexMetadata* indexMetadata = indexIter.UserData(); + MOZ_ASSERT(indexIter.Key()); + MOZ_ASSERT(indexMetadata); // XXX This should really be fallible... - ObjectStoreSpec* objectStoreSpec = - helper->mSpec.objectStores().AppendElement(); - objectStoreSpec->metadata() = aValue->mCommonMetadata; - - AutoRestore ar(helper->mCurrentObjectStoreSpec); - helper->mCurrentObjectStoreSpec = objectStoreSpec; - - aValue->mIndexes.EnumerateRead(Enumerate, helper); - - return PL_DHASH_NEXT; + IndexMetadata* metadata = objectStoreSpec->indexes().AppendElement(); + *metadata = indexMetadata->mCommonMetadata; } - - static PLDHashOperator - Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure) - { - MOZ_ASSERT(aKey); - MOZ_ASSERT(aValue); - MOZ_ASSERT(aClosure); - - auto* helper = static_cast(aClosure); - - MOZ_ASSERT(helper->mCurrentObjectStoreSpec); - - // XXX This should really be fallible... - IndexMetadata* metadata = - helper->mCurrentObjectStoreSpec->indexes().AppendElement(); - *metadata = aValue->mCommonMetadata; - - return PL_DHASH_NEXT; - } - }; - - Helper::CopyToSpec(mMetadata, aSpec); + } } - #ifdef DEBUG void @@ -21075,110 +21028,6 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata) { AssertIsOnBackgroundThread(); - class MOZ_STACK_CLASS Helper final - { - const ObjectStoreTable& mOtherObjectStores; - IndexTable* mCurrentOtherIndexTable; - - public: - static void - AssertConsistent(const ObjectStoreTable& aThisObjectStores, - const ObjectStoreTable& aOtherObjectStores) - { - Helper helper(aOtherObjectStores); - aThisObjectStores.EnumerateRead(Enumerate, &helper); - } - - private: - explicit Helper(const ObjectStoreTable& aOtherObjectStores) - : mOtherObjectStores(aOtherObjectStores) - , mCurrentOtherIndexTable(nullptr) - { } - - static PLDHashOperator - Enumerate(const uint64_t& /* aKey */, - FullObjectStoreMetadata* aThisObjectStore, - void* aClosure) - { - MOZ_ASSERT(aThisObjectStore); - MOZ_ASSERT(!aThisObjectStore->mDeleted); - MOZ_ASSERT(aClosure); - - auto* helper = static_cast(aClosure); - - MOZ_ASSERT(!helper->mCurrentOtherIndexTable); - - auto* otherObjectStore = - MetadataNameOrIdMatcher::Match( - helper->mOtherObjectStores, aThisObjectStore->mCommonMetadata.id()); - MOZ_ASSERT(otherObjectStore); - - MOZ_ASSERT(aThisObjectStore != otherObjectStore); - - MOZ_ASSERT(aThisObjectStore->mCommonMetadata.id() == - otherObjectStore->mCommonMetadata.id()); - MOZ_ASSERT(aThisObjectStore->mCommonMetadata.name() == - otherObjectStore->mCommonMetadata.name()); - MOZ_ASSERT(aThisObjectStore->mCommonMetadata.autoIncrement() == - otherObjectStore->mCommonMetadata.autoIncrement()); - MOZ_ASSERT(aThisObjectStore->mCommonMetadata.keyPath() == - otherObjectStore->mCommonMetadata.keyPath()); - // mNextAutoIncrementId and mComittedAutoIncrementId may be modified - // concurrently with this OpenOp, so it is not possible to assert equality - // here. - MOZ_ASSERT(aThisObjectStore->mNextAutoIncrementId <= - otherObjectStore->mNextAutoIncrementId); - MOZ_ASSERT(aThisObjectStore->mComittedAutoIncrementId <= - otherObjectStore->mComittedAutoIncrementId); - MOZ_ASSERT(!otherObjectStore->mDeleted); - - MOZ_ASSERT(aThisObjectStore->mIndexes.Count() == - otherObjectStore->mIndexes.Count()); - - AutoRestore ar(helper->mCurrentOtherIndexTable); - helper->mCurrentOtherIndexTable = &otherObjectStore->mIndexes; - - aThisObjectStore->mIndexes.EnumerateRead(Enumerate, helper); - - return PL_DHASH_NEXT; - } - - static PLDHashOperator - Enumerate(const uint64_t& /* aKey */, - FullIndexMetadata* aThisIndex, - void* aClosure) - { - MOZ_ASSERT(aThisIndex); - MOZ_ASSERT(!aThisIndex->mDeleted); - MOZ_ASSERT(aClosure); - - auto* helper = static_cast(aClosure); - - MOZ_ASSERT(helper->mCurrentOtherIndexTable); - - auto* otherIndex = - MetadataNameOrIdMatcher::Match( - *helper->mCurrentOtherIndexTable, aThisIndex->mCommonMetadata.id()); - MOZ_ASSERT(otherIndex); - - MOZ_ASSERT(aThisIndex != otherIndex); - - MOZ_ASSERT(aThisIndex->mCommonMetadata.id() == - otherIndex->mCommonMetadata.id()); - MOZ_ASSERT(aThisIndex->mCommonMetadata.name() == - otherIndex->mCommonMetadata.name()); - MOZ_ASSERT(aThisIndex->mCommonMetadata.keyPath() == - otherIndex->mCommonMetadata.keyPath()); - MOZ_ASSERT(aThisIndex->mCommonMetadata.unique() == - otherIndex->mCommonMetadata.unique()); - MOZ_ASSERT(aThisIndex->mCommonMetadata.multiEntry() == - otherIndex->mCommonMetadata.multiEntry()); - MOZ_ASSERT(!otherIndex->mDeleted); - - return PL_DHASH_NEXT; - } - }; - const FullDatabaseMetadata* thisDB = mMetadata; const FullDatabaseMetadata* otherDB = aMetadata; @@ -21203,7 +21052,67 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata) MOZ_ASSERT(thisDB->mObjectStores.Count() == otherDB->mObjectStores.Count()); - Helper::AssertConsistent(thisDB->mObjectStores, otherDB->mObjectStores); + for (auto objectStoreIter = thisDB->mObjectStores.ConstIter(); + !objectStoreIter.Done(); + objectStoreIter.Next()) { + FullObjectStoreMetadata* thisObjectStore = objectStoreIter.UserData(); + MOZ_ASSERT(thisObjectStore); + MOZ_ASSERT(!thisObjectStore->mDeleted); + + auto* otherObjectStore = + MetadataNameOrIdMatcher::Match( + otherDB->mObjectStores, thisObjectStore->mCommonMetadata.id()); + MOZ_ASSERT(otherObjectStore); + + MOZ_ASSERT(thisObjectStore != otherObjectStore); + + MOZ_ASSERT(thisObjectStore->mCommonMetadata.id() == + otherObjectStore->mCommonMetadata.id()); + MOZ_ASSERT(thisObjectStore->mCommonMetadata.name() == + otherObjectStore->mCommonMetadata.name()); + MOZ_ASSERT(thisObjectStore->mCommonMetadata.autoIncrement() == + otherObjectStore->mCommonMetadata.autoIncrement()); + MOZ_ASSERT(thisObjectStore->mCommonMetadata.keyPath() == + otherObjectStore->mCommonMetadata.keyPath()); + // mNextAutoIncrementId and mComittedAutoIncrementId may be modified + // concurrently with this OpenOp, so it is not possible to assert equality + // here. + MOZ_ASSERT(thisObjectStore->mNextAutoIncrementId <= + otherObjectStore->mNextAutoIncrementId); + MOZ_ASSERT(thisObjectStore->mComittedAutoIncrementId <= + otherObjectStore->mComittedAutoIncrementId); + MOZ_ASSERT(!otherObjectStore->mDeleted); + + MOZ_ASSERT(thisObjectStore->mIndexes.Count() == + otherObjectStore->mIndexes.Count()); + + for (auto indexIter = thisObjectStore->mIndexes.Iter(); + !indexIter.Done(); + indexIter.Next()) { + FullIndexMetadata* thisIndex = indexIter.UserData(); + MOZ_ASSERT(thisIndex); + MOZ_ASSERT(!thisIndex->mDeleted); + + auto* otherIndex = + MetadataNameOrIdMatcher:: + Match(otherObjectStore->mIndexes, thisIndex->mCommonMetadata.id()); + MOZ_ASSERT(otherIndex); + + MOZ_ASSERT(thisIndex != otherIndex); + + MOZ_ASSERT(thisIndex->mCommonMetadata.id() == + otherIndex->mCommonMetadata.id()); + MOZ_ASSERT(thisIndex->mCommonMetadata.name() == + otherIndex->mCommonMetadata.name()); + MOZ_ASSERT(thisIndex->mCommonMetadata.keyPath() == + otherIndex->mCommonMetadata.keyPath()); + MOZ_ASSERT(thisIndex->mCommonMetadata.unique() == + otherIndex->mCommonMetadata.unique()); + MOZ_ASSERT(thisIndex->mCommonMetadata.multiEntry() == + otherIndex->mCommonMetadata.multiEntry()); + MOZ_ASSERT(!otherIndex->mDeleted); + } + } } #endif // DEBUG diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index 0a19a83046d..7bc91fc89ca 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -262,7 +262,7 @@ IndexedDatabaseManager::~IndexedDatabaseManager() bool IndexedDatabaseManager::sIsMainProcess = false; bool IndexedDatabaseManager::sFullSynchronousMode = false; -PRLogModuleInfo* IndexedDatabaseManager::sLoggingModule; +mozilla::LazyLogModule IndexedDatabaseManager::sLoggingModule("IndexedDB"); Atomic IndexedDatabaseManager::sLoggingMode( @@ -284,10 +284,6 @@ IndexedDatabaseManager::GetOrCreate() if (!gDBManager) { sIsMainProcess = XRE_IsParentProcess(); - if (!sLoggingModule) { - sLoggingModule = PR_NewLogModule("IndexedDB"); - } - if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) { // See if we're starting up in low disk space conditions. nsCOMPtr watcher = @@ -674,7 +670,7 @@ IndexedDatabaseManager::GetLoggingMode() } // static -PRLogModuleInfo* +mozilla::LogModule* IndexedDatabaseManager::GetLoggingModule() { MOZ_ASSERT(gDBManager, diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h index 4ad1191a65a..3bbb53d2010 100644 --- a/dom/indexedDB/IndexedDatabaseManager.h +++ b/dom/indexedDB/IndexedDatabaseManager.h @@ -19,7 +19,6 @@ #include "nsITimer.h" class nsIEventTarget; -struct PRLogModuleInfo; namespace mozilla { @@ -101,7 +100,7 @@ public: } #endif - static PRLogModuleInfo* + static mozilla::LogModule* GetLoggingModule() #ifdef DEBUG ; @@ -226,7 +225,7 @@ private: static bool sIsMainProcess; static bool sFullSynchronousMode; - static PRLogModuleInfo* sLoggingModule; + static LazyLogModule sLoggingModule; static Atomic sLoggingMode; static mozilla::Atomic sLowDiskSpaceMode; }; diff --git a/dom/indexedDB/ProfilerHelpers.h b/dom/indexedDB/ProfilerHelpers.h index 70a720c02fa..00fc5b88b1e 100644 --- a/dom/indexedDB/ProfilerHelpers.h +++ b/dom/indexedDB/ProfilerHelpers.h @@ -279,7 +279,7 @@ LoggingHelper(bool aUseProfiler, const char* aFmt, ...) IndexedDatabaseManager::Logging_Disabled); MOZ_ASSERT(aFmt); - PRLogModuleInfo* logModule = IndexedDatabaseManager::GetLoggingModule(); + mozilla::LogModule* logModule = IndexedDatabaseManager::GetLoggingModule(); MOZ_ASSERT(logModule); static const mozilla::LogLevel logLevel = LogLevel::Warning; diff --git a/dom/ipc/ProcessPriorityManager.cpp b/dom/ipc/ProcessPriorityManager.cpp index 5811be9234a..ea80c94088f 100644 --- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -28,6 +28,10 @@ #include "nsComponentManagerUtils.h" #include "nsCRT.h" +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::hal; + #ifdef XP_WIN #include #define getpid _getpid @@ -69,12 +73,10 @@ NameWithComma().get(), \ static_cast(ChildID()), Pid(), ##__VA_ARGS__) #else - static PRLogModuleInfo* + static LogModule* GetPPMLog() { - static PRLogModuleInfo *sLog; - if (!sLog) - sLog = PR_NewLogModule("ProcessPriorityManager"); + static LazyLogModule sLog("ProcessPriorityManager"); return sLog; } # define LOG(fmt, ...) \ @@ -87,10 +89,6 @@ static_cast(ChildID()), Pid(), ##__VA_ARGS__)) #endif -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::hal; - namespace { class ParticularProcessPriorityManager; diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp index 747d938fcff..e204b2163c8 100644 --- a/dom/ipc/ScreenManagerParent.cpp +++ b/dom/ipc/ScreenManagerParent.cpp @@ -142,11 +142,9 @@ ScreenManagerParent::RecvScreenForBrowser(const TabId& aTabId, nsCOMPtr widget = tabParent->GetWidget(); nsCOMPtr screen; - if (widget) { - if (widget->GetNativeData(NS_NATIVE_WINDOW)) { - mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), - getter_AddRefs(screen)); - } + if (widget && widget->GetNativeData(NS_NATIVE_WINDOW)) { + mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), + getter_AddRefs(screen)); } else { nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen)); if (NS_WARN_IF(NS_FAILED(rv))) { diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/MP3Demuxer.cpp index f7ce9ae7011..fc4a47862fb 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/MP3Demuxer.cpp @@ -161,7 +161,11 @@ MP3TrackDemuxer::DemuxSample() { media::TimeUnit MP3TrackDemuxer::SeekPosition() const { - return Duration(mFrameIndex); + TimeUnit pos = Duration(mFrameIndex); + if (Duration() > TimeUnit()) { + pos = std::min(Duration(), pos); + } + return pos; } #endif @@ -199,22 +203,22 @@ MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) { const auto& vbr = mParser.VBRInfo(); if (!aTime.ToMicroseconds()) { // Quick seek to the beginning of the stream. - mOffset = mFirstFrameOffset; + mFrameIndex = 0; } else if (vbr.IsTOCPresent()) { // Use TOC for more precise seeking. const float durationFrac = static_cast(aTime.ToMicroseconds()) / Duration().ToMicroseconds(); - mOffset = vbr.Offset(durationFrac); + mFrameIndex = FrameIndexFromOffset(vbr.Offset(durationFrac)); } else if (AverageFrameLength() > 0) { - mOffset = mFirstFrameOffset + FrameIndexFromTime(aTime) * - AverageFrameLength(); + mFrameIndex = FrameIndexFromTime(aTime); } + mOffset = OffsetFromFrameIndex(mFrameIndex); + if (mOffset > mFirstFrameOffset && StreamLength() > 0) { mOffset = std::min(StreamLength() - 1, mOffset); } - mFrameIndex = FrameIndexFromOffset(mOffset); mParser.EndFrameSession(); MP3LOG("FastSeek End TOC=%d avgFrameLen=%f mNumParsedFrames=%" PRIu64 @@ -240,6 +244,10 @@ MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime) { FastSeek(aTime); } + if (Duration(mFrameIndex + 1) > aTime) { + return SeekPosition(); + } + MediaByteRange nextRange = FindNextFrame(); while (SkipNextFrame(nextRange) && Duration(mFrameIndex + 1) < aTime) { nextRange = FindNextFrame(); @@ -253,7 +261,7 @@ MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime) { " mFrameIndex=%" PRId64 " mOffset=%" PRIu64, aTime, AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset); - return Duration(mFrameIndex); + return SeekPosition(); } RefPtr @@ -363,10 +371,26 @@ MP3TrackDemuxer::Duration(int64_t aNumFrames) const { return TimeUnit::FromMicroseconds(aNumFrames * usPerFrame); } +static bool +VerifyFrameConsistency( + const FrameParser::Frame& aFrame1, const FrameParser::Frame& aFrame2) { + const auto& h1 = aFrame1.Header(); + const auto& h2 = aFrame2.Header(); + + return h1.IsValid() && h2.IsValid() && + h1.Layer() == h2.Layer() && + h1.SlotSize() == h2.SlotSize() && + h1.SamplesPerFrame() == h2.SamplesPerFrame() && + h1.Channels() == h2.Channels() && + h1.SampleRate() == h2.SampleRate() && + h1.RawVersion() == h2.RawVersion() && + h1.RawProtection() == h2.RawProtection(); +} + MediaByteRange MP3TrackDemuxer::FindNextFrame() { - static const int BUFFER_SIZE = 4096; - static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE; + static const int BUFFER_SIZE = 64; + static const int MAX_SKIPPED_BYTES = 1024 * BUFFER_SIZE; MP3LOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64 @@ -400,10 +424,20 @@ MP3TrackDemuxer::FindNextFrame() { MOZ_ASSERT(foundFrame || bytesToSkip || !reader.Remaining()); reader.DiscardRemaining(); - // Advance mOffset by the amount of bytes read and if necessary, - // skip an ID3v2 tag which stretches beyond the current buffer. - NS_ENSURE_TRUE(mOffset + read + bytesToSkip > mOffset, MediaByteRange(0, 0)); - mOffset += read + bytesToSkip; + if (foundFrame && mParser.FirstFrame().Length() && + !VerifyFrameConsistency(mParser.FirstFrame(), mParser.CurrentFrame())) { + // We've likely hit a false-positive, ignore it and proceed with the + // search for the next valid frame. + foundFrame = false; + mOffset = frameHeaderOffset + 1; + mParser.EndFrameSession(); + } else { + // Advance mOffset by the amount of bytes read and if necessary, + // skip an ID3v2 tag which stretches beyond the current buffer. + NS_ENSURE_TRUE(mOffset + read + bytesToSkip > mOffset, + MediaByteRange(0, 0)); + mOffset += read + bytesToSkip; + } } if (!foundFrame || !mParser.CurrentFrame().Length()) { @@ -493,6 +527,22 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) { return frame.forget(); } +int64_t +MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const { + int64_t offset = 0; + const auto& vbr = mParser.VBRInfo(); + + if (vbr.NumBytes() && vbr.NumAudioFrames()) { + offset = mFirstFrameOffset + aFrameIndex * vbr.NumBytes().value() / + vbr.NumAudioFrames().value(); + } else if (AverageFrameLength() > 0) { + offset = mFirstFrameOffset + aFrameIndex * AverageFrameLength(); + } + + MP3LOGV("OffsetFromFrameIndex(%" PRId64 ") -> %" PRId64, aFrameIndex, offset); + return std::max(mFirstFrameOffset, offset); +} + int64_t MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const { int64_t frameIndex = 0; @@ -846,7 +896,7 @@ FrameParser::FrameHeader::IsValid(int aPos) const { if (aPos == frame_header::SYNC2_VERSION_LAYER_PROTECTION) { return Sync2() == 7 && RawVersion() != 1 && - RawLayer() != 0; + Layer() == 3; } if (aPos == frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE) { return RawBitrate() != 0xF && RawBitrate() != 0 && @@ -1135,6 +1185,9 @@ ID3Parser::ID3Header::Flags() const { uint32_t ID3Parser::ID3Header::Size() const { + if (!IsValid()) { + return 0; + } return mSize; } diff --git a/dom/media/MP3Demuxer.h b/dom/media/MP3Demuxer.h index fdcffbf7af8..0dc664c89b3 100644 --- a/dom/media/MP3Demuxer.h +++ b/dom/media/MP3Demuxer.h @@ -411,10 +411,13 @@ private: // Updates post-read meta data. void UpdateState(const MediaByteRange& aRange); - // Returns the frame index for the given offset. + // Returns the estimated offset for the given frame index. + int64_t OffsetFromFrameIndex(int64_t aFrameIndex) const; + + // Returns the estimated frame index for the given offset. int64_t FrameIndexFromOffset(int64_t aOffset) const; - // Returns the frame index for the given time. + // Returns the estimated frame index for the given time. int64_t FrameIndexFromTime(const media::TimeUnit& aTime) const; // Reads aSize bytes into aBuffer from the source starting at aOffset. diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h index d1cf5608123..dda03b7578a 100644 --- a/dom/media/MediaDecoderOwner.h +++ b/dom/media/MediaDecoderOwner.h @@ -117,10 +117,10 @@ public: }; // Check if the decoder owner is active. - virtual bool IsActive() = 0; + virtual bool IsActive() const = 0; // Check if the decoder owner is hidden. - virtual bool IsHidden() = 0; + virtual bool IsHidden() const = 0; // Called by the media decoder and the video frame to get the // ImageContainer containing the video data. diff --git a/dom/media/eme/EMEUtils.cpp b/dom/media/eme/EMEUtils.cpp index b89879a6f8e..c75984387d7 100644 --- a/dom/media/eme/EMEUtils.cpp +++ b/dom/media/eme/EMEUtils.cpp @@ -5,6 +5,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/EMEUtils.h" +#include "mozilla/dom/UnionTypes.h" namespace mozilla { @@ -112,4 +113,32 @@ ConstructKeySystem(const nsAString& aKeySystem, aOutKeySystem.Append(aCDMVersion); } +ArrayData +GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView) +{ + MOZ_ASSERT(aBufferOrView.IsArrayBuffer() || aBufferOrView.IsArrayBufferView()); + if (aBufferOrView.IsArrayBuffer()) { + const dom::ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer(); + buffer.ComputeLengthAndData(); + return ArrayData(buffer.Data(), buffer.Length()); + } else if (aBufferOrView.IsArrayBufferView()) { + const dom::ArrayBufferView& bufferview = aBufferOrView.GetAsArrayBufferView(); + bufferview.ComputeLengthAndData(); + return ArrayData(bufferview.Data(), bufferview.Length()); + } + return ArrayData(nullptr, 0); +} + +void +CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView, + nsTArray& aOutData) +{ + ArrayData data = GetArrayBufferViewOrArrayBufferData(aBufferOrView); + aOutData.Clear(); + if (!data.IsValid()) { + return; + } + aOutData.AppendElements(data.mData, data.mLength); +} + } // namespace mozilla diff --git a/dom/media/eme/EMEUtils.h b/dom/media/eme/EMEUtils.h index 6768213b5d9..64a01f5499b 100644 --- a/dom/media/eme/EMEUtils.h +++ b/dom/media/eme/EMEUtils.h @@ -9,9 +9,14 @@ #include "mozilla/Logging.h" #include "nsString.h" +#include "nsTArray.h" namespace mozilla { +namespace dom { +class ArrayBufferViewOrArrayBuffer; +} + #ifndef EME_LOG LogModule* GetEMELog(); #define EME_LOG(...) MOZ_LOG(GetEMELog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) @@ -56,6 +61,49 @@ ConstructKeySystem(const nsAString& aKeySystem, const nsAString& aCDMVersion, nsAString& aOutKeySystem); +// Helper function to extract a copy of data coming in from JS in an +// (ArrayBuffer or ArrayBufferView) IDL typed function argument. +// +// Only call this on a properly initialized ArrayBufferViewOrArrayBuffer. +void +CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView, + nsTArray& aOutData); + +struct ArrayData { + explicit ArrayData(const uint8_t* aData, size_t aLength) + : mData(aData) + , mLength(aLength) + { + } + const uint8_t* mData; + const size_t mLength; + bool IsValid() const { + return mData != nullptr && mLength != 0; + } + bool operator== (const nsTArray& aOther) const { + return mLength == aOther.Length() && + memcmp(mData, aOther.Elements(), mLength) == 0; + } +}; + +// Helper function to extract data coming in from JS in an +// (ArrayBuffer or ArrayBufferView) IDL typed function argument. +// +// Be *very* careful with this! +// +// Only use returned ArrayData inside the lifetime of the +// ArrayBufferViewOrArrayBuffer; the ArrayData struct does not contain +// a copy of the data! +// +// And do *not* call out to anything that could call into JavaScript, +// while the ArrayData is live, as then all bets about the data not changing +// are off! No calls into JS, no calls into JS-implemented WebIDL or XPIDL, +// nothing. Beware! +// +// Only call this on a properly initialized ArrayBufferViewOrArrayBuffer. +ArrayData +GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView); + } // namespace mozilla #endif // EME_LOG_H_ diff --git a/dom/media/eme/MediaKeySession.cpp b/dom/media/eme/MediaKeySession.cpp index 8c31c00c726..4b852dbc994 100644 --- a/dom/media/eme/MediaKeySession.cpp +++ b/dom/media/eme/MediaKeySession.cpp @@ -54,7 +54,7 @@ MediaKeySession::MediaKeySession(JSContext* aCx, , mToken(sMediaKeySessionNum++) , mIsClosed(false) , mUninitialized(true) - , mKeyStatusMap(new MediaKeyStatusMap(aCx, aParent, aRv)) + , mKeyStatusMap(new MediaKeyStatusMap(aParent)) , mExpiration(JS::GenericNaN()) { EME_LOG("MediaKeySession[%p,''] session Id set", this); @@ -124,7 +124,6 @@ MediaKeySession::Closed() const return mClosed; } - void MediaKeySession::UpdateKeyStatusMap() { @@ -175,19 +174,26 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType, EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized", this, NS_ConvertUTF16toUTF8(mSessionId).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.generateRequest()")); + NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.generateRequest()")); return promise.forget(); } mUninitialized = false; + if (aInitDataType.IsEmpty()) { + promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Empty initDataType passed to MediaKeySession.generateRequest()")); + EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initDataType", + this, NS_ConvertUTF16toUTF8(mSessionId).get()); + return promise.forget(); + } + nsTArray data; - if (aInitDataType.IsEmpty() || - !CopyArrayBufferViewOrArrayBufferData(aInitData, data)) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("Bad arguments to MediaKeySession.generateRequest()")); - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, " - "invalid initData or initDataType", + CopyArrayBufferViewOrArrayBufferData(aInitData, data); + if (data.IsEmpty()) { + promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Empty initData passed to MediaKeySession.generateRequest()")); + EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } @@ -282,10 +288,11 @@ MediaKeySession::Update(const ArrayBufferViewOrArrayBuffer& aResponse, ErrorResu this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } - if (!CopyArrayBufferViewOrArrayBufferData(aResponse, data)) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("Invalid response buffer")); - EME_LOG("MediaKeySession[%p,'%s'] Update() failed, invalid response buffer", + CopyArrayBufferViewOrArrayBufferData(aResponse, data); + if (data.IsEmpty()) { + promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Empty response buffer passed to MediaKeySession.update()")); + EME_LOG("MediaKeySession[%p,'%s'] Update() failed, empty response buffer", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } diff --git a/dom/media/eme/MediaKeyStatusMap.cpp b/dom/media/eme/MediaKeyStatusMap.cpp index 7084176b48e..694475e1c76 100644 --- a/dom/media/eme/MediaKeyStatusMap.cpp +++ b/dom/media/eme/MediaKeyStatusMap.cpp @@ -8,53 +8,26 @@ #include "nsPIDOMWindow.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/ToJSValue.h" +#include "mozilla/EMEUtils.h" namespace mozilla { namespace dom { NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeyStatusMap) NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeyStatusMap) - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeyStatusMap) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeyStatusMap, mParent) -NS_IMPL_CYCLE_COLLECTION_CLASS(MediaKeyStatusMap) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaKeyStatusMap) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->mMap = nullptr; -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaKeyStatusMap) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MediaKeyStatusMap) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMap) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -MediaKeyStatusMap::MediaKeyStatusMap(JSContext* aCx, - nsPIDOMWindow* aParent, - ErrorResult& aRv) +MediaKeyStatusMap::MediaKeyStatusMap(nsPIDOMWindow* aParent) : mParent(aParent) - , mUpdateError(NS_OK) { - mMap = JS::NewMapObject(aCx); - if (NS_WARN_IF(!mMap)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - } - - mozilla::HoldJSObjects(this); } MediaKeyStatusMap::~MediaKeyStatusMap() { - mozilla::DropJSObjects(this); } JSObject* @@ -70,110 +43,63 @@ MediaKeyStatusMap::GetParentObject() const } MediaKeyStatus -MediaKeyStatusMap::Get(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - ErrorResult& aRv) const +MediaKeyStatusMap::Get(const ArrayBufferViewOrArrayBuffer& aKey) const { - if (NS_FAILED(mUpdateError)) { - aRv.Throw(mUpdateError); + ArrayData keyId = GetArrayBufferViewOrArrayBufferData(aKey); + if (!keyId.IsValid()) { return MediaKeyStatus::Internal_error; } - JS::Rooted map(aCx, mMap); - JS::Rooted key(aCx); - JS::Rooted val(aCx); - - if (!aKey.ToJSVal(aCx, map, &key) || - !JS::MapGet(aCx, map, key, &val)) { - aRv.Throw(NS_ERROR_FAILURE); - return MediaKeyStatus::Internal_error; + for (const KeyStatus& status : mStatuses) { + if (keyId == status.mKeyId) { + return status.mStatus; + } } - bool ok; - int index = FindEnumStringIndex( - aCx, val, MediaKeyStatusValues::strings, - "MediaKeyStatus", "Invalid MediaKeyStatus value", &ok); - - return ok ? static_cast(index) : - MediaKeyStatus::Internal_error; + return MediaKeyStatus::Internal_error; } bool -MediaKeyStatusMap::Has(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - ErrorResult& aRv) const +MediaKeyStatusMap::Has(const ArrayBufferViewOrArrayBuffer& aKey) const { - if (NS_FAILED(mUpdateError)) { - aRv.Throw(mUpdateError); + ArrayData keyId = GetArrayBufferViewOrArrayBufferData(aKey); + if (!keyId.IsValid()) { return false; } - JS::Rooted map(aCx, mMap); - JS::Rooted key(aCx); - bool result = false; - - if (!aKey.ToJSVal(aCx, map, &key) || - !JS::MapHas(aCx, map, key, &result)) { - aRv.Throw(NS_ERROR_FAILURE); + for (const KeyStatus& status : mStatuses) { + if (keyId == status.mKeyId) { + return true; + } } - return result; -} - -template -static void CallMapMethod(JSContext* aCx, - const JS::Heap& aMap, - JS::MutableHandle aResult, - ErrorResult& aRv, - nsresult aUpdateError) -{ - if (NS_FAILED(aUpdateError)) { - aRv.Throw(aUpdateError); - return; - } - - JS::Rooted map(aCx, aMap); - JS::Rooted result(aCx); - if (!Method(aCx, map, &result)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - aResult.set(&result.toObject()); -} - -void -MediaKeyStatusMap::Keys(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const -{ - CallMapMethod(aCx, mMap, aResult, aRv, mUpdateError); -} - -void -MediaKeyStatusMap::Values(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const -{ - CallMapMethod(aCx, mMap, aResult, aRv, mUpdateError); -} -void -MediaKeyStatusMap::Entries(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const -{ - CallMapMethod(aCx, mMap, aResult, aRv, mUpdateError); + return false; } uint32_t -MediaKeyStatusMap::GetSize(JSContext* aCx, ErrorResult& aRv) const +MediaKeyStatusMap::GetIterableLength() const { - if (NS_FAILED(mUpdateError)) { - aRv.Throw(mUpdateError); - return 0; - } - JS::Rooted map(aCx, mMap); - return JS::MapSize(aCx, map); + return mStatuses.Length(); +} + +TypedArrayCreator +MediaKeyStatusMap::GetKeyAtIndex(uint32_t aIndex) const +{ + MOZ_ASSERT(aIndex < GetIterableLength()); + return TypedArrayCreator(mStatuses[aIndex].mKeyId); +} + +MediaKeyStatus +MediaKeyStatusMap::GetValueAtIndex(uint32_t aIndex) const +{ + MOZ_ASSERT(aIndex < GetIterableLength()); + return mStatuses[aIndex].mStatus; +} + +uint32_t +MediaKeyStatusMap::Size() const +{ + return mStatuses.Length(); } static MediaKeyStatus @@ -188,58 +114,13 @@ ToMediaKeyStatus(GMPMediaKeyStatus aStatus) { } } -static bool -ToJSString(JSContext* aCx, GMPMediaKeyStatus aStatus, - JS::MutableHandle aResult) -{ - auto val = uint32_t(ToMediaKeyStatus(aStatus)); - MOZ_ASSERT(val < ArrayLength(MediaKeyStatusValues::strings)); - JSString* str = JS_NewStringCopyN(aCx, - MediaKeyStatusValues::strings[val].value, - MediaKeyStatusValues::strings[val].length); - if (!str) { - return false; - } - aResult.setString(str); - return true; -} - -nsresult -MediaKeyStatusMap::UpdateInternal(const nsTArray& keys) -{ - AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mParent))) { - return NS_ERROR_FAILURE; - } - - jsapi.TakeOwnershipOfErrorReporting(); - JSContext* cx = jsapi.cx(); - JS::Rooted map(cx, mMap); - if (!JS::MapClear(cx, map)) { - return NS_ERROR_FAILURE; - } - - for (size_t i = 0; i < keys.Length(); i++) { - const auto& ks = keys[i]; - JS::Rooted key(cx); - JS::Rooted val(cx); - if (!ToJSValue(cx, TypedArrayCreator(ks.mId), &key) || - !ToJSString(cx, ks.mStatus, &val) || - !JS::MapSet(cx, map, key, val)) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - - return NS_OK; -} - void -MediaKeyStatusMap::Update(const nsTArray& keys) +MediaKeyStatusMap::Update(const nsTArray& aKeys) { - // Since we can't leave the map in a partial update state, we need - // to remember the error and throw it next time the interface methods - // are called. - mUpdateError = UpdateInternal(keys); + mStatuses.Clear(); + for (const auto& key : aKeys) { + mStatuses.InsertElementSorted(KeyStatus(key.mId, ToMediaKeyStatus(key.mStatus))); + } } } // namespace dom diff --git a/dom/media/eme/MediaKeyStatusMap.h b/dom/media/eme/MediaKeyStatusMap.h index b82b5958430..7355563be0f 100644 --- a/dom/media/eme/MediaKeyStatusMap.h +++ b/dom/media/eme/MediaKeyStatusMap.h @@ -23,6 +23,9 @@ namespace dom { class ArrayBufferViewOrArrayBuffer; +// The MediaKeyStatusMap WebIDL interface; maps a keyId to its status. +// Note that the underlying "map" is stored in an array, since we assume +// that a MediaKeySession won't have many key statuses to report. class MediaKeyStatusMap final : public nsISupports, public nsWrapperCache { @@ -31,9 +34,7 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeyStatusMap) public: - explicit MediaKeyStatusMap(JSContext* aCx, - nsPIDOMWindow* aParent, - ErrorResult& aRv); + explicit MediaKeyStatusMap(nsPIDOMWindow* aParent); protected: ~MediaKeyStatusMap(); @@ -43,36 +44,48 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - MediaKeyStatus Get(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - ErrorResult& aRv) const; + MediaKeyStatus Get(const ArrayBufferViewOrArrayBuffer& aKey) const; + bool Has(const ArrayBufferViewOrArrayBuffer& aKey) const; + uint32_t Size() const; - bool Has(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - ErrorResult& aRv) const; - - void Keys(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const; - - void Values(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const; - - void Entries(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const; - - uint32_t GetSize(JSContext* aCx, ErrorResult& aRv) const; + uint32_t GetIterableLength() const; + TypedArrayCreator GetKeyAtIndex(uint32_t aIndex) const; + MediaKeyStatus GetValueAtIndex(uint32_t aIndex) const; void Update(const nsTArray& keys); private: - nsresult UpdateInternal(const nsTArray& keys); nsCOMPtr mParent; - JS::Heap mMap; - nsresult mUpdateError; + + struct KeyStatus { + KeyStatus(const nsTArray& aKeyId, + MediaKeyStatus aStatus) + : mKeyId(aKeyId) + , mStatus(aStatus) + { + } + bool operator== (const KeyStatus& aOther) const { + return aOther.mKeyId == mKeyId; + } + bool operator<(const KeyStatus& aOther) const { + // Copy chromium and compare keys' bytes. + // Update once https://github.com/w3c/encrypted-media/issues/69 + // is resolved. + const nsTArray& other = aOther.mKeyId; + const nsTArray& self = mKeyId; + size_t length = std::min(other.Length(), self.Length()); + int cmp = memcmp(self.Elements(), other.Elements(), length); + if (cmp != 0) { + return cmp < 0; + } + return self.Length() <= other.Length(); + } + nsTArray mKeyId; + MediaKeyStatus mStatus; + }; + + nsTArray mStatuses; }; } // namespace dom diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index 6663dfcb3a9..85c1b5be154 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -145,9 +145,10 @@ MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, Error } nsTArray data; - if (!CopyArrayBufferViewOrArrayBufferData(aCert, data)) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("Invalid argument to MediaKeys.setServerCertificate()")); + CopyArrayBufferViewOrArrayBufferData(aCert, data); + if (data.IsEmpty()) { + promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Empty certificate passed to MediaKeys.setServerCertificate()")); return promise.forget(); } @@ -502,23 +503,5 @@ MediaKeys::Bind(HTMLMediaElement* aElement) return NS_OK; } -bool -CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBufferOrView, - nsTArray& aOutData) -{ - if (aBufferOrView.IsArrayBuffer()) { - const ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer(); - buffer.ComputeLengthAndData(); - aOutData.AppendElements(buffer.Data(), buffer.Length()); - } else if (aBufferOrView.IsArrayBufferView()) { - const ArrayBufferView& bufferview = aBufferOrView.GetAsArrayBufferView(); - bufferview.ComputeLengthAndData(); - aOutData.AppendElements(bufferview.Data(), bufferview.Length()); - } else { - return false; - } - return true; -} - } // namespace dom } // namespace mozilla diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h index fe9065421bf..07e68681abd 100644 --- a/dom/media/eme/MediaKeys.h +++ b/dom/media/eme/MediaKeys.h @@ -35,12 +35,6 @@ typedef nsRefPtrHashtable PromiseHashMap; typedef nsRefPtrHashtable PendingKeySessionsHashMap; typedef uint32_t PromiseId; -// Helper function to extract data coming in from JS in an -// (ArrayBuffer or ArrayBufferView) IDL typed function argument. -bool -CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBufferOrView, - nsTArray& aOutData); - // This class is used on the main thread only. // Note: it's addref/release is not (and can't be) thread safe! class MediaKeys final : public nsISupports, diff --git a/dom/media/gmp/GMPLoader.cpp b/dom/media/gmp/GMPLoader.cpp index 1ebb1d470d1..99282ba2363 100644 --- a/dom/media/gmp/GMPLoader.cpp +++ b/dom/media/gmp/GMPLoader.cpp @@ -25,6 +25,7 @@ #ifdef XP_MACOSX #include #ifdef HASH_NODE_ID_WITH_DEVICE_ID +#include #include #include #endif diff --git a/dom/media/gtest/MockMediaDecoderOwner.h b/dom/media/gtest/MockMediaDecoderOwner.h index 9e28d13a0bd..148dfe879e6 100644 --- a/dom/media/gtest/MockMediaDecoderOwner.h +++ b/dom/media/gtest/MockMediaDecoderOwner.h @@ -36,8 +36,8 @@ public: virtual void DispatchEncrypted(const nsTArray& aInitData, const nsAString& aInitDataType) override {} #endif // MOZ_EME - virtual bool IsActive() override { return true; } - virtual bool IsHidden() override { return false; } + virtual bool IsActive() const override { return true; } + virtual bool IsHidden() const override { return false; } virtual void DownloadSuspended() override {} virtual void DownloadResumed(bool aForceNetworkLoading) override {} virtual void NotifySuspendedByCache(bool aIsSuspended) override {} diff --git a/dom/media/gtest/MockMediaResource.cpp b/dom/media/gtest/MockMediaResource.cpp index 5635e0f5c7f..32a77c916de 100644 --- a/dom/media/gtest/MockMediaResource.cpp +++ b/dom/media/gtest/MockMediaResource.cpp @@ -61,6 +61,9 @@ MockMediaResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, int64_t MockMediaResource::GetLength() { + if (mFileHandle == nullptr) { + return -1; + } fseek(mFileHandle, 0, SEEK_END); return ftell(mFileHandle); } diff --git a/dom/media/gtest/TestMP3Demuxer.cpp b/dom/media/gtest/TestMP3Demuxer.cpp index d4660d76c0d..eea8d9b45f1 100644 --- a/dom/media/gtest/TestMP3Demuxer.cpp +++ b/dom/media/gtest/TestMP3Demuxer.cpp @@ -12,6 +12,8 @@ using namespace mozilla; using namespace mozilla::mp3; +using media::TimeUnit; + // Regular MP3 file mock resource. class MockMP3MediaResource : public MockMediaResource { @@ -190,6 +192,44 @@ protected: mTargets.push_back(streamRes); } + { + MP3Resource res; + res.mFilePath = "small-shot.mp3"; + res.mIsVBR = true; + res.mFileSize = 6825; + res.mMPEGLayer = 3; + res.mMPEGVersion = 1; + res.mID3MajorVersion = 4; + res.mID3MinorVersion = 0; + res.mID3Flags = 0; + res.mID3Size = 24; + res.mDuration = 336686; + res.mDurationError = 0.01f; + res.mSeekError = 0.2f; + res.mSampleRate = 44100; + res.mSamplesPerFrame = 1152; + res.mNumSamples = 12; + res.mNumTrailingFrames = 0; + res.mBitrate = 256000; + res.mSlotSize = 1; + res.mPrivate = 0; + const int syncs[] = { 34, 556, 1078, 1601, 2123, 2646, 3168, 3691, 4213, + 4736, 5258, 5781, 6303 }; + res.mSyncOffsets.insert(res.mSyncOffsets.begin(), syncs, syncs + 13); + + // No content length can be estimated for CBR stream resources. + MP3Resource streamRes = res; + streamRes.mFileSize = -1; + + res.mResource = new MockMP3MediaResource(res.mFilePath); + res.mDemuxer = new MP3TrackDemuxer(res.mResource); + mTargets.push_back(res); + + streamRes.mResource = new MockMP3StreamMediaResource(streamRes.mFilePath); + streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource); + mTargets.push_back(streamRes); + } + for (auto& target: mTargets) { ASSERT_EQ(NS_OK, target.mResource->Open(nullptr)); ASSERT_TRUE(target.mDemuxer->Init()); @@ -307,11 +347,34 @@ TEST_F(MP3DemuxerTest, Duration) { frameData = target.mDemuxer->DemuxSample(); } } + + // Seek out of range tests. + for (const auto& target: mTargets) { + // Skip tests for stream media resources because of lacking duration. + if (target.mFileSize <= 0) { + continue; + } + + target.mDemuxer->Reset(); + RefPtr frameData(target.mDemuxer->DemuxSample()); + ASSERT_TRUE(frameData); + + const int64_t duration = target.mDemuxer->Duration().ToMicroseconds(); + const int64_t pos = duration + 1e6; + + // Attempt to seek 1 second past the end of stream. + target.mDemuxer->Seek(TimeUnit::FromMicroseconds(pos)); + // The seek should bring us to the end of the stream. + EXPECT_NEAR(duration, target.mDemuxer->SeekPosition().ToMicroseconds(), + target.mSeekError * duration); + + // Since we're at the end of the stream, there should be no frames left. + frameData = target.mDemuxer->DemuxSample(); + ASSERT_FALSE(frameData); + } } TEST_F(MP3DemuxerTest, Seek) { - using media::TimeUnit; - for (const auto& target: mTargets) { RefPtr frameData(target.mDemuxer->DemuxSample()); ASSERT_TRUE(frameData); diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build index e287f1d7dd5..27c76dcb74b 100644 --- a/dom/media/gtest/moz.build +++ b/dom/media/gtest/moz.build @@ -48,6 +48,7 @@ TEST_HARNESS_FILES.gtest += [ 'noise.mp3', 'noise_vbr.mp3', 'short-zero-in-moov.mp4', + 'small-shot.mp3', 'test.webm', ] diff --git a/dom/media/gtest/small-shot.mp3 b/dom/media/gtest/small-shot.mp3 new file mode 100644 index 00000000000..f9397a5106b Binary files /dev/null and b/dom/media/gtest/small-shot.mp3 differ diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index 63dbfe30c3b..df560ab2a0c 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -7,7 +7,7 @@ load 474744-1.html HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file? load 492286-1.xhtml load 493915-1.html -load 495794-1.html +skip-if(B2G) load 495794-1.html # in b2g all the media are muted by default load 576612-1.html load 752784-1.html load 789075-1.html diff --git a/dom/media/test/test_eme_playback.html b/dom/media/test/test_eme_playback.html index 2823a6ae38a..798bad6d314 100644 --- a/dom/media/test/test_eme_playback.html +++ b/dom/media/test/test_eme_playback.html @@ -12,6 +12,19 @@ + + + + + + + diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/navigation-redirect.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/navigation-redirect.https.html new file mode 100644 index 00000000000..7b606cf0c3c --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/navigation-redirect.https.html @@ -0,0 +1,449 @@ + +Service Worker: Navigation redirection + + + + + + + diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js new file mode 100644 index 00000000000..66f3e593619 --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js @@ -0,0 +1,17 @@ +var activatePromiseResolve; + +addEventListener('activate', function(evt) { + evt.waitUntil(new Promise(function(resolve) { + activatePromiseResolve = resolve; + })); +}); + +addEventListener('message', function(evt) { + if (typeof activatePromiseResolve === 'function') { + activatePromiseResolve(); + } +}); + +addEventListener('fetch', function(evt) { + evt.respondWith(new Response('Hello world')); +}); diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-other-origin.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-other-origin.html new file mode 100644 index 00000000000..c1441ba685a --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-other-origin.html @@ -0,0 +1,66 @@ + + + + diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-out-scope.py b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-out-scope.py new file mode 100644 index 00000000000..4b40762d89f --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-out-scope.py @@ -0,0 +1,15 @@ +def main(request, response): + if "url" in request.GET: + headers = [("Location", request.GET["url"])] + return 302, headers, '' + + return [], ''' + + +''' diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope1.py b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope1.py new file mode 100644 index 00000000000..4b40762d89f --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope1.py @@ -0,0 +1,15 @@ +def main(request, response): + if "url" in request.GET: + headers = [("Location", request.GET["url"])] + return 302, headers, '' + + return [], ''' + + +''' diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope2.py b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope2.py new file mode 100644 index 00000000000..4b40762d89f --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-scope2.py @@ -0,0 +1,15 @@ +def main(request, response): + if "url" in request.GET: + headers = [("Location", request.GET["url"])] + return 302, headers, '' + + return [], ''' + + +''' diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-worker.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-worker.js new file mode 100644 index 00000000000..cb15b3ff113 --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/navigation-redirect-worker.js @@ -0,0 +1,75 @@ +// We store an empty response for each fetch event request we see +// in this Cache object so we can get the list of urls in the +// message event. +var cacheName = 'urls-' + self.registration.scope; + +var waitUntilPromiseList = []; + +self.addEventListener('message', function(event) { + var urls; + event.waitUntil(Promise.all(waitUntilPromiseList).then(function() { + waitUntilPromiseList = []; + return caches.open(cacheName); + }).then(function(cache) { + return cache.keys(); + }).then(function(requestList) { + urls = requestList.map(function(request) { return request.url; }); + return caches.delete(cacheName); + }).then(function() { + event.data.port.postMessage({urls: urls}); + })); + }); + +function get_query_params(url) { + var search = (new URL(url)).search; + if (!search) { + return {}; + } + var ret = {}; + var params = search.substring(1).split('&'); + params.forEach(function(param) { + var element = param.split('='); + ret[decodeURIComponent(element[0])] = decodeURIComponent(element[1]); + }); + return ret; +} + +self.addEventListener('fetch', function(event) { + var waitUntilPromise = caches.open(cacheName).then(function(cache) { + return cache.put(event.request, new Response()); + }); + event.waitUntil(waitUntilPromise); + + var params = get_query_params(event.request.url); + if (!params['sw']) { + // To avoid races, add the waitUntil() promise to our global list. + // If we get a message event before we finish here, it will wait + // these promises to complete before proceeding to read from the + // cache. + waitUntilPromiseList.push(waitUntilPromise); + return; + } + + event.respondWith(waitUntilPromise.then(function() { + if (params['sw'] == 'gen') { + return Response.redirect(params['url']); + } else if (params['sw'] == 'fetch') { + return fetch(event.request); + } else if (params['sw'] == 'opaque') { + return fetch(new Request(event.request.url, {redirect: 'manual'})); + } else if (params['sw'] == 'opaqueThroughCache') { + var url = event.request.url; + var cache; + return caches.delete(url) + .then(function() { return self.caches.open(url); }) + .then(function(c) { + cache = c; + return fetch(new Request(url, {redirect: 'manual'})); + }) + .then(function(res) { return cache.put(event.request, res); }) + .then(function() { return cache.match(url); }); + } + + // unexpected... trigger an interception failure + })); + }); diff --git a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html index 2e549fef37f..3b786b50850 100644 --- a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html +++ b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html @@ -449,6 +449,181 @@ gKeyframeSequenceTests.forEach(function(subtest) { " roundtrips"); }); + +// KeyframeEffectOptions +test(function(t) { + var effect = new KeyframeEffectReadOnly( + target, {left: ["10px", "20px"]}); + + var ct = effect.getComputedTiming(); + assert_equals(ct.delay, 0, "default delay"); + assert_equals(ct.fill, "none", "default fill"); + assert_equals(ct.iterations, 1.0, "default iterations"); + assert_equals(ct.duration, 0, "default duration"); + assert_equals(ct.direction, "normal", "default direction"); + + assert_equals(effect.composite, "replace", "default composite"); + assert_equals(effect.iterationComposite, "replace", + "default iterationComposite"); + assert_equals(effect.spacing, "distribute", + "default spacing"); +}, "a KeyframeEffectReadOnly constructed without any " + + "KeyframeEffectOptions object"); + +var gKeyframeEffectOptionTests = [ + { desc: "an empty KeyframeEffectOption", + input: {}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a normal KeyframeEffectOption", + input: {delay: 1000, + fill: "auto", + iterations: 5.5, + duration: "auto", + direction: "alternate"}, + expected: {delay: 1000, + fill: "none", + iterations: 5.5, + duration: 0, + direction: "alternate"} }, + { desc: "a double value", + input: 3000, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 3000, + direction: "normal"} }, + { desc: "+Infinity", + input: Infinity, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: Infinity, + direction: "normal"} }, + { desc: "-Infinity", + input: -Infinity, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "NaN", + input: NaN, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a negative value", + input: -1, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "an Infinity duration", + input: {duration: Infinity}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: Infinity, + direction: "normal"} }, + { desc: "a negative Infinity duration", + input: {duration: -Infinity}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a NaN duration", + input: {duration: NaN}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a negative duration", + input: {duration: -1}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a string duration", + input: {duration: "cabbage"}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "an auto duration", + input: {duration: "auto"}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "an Infinity iterations", + input: {iterations: Infinity}, + expected: {delay: 0, + fill: "none", + iterations: Infinity, + duration: 0, + direction: "normal"} }, + { desc: "a negative Infinity iterations", + input: {iterations: -Infinity}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a NaN iterations", + input: {iterations: NaN}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a negative iterations", + input: {iterations: -1}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "an auto fill", + input: {fill: "auto"}, + expected: {delay: 0, + fill: "none", + iterations: 1, + duration: 0, + direction: "normal"} }, + { desc: "a forwards fill", + input: {fill: "forwards"}, + expected: {delay: 0, + fill: "forwards", + iterations: 1, + duration: 0, + direction: "normal"} } +]; + +gKeyframeEffectOptionTests.forEach(function(stest) { + test(function(t) { + var effect = new KeyframeEffectReadOnly( + target, {left: ["10px", "20px"]}, stest.input); + + var ct = effect.getComputedTiming(); + assert_equals(ct.delay, stest.expected.delay, "initial delay"); + assert_equals(ct.fill, stest.expected.fill, "initial fill"); + assert_equals(ct.iterations, stest.expected.iterations, "initial iterations"); + assert_equals(ct.duration, stest.expected.duration, "initial duration"); + assert_equals(ct.direction, stest.expected.direction, "initial direction"); + }, "a KeyframeEffectReadOnly constructed by " + stest.desc); +}); + done(); diff --git a/toolkit/components/places/tests/cpp/mock_Link.h b/toolkit/components/places/tests/cpp/mock_Link.h index 10c745fe5e6..7d2ec50a39d 100644 --- a/toolkit/components/places/tests/cpp/mock_Link.h +++ b/toolkit/components/places/tests/cpp/mock_Link.h @@ -117,18 +117,6 @@ Link::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const return 0; } -void -Link::URLSearchParamsUpdated(URLSearchParams* aSearchParams) -{ - NS_NOTREACHED("Unexpected call to Link::URLSearchParamsUpdated"); -} - -void -Link::UpdateURLSearchParams() -{ - NS_NOTREACHED("Unexpected call to Link::UpdateURLSearchParams"); -} - NS_IMPL_CYCLE_COLLECTION_CLASS(URLSearchParams) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URLSearchParams) NS_IMPL_CYCLE_COLLECTION_UNLINK_END diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 152500b9e52..2ded6691797 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -467,14 +467,14 @@ "kind": "flag", "description": "XUL cache was disabled" }, - "MEMORY_RESIDENT": { + "MEMORY_RESIDENT_FAST": { "alert_emails": ["memshrink-telemetry-alerts@mozilla.com"], "expires_in_version": "never", "kind": "exponential", "low": "32 * 1024", "high": "16 * 1024 * 1024", - "n_buckets": 200, - "extended_statistics_ok": true, + "n_buckets": 100, + "bug_numbers": [1226196], "description": "Resident memory size (KB)" }, "MEMORY_UNIQUE": { diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm index cf3c9024e86..418cee087f9 100644 --- a/toolkit/components/telemetry/TelemetrySession.jsm +++ b/toolkit/components/telemetry/TelemetrySession.jsm @@ -1041,7 +1041,7 @@ var Impl = { b("MEMORY_VSIZE", "vsize"); b("MEMORY_VSIZE_MAX_CONTIGUOUS", "vsizeMaxContiguous"); - b("MEMORY_RESIDENT", "residentFast"); + b("MEMORY_RESIDENT_FAST", "residentFast"); b("MEMORY_UNIQUE", "residentUnique"); b("MEMORY_HEAP_ALLOCATED", "heapAllocated"); p("MEMORY_HEAP_COMMITTED_UNUSED_RATIO", "heapOverheadRatio"); diff --git a/toolkit/components/telemetry/bucket-whitelist.json b/toolkit/components/telemetry/bucket-whitelist.json index 62ec80501bf..5464acb28a8 100644 --- a/toolkit/components/telemetry/bucket-whitelist.json +++ b/toolkit/components/telemetry/bucket-whitelist.json @@ -1,5 +1,4 @@ [ - "MEMORY_RESIDENT", "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK", "MEMORY_JS_GC_HEAP", "MEMORY_HEAP_ALLOCATED", diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 18c3930370e..327851e4896 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -361,7 +361,6 @@ addEventListener("DOMWindowClose", function (aEvent) { if (!aEvent.isTrusted) return; sendAsyncMessage("DOMWindowClose"); - aEvent.preventDefault(); }, false); addEventListener("ImageContentLoaded", function (aEvent) { diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index a7e49ebf73c..8b7f642199b 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -380,7 +380,7 @@ ? this.video.readyState < this.video.HAVE_CURRENT_DATA : this.video.readyState < this.video.HAVE_FUTURE_DATA)) || (this.timeUpdateCount <= 1 && !this.video.ended && - this.video.readyState < this.video.HAVE_ENOUGH_DATA && + this.video.readyState < this.video.HAVE_FUTURE_DATA && this.video.networkState == this.video.NETWORK_LOADING)) show = true; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 267becc6f8d..5793c7cfa0c 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2637,7 +2637,8 @@ nsWindow::DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) } void -nsWindow::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) +nsWindow::DrawWindowOverlay(LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) { PROFILER_LABEL("nsWindow", "DrawWindowOverlay", js::ProfileEntry::Category::GRAPHICS); diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 2cd4a2f8709..2c9c3c2a44c 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -152,7 +152,7 @@ public: virtual bool NeedsPaint() override; virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) override; - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) override; + virtual void DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override; virtual mozilla::layers::CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight) override; diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index e08c8a0e3b0..7232b003614 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -3316,8 +3316,7 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, if (!rootWindow || !rootView) { return rect; } - rect = nsCocoaUtils::DevPixelsToCocoaPoints(r.ToUnknownRect(), - mWidget->BackingScaleFactor()); + rect = nsCocoaUtils::DevPixelsToCocoaPoints(r, mWidget->BackingScaleFactor()); rect = [rootView convertRect:rect toView:nil]; rect.origin = [rootWindow convertBaseToScreen:rect.origin]; diff --git a/widget/cocoa/VibrancyManager.mm b/widget/cocoa/VibrancyManager.mm index bdadb1465f2..33f04a9e283 100644 --- a/widget/cocoa/VibrancyManager.mm +++ b/widget/cocoa/VibrancyManager.mm @@ -32,7 +32,7 @@ VibrancyManager::UpdateVibrantRegion(VibrancyType aType, const nsIntRegion& aReg for (size_t i = 0; (iterRect = iter.Next()) || i < viewsToRecycle.Length(); ++i) { if (iterRect) { NSView* view = nil; - NSRect rect = mCoordinateConverter.DevPixelsToCocoaPoints(*iterRect); + NSRect rect = mCoordinateConverter.UntypedDevPixelsToCocoaPoints(*iterRect); if (i < viewsToRecycle.Length()) { view = viewsToRecycle[i]; [view setFrame:rect]; @@ -72,7 +72,7 @@ VibrancyManager::ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const nsIntRegionRectIterator iter(aVibrantRegion.region); while (const nsIntRect* rect = iter.Next()) { - NSRectFill(mCoordinateConverter.DevPixelsToCocoaPoints(*rect)); + NSRectFill(mCoordinateConverter.UntypedDevPixelsToCocoaPoints(*rect)); } } diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index 747450a867e..37683f33857 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -403,7 +403,7 @@ public: virtual void* GetNativeData(uint32_t aDataType) override; virtual nsresult ConfigureChildren(const nsTArray& aConfigurations) override; virtual LayoutDeviceIntPoint WidgetToScreenOffset() override; - virtual bool ShowsResizeIndicator(nsIntRect* aResizerRect) override; + virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) override; static bool ConvertStatus(nsEventStatus aStatus) { return aStatus == nsEventStatus_eConsumeNoDefault; } @@ -487,12 +487,13 @@ public: virtual void CleanupWindowEffects() override; virtual bool PreRender(LayerManagerComposite* aManager) override; virtual void PostRender(LayerManagerComposite* aManager) override; - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) override; + virtual void DrawWindowOverlay(LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) override; virtual void UpdateThemeGeometries(const nsTArray& aThemeGeometries) override; virtual void UpdateWindowDraggingRegion(const nsIntRegion& aRegion) override; - const nsIntRegion& GetDraggableRegion() { return mDraggableRegion; } + const LayoutDeviceIntRegion& GetDraggableRegion() { return mDraggableRegion; } virtual void ReportSwipeStarted(uint64_t aInputBlockId, bool aStartSwipe) override; @@ -524,13 +525,18 @@ public: nsIntPoint CocoaPointsToDevPixels(const NSPoint& aPt) const { return nsCocoaUtils::CocoaPointsToDevPixels(aPt, BackingScaleFactor()); } - nsIntRect CocoaPointsToDevPixels(const NSRect& aRect) const { + LayoutDeviceIntRect CocoaPointsToDevPixels(const NSRect& aRect) const { return nsCocoaUtils::CocoaPointsToDevPixels(aRect, BackingScaleFactor()); } CGFloat DevPixelsToCocoaPoints(int32_t aPixels) const { return nsCocoaUtils::DevPixelsToCocoaPoints(aPixels, BackingScaleFactor()); } - NSRect DevPixelsToCocoaPoints(const nsIntRect& aRect) const { + // XXX: all calls to this function should eventually be replaced with calls + // to DevPixelsToCocoaPoints(). + NSRect UntypedDevPixelsToCocoaPoints(const nsIntRect& aRect) const { + return nsCocoaUtils::UntypedDevPixelsToCocoaPoints(aRect, BackingScaleFactor()); + } + NSRect DevPixelsToCocoaPoints(const LayoutDeviceIntRect& aRect) const { return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor()); } @@ -577,19 +583,19 @@ protected: void ConfigureAPZCTreeManager() override; void ConfigureAPZControllerThread() override; - void DoRemoteComposition(const nsIntRect& aRenderRect); + void DoRemoteComposition(const LayoutDeviceIntRect& aRenderRect); // Overlay drawing functions for OpenGL drawing - void DrawWindowOverlay(mozilla::layers::GLManager* aManager, nsIntRect aRect); - void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager, const nsIntRect& aRect); - void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const nsIntRect& aRect); - void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager, const nsIntRect& aRect); + void DrawWindowOverlay(mozilla::layers::GLManager* aManager, LayoutDeviceIntRect aRect); + void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager); + void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const LayoutDeviceIntRect& aRect); + void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager); // Redraw the contents of mTitlebarCGContext on the main thread, as // determined by mDirtyTitlebarRegion. void UpdateTitlebarCGContext(); - nsIntRect RectContainingTitlebarControls(); + LayoutDeviceIntRect RectContainingTitlebarControls(); void UpdateVibrancy(const nsTArray& aThemeGeometries); mozilla::VibrancyManager& EnsureVibrancyManager(); @@ -631,16 +637,16 @@ protected: // May be accessed from any thread, protected // by mEffectsLock. bool mShowsResizeIndicator; - nsIntRect mResizeIndicatorRect; + LayoutDeviceIntRect mResizeIndicatorRect; bool mHasRoundedBottomCorners; int mDevPixelCornerRadius; bool mIsCoveringTitlebar; bool mIsFullscreen; - nsIntRect mTitlebarRect; + LayoutDeviceIntRect mTitlebarRect; // The area of mTitlebarCGContext that needs to be redrawn during the next // transaction. Accessed from any thread, protected by mEffectsLock. - nsIntRegion mUpdatedTitlebarRegion; + LayoutDeviceIntRegion mUpdatedTitlebarRegion; CGContextRef mTitlebarCGContext; // Compositor thread only @@ -653,7 +659,7 @@ protected: // uploaded to to mTitlebarImage. Main thread only. nsIntRegion mDirtyTitlebarRegion; - nsIntRegion mDraggableRegion; + LayoutDeviceIntRegion mDraggableRegion; // Cached value of [mView backingScaleFactor], to avoid sending two obj-c // messages (respondsToSelector, backingScaleFactor) every time we need to diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 126f289e99b..d7578af5cda 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -162,7 +162,7 @@ static uint32_t gNumberOfWidgetsNeedingEventThread = 0; - (void)processPendingRedraws; - (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext; -- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect; +- (LayoutDeviceIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect; - (BOOL)isUsingMainThreadOpenGL; - (BOOL)isUsingOpenGL; - (void)drawUsingOpenGL; @@ -279,13 +279,15 @@ public: virtual ~RectTextureImage(); already_AddRefed - BeginUpdate(const nsIntSize& aNewSize, - const nsIntRegion& aDirtyRegion = nsIntRegion()); + BeginUpdate(const LayoutDeviceIntSize& aNewSize, + const LayoutDeviceIntRegion& aDirtyRegion = + LayoutDeviceIntRegion()); void EndUpdate(bool aKeepSurface = false); - void UpdateIfNeeded(const nsIntSize& aNewSize, - const nsIntRegion& aDirtyRegion, - void (^aCallback)(gfx::DrawTarget*, const nsIntRegion&)) + void UpdateIfNeeded(const LayoutDeviceIntSize& aNewSize, + const LayoutDeviceIntRegion& aDirtyRegion, + void (^aCallback)(gfx::DrawTarget*, + const LayoutDeviceIntRegion&)) { RefPtr drawTarget = BeginUpdate(aNewSize, aDirtyRegion); if (drawTarget) { @@ -294,29 +296,30 @@ public: } } - void UpdateFromCGContext(const nsIntSize& aNewSize, - const nsIntRegion& aDirtyRegion, + void UpdateFromCGContext(const LayoutDeviceIntSize& aNewSize, + const LayoutDeviceIntRegion& aDirtyRegion, CGContextRef aCGContext); - nsIntRegion GetUpdateRegion() { + LayoutDeviceIntRegion GetUpdateRegion() { MOZ_ASSERT(mInUpdate, "update region only valid during update"); return mUpdateRegion; } void Draw(mozilla::layers::GLManager* aManager, - const nsIntPoint& aLocation, + const LayoutDeviceIntPoint& aLocation, const Matrix4x4& aTransform = Matrix4x4()); - static nsIntSize TextureSizeForSize(const nsIntSize& aSize); + static LayoutDeviceIntSize TextureSizeForSize( + const LayoutDeviceIntSize& aSize); protected: RefPtr mUpdateDrawTarget; GLContext* mGLContext; - nsIntRegion mUpdateRegion; - nsIntSize mUsedSize; - nsIntSize mBufferSize; - nsIntSize mTextureSize; + LayoutDeviceIntRegion mUpdateRegion; + LayoutDeviceIntSize mUsedSize; + LayoutDeviceIntSize mBufferSize; + LayoutDeviceIntSize mTextureSize; GLuint mTexture; bool mInUpdate; }; @@ -356,7 +359,7 @@ public: const gfx::Rect& aLayerRect, const gfx::Rect& aTextureRect) override; - void BeginFrame(nsIntSize aRenderSize); + void BeginFrame(LayoutDeviceIntSize aRenderSize); void EndFrame(); NSOpenGLContext* GetNSOpenGLContext() @@ -513,7 +516,8 @@ nsresult nsChildView::Create(nsIWidget *aParent, // create our parallel NSView and hook it up to our parent. Recall // that NS_NATIVE_WIDGET is the NSView. CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView); - NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor); + NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints( + LayoutDeviceIntRect::FromUnknownRect(mBounds), scaleFactor); mView = [(NSView*)CreateCocoaView(r) retain]; if (!mView) { return NS_ERROR_FAILURE; @@ -908,13 +912,9 @@ NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor, // Get this component dimension NS_IMETHODIMP nsChildView::GetBounds(LayoutDeviceIntRect& aRect) { - nsIntRect tmp; - if (!mView) { - tmp = mBounds; - } else { - tmp = CocoaPointsToDevPixels([mView frame]); - } - aRect = LayoutDeviceIntRect::FromUnknownRect(tmp); + aRect = !mView + ? LayoutDeviceIntRect::FromUnknownRect(mBounds) + : CocoaPointsToDevPixels([mView frame]); return NS_OK; } @@ -1006,7 +1006,7 @@ NS_IMETHODIMP nsChildView::Move(double aX, double aY) mBounds.y = y; ManipulateViewWithoutNeedingDisplay(mView, ^{ - [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; + [mView setFrame:UntypedDevPixelsToCocoaPoints(mBounds)]; }); NotifyRollupGeometryChange(); @@ -1031,7 +1031,7 @@ NS_IMETHODIMP nsChildView::Resize(double aWidth, double aHeight, bool aRepaint) mBounds.height = height; ManipulateViewWithoutNeedingDisplay(mView, ^{ - [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; + [mView setFrame:UntypedDevPixelsToCocoaPoints(mBounds)]; }); if (mVisible && aRepaint) @@ -1070,7 +1070,7 @@ NS_IMETHODIMP nsChildView::Resize(double aX, double aY, } ManipulateViewWithoutNeedingDisplay(mView, ^{ - [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; + [mView setFrame:UntypedDevPixelsToCocoaPoints(mBounds)]; }); if (mVisible && aRepaint) @@ -1092,7 +1092,7 @@ NS_IMETHODIMP nsChildView::Resize(double aX, double aY, static const int32_t resizeIndicatorWidth = 15; static const int32_t resizeIndicatorHeight = 15; -bool nsChildView::ShowsResizeIndicator(nsIntRect* aResizerRect) +bool nsChildView::ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) { NSView *topLevelView = mView, *superView = nil; while ((superView = [topLevelView superview])) @@ -1364,10 +1364,10 @@ NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect) if ([NSView focusView]) { // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we // don't lose it. - [mView setNeedsPendingDisplayInRect:DevPixelsToCocoaPoints(aRect)]; + [mView setNeedsPendingDisplayInRect:UntypedDevPixelsToCocoaPoints(aRect)]; } else { - [mView setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)]; + [mView setNeedsDisplayInRect:UntypedDevPixelsToCocoaPoints(aRect)]; } return NS_OK; @@ -1941,7 +1941,7 @@ nsChildView::ConfigureAPZControllerThread() } } -nsIntRect +LayoutDeviceIntRect nsChildView::RectContainingTitlebarControls() { // Start with a thin strip at the top of the window for the highlight line. @@ -2015,7 +2015,8 @@ nsChildView::PostRender(LayerManagerComposite* aManager) } void -nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) +nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) { nsAutoPtr manager(GLManager::CreateGLManager(aManager)); if (manager) { @@ -2024,20 +2025,20 @@ nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) } void -nsChildView::DrawWindowOverlay(GLManager* aManager, nsIntRect aRect) +nsChildView::DrawWindowOverlay(GLManager* aManager, LayoutDeviceIntRect aRect) { GLContext* gl = aManager->gl(); ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false); - MaybeDrawTitlebar(aManager, aRect); - MaybeDrawResizeIndicator(aManager, aRect); + MaybeDrawTitlebar(aManager); + MaybeDrawResizeIndicator(aManager); MaybeDrawRoundedCorners(aManager, aRect); } static void -ClearRegion(gfx::DrawTarget *aDT, nsIntRegion aRegion) +ClearRegion(gfx::DrawTarget *aDT, LayoutDeviceIntRegion aRegion) { - gfxUtils::ClipToRegion(aDT, aRegion); + gfxUtils::ClipToRegion(aDT, aRegion.ToUnknownRegion()); aDT->ClearRect(gfx::Rect(0, 0, aDT->GetSize().width, aDT->GetSize().height)); aDT->PopClip(); } @@ -2076,7 +2077,7 @@ DrawResizer(CGContextRef aCtx) } void -nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect) +nsChildView::MaybeDrawResizeIndicator(GLManager* aManager) { MutexAutoLock lock(mEffectsLock); if (!mShowsResizeIndicator) { @@ -2087,8 +2088,8 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRec mResizerImage = new RectTextureImage(aManager->gl()); } - nsIntSize size = mResizeIndicatorRect.Size(); - mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) { + LayoutDeviceIntSize size = mResizeIndicatorRect.Size(); + mResizerImage->UpdateIfNeeded(size, LayoutDeviceIntRegion(), ^(gfx::DrawTarget* drawTarget, const LayoutDeviceIntRegion& updateRegion) { ClearRegion(drawTarget, updateRegion); gfx::BorrowedCGContext borrow(drawTarget); DrawResizer(borrow.cg); @@ -2131,7 +2132,7 @@ DrawTitlebarHighlight(NSSize aWindowSize, CGFloat aRadius, CGFloat aDevicePixelW } static CGContextRef -CreateCGContext(const nsIntSize& aSize) +CreateCGContext(const LayoutDeviceIntSize& aSize) { CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); CGContextRef ctx = @@ -2164,7 +2165,8 @@ nsChildView::UpdateTitlebarCGContext() NSRect dirtyRect = [mView convertRect:[(BaseWindow*)[mView window] getAndResetNativeDirtyRect] fromView:nil]; NSRect dirtyTitlebarRect = NSIntersectionRect(titlebarRect, dirtyRect); - nsIntSize texSize = RectTextureImage::TextureSizeForSize(mTitlebarRect.Size()); + LayoutDeviceIntSize texSize = + RectTextureImage::TextureSizeForSize(mTitlebarRect.Size()); if (!mTitlebarCGContext || CGBitmapContextGetWidth(mTitlebarCGContext) != size_t(texSize.width) || CGBitmapContextGetHeight(mTitlebarCGContext) != size_t(texSize.height)) { @@ -2285,14 +2287,14 @@ nsChildView::UpdateTitlebarCGContext() // GLContext surface. In order to make the titlebar controls visible, we have // to redraw them inside the OpenGL context surface. void -nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect) +nsChildView::MaybeDrawTitlebar(GLManager* aManager) { MutexAutoLock lock(mEffectsLock); if (!mIsCoveringTitlebar || mIsFullscreen) { return; } - nsIntRegion updatedTitlebarRegion; + LayoutDeviceIntRegion updatedTitlebarRegion; updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect); mUpdatedTitlebarRegion.SetEmpty(); @@ -2315,7 +2317,8 @@ DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius) } void -nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect) +nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, + const LayoutDeviceIntRect& aRect) { MutexAutoLock lock(mEffectsLock); @@ -2323,8 +2326,8 @@ nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect mCornerMaskImage = new RectTextureImage(aManager->gl()); } - nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius); - mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) { + LayoutDeviceIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius); + mCornerMaskImage->UpdateIfNeeded(size, LayoutDeviceIntRegion(), ^(gfx::DrawTarget* drawTarget, const LayoutDeviceIntRegion& updateRegion) { ClearRegion(drawTarget, updateRegion); RefPtr builder = drawTarget->CreatePathBuilder(); builder->Arc(gfx::Point(mDevPixelCornerRadius, mDevPixelCornerRadius), mDevPixelCornerRadius, 0, 2.0f * M_PI); @@ -2392,17 +2395,17 @@ FindUnifiedToolbarBottom(const nsTArray& aThemeGeometr return unifiedToolbarBottom; } -static nsIntRect +static LayoutDeviceIntRect FindFirstRectOfType(const nsTArray& aThemeGeometries, nsITheme::ThemeGeometryType aThemeGeometryType) { for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; if (g.mType == aThemeGeometryType) { - return g.mRect; + return LayoutDeviceIntRect::FromUnknownRect(g.mRect); } } - return nsIntRect(); + return LayoutDeviceIntRect(); } void @@ -2434,9 +2437,9 @@ nsChildView::UpdateThemeGeometries(const nsTArray& aThemeGeometri [win setSheetAttachmentPosition:DevPixelsToCocoaPoints(devSheetPosition)]; // Update titlebar control offsets. - nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeWindowButtons); + LayoutDeviceIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeWindowButtons); [win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]]; - nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeFullscreenButton); + LayoutDeviceIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeFullscreenButton); [win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]]; } @@ -2632,8 +2635,9 @@ nsChildView::StartRemoteDrawing() } } - nsIntRegion dirtyRegion = mBounds; - nsIntSize renderSize = mBounds.Size(); + LayoutDeviceIntRegion dirtyRegion(LayoutDeviceIntRect::FromUnknownRect(mBounds)); + LayoutDeviceIntSize renderSize = + LayoutDeviceIntSize::FromUnknownSize(mBounds.Size()); if (!mBasicCompositorImage) { mBasicCompositorImage = new RectTextureImage(mGLPresenter->gl()); @@ -2644,7 +2648,7 @@ nsChildView::StartRemoteDrawing() if (!drawTarget) { // Composite unchanged textures. - DoRemoteComposition(mBounds); + DoRemoteComposition(LayoutDeviceIntRect::FromUnknownRect(mBounds)); return nullptr; } @@ -2655,7 +2659,7 @@ void nsChildView::EndRemoteDrawing() { mBasicCompositorImage->EndUpdate(true); - DoRemoteComposition(mBounds); + DoRemoteComposition(LayoutDeviceIntRect::FromUnknownRect(mBounds)); } void @@ -2682,7 +2686,7 @@ nsChildView::InitCompositor(Compositor* aCompositor) } void -nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect) +nsChildView::DoRemoteComposition(const LayoutDeviceIntRect& aRenderRect) { if (![(ChildView*)mView preRender:mGLPresenter->GetNSOpenGLContext()]) { return; @@ -2690,7 +2694,7 @@ nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect) mGLPresenter->BeginFrame(aRenderRect.Size()); // Draw the result from the basic compositor. - mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0)); + mBasicCompositorImage->Draw(mGLPresenter, LayoutDeviceIntPoint(0, 0)); // DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint // anything during the basic compositor transaction. Draw the overlay now. @@ -2704,8 +2708,10 @@ nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect) void nsChildView::UpdateWindowDraggingRegion(const nsIntRegion& aRegion) { - if (mDraggableRegion != aRegion) { - mDraggableRegion = aRegion; + LayoutDeviceIntRegion region = + LayoutDeviceIntRegion::FromUnknownRegion(aRegion); + if (mDraggableRegion != region) { + mDraggableRegion = region; [(ChildView*)mView updateWindowDraggableState]; } } @@ -2875,29 +2881,30 @@ RectTextureImage::~RectTextureImage() } } -nsIntSize -RectTextureImage::TextureSizeForSize(const nsIntSize& aSize) +LayoutDeviceIntSize +RectTextureImage::TextureSizeForSize(const LayoutDeviceIntSize& aSize) { - return nsIntSize(gfx::NextPowerOfTwo(aSize.width), - gfx::NextPowerOfTwo(aSize.height)); + return LayoutDeviceIntSize(gfx::NextPowerOfTwo(aSize.width), + gfx::NextPowerOfTwo(aSize.height)); } already_AddRefed -RectTextureImage::BeginUpdate(const nsIntSize& aNewSize, - const nsIntRegion& aDirtyRegion) +RectTextureImage::BeginUpdate(const LayoutDeviceIntSize& aNewSize, + const LayoutDeviceIntRegion& aDirtyRegion) { MOZ_ASSERT(!mInUpdate, "Beginning update during update!"); mUpdateRegion = aDirtyRegion; if (aNewSize != mUsedSize) { mUsedSize = aNewSize; - mUpdateRegion = gfx::IntRect(gfx::IntPoint(0, 0), aNewSize); + mUpdateRegion = + LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), aNewSize); } if (mUpdateRegion.IsEmpty()) { return nullptr; } - nsIntSize neededBufferSize = TextureSizeForSize(mUsedSize); + LayoutDeviceIntSize neededBufferSize = TextureSizeForSize(mUsedSize); if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) { gfx::IntSize size(neededBufferSize.width, neededBufferSize.height); mUpdateDrawTarget = @@ -2926,14 +2933,15 @@ RectTextureImage::EndUpdate(bool aKeepSurface) MOZ_ASSERT(mInUpdate, "Ending update while not in update"); bool overwriteTexture = false; - nsIntRegion updateRegion = mUpdateRegion; + LayoutDeviceIntRegion updateRegion = mUpdateRegion; if (!mTexture || (mTextureSize != mBufferSize)) { overwriteTexture = true; mTextureSize = mBufferSize; } if (overwriteTexture || !CanUploadSubtextures()) { - updateRegion = gfx::IntRect(gfx::IntPoint(0, 0), mTextureSize); + updateRegion = + LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), mTextureSize); } RefPtr snapshot = mUpdateDrawTarget->Snapshot(); @@ -2941,10 +2949,10 @@ RectTextureImage::EndUpdate(bool aKeepSurface) UploadSurfaceToTexture(mGLContext, dataSnapshot, - updateRegion, + updateRegion.ToUnknownRegion(), mTexture, overwriteTexture, - updateRegion.GetBounds().TopLeft(), + updateRegion.GetBounds().TopLeft().ToUnknownPoint(), false, LOCAL_GL_TEXTURE0, LOCAL_GL_TEXTURE_RECTANGLE_ARB); @@ -2957,8 +2965,8 @@ RectTextureImage::EndUpdate(bool aKeepSurface) } void -RectTextureImage::UpdateFromCGContext(const nsIntSize& aNewSize, - const nsIntRegion& aDirtyRegion, +RectTextureImage::UpdateFromCGContext(const LayoutDeviceIntSize& aNewSize, + const LayoutDeviceIntRegion& aDirtyRegion, CGContextRef aCGContext) { gfx::IntSize size = gfx::IntSize(CGBitmapContextGetWidth(aCGContext), @@ -2967,7 +2975,7 @@ RectTextureImage::UpdateFromCGContext(const nsIntSize& aNewSize, RefPtr dt = BeginUpdate(aNewSize, aDirtyRegion); if (dt) { gfx::Rect rect(0, 0, size.width, size.height); - gfxUtils::ClipToRegion(dt, GetUpdateRegion()); + gfxUtils::ClipToRegion(dt, GetUpdateRegion().ToUnknownRegion()); RefPtr sourceSurface = dt->CreateSourceSurfaceFromData(static_cast(CGBitmapContextGetData(aCGContext)), size, @@ -2983,7 +2991,7 @@ RectTextureImage::UpdateFromCGContext(const nsIntSize& aNewSize, void RectTextureImage::Draw(GLManager* aManager, - const nsIntPoint& aLocation, + const LayoutDeviceIntPoint& aLocation, const Matrix4x4& aTransform) { ShaderProgramOGL* program = aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB, @@ -3076,7 +3084,7 @@ GLPresenter::BindAndDrawQuad(ShaderProgramOGL *aProgram, } void -GLPresenter::BeginFrame(nsIntSize aRenderSize) +GLPresenter::BeginFrame(LayoutDeviceIntSize aRenderSize) { mGLContext->MakeCurrent(); @@ -3610,9 +3618,9 @@ NSEvent* gLastDragMouseDownEvent = nil; return mGeckoChild->VibrancyFontSmoothingBackgroundColorForThemeGeometryType(aThemeGeometryType); } -- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect +- (LayoutDeviceIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect { - nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); + LayoutDeviceIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); const NSRect *rects; NSInteger count; [self getRectsBeingDrawn:&rects count:&count]; @@ -3621,7 +3629,7 @@ NSEvent* gLastDragMouseDownEvent = nil; return boundingRect; } - nsIntRegion region; + LayoutDeviceIntRegion region; for (NSInteger i = 0; i < count; ++i) { region.Or(region, mGeckoChild->CocoaPointsToDevPixels(rects[i])); } @@ -3698,7 +3706,7 @@ NSEvent* gLastDragMouseDownEvent = nil; CGContextSaveGState(aContext); - nsIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect]; + LayoutDeviceIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect]; // Create Cairo objects. RefPtr targetSurface; @@ -3712,10 +3720,10 @@ NSEvent* gLastDragMouseDownEvent = nil; RefPtr targetContext = new gfxContext(dt); // Set up the clip region. - nsIntRegionRectIterator iter(region); + LayoutDeviceIntRegion::RectIterator iter(region); targetContext->NewPath(); for (;;) { - const nsIntRect* r = iter.Next(); + const LayoutDeviceIntRect* r = iter.Next(); if (!r) break; targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height)); @@ -3727,10 +3735,10 @@ NSEvent* gLastDragMouseDownEvent = nil; if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) { nsBaseWidget::AutoLayerManagerSetup setupLayerManager(mGeckoChild, targetContext, BufferMode::BUFFER_NONE); - painted = mGeckoChild->PaintWindow(region); + painted = mGeckoChild->PaintWindow(region.ToUnknownRegion()); } else if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) { // We only need this so that we actually get DidPaintWindow fired - painted = mGeckoChild->PaintWindow(region); + painted = mGeckoChild->PaintWindow(region.ToUnknownRegion()); } targetContext = nullptr; @@ -4588,15 +4596,16 @@ NSEvent* gLastDragMouseDownEvent = nil; } static CGSRegionObj -NewCGSRegionFromRegion(const nsIntRegion& aRegion, - CGRect (^aRectConverter)(const nsIntRect&)) +NewCGSRegionFromRegion(const LayoutDeviceIntRegion& aRegion, + CGRect (^aRectConverter)(const LayoutDeviceIntRect&)) { nsTArray rects; - nsIntRegionRectIterator iter(aRegion); + LayoutDeviceIntRegion::RectIterator iter(aRegion); for (;;) { - const nsIntRect* r = iter.Next(); - if (!r) + const LayoutDeviceIntRect* r = iter.Next(); + if (!r) { break; + } rects.AppendElement(aRectConverter(*r)); } @@ -4615,12 +4624,12 @@ NewCGSRegionFromRegion(const nsIntRegion& aRegion, return [super _regionForOpaqueDescendants:aRect forMove:aForMove]; } - nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); + LayoutDeviceIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); - nsIntRegion opaqueRegion; + LayoutDeviceIntRegion opaqueRegion; opaqueRegion.Sub(boundingRect, mGeckoChild->GetDraggableRegion()); - return NewCGSRegionFromRegion(opaqueRegion, ^(const nsIntRect& r) { + return NewCGSRegionFromRegion(opaqueRegion, ^(const LayoutDeviceIntRect& r) { return [self convertToFlippedWindowCoordinates:mGeckoChild->DevPixelsToCocoaPoints(r)]; }); } diff --git a/widget/cocoa/nsClipboard.mm b/widget/cocoa/nsClipboard.mm index abc7031e88f..870638ac7e1 100644 --- a/widget/cocoa/nsClipboard.mm +++ b/widget/cocoa/nsClipboard.mm @@ -153,7 +153,12 @@ nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteb if (!pString) continue; - NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; + NSData* stringData; + if ([pboardType isEqualToString:NSRTFPboardType]) { + stringData = [pString dataUsingEncoding:NSASCIIStringEncoding]; + } else { + stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; + } unsigned int dataLength = [stringData length]; void* clipboardDataPtr = malloc(dataLength); if (!clipboardDataPtr) @@ -581,12 +586,14 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable) bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType) { - if (aMIMEType.EqualsLiteral(kUnicodeMime) || - aMIMEType.EqualsLiteral(kHTMLMime)) { - if (aMIMEType.EqualsLiteral(kUnicodeMime)) - *aPasteboardType = NSStringPboardType; - else - *aPasteboardType = NSHTMLPboardType; + if (aMIMEType.EqualsLiteral(kUnicodeMime)) { + *aPasteboardType = NSStringPboardType; + return true; + } else if (aMIMEType.EqualsLiteral(kRTFMime)) { + *aPasteboardType = NSRTFPboardType; + return true; + } else if (aMIMEType.EqualsLiteral(kHTMLMime)) { + *aPasteboardType = NSHTMLPboardType; return true; } else { return false; diff --git a/widget/cocoa/nsCocoaUtils.h b/widget/cocoa/nsCocoaUtils.h index e5a13120ab9..287cec0b448 100644 --- a/widget/cocoa/nsCocoaUtils.h +++ b/widget/cocoa/nsCocoaUtils.h @@ -129,6 +129,7 @@ struct KeyBindingsCommand class nsCocoaUtils { typedef mozilla::gfx::SourceSurface SourceSurface; + typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; public: @@ -159,13 +160,13 @@ public: NSToIntRound(aPt.y * aBackingScale)); } - static nsIntRect + static LayoutDeviceIntRect CocoaPointsToDevPixels(const NSRect& aRect, CGFloat aBackingScale) { - return nsIntRect(NSToIntRound(aRect.origin.x * aBackingScale), - NSToIntRound(aRect.origin.y * aBackingScale), - NSToIntRound(aRect.size.width * aBackingScale), - NSToIntRound(aRect.size.height * aBackingScale)); + return LayoutDeviceIntRect(NSToIntRound(aRect.origin.x * aBackingScale), + NSToIntRound(aRect.origin.y * aBackingScale), + NSToIntRound(aRect.size.width * aBackingScale), + NSToIntRound(aRect.size.height * aBackingScale)); } static CGFloat @@ -182,8 +183,20 @@ public: (CGFloat)aPt.y / aBackingScale); } + // XXX: all calls to this function should eventually be replaced with calls + // to DevPixelsToCocoaPoints(). static NSRect - DevPixelsToCocoaPoints(const nsIntRect& aRect, CGFloat aBackingScale) + UntypedDevPixelsToCocoaPoints(const nsIntRect& aRect, CGFloat aBackingScale) + { + return NSMakeRect((CGFloat)aRect.x / aBackingScale, + (CGFloat)aRect.y / aBackingScale, + (CGFloat)aRect.width / aBackingScale, + (CGFloat)aRect.height / aBackingScale); + } + + static NSRect + DevPixelsToCocoaPoints(const LayoutDeviceIntRect& aRect, + CGFloat aBackingScale) { return NSMakeRect((CGFloat)aRect.x / aBackingScale, (CGFloat)aRect.y / aBackingScale, @@ -217,8 +230,8 @@ public: // See explanation for geckoRectToCocoaRect, guess what this does... static nsIntRect CocoaRectToGeckoRect(const NSRect &cocoaRect); - static nsIntRect CocoaRectToGeckoRectDevPix(const NSRect &aCocoaRect, - CGFloat aBackingScale); + static mozilla::LayoutDeviceIntRect CocoaRectToGeckoRectDevPix( + const NSRect& aCocoaRect, CGFloat aBackingScale); // Gives the location for the event in screen coordinates. Do not call this // unless the window the event was originally targeted at is still alive! diff --git a/widget/cocoa/nsCocoaUtils.mm b/widget/cocoa/nsCocoaUtils.mm index 8a3adb2cc84..fa475a1d856 100644 --- a/widget/cocoa/nsCocoaUtils.mm +++ b/widget/cocoa/nsCocoaUtils.mm @@ -97,10 +97,10 @@ nsIntRect nsCocoaUtils::CocoaRectToGeckoRect(const NSRect &cocoaRect) return rect; } -nsIntRect nsCocoaUtils::CocoaRectToGeckoRectDevPix(const NSRect &aCocoaRect, - CGFloat aBackingScale) +LayoutDeviceIntRect nsCocoaUtils::CocoaRectToGeckoRectDevPix( + const NSRect& aCocoaRect, CGFloat aBackingScale) { - nsIntRect rect; + LayoutDeviceIntRect rect; rect.x = NSToIntRound(aCocoaRect.origin.x * aBackingScale); rect.y = NSToIntRound(FlippedScreenY(aCocoaRect.origin.y + aCocoaRect.size.height) * aBackingScale); rect.width = NSToIntRound((aCocoaRect.origin.x + aCocoaRect.size.width) * aBackingScale) - rect.x; diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 5adf27fd87d..7964805a219 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -1573,8 +1573,7 @@ NS_IMETHODIMP nsCocoaWindow::GetClientBounds(mozilla::LayoutDeviceIntRect& aRect CGFloat scaleFactor = BackingScaleFactor(); if (!mWindow) { - aRect = LayoutDeviceIntRect::FromUnknownRect( - nsCocoaUtils::CocoaRectToGeckoRectDevPix(NSZeroRect, scaleFactor)); + aRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(NSZeroRect, scaleFactor); return NS_OK; } @@ -1586,8 +1585,7 @@ NS_IMETHODIMP nsCocoaWindow::GetClientBounds(mozilla::LayoutDeviceIntRect& aRect r = [mWindow contentRectForFrameRect:[mWindow frame]]; } - aRect = LayoutDeviceIntRect::FromUnknownRect( - nsCocoaUtils::CocoaRectToGeckoRectDevPix(r, scaleFactor)); + aRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(r, scaleFactor); return NS_OK; @@ -1601,7 +1599,8 @@ nsCocoaWindow::UpdateBounds() if (mWindow) { frame = [mWindow frame]; } - mBounds = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor()); + mBounds = nsCocoaUtils::CocoaRectToGeckoRectDevPix( + frame, BackingScaleFactor()).ToUnknownRect(); } NS_IMETHODIMP nsCocoaWindow::GetScreenBounds(LayoutDeviceIntRect &aRect) @@ -1609,8 +1608,8 @@ NS_IMETHODIMP nsCocoaWindow::GetScreenBounds(LayoutDeviceIntRect &aRect) NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; #ifdef DEBUG - nsIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix([mWindow frame], BackingScaleFactor()); - NS_ASSERTION(mWindow && mBounds == r, "mBounds out of sync!"); + LayoutDeviceIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix([mWindow frame], BackingScaleFactor()); + NS_ASSERTION(mWindow && mBounds == r.ToUnknownRect(), "mBounds out of sync!"); #endif aRect = LayoutDeviceIntRect::FromUnknownRect(mBounds); @@ -1986,13 +1985,13 @@ LayoutDeviceIntPoint nsCocoaWindow::WidgetToScreenOffset() NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; NSRect rect = NSZeroRect; - nsIntRect r; + LayoutDeviceIntRect r; if (mWindow) { rect = [mWindow contentRectForFrameRect:[mWindow frame]]; } r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(rect, BackingScaleFactor()); - return LayoutDeviceIntPoint::FromUnknownPoint(r.TopLeft()); + return r.TopLeft(); NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntPoint(0,0)); } @@ -2019,12 +2018,12 @@ nsCocoaWindow::ClientToWindowSize(const LayoutDeviceIntSize& aClientSize) return LayoutDeviceIntSize(0, 0); CGFloat backingScale = BackingScaleFactor(); - nsIntRect r(0, 0, aClientSize.width, aClientSize.height); + LayoutDeviceIntRect r(0, 0, aClientSize.width, aClientSize.height); NSRect rect = nsCocoaUtils::DevPixelsToCocoaPoints(r, backingScale); NSRect inflatedRect = [mWindow frameRectForContentRect:rect]; r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(inflatedRect, backingScale); - return LayoutDeviceIntSize(r.width, r.height); + return r.Size(); NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntSize(0,0)); } diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm index 6618ff4abea..121fb131c8f 100644 --- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -493,9 +493,16 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) pString = GetStringForType(item, (const NSString*)kUTTypeURL); } else if (flavorStr.EqualsLiteral(kURLDescriptionMime)) { pString = GetTitleForURL(item); + } else if (flavorStr.EqualsLiteral(kRTFMime)) { + pString = GetStringForType(item, (const NSString*)kUTTypeRTF); } if (pString) { - NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; + NSData* stringData; + if (flavorStr.EqualsLiteral(kRTFMime)) { + stringData = [pString dataUsingEncoding:NSASCIIStringEncoding]; + } else { + stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; + } unsigned int dataLength = [stringData length]; void* clipboardDataPtr = malloc(dataLength); if (!clipboardDataPtr) @@ -601,6 +608,8 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) type = (const NSString*)kUTTypeURL; } else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) { type = (const NSString*)kUTTypeURLName; + } else if (dataFlavor.EqualsLiteral(kRTFMime)) { + type = (const NSString*)kUTTypeRTF; } NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]]; if (availableType && IsValidType(availableType, allowFileURL)) { diff --git a/widget/cocoa/nsScreenCocoa.mm b/widget/cocoa/nsScreenCocoa.mm index 5a9ccb6e26c..1b72bbf82e1 100644 --- a/widget/cocoa/nsScreenCocoa.mm +++ b/widget/cocoa/nsScreenCocoa.mm @@ -44,7 +44,8 @@ nsScreenCocoa::GetRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t { NSRect frame = [mScreen frame]; - nsIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor()); + LayoutDeviceIntRect r = + nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor()); *outX = r.x; *outY = r.y; @@ -59,7 +60,8 @@ nsScreenCocoa::GetAvailRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int { NSRect frame = [mScreen visibleFrame]; - nsIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor()); + LayoutDeviceIntRect r = + nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor()); *outX = r.x; *outY = r.y; diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 991c03a1b3f..81863428865 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2233,8 +2233,7 @@ nsWindow::OnExposeEvent(cairo_t *cr) // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be // our private interface so we can rework things to avoid this. boundsRect = region.GetBounds(); - dt->PushClipRect(Rect(boundsRect.x, boundsRect.y, - boundsRect.width, boundsRect.height)); + dt->PushClipRect(Rect(boundsRect)); } else { gfxUtils::ClipToRegion(dt, region); } @@ -2244,18 +2243,19 @@ nsWindow::OnExposeEvent(cairo_t *cr) // The double buffering is done here to extract the shape mask. // (The shape mask won't be necessary when a visual with an alpha // channel is used on compositing window managers.) - layerBuffering = mozilla::layers::BufferMode::BUFFER_NONE; - RefPtr destDT = dt->CreateSimilarDrawTarget(IntSize(boundsRect.width, boundsRect.height), SurfaceFormat::B8G8R8A8); - ctx = new gfxContext(destDT, Point(boundsRect.x, boundsRect.y)); -#ifdef MOZ_HAVE_SHMIMAGE + layerBuffering = BufferMode::BUFFER_NONE; + RefPtr destDT = dt->CreateSimilarDrawTarget(boundsRect.Size(), SurfaceFormat::B8G8R8A8); + ctx = new gfxContext(destDT, boundsRect.TopLeft()); } else { +#ifdef MOZ_HAVE_SHMIMAGE if (nsShmImage::UseShm()) { // We're using an xshm mapping as a back buffer. - layerBuffering = mozilla::layers::BufferMode::BUFFER_NONE; + layerBuffering = BufferMode::BUFFER_NONE; + } else #endif // MOZ_HAVE_SHMIMAGE - } else { + { // Get the layer manager to do double buffering (if necessary). - layerBuffering = mozilla::layers::BufferMode::BUFFERED; + layerBuffering = BufferMode::BUFFERED; } ctx = new gfxContext(dt); } @@ -2291,8 +2291,7 @@ nsWindow::OnExposeEvent(cairo_t *cr) UpdateAlpha(surf, boundsRect); - dt->DrawSurface(surf, Rect(boundsRect.x, boundsRect.y, boundsRect.width, boundsRect.height), - Rect(0, 0, boundsRect.width, boundsRect.height), + dt->DrawSurface(surf, Rect(boundsRect), Rect(0, 0, boundsRect.width, boundsRect.height), DrawSurfaceOptions(Filter::POINT), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); } } @@ -2346,7 +2345,7 @@ nsWindow::UpdateAlpha(SourceSurface* aSourceSurface, nsIntRect aBoundsRect) stride, SurfaceFormat::A8); if (drawTarget) { - drawTarget->DrawSurface(aSourceSurface, Rect(aBoundsRect.x, aBoundsRect.y, aBoundsRect.width, aBoundsRect.height), + drawTarget->DrawSurface(aSourceSurface, Rect(0, 0, aBoundsRect.width, aBoundsRect.height), Rect(0, 0, aSourceSurface->GetSize().width, aSourceSurface->GetSize().height), DrawSurfaceOptions(Filter::POINT), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); } diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 1eb406e6ff6..31b40108403 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -1479,7 +1479,7 @@ nsBaseWidget::SetWindowTitlebarColor(nscolor aColor, bool aActive) } bool -nsBaseWidget::ShowsResizeIndicator(nsIntRect* aResizerRect) +nsBaseWidget::ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) { return false; } diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index bc179660f30..51673e3382f 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -167,7 +167,7 @@ public: virtual bool PreRender(LayerManagerComposite* aManager) override { return true; } virtual void PostRender(LayerManagerComposite* aManager) override {} virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) override {} - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) override {} + virtual void DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {} virtual already_AddRefed StartRemoteDrawing() override; virtual void EndRemoteDrawing() override { }; virtual void CleanupRemoteDrawing() override { }; @@ -202,7 +202,7 @@ public: NS_IMETHOD SetIcon(const nsAString &anIconSpec) override; NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive) override; virtual void SetDrawsInTitlebar(bool aState) override {} - virtual bool ShowsResizeIndicator(nsIntRect* aResizerRect) override; + virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) override; virtual void FreeNativeData(void * data, uint32_t aDataType) override {} NS_IMETHOD BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent, int32_t aHorizontal, diff --git a/widget/nsClipboardProxy.cpp b/widget/nsClipboardProxy.cpp index b88fd1d637f..28f05ae97d2 100644 --- a/widget/nsClipboardProxy.cpp +++ b/widget/nsClipboardProxy.cpp @@ -92,7 +92,8 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*)); NS_ENSURE_SUCCESS(rv, rv); - } else if (flavor.EqualsLiteral(kNativeHTMLMime)) { + } else if (flavor.EqualsLiteral(kNativeHTMLMime) || + flavor.EqualsLiteral(kRTFMime)) { nsCOMPtr dataWrapper = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); diff --git a/widget/nsITransferable.idl b/widget/nsITransferable.idl index bc19b1b5ab0..ab35d69f973 100644 --- a/widget/nsITransferable.idl +++ b/widget/nsITransferable.idl @@ -15,6 +15,7 @@ interface nsIDOMNode; // these probably shouldn't live here, but in some central repository shared // by the entire app. #define kTextMime "text/plain" +#define kRTFMime "text/rtf" #define kUnicodeMime "text/unicode" #define kMozTextInternal "text/x-moz-text-internal" // text data which isn't suppoed to be parsed by other apps. #define kHTMLMime "text/html" diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 0584e6c96ad..0c3b36c72f8 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -335,6 +335,7 @@ class nsIWidget : public nsISupports { typedef mozilla::LayoutDeviceIntMargin LayoutDeviceIntMargin; typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint; typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; + typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion; typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; // Used in UpdateThemeGeometries. @@ -1258,7 +1259,8 @@ class nsIWidget : public nsISupports { * * Always called from the compositing thread. */ - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) = 0; + virtual void DrawWindowOverlay(LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) = 0; /** * Return a DrawTarget for the window which can be composited into. @@ -1500,7 +1502,7 @@ class nsIWidget : public nsISupports { * @param aResizerRect The resizer's rect in device pixels. * @return Whether a resize widget is shown. */ - virtual bool ShowsResizeIndicator(nsIntRect* aResizerRect) = 0; + virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) = 0; /** * Return the popup that was last rolled up, or null if there isn't one. diff --git a/widget/nsPrimitiveHelpers.cpp b/widget/nsPrimitiveHelpers.cpp index 71c88ca37e1..fe70262061c 100644 --- a/widget/nsPrimitiveHelpers.cpp +++ b/widget/nsPrimitiveHelpers.cpp @@ -45,7 +45,8 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* if ( !aPrimitive ) return; - if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ) { + if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 || + strcmp(aFlavor,kRTFMime) == 0) { nsCOMPtr primitive = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID); if ( primitive ) { @@ -79,6 +80,40 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* } // CreatePrimitiveForData +// +// CreatePrimitiveForCFHTML +// +// Platform specific CreatePrimitive, windows CF_HTML. +// +void +nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff, + uint32_t* aDataLen, nsISupports** aPrimitive ) +{ + if (!aPrimitive) + return; + + nsCOMPtr primitive = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID); + if (!primitive) + return; + + // We need to duplicate the input buffer, since the removal of linebreaks + // might reallocte it. + void* utf8 = moz_xmalloc(*aDataLen); + if (!utf8) + return; + memcpy(utf8, aDataBuff, *aDataLen); + int32_t signedLen = static_cast(*aDataLen); + nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(kTextMime, &utf8, &signedLen); + *aDataLen = signedLen; + + nsAutoString str(NS_ConvertUTF8toUTF16(reinterpret_cast(utf8), *aDataLen)); + free(utf8); + *aDataLen = str.Length() * sizeof(char16_t); + primitive->SetData(str); + NS_ADDREF(*aPrimitive = primitive); +} + // // CreateDataFromPrimitive @@ -136,7 +171,7 @@ nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, voi nsresult retVal = NS_OK; - if ( strcmp(inFlavor, "text/plain") == 0 ) { + if ( strcmp(inFlavor, kTextMime) == 0 || strcmp(inFlavor, kRTFMime) == 0) { char* buffAsChars = reinterpret_cast(*ioData); char* oldBuffer = buffAsChars; retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny, diff --git a/widget/nsPrimitiveHelpers.h b/widget/nsPrimitiveHelpers.h index d6a9dae5319..952803a6606 100644 --- a/widget/nsPrimitiveHelpers.h +++ b/widget/nsPrimitiveHelpers.h @@ -23,6 +23,10 @@ public: static void CreatePrimitiveForData ( const char* aFlavor, const void* aDataBuff, uint32_t aDataLen, nsISupports** aPrimitive ) ; + // A specific case of CreatePrimitive for windows CF_HTML handling in DataTransfer + static void CreatePrimitiveForCFHTML ( const void* aDataBuff, + uint32_t* aDataLen, nsISupports** aPrimitive ) ; + // Given a nsISupports* primitive and the flavor it represents, creates a new data // buffer with the data in it. This data will be null terminated, but the length // parameter does not reflect that. diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index 32190a29f36..67cdee82ea8 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -95,6 +95,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr) if (strcmp(aMimeStr, kTextMime) == 0 || strcmp(aMimeStr, kUnicodeMime) == 0) format = CF_UNICODETEXT; + else if (strcmp(aMimeStr, kRTFMime) == 0) + format = ::RegisterClipboardFormat(L"Rich Text Format"); else if (strcmp(aMimeStr, kJPEGImageMime) == 0 || strcmp(aMimeStr, kJPGImageMime) == 0 || strcmp(aMimeStr, kPNGImageMime) == 0) @@ -102,7 +104,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr) else if (strcmp(aMimeStr, kFileMime) == 0 || strcmp(aMimeStr, kFilePromiseMime) == 0) format = CF_HDROP; - else if (strcmp(aMimeStr, kNativeHTMLMime) == 0) + else if (strcmp(aMimeStr, kNativeHTMLMime) == 0 || + strcmp(aMimeStr, kHTMLMime) == 0) format = CF_HTML; else format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get()); @@ -624,11 +627,12 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, genericDataWrapper = do_QueryInterface(file); free(data); } - else if ( strcmp(flavorStr, kNativeHTMLMime) == 0) { + else if ( strcmp(flavorStr, kNativeHTMLMime) == 0 ) { + uint32_t dummy; // the editor folks want CF_HTML exactly as it's on the clipboard, no conversions, // no fancy stuff. Pull it off the clipboard, stuff it into a wrapper and hand // it back to them. - if ( FindPlatformHTML(aDataObject, anIndex, &data, &dataLen) ) + if ( FindPlatformHTML(aDataObject, anIndex, &data, &dummy, &dataLen) ) nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); else { @@ -637,6 +641,23 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, } free(data); } + else if ( strcmp(flavorStr, kHTMLMime) == 0 ) { + uint32_t startOfData = 0; + // The JS folks want CF_HTML exactly as it is on the clipboard, but + // minus the CF_HTML header index information. + // It also needs to be converted to UTF16 and have linebreaks changed. + if ( FindPlatformHTML(aDataObject, anIndex, &data, &startOfData, &dataLen) ) { + dataLen -= startOfData; + nsPrimitiveHelpers::CreatePrimitiveForCFHTML ( static_cast(data) + startOfData, + &dataLen, getter_AddRefs(genericDataWrapper) ); + } + else + { + free(data); + continue; // something wrong with this flavor, keep looking for other data + } + free(data); + } else if ( strcmp(flavorStr, kJPEGImageMime) == 0 || strcmp(flavorStr, kJPGImageMime) == 0 || strcmp(flavorStr, kPNGImageMime) == 0) { @@ -651,6 +672,12 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen ); dataLen = signedLen; + if (strcmp(flavorStr, kRTFMime) == 0) { + // RTF on Windows is known to sometimes deliver an extra null byte. + if (dataLen > 0 && static_cast(data)[dataLen - 1] == '\0') + dataLen--; + } + nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); free(data); } @@ -678,7 +705,9 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, // Someone asked for the OS CF_HTML flavor. We give it back to them exactly as-is. // bool -nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) +nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, + void** outData, uint32_t* outStartOfData, + uint32_t* outDataLen ) { // Reference: MSDN doc entitled "HTML Clipboard Format" // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx#unknown_854 @@ -721,6 +750,10 @@ nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void* // We want to return the buffer not offset by startOfData because it will be // parsed out later (probably by nsHTMLEditor::ParseCFHTML) when it is still // in CF_HTML format. + + // We return the byte offset from the start of the data buffer to where the + // HTML data starts. The caller might want to extract the HTML only. + *outStartOfData = startOfData; *outDataLen = endOfData; return true; } diff --git a/widget/windows/nsClipboard.h b/widget/windows/nsClipboard.h index b1157eb510e..39456ce3e87 100644 --- a/widget/windows/nsClipboard.h +++ b/widget/windows/nsClipboard.h @@ -63,7 +63,8 @@ protected: static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ; static bool FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ; static bool FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ; - static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ); + static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, + uint32_t* outStartOfData, uint32_t* outDataLen ); static void ResolveShortcut ( nsIFile* inFileName, nsACString& outURL ) ; nsIWidget * mWindow; diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index 6d4a30988f1..3462ee6cf3e 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -539,6 +539,14 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) if (mDataObject->QueryGetData(&fe) == S_OK) *_retval = true; // found it! } + else if (strcmp(aDataFlavor, kHTMLMime) == 0) { + // If the client wants html, maybe it's in "HTML Format". + format = nsClipboard::GetFormat(kHTMLMime); + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, + TYMED_HGLOBAL); + if (mDataObject->QueryGetData(&fe) == S_OK) + *_retval = true; // found it! + } } // else try again } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 2f4572b5175..a046f6ea705 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2832,7 +2832,7 @@ nsCycleCollector::ForgetSkippable(bool aRemoveChildlessNodes, mozilla::Maybe marker; if (NS_IsMainThread()) { - marker.emplace("nsCycleCollector::ForgetSkippable"); + marker.emplace("nsCycleCollector::ForgetSkippable", MarkerStackRequest::NO_STACK); } // If we remove things from the purple buffer during graph building, we may @@ -3584,7 +3584,7 @@ nsCycleCollector::Collect(ccType aCCType, mozilla::Maybe marker; if (NS_IsMainThread()) { - marker.emplace("nsCycleCollector::Collect"); + marker.emplace("nsCycleCollector::Collect", MarkerStackRequest::NO_STACK); } bool startedIdle = IsIdle();