Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2015-03-18 13:55:20 +01:00
Родитель 4acf06d593 3c57b5be0b
Коммит b1b0b8cf14
124 изменённых файлов: 1176 добавлений и 835 удалений

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

@ -322,6 +322,7 @@ pref("media.fragmented-mp4.gonk.enabled", true);
pref("media.video-queue.default-size", 3);
// optimize images' memory usage
pref("image.downscale-during-decode.enabled", true);
pref("image.mem.decodeondraw", true);
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,11 +19,11 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b21ae3a28067fd69fc02271029bb1828e69e795"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="527d1c939ee57deb7192166e56e2a3fffa8cb087"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- Stock Android things -->

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,11 +19,11 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8b21ae3a28067fd69fc02271029bb1828e69e795"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="527d1c939ee57deb7192166e56e2a3fffa8cb087"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- Stock Android things -->

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>

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

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "647c9c649965d5a14f32f7d09f4eacc2a9f2136e",
"git_revision": "b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "129de2db0b13101cdc30e4214dad02027f2e5c18",
"revision": "18a7681ac7c78cd21cc22de6ea1746fcab1c2f62",
"repo_path": "integration/gaia-central"
}

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="40f5ce12859076b63307480ff2f0bbdf42bbf258"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="647c9c649965d5a14f32f7d09f4eacc2a9f2136e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b8051d370ddf4e5bd8e7d8a19fb9eeb5fd6ffb39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -141,7 +141,7 @@
<default remote="caf" revision="refs/tags/android-5.0.0_r6" sync-j="4"/>
<!-- Nexus 5 specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="ba62cc8b78c30d36181b8060a2016cc8da166236"/>
<project name="device-hammerhead" path="device/lge/hammerhead" remote="b2g" revision="9be31ff74652fe3f835b8a5f5ae3e29e3156cbae"/>
<project name="device-hammerhead" path="device/lge/hammerhead" remote="b2g" revision="c37663f828891cf7a49451a04f3f1ce7f7e5c054"/>
<project name="device/qcom/common" path="device/qcom/common" remote="caf" revision="3697e5acf25629b82658334e3f8ee3b6df5becab"/>
<project name="device_lge_hammerhead-kernel" path="device/lge/hammerhead-kernel" remote="b2g" revision="1268f640184df5ef759ada669f101a613451673a"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="0cb8574d338bf9f15b45ace7c08ad6deae9673ee"/>

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

@ -14,7 +14,7 @@
to { transform: translate(100px) }
}
.target {
// Element needs geometry to be eligible for layerization
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
background-color: white;

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

@ -22,4 +22,3 @@ skip-if = buildapp == 'mulet'
[css-transitions/test_element-get-animation-players.html]
skip-if = buildapp == 'mulet'
[mozilla/test_deferred_start.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 1113425, 1119981

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

@ -11,7 +11,7 @@
to { transform: translate(100px); }
}
.target {
// Element needs geometry to be eligible for layerization
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
background-color: white;
@ -60,13 +60,18 @@ async_test(function(t) {
assert_unreached('ready promise was rejected');
});
// We need to wait for up to two frames since the animation may not start
// until the beginning of the next refresh driver tick and it won't queue
// the ready Promise callback until that point.
}).then(waitForFrame).then(waitForFrame).then(t.step_func(function() {
// We need to wait for up to three frames. This is because in some
// cases it can take up to two frames for the initial layout
// to take place. Even after that happens we don't actually resolve the
// ready promise until the following tick.
})
.then(waitForFrame)
.then(waitForFrame)
.then(waitForFrame)
.then(t.step_func(function() {
assert_true(promiseCallbackDone,
'ready promise callback was called before the next'
+ ' requestAnimationFrame callback');
'ready promise for an empty animation was resolved'
+ ' within three animation frames');
t.done();
}));
}, 'AnimationPlayer.ready is resolved for an empty animation');

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

@ -1832,7 +1832,7 @@ Element::IsLabelable() const
}
bool
Element::IsInteractiveHTMLContent() const
Element::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return false;
}

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

@ -276,7 +276,7 @@ public:
/**
* Returns if the element is interactive content as per HTML specification.
*/
virtual bool IsInteractiveHTMLContent() const;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const;
/**
* Is the attribute named stored in the mapped attributes?

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

@ -74,6 +74,7 @@ EXPORTS += [
'nsDOMNavigationTiming.h',
'nsDOMString.h',
'nsFocusManager.h',
'nsFormData.h',
'nsFrameMessageManager.h',
'nsGenericDOMDataNode.h',
'nsGkAtomList.h',

55
dom/cache/TypeUtils.cpp поставляемый
Просмотреть файл

@ -229,7 +229,7 @@ TypeUtils::ToPCacheResponseWithoutBody(PCacheResponse& aOut,
aOut.status() = aIn.GetStatus();
aOut.statusText() = aIn.GetStatusText();
nsRefPtr<InternalHeaders> headers = aIn.Headers();
nsRefPtr<InternalHeaders> headers = aIn.UnfilteredHeaders();
MOZ_ASSERT(headers);
headers->GetPHeaders(aOut.headers());
aOut.headersGuard() = headers->Guard();
@ -278,37 +278,14 @@ TypeUtils::ToPCacheQueryParams(PCacheQueryParams& aOut,
already_AddRefed<Response>
TypeUtils::ToResponse(const PCacheResponse& aIn)
{
nsRefPtr<InternalResponse> ir;
switch (aIn.type())
{
case ResponseType::Error:
ir = InternalResponse::NetworkError();
break;
case ResponseType::Opaque:
ir = InternalResponse::OpaqueResponse();
break;
case ResponseType::Default:
ir = new InternalResponse(aIn.status(), aIn.statusText());
break;
case ResponseType::Basic:
{
nsRefPtr<InternalResponse> inner = new InternalResponse(aIn.status(),
aIn.statusText());
ir = InternalResponse::BasicResponse(inner);
break;
}
case ResponseType::Cors:
{
nsRefPtr<InternalResponse> inner = new InternalResponse(aIn.status(),
aIn.statusText());
ir = InternalResponse::CORSResponse(inner);
break;
}
default:
MOZ_CRASH("Unexpected ResponseType!");
if (aIn.type() == ResponseType::Error) {
nsRefPtr<InternalResponse> error = InternalResponse::NetworkError();
nsRefPtr<Response> r = new Response(GetGlobalObject(), error);
return r.forget();
}
MOZ_ASSERT(ir);
nsRefPtr<InternalResponse> ir = new InternalResponse(aIn.status(),
aIn.statusText());
ir->SetUrl(NS_ConvertUTF16toUTF8(aIn.url()));
nsRefPtr<InternalHeaders> internalHeaders =
@ -324,6 +301,24 @@ TypeUtils::ToResponse(const PCacheResponse& aIn)
nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
ir->SetBody(stream);
switch (aIn.type())
{
case ResponseType::Default:
break;
case ResponseType::Opaque:
ir = ir->OpaqueResponse();
break;
case ResponseType::Basic:
ir = ir->BasicResponse();
break;
case ResponseType::Cors:
ir = ir->CORSResponse();
break;
default:
MOZ_CRASH("Unexpected ResponseType!");
}
MOZ_ASSERT(ir);
nsRefPtr<Response> ref = new Response(GetGlobalObject(), ir);
return ref.forget();
}

3
dom/cache/test/mochitest/driver.js поставляемый
Просмотреть файл

@ -81,8 +81,7 @@ function runTests(testFile, order) {
SimpleTest.waitForExplicitFinish();
if (typeof order == "undefined") {
order = "sequential"; // sequential by default, see bug 1143222.
// TODO: Make this "both".
order = "both"; // both by default
}
ok(order == "parallel" || order == "sequential" || order == "both",

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

@ -18,7 +18,10 @@ function checkResponse(r, response, responseText) {
is(r.statusText, response.statusText,
"Both responses should have the same status text");
return r.text().then(function(text) {
is(text, responseText, "The response body should be correct");
// Avoid dumping out the large response text to the log if they're equal.
if (text !== responseText) {
is(text, responseText, "The response body should be correct");
}
});
}

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

@ -16,7 +16,10 @@ function checkResponse(r) {
is(r.statusText, response.statusText,
"Both responses should have the same status text");
return r.text().then(function(text) {
is(text, responseText, "The response body should be correct");
// Avoid dumping out the large response text to the log if they're equal.
if (text !== responseText) {
is(text, responseText, "The response body should be correct");
}
});
}

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

@ -32,6 +32,7 @@
#include "InternalRequest.h"
#include "InternalResponse.h"
#include "nsFormData.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerScope.h"
@ -452,6 +453,16 @@ ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
return NS_OK;
}
nsresult
ExtractFromFormData(nsFormData& aFormData, nsIInputStream** aStream,
nsCString& aContentType)
{
uint64_t unusedContentLength;
nsAutoCString unusedCharset;
return aFormData.GetSendInfo(aStream, &unusedContentLength,
aContentType, unusedCharset);
}
nsresult
ExtractFromUSVString(const nsString& aStr,
nsIInputStream** aStream,
@ -502,7 +513,7 @@ ExtractFromURLSearchParams(const URLSearchParams& aParams,
} // anonymous namespace
nsresult
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType)
{
@ -517,6 +528,9 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStr
} else if (aBodyInit.IsBlob()) {
const File& blob = aBodyInit.GetAsBlob();
return ExtractFromBlob(blob, aStream, aContentType);
} else if (aBodyInit.IsFormData()) {
nsFormData& form = aBodyInit.GetAsFormData();
return ExtractFromFormData(form, aStream, aContentType);
} else if (aBodyInit.IsUSVString()) {
nsAutoString str;
str.Assign(aBodyInit.GetAsUSVString());
@ -531,7 +545,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStr
}
nsresult
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType)
{
@ -546,6 +560,9 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrU
} else if (aBodyInit.IsBlob()) {
const File& blob = aBodyInit.GetAsBlob();
return ExtractFromBlob(blob, aStream, aContentType);
} else if (aBodyInit.IsFormData()) {
nsFormData& form = aBodyInit.GetAsFormData();
return ExtractFromFormData(form, aStream, aContentType);
} else if (aBodyInit.IsUSVString()) {
nsAutoString str;
str.Assign(aBodyInit.GetAsUSVString());

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

@ -26,9 +26,9 @@ class nsIGlobalObject;
namespace mozilla {
namespace dom {
class ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
class InternalRequest;
class OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
class OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
class RequestOrUSVString;
namespace workers {
@ -48,7 +48,7 @@ UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
* Stores content type in out param aContentType.
*/
nsresult
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType);
@ -56,7 +56,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStr
* Non-owning version.
*/
nsresult
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
nsIInputStream** aStream,
nsCString& aContentType);

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

@ -485,16 +485,24 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
internalChan->ForceNoIntercept();
}
// Set up a CORS proxy that will handle the various requirements of the CORS
// protocol. It handles the preflight cache and CORS response headers.
// If the request is allowed, it will start our original request
// and our observer will be notified. On failure, our observer is notified
// directly.
nsRefPtr<nsCORSListenerProxy> corsListener =
new nsCORSListenerProxy(this, mPrincipal, useCredentials);
rv = corsListener->Init(chan, true /* allow data uri */);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
nsCOMPtr<nsIStreamListener> listener = this;
// Unless the cors mode is explicitly no-cors, we set up a cors proxy even in
// the same-origin case, since the proxy does not enforce cors header checks
// in the same-origin case.
if (mRequest->Mode() != RequestMode::No_cors) {
// Set up a CORS proxy that will handle the various requirements of the CORS
// protocol. It handles the preflight cache and CORS response headers.
// If the request is allowed, it will start our original request
// and our observer will be notified. On failure, our observer is notified
// directly.
nsRefPtr<nsCORSListenerProxy> corsListener =
new nsCORSListenerProxy(this, mPrincipal, useCredentials);
rv = corsListener->Init(chan, true /* allow data uri */);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}
listener = corsListener.forget();
}
// If preflight is required, start a "CORS preflight fetch"
@ -507,12 +515,12 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
nsAutoTArray<nsCString, 5> unsafeHeaders;
mRequest->Headers()->GetUnsafeHeaders(unsafeHeaders);
rv = NS_StartCORSPreflight(chan, corsListener, mPrincipal,
rv = NS_StartCORSPreflight(chan, listener, mPrincipal,
useCredentials,
unsafeHeaders,
getter_AddRefs(preflightChannel));
} else {
rv = chan->AsyncOpen(corsListener, nullptr);
rv = chan->AsyncOpen(listener, nullptr);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -548,13 +556,13 @@ FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse)
nsRefPtr<InternalResponse> filteredResponse;
switch (mRequest->GetResponseTainting()) {
case InternalRequest::RESPONSETAINT_BASIC:
filteredResponse = InternalResponse::BasicResponse(aResponse);
filteredResponse = aResponse->BasicResponse();
break;
case InternalRequest::RESPONSETAINT_CORS:
filteredResponse = InternalResponse::CORSResponse(aResponse);
filteredResponse = aResponse->CORSResponse();
break;
case InternalRequest::RESPONSETAINT_OPAQUE:
filteredResponse = InternalResponse::OpaqueResponse();
filteredResponse = aResponse->OpaqueResponse();
break;
default:
MOZ_CRASH("Unexpected case");
@ -775,7 +783,7 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = DoesNotRequirePreflight(aNewChannel);
if (NS_FAILED(rv)) {
NS_WARNING("nsXMLHttpRequest::OnChannelRedirect: "
NS_WARNING("FetchDriver::OnChannelRedirect: "
"DoesNotRequirePreflight returned failure");
return rv;
}

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

@ -23,25 +23,17 @@ InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusTe
{
}
// Headers are not copied since BasicResponse and CORSResponse both need custom
// header handling. Body is not copied as it cannot be shared directly.
InternalResponse::InternalResponse(const InternalResponse& aOther)
: mType(aOther.mType)
, mTerminationReason(aOther.mTerminationReason)
, mURL(aOther.mURL)
, mFinalURL(aOther.mFinalURL)
, mStatus(aOther.mStatus)
, mStatusText(aOther.mStatusText)
, mContentType(aOther.mContentType)
, mSecurityInfo(aOther.mSecurityInfo)
{
}
already_AddRefed<InternalResponse>
InternalResponse::Clone()
{
nsRefPtr<InternalResponse> clone = new InternalResponse(*this);
nsRefPtr<InternalResponse> clone = CreateIncompleteCopy();
clone->mHeaders = new InternalHeaders(*mHeaders);
if (mWrappedResponse) {
clone->mWrappedResponse = mWrappedResponse->Clone();
MOZ_ASSERT(!mBody);
return clone.forget();
}
if (!mBody) {
return clone.forget();
@ -62,27 +54,25 @@ InternalResponse::Clone()
return clone.forget();
}
// static
already_AddRefed<InternalResponse>
InternalResponse::BasicResponse(InternalResponse* aInner)
InternalResponse::BasicResponse()
{
MOZ_ASSERT(aInner);
nsRefPtr<InternalResponse> basic = new InternalResponse(*aInner);
MOZ_ASSERT(!mWrappedResponse, "Can't BasicResponse a already wrapped response");
nsRefPtr<InternalResponse> basic = CreateIncompleteCopy();
basic->mType = ResponseType::Basic;
basic->mHeaders = InternalHeaders::BasicHeaders(aInner->mHeaders);
basic->mBody.swap(aInner->mBody);
basic->mHeaders = InternalHeaders::BasicHeaders(Headers());
basic->mWrappedResponse = this;
return basic.forget();
}
// static
already_AddRefed<InternalResponse>
InternalResponse::CORSResponse(InternalResponse* aInner)
InternalResponse::CORSResponse()
{
MOZ_ASSERT(aInner);
nsRefPtr<InternalResponse> cors = new InternalResponse(*aInner);
MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response");
nsRefPtr<InternalResponse> cors = CreateIncompleteCopy();
cors->mType = ResponseType::Cors;
cors->mHeaders = InternalHeaders::CORSHeaders(aInner->mHeaders);
cors->mBody.swap(aInner->mBody);
cors->mHeaders = InternalHeaders::CORSHeaders(Headers());
cors->mWrappedResponse = this;
return cors.forget();
}

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

@ -38,27 +38,34 @@ public:
return response.forget();
}
static already_AddRefed<InternalResponse>
already_AddRefed<InternalResponse>
OpaqueResponse()
{
MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
response->mType = ResponseType::Opaque;
response->mTerminationReason = mTerminationReason;
response->mURL = mURL;
response->mFinalURL = mFinalURL;
response->mSecurityInfo = mSecurityInfo;
response->mWrappedResponse = this;
return response.forget();
}
// DO NOT use the inner response after filtering it since the filtered
// response will adopt the inner response's body.
static already_AddRefed<InternalResponse>
BasicResponse(InternalResponse* aInner);
already_AddRefed<InternalResponse>
BasicResponse();
// DO NOT use the inner response after filtering it since the filtered
// response will adopt the inner response's body.
static already_AddRefed<InternalResponse>
CORSResponse(InternalResponse* aInner);
already_AddRefed<InternalResponse>
CORSResponse();
ResponseType
Type() const
{
MOZ_ASSERT_IF(mType == ResponseType::Error, !mWrappedResponse);
MOZ_ASSERT_IF(mType == ResponseType::Default, !mWrappedResponse);
MOZ_ASSERT_IF(mType == ResponseType::Basic, mWrappedResponse);
MOZ_ASSERT_IF(mType == ResponseType::Cors, mWrappedResponse);
MOZ_ASSERT_IF(mType == ResponseType::Opaque, mWrappedResponse);
return mType;
}
@ -111,9 +118,28 @@ public:
return mHeaders;
}
InternalHeaders*
UnfilteredHeaders()
{
if (mWrappedResponse) {
return mWrappedResponse->Headers();
};
return Headers();
}
void
GetBody(nsIInputStream** aStream)
{
if (Type() == ResponseType::Opaque) {
*aStream = nullptr;
return;
}
if (mWrappedResponse) {
MOZ_ASSERT(!mBody);
return mWrappedResponse->GetBody(aStream);
}
nsCOMPtr<nsIInputStream> stream = mBody;
stream.forget(aStream);
}
@ -121,6 +147,9 @@ public:
void
SetBody(nsIInputStream* aBody)
{
if (mWrappedResponse) {
return mWrappedResponse->SetBody(aBody);
}
// A request's body may not be reset once set.
MOZ_ASSERT(!mBody);
mBody = aBody;
@ -142,9 +171,22 @@ private:
~InternalResponse()
{ }
// Used to create filtered and cloned responses.
// Does not copy headers or body stream.
explicit InternalResponse(const InternalResponse& aOther);
explicit InternalResponse(const InternalResponse& aOther) = delete;
InternalResponse& operator=(const InternalResponse&) = delete;
// Returns an instance of InternalResponse which is a copy of this
// InternalResponse, except headers, body and wrapped response (if any) which
// are left uninitialized. Used for cloning and filtering.
already_AddRefed<InternalResponse> CreateIncompleteCopy()
{
nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
copy->mType = mType;
copy->mTerminationReason = mTerminationReason;
copy->mURL = mURL;
copy->mFinalURL = mFinalURL;
copy->mSecurityInfo = mSecurityInfo;
return copy.forget();
}
ResponseType mType;
nsCString mTerminationReason;
@ -154,8 +196,13 @@ private:
const nsCString mStatusText;
nsRefPtr<InternalHeaders> mHeaders;
nsCOMPtr<nsIInputStream> mBody;
nsCString mContentType;
nsCString mSecurityInfo;
// For filtered responses.
// Cache, and SW interception should always serialize/access the underlying
// unfiltered headers and when deserializing, create an InternalResponse
// with the unfiltered headers followed by wrapping it.
nsRefPtr<InternalResponse> mWrappedResponse;
};
} // namespace dom

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

@ -228,7 +228,7 @@ Request::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
nsCOMPtr<nsIInputStream> stream;
nsCString contentType;
aRv = ExtractByteStreamFromBody(bodyInit,

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

@ -99,7 +99,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
return nullptr;
}
Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams> body;
Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams> body;
ResponseInit init;
init.mStatus = aStatus;
nsRefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
@ -120,7 +120,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
/*static*/ already_AddRefed<Response>
Response::Constructor(const GlobalObject& aGlobal,
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
const ResponseInit& aInit, ErrorResult& aRv)
{
if (aInit.mStatus < 200 || aInit.mStatus > 599) {

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

@ -103,7 +103,7 @@ public:
static already_AddRefed<Response>
Constructor(const GlobalObject& aGlobal,
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
const ResponseInit& aInit, ErrorResult& rv);
nsIGlobalObject* GetParentObject() const

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

@ -43,7 +43,7 @@ public:
virtual bool Draggable() const MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -41,7 +41,7 @@ HTMLAudioElement::~HTMLAudioElement()
}
bool
HTMLAudioElement::IsInteractiveHTMLContent() const
HTMLAudioElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::controls);
}

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

@ -24,7 +24,7 @@ public:
explicit HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo);
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
// nsIDOMHTMLMediaElement
using HTMLMediaElement::GetPaused;

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

@ -37,7 +37,7 @@ public:
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLButtonElement, button)
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -27,7 +27,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -149,7 +149,7 @@ NS_IMPL_STRING_ATTR(HTMLImageElement, UseMap, usemap)
NS_IMPL_INT_ATTR(HTMLImageElement, Vspace, vspace)
bool
HTMLImageElement::IsInteractiveHTMLContent() const
HTMLImageElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap);
}

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

@ -47,7 +47,7 @@ public:
virtual bool Draggable() const MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
// nsIDOMHTMLImageElement
NS_DECL_NSIDOMHTMLIMAGEELEMENT

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

@ -3222,7 +3222,7 @@ HTMLInputElement::Focus(ErrorResult& aError)
}
bool
HTMLInputElement::IsInteractiveHTMLContent() const
HTMLInputElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return mType != NS_FORM_INPUT_HIDDEN;
}

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

@ -120,7 +120,7 @@ public:
virtual void Focus(ErrorResult& aError) MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
// nsIDOMHTMLInputElement
NS_DECL_NSIDOMHTMLINPUTELEMENT

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

@ -88,7 +88,7 @@ InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop)
nsIContent* content = aContent;
while (content && content != aStop) {
if (content->IsElement() &&
content->AsElement()->IsInteractiveHTMLContent()) {
content->AsElement()->IsInteractiveHTMLContent(true)) {
return true;
}
content = content->GetParent();

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

@ -33,7 +33,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -50,7 +50,7 @@ HTMLObjectElement::~HTMLObjectElement()
}
bool
HTMLObjectElement::IsInteractiveHTMLContent() const
HTMLObjectElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap);
}

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

@ -37,7 +37,7 @@ public:
#endif
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
// nsIDOMHTMLObjectElement
NS_DECL_NSIDOMHTMLOBJECTELEMENT

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

@ -148,7 +148,7 @@ public:
virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -54,7 +54,7 @@ public:
virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE
{
return true;
}

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

@ -127,7 +127,7 @@ nsresult HTMLVideoElement::SetAcceptHeader(nsIHttpChannel* aChannel)
}
bool
HTMLVideoElement::IsInteractiveHTMLContent() const
HTMLVideoElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return HasAttr(kNameSpaceID_None, nsGkAtoms::controls);
}

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

@ -50,7 +50,7 @@ public:
virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE;
// Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
// WebIDL

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

@ -1794,11 +1794,11 @@ nsGenericHTMLElement::IsLabelable() const
}
bool
nsGenericHTMLElement::IsInteractiveHTMLContent() const
nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
return IsAnyOfHTMLElements(nsGkAtoms::details, nsGkAtoms::embed,
nsGkAtoms::keygen) ||
HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex);
(!aIgnoreTabindex && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
}
already_AddRefed<UndoManager>

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

@ -923,7 +923,7 @@ public:
}
virtual bool IsLabelable() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const MOZ_OVERRIDE;
static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */);

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

@ -32,13 +32,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=229925
<select id="yes12"><option>select</option></select>
<textarea id="yes13" cols="1" rows="1"></textarea>
<video id="yes14" controls></video>
<span id="yes15" tabindex="1">tabindex</span>
<audio id="no1"></audio>
<img id="no2" src="data:image/png,">
<input id="no3" type="hidden">
<object id="no4">object</object>
<video id="no5"></video>
<span id="no6" tabindex="1">tabindex</span>
</label>
</form>
<script class="testbody" type="text/javascript">
@ -62,7 +62,6 @@ var yes_nodes = [
document.getElementById("yes12"),
document.getElementById("yes13"),
document.getElementById("yes14"),
document.getElementById("yes15"),
];
var no_nodes = [
@ -72,6 +71,7 @@ var no_nodes = [
document.getElementById("no3"),
document.getElementById("no4"),
document.getElementById("no5"),
document.getElementById("no6"),
];
var target_clicked = false;

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

@ -233,6 +233,12 @@ ExtractH264CodecDetails(const nsAString& aCodec,
aLevel = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
NS_ENSURE_SUCCESS(rv, false);
if (aLevel == 9) {
aLevel = H264_LEVEL_1_b;
} else if (aLevel <= 5) {
aLevel *= 10;
}
// Capture the constraint_set flag value for the purpose of Telemetry.
// We don't NS_ENSURE_SUCCESS here because ExtractH264CodecDetails doesn't
// care about this, but we make sure constraints is above 4 (constraint_set5_flag)

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

@ -486,9 +486,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
mInfo.mVideo.mDisplay =
nsIntSize(video.display_width, video.display_height);
mVideo.mCallback = new DecoderCallback(this, kVideo);
if (!mIsEncrypted && mSharedDecoderManager) {
// Note: Don't use SharedDecoderManager in EME content, as it doesn't
// handle reiniting the decoder properly yet.
if (mSharedDecoderManager) {
mVideo.mDecoder =
mSharedDecoderManager->CreateVideoDecoder(mPlatform,
video,
@ -580,7 +578,7 @@ MP4Reader::GetNextKeyframeTime()
void
MP4Reader::DisableHardwareAcceleration()
{
if (HasVideo() && !mIsEncrypted && mSharedDecoderManager) {
if (HasVideo() && mSharedDecoderManager) {
mPlatform->DisableHardwareAcceleration();
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
@ -1111,9 +1109,7 @@ void MP4Reader::NotifyResourcesStatusChanged()
void
MP4Reader::SetIdle()
{
if (!mIsEncrypted && mSharedDecoderManager && mVideo.mDecoder) {
// Note: Don't use SharedDecoderManager in EME content, as it doesn't
// handle reiniting the decoder properly yet.
if (mSharedDecoderManager && mVideo.mDecoder) {
mSharedDecoderManager->SetIdle(mVideo.mDecoder);
NotifyResourcesStatusChanged();
}

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

@ -233,11 +233,27 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
return nullptr;
}
mSourceBuffers->Append(sourceBuffer);
mActiveSourceBuffers->Append(sourceBuffer);
MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
return sourceBuffer.forget();
}
void
MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
mActiveSourceBuffers->ClearSimple();
bool found = false;
for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
MOZ_ALWAYS_TRUE(found);
if (sourceBuffer == aSourceBuffer) {
mActiveSourceBuffers->Append(aSourceBuffer);
} else if (sourceBuffer->IsActive()) {
mActiveSourceBuffers->AppendSimple(sourceBuffer);
}
}
}
void
MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
{

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

@ -122,7 +122,7 @@ private:
// MediaSourceDecoder uses DurationChange to set the duration
// without hitting the checks in SetDuration.
friend class mozilla::MediaSourceDecoder;
// SourceBuffer uses SetDuration
// SourceBuffer uses SetDuration and SourceBufferIsActive
friend class mozilla::dom::SourceBuffer;
~MediaSource();
@ -140,6 +140,9 @@ private:
// SetDuration with no checks.
void SetDuration(double aDuration, MSRangeRemovalAction aAction);
// Mark SourceBuffer as active and rebuild ActiveSourceBuffers.
void SourceBufferIsActive(SourceBuffer* aSourceBuffer);
nsRefPtr<SourceBufferList> mSourceBuffers;
nsRefPtr<SourceBufferList> mActiveSourceBuffers;

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

@ -120,7 +120,7 @@ MediaSourceReader::RequestAudioData()
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
MOZ_DIAGNOSTIC_ASSERT(mAudioPromise.IsEmpty(), "No duplicate sample requests");
nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
MSE_DEBUGV("");
MSE_DEBUGV("mLastAudioTime=%lld", mLastAudioTime);
if (!mAudioTrack) {
MSE_DEBUG("called with no audio track");
mAudioPromise.Reject(DECODE_ERROR, __func__);
@ -236,20 +236,21 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
mAudioRequest.Complete();
MSE_DEBUG("aReason=%u IsEnded: %d", aReason, IsEnded());
if (aReason == DECODE_ERROR || aReason == CANCELED) {
mAudioPromise.Reject(aReason, __func__);
if (aReason == CANCELED) {
mAudioPromise.Reject(CANCELED, __func__);
return;
}
// End of stream. Force switching past this stream to another reader by
// If End of stream. Force switching past this stream to another reader by
// switching to the end of the buffered range.
MOZ_ASSERT(aReason == END_OF_STREAM);
if (mAudioSourceDecoder) {
int64_t lastAudioTime = mLastAudioTime;
if (aReason == END_OF_STREAM && mAudioSourceDecoder) {
AdjustEndTime(&mLastAudioTime, mAudioSourceDecoder);
}
SwitchSourceResult result = SwitchAudioSource(&mLastAudioTime);
// See if we can find a different source that can pick up where we left off.
if (SwitchAudioSource(&mLastAudioTime) == SOURCE_NEW) {
if (result == SOURCE_NEW) {
GetAudioReader()->ResetDecode();
mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
@ -258,7 +259,22 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
return;
}
// If we got a DECODE_ERROR and we have buffered data in the requested range
// then it must be a genuine decoding error.
// Otherwise we can assume that the data was either evicted or explicitely
// removed from the source buffer and we should wait for new data.
if (aReason == DECODE_ERROR && result != SOURCE_NONE) {
mAudioPromise.Reject(DECODE_ERROR, __func__);
return;
}
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
if (mLastAudioTime - lastAudioTime >= EOS_FUZZ_US) {
// No decoders are available to switch to. We will re-attempt from the last
// failing position.
mLastAudioTime = lastAudioTime;
}
}
nsRefPtr<MediaDecoderReader::VideoDataPromise>
@ -268,8 +284,8 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty(), "No duplicate sample requests");
nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
MSE_DEBUGV("RequestVideoData(%d, %lld)",
aSkipToNextKeyframe, aTimeThreshold);
MSE_DEBUGV("RequestVideoData(%d, %lld), mLastVideoTime=%lld",
aSkipToNextKeyframe, aTimeThreshold, mLastVideoTime);
if (!mVideoTrack) {
MSE_DEBUG("called with no video track");
mVideoPromise.Reject(DECODE_ERROR, __func__);
@ -367,20 +383,22 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
mVideoRequest.Complete();
MSE_DEBUG("aReason=%u IsEnded: %d", aReason, IsEnded());
if (aReason == DECODE_ERROR || aReason == CANCELED) {
mVideoPromise.Reject(aReason, __func__);
if (aReason == CANCELED) {
mVideoPromise.Reject(CANCELED, __func__);
return;
}
// End of stream. Force switching past this stream to another reader by
// if End of stream. Force switching past this stream to another reader by
// switching to the end of the buffered range.
MOZ_ASSERT(aReason == END_OF_STREAM);
if (mVideoSourceDecoder) {
int64_t lastVideoTime = mLastVideoTime;
if (aReason == END_OF_STREAM && mVideoSourceDecoder) {
AdjustEndTime(&mLastVideoTime, mVideoSourceDecoder);
}
// See if we can find a different reader that can pick up where we left off.
if (SwitchVideoSource(&mLastVideoTime) == SOURCE_NEW) {
SwitchSourceResult result = SwitchVideoSource(&mLastVideoTime);
if (result == SOURCE_NEW) {
GetVideoReader()->ResetDecode();
mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
@ -389,7 +407,22 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
return;
}
// If we got a DECODE_ERROR and we have buffered data in the requested range
// then it must be a genuine decoding error.
// Otherwise we can assume that the data was either evicted or explicitely
// removed from the source buffer and we should wait for new data.
if (aReason == DECODE_ERROR && result != SOURCE_NONE) {
mVideoPromise.Reject(DECODE_ERROR, __func__);
return;
}
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
if (mLastVideoTime - lastVideoTime >= EOS_FUZZ_US) {
// No decoders are available to switch to. We will re-attempt from the last
// failing position.
mLastVideoTime = lastVideoTime;
}
}
void

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

@ -322,6 +322,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
, mTimestampOffset(0)
, mAppendMode(SourceBufferAppendMode::Segments)
, mUpdating(false)
, mActive(false)
, mUpdateID(0)
, mType(aType)
{
@ -475,7 +476,11 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
}
if (mTrackBuffer->HasInitSegment()) {
mMediaSource->QueueInitializationEvent();
if (!mActive) {
mActive = true;
mMediaSource->SourceBufferIsActive(this);
mMediaSource->QueueInitializationEvent();
}
}
if (aGotMedia) {

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

@ -117,6 +117,11 @@ public:
// Actually remove data between aStart and aEnd
void DoRangeRemoval(double aStart, double aEnd);
bool IsActive() const
{
return mActive;
}
#if defined(DEBUG)
void Dump(const char* aPath);
#endif
@ -174,6 +179,8 @@ private:
SourceBufferAppendMode mAppendMode;
bool mUpdating;
bool mActive;
// Each time mUpdating is set to true, mUpdateID will be incremented.
// This allows for a queued AppendData task to identify if it was earlier
// aborted and another AppendData queued.

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

@ -61,6 +61,13 @@ SourceBufferList::Append(SourceBuffer* aSourceBuffer)
QueueAsyncSimpleEvent("addsourcebuffer");
}
void
SourceBufferList::AppendSimple(SourceBuffer* aSourceBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
mSourceBuffers.AppendElement(aSourceBuffer);
}
void
SourceBufferList::Remove(SourceBuffer* aSourceBuffer)
{
@ -88,6 +95,13 @@ SourceBufferList::Clear()
QueueAsyncSimpleEvent("removesourcebuffer");
}
void
SourceBufferList::ClearSimple()
{
MOZ_ASSERT(NS_IsMainThread());
mSourceBuffers.Clear();
}
bool
SourceBufferList::IsEmpty()
{

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

@ -78,6 +78,13 @@ public:
// Returns the highest end time of any of the Sourcebuffers.
double GetHighestBufferedEndTime();
// Append a SourceBuffer to the list. No event is fired.
void AppendSimple(SourceBuffer* aSourceBuffer);
// Remove all SourceBuffers from mSourceBuffers.
// No event is fired and no action is performed on the sourcebuffers.
void ClearSimple();
#if defined(DEBUG)
void Dump(const char* aPath);
#endif

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

@ -47,7 +47,8 @@ runWithMSE(function () {
ok(sb, "Create a SourceBuffer");
is(ms.sourceBuffers.length, 1, "MediaSource.sourceBuffers is expected length");
is(ms.sourceBuffers[0], sb, "SourceBuffer in list matches our SourceBuffer");
is(ms.activeSourceBuffers[0], sb, "SourceBuffer in active list matches our SourceBuffer");
is(ms.activeSourceBuffers.length, 0, "MediaSource.activeSourceBuffers is expected length");
fetchWithXHR("seek.webm", function (arrayBuffer) {
sb.appendBuffer(new Uint8Array(arrayBuffer));
@ -70,6 +71,7 @@ runWithMSE(function () {
});
sb.addEventListener("updateend", function () {
is(ms.activeSourceBuffers[0], sb, "SourceBuffer in active list matches our SourceBuffer");
is(sb.updating, false, "SourceBuffer.updating is expected value in updateend event");
updateendCount++;
v.play();

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

@ -580,8 +580,9 @@ NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char16_t *aStatusMsg)
NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
{
if (!aDocument)
if (!aDocument || !mContent) {
return NS_ERROR_NULL_POINTER;
}
// XXX sXBL/XBL2 issue: current doc or owner doc?
// But keep in mind bug 322414 comment 33

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

@ -990,42 +990,13 @@ DataConnectionHandler.prototype = {
},
_compareDataCallOptions: function(dataCall, newDataCall) {
return dataCall.apnProfile.apn == newDataCall.apn &&
dataCall.apnProfile.user == newDataCall.user &&
dataCall.apnProfile.password == newDataCall.passwd &&
return dataCall.apnProfile.apn == newDataCall.apnProfile.apn &&
dataCall.apnProfile.user == newDataCall.apnProfile.user &&
dataCall.apnProfile.password == newDataCall.apnProfile.passwd &&
dataCall.chappap == newDataCall.chappap &&
dataCall.pdptype == newDataCall.pdptype;
},
_deliverDataCallMessage: function(name, args) {
for (let i = 0; i < this._dataCalls.length; i++) {
let datacall = this._dataCalls[i];
// Send message only to the DataCall that matches the data call options.
// Currently, args always contain only one datacall info.
if (!this._compareDataCallOptions(datacall, args[0])) {
continue;
}
// Do not deliver message to DataCall that contains cid but mistmaches
// with the cid in the current message.
if (args[0].cid !== undefined && datacall.linkInfo.cid != null &&
args[0].cid != datacall.linkInfo.cid) {
continue;
}
try {
let handler = datacall[name];
if (typeof handler !== "function") {
throw new Error("No handler for " + name);
}
handler.apply(datacall, args);
} catch (e) {
if (DEBUG) {
this.debug("Handler for " + name + " threw an exception: " + e);
}
}
}
},
/**
* This function will do the following steps:
* 1. Clear the cached APN settings in the RIL.
@ -1337,10 +1308,62 @@ DataConnectionHandler.prototype = {
return dataDisconnecting;
},
_findDataCallByCid: function(cid) {
if (cid === undefined || cid < 0) {
return -1;
}
for (let i = 0; i < this._dataCalls.length; i++) {
let datacall = this._dataCalls[i];
if (datacall.linkInfo.cid != null &&
datacall.linkInfo.cid === cid) {
return i;
}
}
return -1;
},
/**
* Handle data errors.
* Handle unsolicidated data call list changed, called from RadioInterface.
*/
handleDataCallError: function(message) {
handleDataCallListChanged: function(dataCallList) {
let currentDataCalls = this._dataCalls.slice();
for (let i = 0; i < dataCallList.length; i++) {
let dataCall = dataCallList[i];
let index = this._findDataCallByCid(dataCall.cid);
if (index == -1) {
if (DEBUG) {
this.debug("Unexpected new data call: " + JSON.stringify(dataCall));
}
continue;
}
currentDataCalls[index].onDataCallChanged(dataCall);
currentDataCalls[index] = null;
}
// If there is any CONNECTED DataCall left in currentDataCalls, means that
// it is missing in dataCallList, we should send a DISCONNECTED event to
// notify about this.
for (let i = 0; i < currentDataCalls.length; i++) {
let currentDataCall = currentDataCalls[i];
if (currentDataCall && currentDataCall.linkInfo.cid != null &&
currentDataCall.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
if (DEBUG) {
this.debug("Expected data call missing: " + JSON.stringify(
currentDataCall.apnProfile) + ", must have been DISCONNECTED.");
}
currentDataCall.onDataCallChanged({
state: RIL.GECKO_NETWORK_STATE_DISCONNECTED
});
}
}
},
/**
* Notify about data call setup error, called from DataCall.
*/
notifyDataCallError: function(message) {
// Notify data call error only for data APN
let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE);
if (networkInterface && networkInterface.enabled) {
@ -1348,7 +1371,7 @@ DataConnectionHandler.prototype = {
// If there is a cid, compare cid; otherwise it is probably an error on
// data call setup.
if (message.cid !== undefined) {
if (message.cid == dataCall.linkInfo.cid) {
if (message.linkInfo.cid == dataCall.linkInfo.cid) {
gMobileConnectionService.notifyDataError(this.clientId, message);
}
} else {
@ -1357,23 +1380,20 @@ DataConnectionHandler.prototype = {
}
}
}
this._deliverDataCallMessage("dataCallError", [message]);
},
/**
* Handle data call state changes.
* Notify about data call changed, called from DataCall.
*/
handleDataCallState: function(datacall) {
this._deliverDataCallMessage("dataCallStateChanged", [datacall]);
notifyDataCallChanged: function(updatedDataCall) {
// Process pending radio power off request after all data calls
// are disconnected.
if (datacall.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED &&
if (updatedDataCall.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED ||
updatedDataCall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
this.allDataDisconnected()) {
if (gRadioEnabledController.isDeactivatingDataCalls()) {
if (DEBUG) {
this.debug("All data connections are disconnected.");
this.debug("All data calls are disconnected.");
}
gRadioEnabledController.finishDeactivatingDataCalls(this.clientId);
}
@ -1870,22 +1890,8 @@ RadioInterface.prototype = {
gTelephonyService.notifyUssdReceived(this.clientId, message.message,
message.sessionEnded);
break;
case "datacallerror":
connHandler.handleDataCallError(message);
break;
case "datacallstatechange":
let addresses = [];
for (let i = 0; i < message.addresses.length; i++) {
let [address, prefixLength] = message.addresses[i].split("/");
// From AOSP hardware/ril/include/telephony/ril.h, that address prefix
// is said to be OPTIONAL, but we never met such case before.
addresses.push({
address: address,
prefixLength: prefixLength ? parseInt(prefixLength, 10) : 0
});
}
message.addresses = addresses;
connHandler.handleDataCallState(message);
case "datacalllistchanged":
connHandler.handleDataCallListChanged(message.datacalls);
break;
case "emergencyCbModeChange":
gMobileConnectionService.notifyEmergencyCallbackModeChanged(this.clientId,
@ -2645,8 +2651,7 @@ function DataCall(clientId, apnSetting) {
this.linkInfo = {
cid: null,
ifname: null,
ips: [],
prefixLengths: [],
addresses: [],
dnses: [],
gateways: []
};
@ -2678,98 +2683,169 @@ DataCall.prototype = {
// Holds the authentication type sent to ril worker.
chappap: null,
dataCallError: function(message) {
if (DEBUG) {
this.debug("Data call error on APN " + message.apn + ": " +
message.errorMsg + " (" + message.status + "), retry time: " +
message.suggestedRetryTime);
}
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTED;
if (this.requestedNetworkIfaces.length === 0) {
if (DEBUG) this.debug("This DataCall is not requested anymore.");
return;
/**
* @return "deactivate" if <ifname> changes or one of the currentDataCall
* addresses is missing in updatedDataCall, or "identical" if no
* changes found, or "changed" otherwise.
*/
_compareDataCallLink: function(updatedDataCall, currentDataCall) {
// If network interface is changed, report as "deactivate".
if (updatedDataCall.ifname != currentDataCall.ifname) {
return "deactivate";
}
// For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry.
if (message.suggestedRetryTime === INT32_MAX ||
this.isPermanentFail(message.status, message.errorMsg)) {
if (DEBUG) this.debug("Data call error: no retry needed.");
return;
// If any existing address is missing, report as "deactivate".
for (let i = 0; i < currentDataCall.addresses.length; i++) {
let address = currentDataCall.addresses[i];
if (updatedDataCall.addresses.indexOf(address) < 0) {
return "deactivate";
}
}
this.retry(message.suggestedRetryTime);
if (currentDataCall.addresses.length != updatedDataCall.addresses.length) {
// Since now all |currentDataCall.addresses| are found in
// |updatedDataCall.addresses|, this means one or more new addresses are
// reported.
return "changed";
}
let fields = ["gateways", "dnses"];
for (let i = 0; i < fields.length; i++) {
// Compare <datacall>.<field>.
let field = fields[i];
let lhs = updatedDataCall[field], rhs = currentDataCall[field];
if (lhs.length != rhs.length) {
return "changed";
}
for (let i = 0; i < lhs.length; i++) {
if (lhs[i] != rhs[i]) {
return "changed";
}
}
}
return "identical";
},
dataCallStateChanged: function(datacall) {
if (DEBUG) {
this.debug("Data call ID: " + datacall.cid + ", interface name: " +
datacall.ifname + ", APN name: " + datacall.apn + ", state: " +
datacall.state);
onSetupDataCallResult: function(dataCall) {
if (dataCall.status && dataCall.status != RIL.DATACALL_FAIL_NONE) {
dataCall.errorMsg =
RIL.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[dataCall.status];
}
if (this.state == datacall.state &&
datacall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
if (dataCall.errorMsg) {
if (DEBUG) {
this.debug("SetupDataCall error for apn " + dataCall.apn + ": " +
dataCall.errorMsg + " (" + dataCall.status + "), retry time: " +
dataCall.suggestedRetryTime);
}
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTED;
if (this.requestedNetworkIfaces.length === 0) {
if (DEBUG) this.debug("This DataCall is not requested anymore.");
return;
}
// Let DataConnectionHandler notify MobileConnectionService
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
connHandler.notifyDataCallError(this);
// For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry.
if (dataCall.suggestedRetryTime === INT32_MAX ||
this.isPermanentFail(dataCall.status, dataCall.errorMsg)) {
if (DEBUG) this.debug("Data call error: no retry needed.");
return;
}
this.retry(dataCall.suggestedRetryTime);
return;
}
switch (datacall.state) {
case RIL.GECKO_NETWORK_STATE_CONNECTED:
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTING) {
this.apnRetryCounter = 0;
this.linkInfo.cid = datacall.cid;
this.apnRetryCounter = 0;
this.linkInfo.cid = dataCall.cid;
if (this.requestedNetworkIfaces.length === 0) {
if (DEBUG) {
this.debug("State is connected, but no network interface requested" +
" this DataCall");
}
if (this.requestedNetworkIfaces.length === 0) {
if (DEBUG) {
this.debug("State is connected, but no network interface requested" +
" this DataCall");
}
this.deactivate();
return;
}
this.linkInfo.ifname = dataCall.ifname;
this.linkInfo.addresses = dataCall.addresses.slice();
this.linkInfo.gateways = dataCall.gateways.slice();
this.linkInfo.dnses = dataCall.dnses.slice();
this.state = dataCall.state;
// Notify DataConnectionHandler about data call connected.
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
connHandler.notifyDataCallChanged(this);
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
}
},
onDeactivateDataCallResult: function() {
this.reset();
if (this.requestedNetworkIfaces.length > 0) {
if (DEBUG) {
this.debug("State is disconnected/unknown, but this DataCall is" +
" requested.");
}
this.setup();
return;
}
// Notify DataConnectionHandler about data call disconnected.
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
connHandler.notifyDataCallChanged(this);
},
onDataCallChanged: function(updatedDataCall) {
if (DEBUG) {
this.debug("onDataCallChanged: " + JSON.stringify(updatedDataCall));
}
if (this.state == updatedDataCall.state &&
updatedDataCall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) {
return;
}
switch (updatedDataCall.state) {
case RIL.GECKO_NETWORK_STATE_CONNECTED:
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
let result =
this._compareDataCallLink(updatedDataCall, this.linkInfo);
if (result == "identical") {
if (DEBUG) this.debug("No changes in data call.");
return;
}
if (result == "deactivate") {
if (DEBUG) this.debug("Data link changed, cleanup.");
this.deactivate();
return;
}
this.linkInfo.ifname = datacall.ifname;
for (let entry of datacall.addresses) {
this.linkInfo.ips.push(entry.address);
this.linkInfo.prefixLengths.push(entry.prefixLength);
}
this.linkInfo.gateways = datacall.gateways.slice();
this.linkInfo.dnses = datacall.dnses.slice();
} else if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
// configuration changed.
let changed = false;
if (this.linkInfo.ips.length != datacall.addresses.length) {
changed = true;
this.linkInfo.ips = [];
this.linkInfo.prefixLengths = [];
for (let entry of datacall.addresses) {
this.linkInfo.ips.push(entry.address);
this.linkInfo.prefixLengths.push(entry.prefixLength);
}
// Minor change, just update and notify.
if (DEBUG) {
this.debug("Data link minor change, just update and notify.");
}
let reduceFunc = function(aRhs, aChanged, aElement, aIndex) {
return aChanged || (aElement != aRhs[aIndex]);
};
for (let field of ["gateways", "dnses"]) {
let lhs = this.linkInfo[field], rhs = datacall[field];
if (lhs.length != rhs.length ||
lhs.reduce(reduceFunc.bind(null, rhs), false)) {
changed = true;
this.linkInfo[field] = rhs.slice();
}
}
if (!changed) {
return;
}
this.linkInfo.addresses = updatedDataCall.addresses.slice();
this.linkInfo.gateways = updatedDataCall.gateways.slice();
this.linkInfo.dnses = updatedDataCall.dnses.slice();
}
break;
case RIL.GECKO_NETWORK_STATE_DISCONNECTED:
case RIL.GECKO_NETWORK_STATE_UNKNOWN:
if (this.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
// Notify first on unexpected data call disconnection.
this.state = datacall.state;
this.state = updatedDataCall.state;
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
}
@ -2787,7 +2863,12 @@ DataCall.prototype = {
break;
}
this.state = datacall.state;
this.state = updatedDataCall.state;
// Notify DataConnectionHandler about data call changed.
let connHandler = gDataConnectionManager.getConnectionHandler(this.clientId);
connHandler.notifyDataCallChanged(this);
for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
}
@ -2854,8 +2935,7 @@ DataCall.prototype = {
reset: function() {
this.linkInfo.cid = null;
this.linkInfo.ifname = null;
this.linkInfo.ips = [];
this.linkInfo.prefixLengths = [];
this.linkInfo.addresses = [];
this.linkInfo.dnses = [];
this.linkInfo.gateways = [];
@ -2949,7 +3029,7 @@ DataCall.prototype = {
passwd: this.apnProfile.password,
chappap: authType,
pdptype: pdpType
});
}, this.onSetupDataCallResult.bind(this));
this.state = RIL.GECKO_NETWORK_STATE_CONNECTING;
},
@ -3034,7 +3114,8 @@ DataCall.prototype = {
radioInterface.sendWorkerMessage("deactivateDataCall", {
cid: this.linkInfo.cid,
reason: reason
});
}, this.onDeactivateDataCallResult.bind(this));
this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTING;
},
@ -3104,29 +3185,37 @@ RILNetworkInterface.prototype = {
return this.apnSetting.port || "";
},
getAddresses: function(ips, prefixLengths) {
let linkInfo = this.dataCall.linkInfo;
getAddresses: function(aIps, aPrefixLengths) {
let addresses = this.dataCall.linkInfo.addresses;
ips.value = linkInfo.ips.slice();
prefixLengths.value = linkInfo.prefixLengths.slice();
let ips = [];
let prefixLengths = [];
for (let i = 0; i < addresses.length; i++) {
let [ip, prefixLength] = addresses[i].split("/");
ips.push(ip);
prefixLengths.push();
}
return linkInfo.ips.length;
aIps.value = ips.slice();
aPrefixLengths.value = prefixLengths.slice();
return aIps.length;
},
getGateways: function(count) {
getGateways: function(aCount) {
let linkInfo = this.dataCall.linkInfo;
if (count) {
count.value = linkInfo.gateways.length;
if (aCount) {
aCount.value = linkInfo.gateways.length;
}
return linkInfo.gateways.slice();
},
getDnses: function(count) {
getDnses: function(aCount) {
let linkInfo = this.dataCall.linkInfo;
if (count) {
count.value = linkInfo.dnses.length;
if (aCount) {
aCount.value = linkInfo.dnses.length;
}
return linkInfo.dnses.slice();
},

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

@ -225,7 +225,6 @@ function RilObject(aContext) {
this.telephonyRequestQueue = new TelephonyRequestQueue(this);
this.currentCalls = {};
this.currentConferenceState = CALL_STATE_UNKNOWN;
this.currentDataCalls = {};
this._pendingSentSmsMap = {};
this.pendingNetworkType = {};
this._receivedSmsCbPagesMap = {};
@ -255,11 +254,6 @@ RilObject.prototype = {
*/
currentConferenceState: null,
/**
* Existing data calls.
*/
currentDataCalls: null,
/**
* Outgoing messages waiting for SMS-STATUS-REPORT.
*/
@ -366,11 +360,6 @@ RilObject.prototype = {
this._handleDisconnectedCall(currentCall);
}
// Deactivate this.currentDataCalls: rild might have restarted.
for each (let datacall in this.currentDataCalls) {
this.deactivateDataCall(datacall);
}
// Don't clean up this._pendingSentSmsMap
// because on rild restart: we may continue with the pending segments.
@ -2107,11 +2096,6 @@ RilObject.prototype = {
* One of DATACALL_DEACTIVATE_* constants.
*/
deactivateDataCall: function(options) {
let datacall = this.currentDataCalls[options.cid];
if (!datacall) {
return;
}
let Buf = this.context.Buf;
Buf.newParcel(REQUEST_DEACTIVATE_DATA_CALL, options);
Buf.writeInt32(2);
@ -2123,8 +2107,8 @@ RilObject.prototype = {
/**
* Get a list of data calls.
*/
getDataCallList: function() {
this.context.Buf.simpleRequest(REQUEST_DATA_CALL_LIST);
getDataCallList: function(options) {
this.context.Buf.simpleRequest(REQUEST_DATA_CALL_LIST, options);
},
_attachDataRegistration: false,
@ -3915,158 +3899,6 @@ RilObject.prototype = {
this.sendChromeMessage(message);
},
_sendDataCallError: function(message, errorCode) {
// Should not include token for unsolicited response.
delete message.rilMessageToken;
message.rilMessageType = "datacallerror";
if (errorCode !== ERROR_GENERIC_FAILURE) {
message.errorMsg = RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[errorCode];
}
this.sendChromeMessage(message);
},
/**
* @return "deactivate" if <ifname> changes or one of the currentDataCall
* addresses is missing in updatedDataCall, or "identical" if no
* changes found, or "changed" otherwise.
*/
_compareDataCallLink: function(updatedDataCall, currentDataCall) {
// If network interface is changed, report as "deactivate".
if (updatedDataCall.ifname != currentDataCall.ifname) {
return "deactivate";
}
// If any existing address is missing, report as "deactivate".
for (let i = 0; i < currentDataCall.addresses.length; i++) {
let address = currentDataCall.addresses[i];
if (updatedDataCall.addresses.indexOf(address) < 0) {
return "deactivate";
}
}
if (currentDataCall.addresses.length != updatedDataCall.addresses.length) {
// Since now all |currentDataCall.addresses| are found in
// |updatedDataCall.addresses|, this means one or more new addresses are
// reported.
return "changed";
}
let fields = ["gateways", "dnses"];
for (let i = 0; i < fields.length; i++) {
// Compare <datacall>.<field>.
let field = fields[i];
let lhs = updatedDataCall[field], rhs = currentDataCall[field];
if (lhs.length != rhs.length) {
return "changed";
}
for (let i = 0; i < lhs.length; i++) {
if (lhs[i] != rhs[i]) {
return "changed";
}
}
}
return "identical";
},
_processDataCallList: function(datacalls, newDataCallOptions) {
// Check for possible PDP errors: We check earlier because the datacall
// can be removed if is the same as the current one.
for each (let newDataCall in datacalls) {
if (newDataCall.status != DATACALL_FAIL_NONE) {
if (newDataCallOptions) {
newDataCallOptions.status = newDataCall.status;
newDataCallOptions.suggestedRetryTime = newDataCall.suggestedRetryTime;
}
this._sendDataCallError(newDataCallOptions || newDataCall,
newDataCall.status);
}
}
for each (let currentDataCall in this.currentDataCalls) {
let updatedDataCall;
if (datacalls) {
updatedDataCall = datacalls[currentDataCall.cid];
delete datacalls[currentDataCall.cid];
}
if (!updatedDataCall) {
// If datacalls list is coming from REQUEST_SETUP_DATA_CALL response,
// we do not change state for any currentDataCalls not in datacalls list.
if (!newDataCallOptions) {
delete this.currentDataCalls[currentDataCall.cid];
currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
currentDataCall.rilMessageType = "datacallstatechange";
this.sendChromeMessage(currentDataCall);
}
continue;
}
this._setDataCallGeckoState(updatedDataCall);
if (updatedDataCall.state != currentDataCall.state) {
if (updatedDataCall.state == GECKO_NETWORK_STATE_DISCONNECTED) {
delete this.currentDataCalls[currentDataCall.cid];
}
currentDataCall.status = updatedDataCall.status;
currentDataCall.active = updatedDataCall.active;
currentDataCall.state = updatedDataCall.state;
currentDataCall.rilMessageType = "datacallstatechange";
this.sendChromeMessage(currentDataCall);
continue;
}
// State not changed, now check links.
let result =
this._compareDataCallLink(updatedDataCall, currentDataCall);
if (result == "identical") {
if (DEBUG) this.context.debug("No changes in data call.");
continue;
}
if (result == "deactivate") {
if (DEBUG) this.context.debug("Data link changed, cleanup.");
this.deactivateDataCall(currentDataCall);
continue;
}
// Minor change, just update and notify.
if (DEBUG) {
this.context.debug("Data link minor change, just update and notify.");
}
currentDataCall.addresses = updatedDataCall.addresses.slice();
currentDataCall.dnses = updatedDataCall.dnses.slice();
currentDataCall.gateways = updatedDataCall.gateways.slice();
currentDataCall.rilMessageType = "datacallstatechange";
this.sendChromeMessage(currentDataCall);
}
for each (let newDataCall in datacalls) {
if (!newDataCall.ifname) {
continue;
}
if (!newDataCallOptions) {
if (DEBUG) {
this.context.debug("Unexpected new data call: " +
JSON.stringify(newDataCall));
}
continue;
}
this.currentDataCalls[newDataCall.cid] = newDataCall;
this._setDataCallGeckoState(newDataCall);
newDataCall.radioTech = newDataCallOptions.radioTech;
newDataCall.apn = newDataCallOptions.apn;
newDataCall.user = newDataCallOptions.user;
newDataCall.passwd = newDataCallOptions.passwd;
newDataCall.chappap = newDataCallOptions.chappap;
newDataCall.pdptype = newDataCallOptions.pdptype;
newDataCallOptions = null;
newDataCall.rilMessageType = "datacallstatechange";
this.sendChromeMessage(newDataCall);
}
},
_setDataCallGeckoState: function(datacall) {
switch (datacall.active) {
case DATACALL_INACTIVE:
@ -5455,8 +5287,8 @@ RilObject.prototype.readSetupDataCall_v5 = function readSetupDataCall_v5(options
RilObject.prototype[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) {
if (options.rilRequestError) {
// On Data Call generic errors, we shall notify caller
this._sendDataCallError(options, options.rilRequestError);
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendChromeMessage(options);
return;
}
@ -5464,17 +5296,21 @@ RilObject.prototype[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(
// Populate the `options` object with the data call information. That way
// we retain the APN and other info about how the data call was set up.
this.readSetupDataCall_v5(options);
this.currentDataCalls[options.cid] = options;
options.rilMessageType = "datacallstatechange";
this.sendChromeMessage(options);
// Let's get the list of data calls to ensure we know whether it's active
// or not.
this.getDataCallList();
return;
}
// Pass `options` along. That way we retain the APN and other info about
// how the data call was set up.
this[REQUEST_DATA_CALL_LIST](length, options);
let Buf = this.context.Buf;
// Skip version of data call.
Buf.readInt32();
// Skip number of data calls.
Buf.readInt32();
this.readDataCall_v6(options);
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) {
if (options.rilRequestError) {
@ -5770,14 +5606,10 @@ RilObject.prototype[REQUEST_ANSWER] = function REQUEST_ANSWER(length, options) {
};
RilObject.prototype[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL(length, options) {
if (options.rilRequestError) {
return;
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
}
let datacall = this.currentDataCalls[options.cid];
delete this.currentDataCalls[options.cid];
datacall.state = GECKO_NETWORK_STATE_DISCONNECTED;
datacall.rilMessageType = "datacallstatechange";
this.sendChromeMessage(datacall);
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILITY_LOCK(length, options) {
options.success = (options.rilRequestError === 0);
@ -5978,6 +5810,7 @@ RilObject.prototype.readDataCall_v5 = function(options) {
options.addresses = addresses ? addresses.split(" ") : [];
options.dnses = dnses ? dnses.split(" ") : [];
options.gateways = [];
this._setDataCallGeckoState(options);
return options;
};
@ -5998,16 +5831,27 @@ RilObject.prototype.readDataCall_v6 = function(options) {
options.addresses = addresses ? addresses.split(" ") : [];
options.dnses = dnses ? dnses.split(" ") : [];
options.gateways = gateways ? gateways.split(" ") : [];
this._setDataCallGeckoState(options);
return options;
};
RilObject.prototype[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length, options) {
if (options.rilRequestError) {
if (options.rilMessageType) {
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendChromeMessage(options);
}
return;
}
if (!options.rilMessageType) {
// This is an unsolicited data call list changed.
options.rilMessageType = "datacalllistchanged";
}
if (!length) {
this._processDataCallList(null);
options.datacalls = [];
this.sendChromeMessage(options);
return;
}
@ -6017,7 +5861,7 @@ RilObject.prototype[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(le
version = Buf.readInt32();
}
let num = Buf.readInt32();
let datacalls = {};
let datacalls = [];
for (let i = 0; i < num; i++) {
let datacall;
if (version < 6) {
@ -6025,14 +5869,11 @@ RilObject.prototype[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(le
} else {
datacall = this.readDataCall_v6();
}
datacalls[datacall.cid] = datacall;
datacalls.push(datacall);
}
let newDataCallOptions = null;
if (options.rilRequestType == REQUEST_SETUP_DATA_CALL) {
newDataCallOptions = options;
}
this._processDataCallList(datacalls, newDataCallOptions);
options.datacalls = datacalls;
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_RESET_RADIO] = null;
RilObject.prototype[REQUEST_OEM_HOOK_RAW] = null;
@ -6763,6 +6604,8 @@ RilObject.prototype[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNEC
}
this.initRILState();
// rild might have restarted, ensure data call list.
this.getDataCallList();
// Always ensure that we are not in emergency callback mode when init.
this.exitEmergencyCbMode();
// Reset radio in the case that b2g restart (or crash).

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

@ -134,6 +134,60 @@ function testBlob() {
});
}
// This test is a copy of dom/html/test/formData_test.js testSend() modified to
// use the fetch API. Please change this if you change that.
function testFormDataSend() {
var file, blob = new Blob(['hey'], {type: 'text/plain'});
var fd = new FormData();
fd.append("string", "hey");
fd.append("empty", blob);
fd.append("explicit", blob, "explicit-file-name");
fd.append("explicit-empty", blob, "");
file = new File([blob], 'testname', {type: 'text/plain'});
fd.append("file-name", file);
file = new File([blob], '', {type: 'text/plain'});
fd.append("empty-file-name", file);
file = new File([blob], 'testname', {type: 'text/plain'});
fd.append("file-name-overwrite", file, "overwrite");
var req = new Request("/tests/dom/html/test/form_submit_server.sjs", {
method: 'POST',
body: fd,
});
return fetch(req).then((r) => {
ok(r.status, 200, "status should match");
return r.json().then((response) => {
for (var entry of response) {
if (entry.headers['Content-Disposition'] != 'form-data; name="string"') {
is(entry.headers['Content-Type'], 'text/plain');
}
is(entry.body, 'hey');
}
is(response[1].headers['Content-Disposition'],
'form-data; name="empty"; filename="blob"');
is(response[2].headers['Content-Disposition'],
'form-data; name="explicit"; filename="explicit-file-name"');
is(response[3].headers['Content-Disposition'],
'form-data; name="explicit-empty"; filename=""');
is(response[4].headers['Content-Disposition'],
'form-data; name="file-name"; filename="testname"');
is(response[5].headers['Content-Disposition'],
'form-data; name="empty-file-name"; filename=""');
is(response[6].headers['Content-Disposition'],
'form-data; name="file-name-overwrite"; filename="overwrite"');
});
});
}
function runTest() {
return Promise.resolve()
.then(testURL)
@ -141,5 +195,6 @@ function runTest() {
.then(testRequestGET)
.then(testResponses)
.then(testBlob)
.then(testFormDataSend)
// Put more promise based tests here.
}

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

@ -46,9 +46,11 @@ var corsServerPath = "/tests/dom/base/test/file_CrossSiteXHR_server.sjs?";
function testModeNoCors() {
// Fetch spec, section 4, step 4, response tainting should be set opaque, so
// that fetching leads to an opaque filtered response in step 8.
var r = new Request("http://example.com" + corsServerPath + "status=200&allowOrigin=*", { mode: "no-cors" });
var r = new Request("http://example.com" + corsServerPath + "status=200", { mode: "no-cors" });
return fetch(r).then(function(res) {
ok(isOpaqueResponse(res), "no-cors Request fetch should result in opaque response");
}, function(e) {
ok(false, "no-cors Request fetch should not error");
});
}
@ -1019,7 +1021,7 @@ function testRedirects() {
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.mochi.test:8000",
{ server: "http://test2.mochi.test:8888",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
@ -1035,7 +1037,7 @@ function testRedirects() {
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.mochi.test:8000",
{ server: "http://test2.mochi.test:8888",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
@ -1067,7 +1069,7 @@ function testRedirects() {
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.mochi.test:8000",
{ server: "http://test2.mochi.test:8888",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
@ -1083,7 +1085,7 @@ function testRedirects() {
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.mochi.test:8000",
{ server: "http://test2.mochi.test:8888",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
@ -1099,7 +1101,7 @@ function testRedirects() {
hops: [{ server: "http://example.com",
allowOrigin: origin
},
{ server: "http://test2.mochi.test:8000",
{ server: "http://test2.mochi.test:8888",
allowOrigin: origin
},
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",

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

@ -8,9 +8,7 @@
*/
typedef object JSON;
// FIXME(nsm): Bug 739173: FormData is not available in workers.
// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
typedef (ArrayBuffer or ArrayBufferView or Blob or USVString or URLSearchParams) BodyInit;
typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
[NoInterfaceObject, Exposed=(Window,Worker)]
interface Body {

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

@ -1135,22 +1135,8 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
// When testing we synchronously update the shadow tree with the animated
// values to avoid race conditions when calling GetAnimationTransform etc.
// (since the above SetShadowProperties will remove animation effects).
// However, we only do this update when a composite operation is already
// scheduled in order to better match the behavior under regular sampling
// conditions.
bool needTestComposite = mIsTesting && root &&
(mCurrentCompositeTask ||
(mCompositorVsyncObserver &&
mCompositorVsyncObserver->NeedsComposite()));
if (needTestComposite) {
AutoResolveRefLayers resolve(mCompositionManager);
bool requestNextFrame =
mCompositionManager->TransformShadowTree(mTestTime);
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is waiting for this event.
DidComposite();
}
if (mIsTesting) {
ApplyAsyncProperties(aLayerTree);
}
}
mLayerManager->NotifyShadowTreeTransaction();
@ -1197,6 +1183,31 @@ CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
mIsTesting = false;
}
void
CompositorParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
{
// NOTE: This should only be used for testing. For example, when mIsTesting is
// true or when called from test-only methods like
// LayerTransactionParent::RecvGetAnimationTransform.
// Synchronously update the layer tree, but only if a composite was already
// scehduled.
if (aLayerTree->GetRoot() &&
(mCurrentCompositeTask ||
(mCompositorVsyncObserver &&
mCompositorVsyncObserver->NeedsComposite()))) {
AutoResolveRefLayers resolve(mCompositionManager);
TimeStamp time = mIsTesting ? mTestTime : mLastCompose;
bool requestNextFrame =
mCompositionManager->TransformShadowTree(time);
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is waiting for this event.
DidComposite();
}
}
}
bool
CompositorParent::RecvRequestOverfill()
{

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

@ -194,6 +194,8 @@ public:
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) MOZ_OVERRIDE;
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
MOZ_OVERRIDE;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) MOZ_OVERRIDE;
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE { return mCompositionManager; }

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

@ -682,6 +682,12 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
return false;
}
// Make sure we apply the latest animation style or else we can end up with
// a race between when we temporarily clear the animation transform (in
// CompositorParent::SetShadowProperties) and when animation recalculates
// the value.
mShadowLayersManager->ApplyAsyncProperties(this);
// This method is specific to transforms applied by animation.
// This is because this method uses the information stored with an animation
// such as the origin of the reference frame corresponding to the layer, to

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

@ -35,6 +35,7 @@ public:
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) { return true; }
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) { }
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) { }
};

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

@ -232,7 +232,7 @@ private:
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024);
DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, false);
DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);

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

@ -98,7 +98,7 @@ native nsIntRectByVal(nsIntRect);
[ref] native nsIntSize(nsIntSize);
native nsSize(nsSize);
[ptr] native nsIFrame(nsIFrame);
[ptr] native ImageContainer(mozilla::layers::ImageContainer);
native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
[ref] native ImageRegion(mozilla::image::ImageRegion);
[ptr] native LayerManager(mozilla::layers::LayerManager);
native Orientation(mozilla::image::Orientation);
@ -116,7 +116,7 @@ native nsIntSizeByVal(nsIntSize);
*
* Internally, imgIContainer also manages animation of images.
*/
[scriptable, builtinclass, uuid(9a43298b-bf49-44fc-9abe-9ff702f1bd25)]
[scriptable, builtinclass, uuid(44fbd7d5-e417-4d31-ae4a-8ad61d07eb3c)]
interface imgIContainer : nsISupports
{
/**
@ -277,8 +277,17 @@ interface imgIContainer : nsISupports
/**
* Attempts to create an ImageContainer (and Image) containing the current
* frame. Only valid for RASTER type images.
*
* @param aManager The LayerManager which will be used to create the
* ImageContainer.
* @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
* Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
* are supported.
* @return An ImageContainer for the current frame, or nullptr if one could
* not be created.
*/
[noscript] ImageContainer getImageContainer(in LayerManager aManager);
[noscript, notxpcom] TempRefImageContainer getImageContainer(in LayerManager aManager,
in uint32_t aFlags);
/**
* Draw the requested frame of this image onto the context specified.

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

@ -266,8 +266,8 @@ ClippedImage::GetFrameInternal(const nsIntSize& aSize,
return mCachedSurface->Surface();
}
NS_IMETHODIMP
ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ClippedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
// XXX(seth): We currently don't have a way of clipping the result of
// GetImageContainer. We work around this by always returning null, but if it
@ -276,11 +276,10 @@ ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval
// that method for performance reasons.
if (!ShouldClip()) {
return InnerImage()->GetImageContainer(aManager, _retval);
return InnerImage()->GetImageContainer(aManager, aFlags);
}
*_retval = nullptr;
return NS_OK;
return nullptr;
}
static bool

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

@ -37,8 +37,9 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

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

@ -205,12 +205,10 @@ DynamicImage::IsOpaque()
return false;
}
NS_IMETHODIMP
DynamicImage::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
DynamicImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
*_retval = nullptr;
return NS_OK;
return nullptr;
}
NS_IMETHODIMP_(DrawResult)

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

@ -44,18 +44,15 @@ FrozenImage::GetFrame(uint32_t aWhichFrame,
return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
}
NS_IMETHODIMP
FrozenImage::GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
FrozenImage::GetImageContainer(layers::LayerManager* aManager, uint32_t aFlags)
{
// XXX(seth): GetImageContainer does not currently support anything but the
// current frame. We work around this by always returning null, but if it ever
// turns out that FrozenImage is widely used on codepaths that can actually
// benefit from GetImageContainer, it would be a good idea to fix that method
// for performance reasons.
*_retval = nullptr;
return NS_OK;
return nullptr;
}
NS_IMETHODIMP_(DrawResult)

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

@ -37,8 +37,9 @@ public:
NS_IMETHOD GetAnimated(bool* aAnimated) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

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

@ -192,11 +192,10 @@ ImageWrapper::IsOpaque()
return mInnerImage->IsOpaque();
}
NS_IMETHODIMP
ImageWrapper::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ImageWrapper::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
return mInnerImage->GetImageContainer(aManager, _retval);
return mInnerImage->GetImageContainer(aManager, aFlags);
}
NS_IMETHODIMP_(DrawResult)

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

@ -122,9 +122,8 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
return target->Snapshot();
}
NS_IMETHODIMP
OrientedImage::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
OrientedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
// XXX(seth): We currently don't have a way of orienting the result of
// GetImageContainer. We work around this by always returning null, but if it
@ -133,11 +132,10 @@ OrientedImage::GetImageContainer(LayerManager* aManager,
// that method for performance reasons.
if (mOrientation.IsIdentity()) {
return InnerImage()->GetImageContainer(aManager, _retval);
return InnerImage()->GetImageContainer(aManager, aFlags);
}
*_retval = nullptr;
return NS_OK;
return nullptr;
}
struct MatrixBuilder

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

@ -34,8 +34,9 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

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

@ -256,6 +256,7 @@ RasterImage::RasterImage(ProgressTracker* aProgressTracker,
mLockCount(0),
mDecodeCount(0),
mRequestedSampleSize(0),
mLastImageContainerDrawResult(DrawResult::NOT_READY),
#ifdef DEBUG
mFramesNotified(0),
#endif
@ -325,6 +326,7 @@ RasterImage::Init(const char* aMimeType,
// Lock this image's surfaces in the SurfaceCache if we're not discardable.
if (!mDiscardable) {
mLockCount++;
SurfaceCache::LockImage(ImageKey(this));
}
@ -727,19 +729,21 @@ NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
{
return GetFrameInternal(aWhichFrame, aFlags);
return GetFrameInternal(aWhichFrame, aFlags).second().forget();
}
TemporaryRef<SourceSurface>
Pair<DrawResult, RefPtr<SourceSurface>>
RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aWhichFrame > FRAME_MAX_VALUE)
return nullptr;
if (aWhichFrame > FRAME_MAX_VALUE) {
return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
}
if (mError)
return nullptr;
if (mError) {
return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>());
}
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
@ -748,7 +752,7 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
if (!frameRef) {
// The OS threw this frame away and we couldn't redecode it.
return nullptr;
return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
}
// If this frame covers the entire image, we can just reuse its existing
@ -767,50 +771,57 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
frameSurf = CopyFrame(aWhichFrame, aFlags);
}
return frameSurf;
if (!frameRef->IsImageComplete()) {
return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
}
return MakePair(DrawResult::SUCCESS, Move(frameSurf));
}
already_AddRefed<layers::Image>
RasterImage::GetCurrentImage(ImageContainer* aContainer)
Pair<DrawResult, nsRefPtr<layers::Image>>
RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
RefPtr<SourceSurface> surface =
GetFrameInternal(FRAME_CURRENT, FLAG_ASYNC_NOTIFY);
if (!surface) {
auto result = GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
if (!result.second()) {
// The OS threw out some or all of our buffer. We'll need to wait for the
// redecode (which was automatically triggered by GetFrame) to complete.
return nullptr;
return MakePair(result.first(), nsRefPtr<layers::Image>());
}
CairoImage::Data cairoData;
GetWidth(&cairoData.mSize.width);
GetHeight(&cairoData.mSize.height);
cairoData.mSourceSurface = surface;
cairoData.mSourceSurface = result.second();
nsRefPtr<layers::Image> image =
aContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
NS_ASSERTION(image, "Failed to create Image");
MOZ_ASSERT(image);
static_cast<CairoImage*>(image.get())->SetData(cairoData);
return image.forget();
return MakePair(result.first(), Move(image));
}
NS_IMETHODIMP
RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aManager);
MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
FLAG_SYNC_DECODE_IF_FAST |
FLAG_ASYNC_NOTIFY))
== FLAG_NONE,
"Unsupported flag passed to GetImageContainer");
int32_t maxTextureSize = aManager->GetMaxTextureSize();
if (!mHasSize ||
mSize.width > maxTextureSize ||
mSize.height > maxTextureSize) {
*_retval = nullptr;
return NS_OK;
return nullptr;
}
if (IsUnlocked() && mProgressTracker) {
@ -818,28 +829,34 @@ RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
}
nsRefPtr<layers::ImageContainer> container = mImageContainer.get();
if (container) {
container.forget(_retval);
return NS_OK;
bool mustRedecode =
(aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST)) &&
mLastImageContainerDrawResult != DrawResult::SUCCESS &&
mLastImageContainerDrawResult != DrawResult::BAD_IMAGE;
if (container && !mustRedecode) {
return container.forget();
}
// We need a new ImageContainer, so create one.
container = LayerManager::CreateImageContainer();
nsRefPtr<layers::Image> image = GetCurrentImage(container);
if (!image) {
return NS_ERROR_NOT_AVAILABLE;
auto result = GetCurrentImage(container, aFlags);
if (!result.second()) {
// We couldn't get an Image.
return nullptr;
}
// |image| holds a reference to a SourceSurface which in turn holds a lock on
// the current frame's VolatileBuffer, ensuring that it doesn't get freed as
// long as the layer system keeps this ImageContainer alive.
container->SetCurrentImageInTransaction(image);
// |result.second()| holds a reference to a SourceSurface which in turn holds
// a lock on the current frame's VolatileBuffer, ensuring that it doesn't get
// freed as long as the layer system keeps this ImageContainer alive.
container->SetCurrentImageInTransaction(result.second());
mLastImageContainerDrawResult = result.first();
mImageContainer = container;
container.forget(_retval);
return NS_OK;
return container.forget();
}
void
@ -852,12 +869,14 @@ RasterImage::UpdateImageContainer()
return;
}
nsRefPtr<layers::Image> image = GetCurrentImage(container);
if (!image) {
auto result = GetCurrentImage(container, FLAG_NONE);
if (!result.second()) {
// We couldn't get an Image.
return;
}
container->SetCurrentImage(image);
mLastImageContainerDrawResult = result.first();
container->SetCurrentImage(result.second());
}
size_t
@ -1488,12 +1507,6 @@ RasterImage::Decode(const Maybe<nsIntSize>& aSize, uint32_t aFlags)
return NS_OK;
}
// Create a decoder.
nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
if (!decoder) {
return NS_ERROR_FAILURE;
}
if (mDownscaleDuringDecode && aSize) {
// We're about to decode again, which may mean that some of the previous
// sizes we've decoded at aren't useful anymore. We can allow them to
@ -1505,6 +1518,12 @@ RasterImage::Decode(const Maybe<nsIntSize>& aSize, uint32_t aFlags)
SurfaceCache::UnlockSurfaces(ImageKey(this));
}
// Create a decoder.
nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
if (!decoder) {
return NS_ERROR_FAILURE;
}
if (aSize) {
// This isn't a size decode (which doesn't send any early notifications), so
// send out notifications right away.

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

@ -30,6 +30,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Pair.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/UniquePtr.h"
@ -297,8 +298,9 @@ private:
TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags);
TemporaryRef<gfx::SourceSurface> GetFrameInternal(uint32_t aWhichFrame,
uint32_t aFlags);
Pair<DrawResult, RefPtr<gfx::SourceSurface>>
GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
DrawableFrameRef LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,
@ -314,8 +316,9 @@ private:
size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
already_AddRefed<layers::Image>
GetCurrentImage(layers::ImageContainer* aContainer);
Pair<DrawResult, nsRefPtr<layers::Image>>
GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
void UpdateImageContainer();
// We would like to just check if we have a zero lock count, but we can't do
@ -381,6 +384,10 @@ private: // data
// the layer system needs it.
WeakPtr<layers::ImageContainer> mImageContainer;
// If mImageContainer is non-null, this contains the DrawResult we obtained
// the last time we updated it.
DrawResult mLastImageContainerDrawResult;
#ifdef DEBUG
uint32_t mFramesNotified;
#endif

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

@ -697,12 +697,10 @@ VectorImage::GetFrame(uint32_t aWhichFrame,
//******************************************************************************
/* [noscript] ImageContainer getImageContainer(); */
NS_IMETHODIMP
VectorImage::GetImageContainer(LayerManager* aManager,
layers::ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
VectorImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
*_retval = nullptr;
return NS_OK;
return nullptr;
}
struct SVGDrawingParameters

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

@ -46,4 +46,4 @@ load multiple-png-hassize.ico
# Asserts in the debug build
load 856616.gif
skip-if(AddressSanitizer) load 944353.jpg
skip-if(AddressSanitizer) skip-if(B2G) load 944353.jpg

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

@ -707,6 +707,33 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
}
}
void
MessageChannel::ProcessPendingRequests()
{
// Loop until there aren't any more priority messages to process.
for (;;) {
mozilla::Vector<Message> toProcess;
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
Message &msg = *it;
if (!ShouldDeferMessage(msg)) {
toProcess.append(Move(msg));
it = mPending.erase(it);
continue;
}
it++;
}
if (toProcess.empty())
break;
// Processing these messages could result in more messages, so we
// loop around to check for more afterwards.
for (auto it = toProcess.begin(); it != toProcess.end(); it++)
ProcessPendingRequest(*it);
}
}
bool
MessageChannel::Send(Message* aMsg, Message* aReply)
{
@ -766,31 +793,12 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
int32_t transaction = mCurrentTransaction;
msg->set_transaction_id(transaction);
ProcessPendingRequests();
mLink->SendMessage(msg.forget());
while (true) {
// Loop until there aren't any more priority messages to process.
for (;;) {
mozilla::Vector<Message> toProcess;
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
Message &msg = *it;
if (!ShouldDeferMessage(msg)) {
toProcess.append(Move(msg));
it = mPending.erase(it);
continue;
}
it++;
}
if (toProcess.empty())
break;
// Processing these messages could result in more messages, so we
// loop around to check for more afterwards.
for (auto it = toProcess.begin(); it != toProcess.end(); it++)
ProcessPendingRequest(*it);
}
ProcessPendingRequests();
// See if we've received a reply.
if (mRecvdErrors) {

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

@ -227,6 +227,7 @@ class MessageChannel : HasResultCodes
bool InterruptEventOccurred();
bool HasPendingEvents();
void ProcessPendingRequests();
bool ProcessPendingRequest(const Message &aUrgent);
void MaybeUndeferIncall();

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

@ -7,9 +7,7 @@ parent:
prio(high) sync Test1_Start() returns (uint32_t result);
prio(high) sync Test1_InnerEvent() returns (uint32_t result);
async Test2_Start();
prio(high) sync Test2_Msg2();
prio(high) sync Test2_FirstUrgent();
prio(high) sync Test2_SecondUrgent();
prio(high) sync Test2_OutOfOrder();
sync Test3_Start() returns (uint32_t result);
prio(high) sync Test3_InnerEvent() returns (uint32_t result);
@ -17,8 +15,8 @@ child:
async Start();
prio(high) sync Test1_InnerQuery() returns (uint32_t result);
prio(high) sync Test1_NoReenter() returns (uint32_t result);
prio(high) sync Test2_Msg1();
prio(high) sync Test2_Msg3();
prio(high) sync Test2_FirstUrgent();
prio(high) sync Test2_SecondUrgent();
prio(high) sync Test3_WakeUp() returns (uint32_t result);
};

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

@ -84,6 +84,8 @@ TestHangsParent::ShouldContinueFromReplyTimeout()
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableMethod(this, &TestHangsParent::CleanUp));
GetIPCChannel()->CloseWithTimeout();
return false;
}

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

@ -14,6 +14,8 @@ namespace _ipdltest {
// parent
TestRPCParent::TestRPCParent()
: reentered_(false),
resolved_first_cpow_(false)
{
MOZ_COUNT_CTOR(TestRPCParent);
}
@ -59,30 +61,25 @@ TestRPCParent::RecvTest1_InnerEvent(uint32_t* aResult)
bool
TestRPCParent::RecvTest2_Start()
{
if (!SendTest2_Msg1())
fail("SendTest2_Msg1");
// Send a CPOW. During this time, we must NOT process the RPC message, as
// we could start receiving CPOW replies out-of-order.
if (!SendTest2_FirstUrgent())
fail("SendTest2_FirstUrgent");
MOZ_ASSERT(!reentered_);
resolved_first_cpow_ = true;
return true;
}
bool
TestRPCParent::RecvTest2_Msg2()
TestRPCParent::RecvTest2_OutOfOrder()
{
if (!SendTest2_Msg3())
fail("SendTest2_Msg3");
// Send a CPOW. If this RPC call was initiated while waiting for the first
// CPOW to resolve, replies will be processed out of order, and we'll crash.
if (!SendTest2_SecondUrgent())
fail("SendTest2_SecondUrgent");
return true;
}
bool
TestRPCParent::RecvTest2_FirstUrgent()
{
return true;
}
bool
TestRPCParent::RecvTest2_SecondUrgent()
{
reentered_ = true;
return true;
}
@ -107,8 +104,6 @@ TestRPCParent::RecvTest3_InnerEvent(uint32_t* aResult)
TestRPCChild::TestRPCChild()
: reentered_(false),
resolved_first_cpow_(false)
{
MOZ_COUNT_CTOR(TestRPCChild);
}
@ -130,8 +125,8 @@ TestRPCChild::RecvStart()
if (!SendTest2_Start())
fail("SendTest2_Start");
if (!SendTest2_Msg2())
fail("SendTest2_Msg2");
if (!SendTest2_OutOfOrder())
fail("SendTest2_OutOfOrder");
result = 0;
if (!SendTest3_Start(&result))
@ -163,29 +158,15 @@ TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult)
return true;
}
bool TestRPCChild::RecvTest2_Msg1()
bool
TestRPCChild::RecvTest2_FirstUrgent()
{
MOZ_ASSERT(resolved_first_cpow_);
// Send a CPOW. If this RPC call was initiated while waiting for the first
// CPOW to resolve, replies will be processed out of order, and we'll crash.
if (!SendTest2_SecondUrgent())
fail("SendTest2_SecondUrgent");
reentered_ = true;
return true;
}
bool
TestRPCChild::RecvTest2_Msg3()
TestRPCChild::RecvTest2_SecondUrgent()
{
// Send a CPOW. During this time, we must NOT process the RPC message, as
// we could start receiving CPOW replies out-of-order.
if (!SendTest2_FirstUrgent())
fail("SendTest2_FirstUrgent");
MOZ_ASSERT(!reentered_);
resolved_first_cpow_ = true;
return true;
}

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

@ -25,9 +25,7 @@ public:
bool RecvTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest2_Start() MOZ_OVERRIDE;
bool RecvTest2_Msg2() MOZ_OVERRIDE;
bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
bool RecvTest2_OutOfOrder() MOZ_OVERRIDE;
bool RecvTest3_Start(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
@ -35,9 +33,17 @@ public:
{
if (NormalShutdown != why)
fail("unexpected destruction!");
if (!reentered_)
fail("never processed raced RPC call!");
if (!resolved_first_cpow_)
fail("never resolved first CPOW!");
passed("ok");
QuitParent();
}
private:
bool reentered_;
bool resolved_first_cpow_;
};
@ -51,8 +57,8 @@ public:
bool RecvStart() MOZ_OVERRIDE;
bool RecvTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest2_Msg1() MOZ_OVERRIDE;
bool RecvTest2_Msg3() MOZ_OVERRIDE;
bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
bool RecvTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
@ -61,10 +67,6 @@ public:
fail("unexpected destruction!");
QuitChild();
}
private:
bool reentered_;
bool resolved_first_cpow_;
};

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

@ -138,9 +138,9 @@ TestUrgentHangsChild::RecvTest4()
{
PR_Sleep(PR_SecondsToInterval(2));
// This should fail because Test4_1 timed out and hasn't gotten a response
// yet.
if (SendTestInner())
// This won't fail because we should handle Test4_1 here before actually
// sending TestInner to the parent.
if (!SendTestInner())
fail("sending TestInner");
return true;

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

@ -4124,6 +4124,97 @@ MLoadElement::foldsTo(TempAllocator &alloc)
return foldsToStoredValue(alloc, store->value());
}
// Gets the MDefinition* representing the source/target object's storage.
// Usually this is just an MElements*, but sometimes there are layers
// of indirection or inlining, which are handled elsewhere.
static inline const MElements *
MaybeUnwrapElements(const MDefinition *elementsOrObj)
{
// Sometimes there is a level of indirection for conversion.
if (elementsOrObj->isConvertElementsToDoubles())
return MaybeUnwrapElements(elementsOrObj->toConvertElementsToDoubles()->elements());
// For inline elements, the object may be passed directly, for example as MUnbox.
if (elementsOrObj->type() == MIRType_Object)
return nullptr;
return elementsOrObj->toElements();
}
// Gets the MDefinition of the target Object for the given store operation.
static inline const MDefinition *
GetStoreObject(const MDefinition *store)
{
switch (store->op()) {
case MDefinition::Op_StoreElement: {
const MDefinition *elementsOrObj = store->toStoreElement()->elements();
const MDefinition *elements = MaybeUnwrapElements(elementsOrObj);
if (elements)
return elements->toElements()->input();
MOZ_ASSERT(elementsOrObj->type() == MIRType_Object);
return elementsOrObj;
}
case MDefinition::Op_StoreElementHole:
return store->toStoreElementHole()->object();
default:
return nullptr;
}
}
// Implements mightAlias() logic common to all load operations.
static bool
GenericLoadMightAlias(const MDefinition *elementsOrObj, const MDefinition *store)
{
const MElements *elements = MaybeUnwrapElements(elementsOrObj);
if (elements)
return elements->mightAlias(store);
// If MElements couldn't be extracted, then storage must be inline.
// Refer to IsValidElementsType().
const MDefinition *object = elementsOrObj;
MOZ_ASSERT(object->type() == MIRType_Object);
if (!object->resultTypeSet())
return true;
const MDefinition *storeObject = GetStoreObject(store);
if (!storeObject)
return true;
if (!storeObject->resultTypeSet())
return true;
return object->resultTypeSet()->objectsIntersect(storeObject->resultTypeSet());
}
bool
MElements::mightAlias(const MDefinition *store) const
{
if (!input()->resultTypeSet())
return true;
const MDefinition *storeObj = GetStoreObject(store);
if (!storeObj)
return true;
if (!storeObj->resultTypeSet())
return true;
return input()->resultTypeSet()->objectsIntersect(storeObj->resultTypeSet());
}
bool
MLoadElement::mightAlias(const MDefinition *store) const
{
return GenericLoadMightAlias(elements(), store);
}
bool
MInitializedLength::mightAlias(const MDefinition *store) const
{
return GenericLoadMightAlias(elements(), store);
}
bool
MGuardReceiverPolymorphic::congruentTo(const MDefinition *ins) const
{

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

@ -7494,6 +7494,7 @@ class MElements
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::Load(AliasSet::ObjectFields);
}
bool mightAlias(const MDefinition *store) const;
ALLOW_CLONE(MElements)
};
@ -7681,6 +7682,7 @@ class MInitializedLength
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::Load(AliasSet::ObjectFields);
}
bool mightAlias(const MDefinition *store) const;
void computeRange(TempAllocator &alloc) MOZ_OVERRIDE;
@ -8184,6 +8186,7 @@ class MLoadElement
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::Load(AliasSet::Element);
}
bool mightAlias(const MDefinition *store) const;
ALLOW_CLONE(MLoadElement)
};

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

@ -419,6 +419,23 @@ TypeSet::isSubset(const TypeSet *other) const
return true;
}
bool
TypeSet::objectsIntersect(const TypeSet *other) const
{
if (unknownObject() || other->unknownObject())
return true;
for (unsigned i = 0; i < getObjectCount(); i++) {
ObjectKey *key = getObject(i);
if (!key)
continue;
if (other->hasType(ObjectType(key)))
return true;
}
return false;
}
template <class TypeListT>
bool
TypeSet::enumerateTypes(TypeListT *list) const

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

@ -492,6 +492,8 @@ class TypeSet
return this->isSubset(other) && other->isSubset(this);
}
bool objectsIntersect(const TypeSet *other) const;
/* Forward all types in this set to the specified constraint. */
bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);

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

@ -3936,6 +3936,7 @@ ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData,
MOZ_ASSERT(layerState == LAYER_ACTIVE_EMPTY);
nsRefPtr<Layer> scrollInfoLayer = item->BuildLayer(mBuilder, mManager, mParameters);
if (!scrollInfoLayer) {
item->~nsDisplayScrollInfoLayer();
continue;
}
@ -3972,7 +3973,9 @@ ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData,
}
layer = scrollInfoLayer;
item->~nsDisplayScrollInfoLayer();
}
mNewChildLayers[i].mScrollInfoItems.Clear();
}
}

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

@ -5195,13 +5195,11 @@ nsImageRenderer::IsAnimatedImage()
already_AddRefed<mozilla::layers::ImageContainer>
nsImageRenderer::GetContainer(LayerManager* aManager)
{
if (mType != eStyleImageType_Image || !mImageContainer)
if (mType != eStyleImageType_Image || !mImageContainer) {
return nullptr;
}
nsRefPtr<ImageContainer> container;
nsresult rv = mImageContainer->GetImageContainer(aManager, getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nullptr);
return container.forget();
return mImageContainer->GetImageContainer(aManager, imgIContainer::FLAG_NONE);
}
#define MAX_BLUR_RADIUS 300

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

@ -133,7 +133,8 @@ public:
return false;
}
if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS) {
if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS ||
mLastDrawResult == mozilla::image::DrawResult::BAD_IMAGE) {
return false;
}

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

@ -1171,6 +1171,28 @@ public:
nsDisplayAltFeedback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame) {}
virtual nsDisplayItemGeometry*
AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
{
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) MOZ_OVERRIDE
{
auto geometry =
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
if (aBuilder->ShouldSyncDecodeImages() &&
geometry->ShouldInvalidateToSyncDecodeImages()) {
bool snap;
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
}
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) MOZ_OVERRIDE
{
@ -1181,25 +1203,33 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) MOZ_OVERRIDE
{
// Always sync decode, because these icons are UI, and since they're not
// discardable we'll pay the price of sync decoding at most once.
uint32_t flags = imgIContainer::FLAG_SYNC_DECODE;
nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
EventStates state = f->GetContent()->AsElement()->State();
f->DisplayAltFeedback(*aCtx,
mVisibleRect,
IMAGE_OK(state, true)
? nsImageFrame::gIconLoad->mLoadingImage
: nsImageFrame::gIconLoad->mBrokenImage,
ToReferenceFrame());
DrawResult result =
f->DisplayAltFeedback(*aCtx,
mVisibleRect,
IMAGE_OK(state, true)
? nsImageFrame::gIconLoad->mLoadingImage
: nsImageFrame::gIconLoad->mBrokenImage,
ToReferenceFrame(),
flags);
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
}
NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)
};
void
DrawResult
nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt)
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt,
uint32_t aFlags)
{
// We should definitely have a gIconLoad here.
MOZ_ASSERT(gIconLoad, "How did we succeed in Init then?");
@ -1219,7 +1249,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
// Make sure we have enough room to actually render the border within
// our frame bounds
if ((inner.width < 2 * borderEdgeWidth) || (inner.height < 2 * borderEdgeWidth)) {
return;
return DrawResult::SUCCESS;
}
// Paint the border
@ -1233,7 +1263,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
inner.Deflate(nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH),
nsPresContext::CSSPixelsToAppUnits(ICON_PADDING+ALT_BORDER_WIDTH));
if (inner.IsEmpty()) {
return;
return DrawResult::SUCCESS;
}
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
@ -1244,11 +1274,13 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
gfx->Clip(NSRectToSnappedRect(inner, PresContext()->AppUnitsPerDevPixel(),
*drawTarget));
// Check if we should display image placeholders
if (gIconLoad->mPrefShowPlaceholders) {
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
DrawResult result = DrawResult::NOT_READY;
bool iconUsed = false;
// Check if we should display image placeholders
if (!gIconLoad->mPrefShowPlaceholders) {
result = DrawResult::SUCCESS;
} else {
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
// If we weren't previously displaying an icon, register ourselves
// as an observer for load and animation updates and flag that we're
@ -1262,7 +1294,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
bool flushRight =
(!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL();
// If the icon in question is loaded and decoded, draw it
// If the icon in question is loaded, draw it.
uint32_t imageStatus = 0;
if (aRequest)
aRequest->GetImageStatus(&imageStatus);
@ -1272,15 +1304,13 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
MOZ_ASSERT(imgCon, "Load complete, but no image container?");
nsRect dest(flushRight ? inner.XMost() - size : inner.x,
inner.y, size, size);
nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon,
result = nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon,
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
nullptr, imgIContainer::FLAG_SYNC_DECODE);
iconUsed = true;
nullptr, aFlags);
}
// if we could not draw the icon, flag that we're waiting for it and
// just draw some graffiti in the mean time
if (!iconUsed) {
// If we could not draw the icon, just draw some graffiti in the mean time.
if (result == DrawResult::NOT_READY) {
ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
@ -1331,6 +1361,8 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
}
aRenderingContext.ThebesContext()->Restore();
return result;
}
#ifdef DEBUG
@ -1395,9 +1427,11 @@ already_AddRefed<ImageContainer>
nsDisplayImage::GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
nsRefPtr<ImageContainer> container;
mImage->GetImageContainer(aManager, getter_AddRefs(container));
return container.forget();
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
return mImage->GetImageContainer(aManager, flags);
}
gfxRect
@ -1457,8 +1491,12 @@ nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
}
}
nsRefPtr<ImageContainer> container;
mImage->GetImageContainer(aManager, getter_AddRefs(container));
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsRefPtr<ImageContainer> container =
mImage->GetImageContainer(aManager, flags);
if (!container) {
return LAYER_NONE;
}
@ -1502,9 +1540,15 @@ nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
nsRefPtr<ImageContainer> container;
nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nullptr);
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsRefPtr<ImageContainer> container =
mImage->GetImageContainer(aManager, flags);
if (!container) {
return nullptr;
}
nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));

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

@ -143,10 +143,11 @@ public:
static bool ShouldCreateImageFrameFor(mozilla::dom::Element* aElement,
nsStyleContext* aStyleContext);
void DisplayAltFeedback(nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt);
DrawResult DisplayAltFeedback(nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt,
uint32_t aFlags);
nsRect GetInnerArea() const;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше