merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-10-28 10:43:33 +01:00
Родитель f7861e7c36 b53bda208d
Коммит 3ec5c00413
173 изменённых файлов: 2375 добавлений и 1442 удалений

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

@ -84,13 +84,6 @@ exports['test exceptions'] = function(assert) {
}
};
exports['test opt version'] = function(assert) {
let fixture = sandbox();
assert.throws(function() {
evaluate(fixture, 'let a = 2;', 'test.js', 1, '1.5');
}, 'No let in js 1.5');
};
exports['test load'] = function(assert) {
let fixture = sandbox();
load(fixture, fixturesURI + 'sandbox-normal.js');

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

@ -1,16 +0,0 @@
[
{
"size": 80458572,
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -1,16 +0,0 @@
[
{
"size": 80458572,
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -39,7 +39,7 @@
},
"b2g_manifest": "aries.xml",
"b2g_manifest_intree": true,
"additional_source_tarballs": [],
"additional_source_tarballs": ["backup-aries.tar.xz"],
"gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
"gaia": {
"l10n": {

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

@ -1,16 +1,16 @@
[
{
"size": 135359412,
"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b",
"algorithm": "sha512",
"filename": "backup-aries.tar.xz",
"comment": "v18D"
},
{
"size": 80458572,
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -1,16 +0,0 @@
[
{
"size": 80458572,
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -5,12 +5,5 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -1,16 +0,0 @@
[
{
"size": 80458572,
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -12,12 +12,5 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -10,12 +10,5 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -23,13 +23,6 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -23,13 +23,6 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

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

@ -4,12 +4,4 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]
}]

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

@ -31,7 +31,7 @@ from check_utils import get_all_toplevel_filenames
architecture_independent = set([ 'generic' ])
all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips32' ])
all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64', 'mips32' ])
all_shared_architecture_names = set([ 'x86_shared', 'mips_shared', 'arm', 'arm64' ])
reBeforeArg = "(?<=[(,\s])"
reArgType = "(?P<type>[\w\s:*&]+)"

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

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ChromeNodeList.h"
#include "mozilla/dom/ChromeNodeListBinding.h"
using namespace mozilla;
using namespace mozilla::dom;
already_AddRefed<ChromeNodeList>
ChromeNodeList::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
nsIDocument* root = win ? win->GetExtantDoc() : nullptr;
RefPtr<ChromeNodeList> list = new ChromeNodeList(root);
return list.forget();
}
JSObject*
ChromeNodeList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ChromeNodeListBinding::Wrap(aCx, this, aGivenProto);
}
void
ChromeNodeList::Append(nsINode& aNode, ErrorResult& aError)
{
if (!aNode.IsContent()) {
// nsINodeList deals with nsIContent objects only, so need to
// filter out other nodes for now.
aError.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
AppendElement(aNode.AsContent());
}
void
ChromeNodeList::Remove(nsINode& aNode, ErrorResult& aError)
{
if (!aNode.IsContent()) {
aError.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
RemoveElement(aNode.AsContent());
}

35
dom/base/ChromeNodeList.h Normal file
Просмотреть файл

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMArray.h"
#include "nsContentList.h"
namespace mozilla {
class ErrorResult;
namespace dom {
class GlobalObject;
class ChromeNodeList final : public nsSimpleContentList
{
public:
explicit ChromeNodeList(nsINode* aOwner)
: nsSimpleContentList(aOwner)
{
}
static already_AddRefed<ChromeNodeList>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
void Append(nsINode& aNode, ErrorResult& aError);
void Remove(nsINode& aNode, ErrorResult& aError);
};
} // namespace dom
} // namespace mozilla

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

@ -16,6 +16,7 @@
#include "mozilla/dom/Promise.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_INHERITED(ScreenOrientation,

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

@ -154,6 +154,7 @@ EXPORTS.mozilla.dom += [
'BarProps.h',
'BlobSet.h',
'ChildIterator.h',
'ChromeNodeList.h',
'ChromeUtils.h',
'Comment.h',
'Console.h',
@ -217,6 +218,7 @@ UNIFIED_SOURCES += [
'Attr.cpp',
'BarProps.cpp',
'ChildIterator.cpp',
'ChromeNodeList.cpp',
'ChromeUtils.cpp',
'Comment.cpp',
'Console.cpp',

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

@ -7372,6 +7372,7 @@ nsContentUtils::CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
void
nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
nsTArray<IPCDataTransfer>& aIPC,
bool aInSyncMessage,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent)
{
@ -7384,14 +7385,71 @@ nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables
nsCOMPtr<nsISupports> genericItem;
aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
nsCOMPtr<nsITransferable> transferable(do_QueryInterface(genericItem));
TransferableToIPCTransferable(transferable, dt, aChild, aParent);
TransferableToIPCTransferable(transferable, dt, aInSyncMessage, aChild, aParent);
}
}
}
nsresult
nsContentUtils::SlurpFileToString(nsIFile* aFile, nsACString& aString)
{
aString.Truncate();
nsCOMPtr<nsIURI> fileURI;
nsresult rv = NS_NewFileURI(getter_AddRefs(fileURI), aFile);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
fileURI,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIInputStream> stream;
rv = channel->Open2(getter_AddRefs(stream));
if (NS_FAILED(rv)) {
return rv;
}
rv = NS_ConsumeStream(stream, UINT32_MAX, aString);
if (NS_FAILED(rv)) {
return rv;
}
rv = stream->Close();
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
bool
nsContentUtils::IsFileImage(nsIFile* aFile, nsACString& aType)
{
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
if (!mime) {
return false;
}
nsresult rv = mime->GetTypeFromFile(aFile, aType);
if (NS_FAILED(rv)) {
return false;
}
return StringBeginsWith(aType, NS_LITERAL_CSTRING("image/"));
}
void
nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
IPCDataTransfer* aIPCDataTransfer,
bool aInSyncMessage,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent)
{
@ -7465,7 +7523,7 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
int32_t stride;
mozilla::UniquePtr<char[]> surfaceData =
nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = nsCString(flavorStr);
item->data() = nsCString(surfaceData.get(), length);
@ -7485,6 +7543,22 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
nsCOMPtr<BlobImpl> blobImpl;
nsCOMPtr<nsIFile> file = do_QueryInterface(data);
if (file) {
// If we can send this over as a blob, do so. Otherwise, we're
// responding to a sync message and the child can't process the blob
// constructor before processing our response, which would crash. In
// that case, hope that the caller is nsClipboardProxy::GetData,
// called from editor and send over images as raw data.
if (aInSyncMessage) {
nsAutoCString type;
if (IsFileImage(file, type)) {
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = type;
SlurpFileToString(file, item->data());
}
continue;
}
blobImpl = new BlobImplFile(file, false);
ErrorResult rv;
// Ensure that file data is cached no that the content process
@ -7493,6 +7567,10 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
blobImpl->GetLastModified(rv);
blobImpl->LookupAndCacheIsDirectory();
} else {
if (aInSyncMessage) {
// Can't do anything.
continue;
}
blobImpl = do_QueryInterface(data);
}
if (blobImpl) {

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

@ -2408,13 +2408,30 @@ public:
CallOnRemoteChildFunction aCallback,
void* aArg);
/**
* Given an nsIFile, attempts to read it into aString.
*
* Note: Use sparingly! This causes main-thread I/O, which causes jank and all
* other bad things.
*/
static nsresult SlurpFileToString(nsIFile* aFile, nsACString& aString);
/**
* Returns true if the mime service thinks this file contains an image.
*
* The content type is returned in aType.
*/
static bool IsFileImage(nsIFile* aFile, nsACString& aType);
static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
bool aInSyncMessage,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent);
static void TransferableToIPCTransferable(nsITransferable* aTransferable,
mozilla::dom::IPCDataTransfer* aIPCDataTransfer,
bool aInSyncMessage,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent);

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

@ -26,6 +26,7 @@ support-files =
window_nsITextInputProcessor.xul
title_window.xul
[test_bug120684.xul]
[test_bug206691.xul]
[test_bug339494.xul]
[test_bug357450.xul]

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

@ -0,0 +1,80 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=120684
-->
<window title="Mozilla Bug 120684"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=120684"
target="_blank">Mozilla Bug 120684</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 120684 **/
var list = new ChromeNodeList();
is(list.length, 0, "Length should be initially 0.");
ok(list instanceof NodeList, "ChromeNodeList object should be an instance of NodeList.");
try {
list.append(document);
ok(false, "should have throw!");
} catch(ex) {
ok(true, "ChromeNodeList supports only nsIContent objects for now.");
}
try {
list.remove(document);
ok(false, "should have throw!");
} catch(ex) {
ok(true, "ChromeNodeList supports only nsIContent objects for now.");
}
is(list.length, 0, "Length should be 0.");
list.append(document.documentElement);
is(list.length, 1, "Length should be 1.");
is(list[0], document.documentElement);
is(list[1], undefined);
// Removing element which isn't in the list shouldn't do anything.
list.remove(document.createElement("foo"));
is(list.length, 1, "Length should be 1.");
is(list[0], document.documentElement);
list.remove(document.documentElement);
is(list.length, 0, "Length should be 0.");
is(list[0], undefined);
var e1 = document.createElement("foo");
var e2 = document.createElement("foo");
var e3 = document.createElement("foo");
list.append(e1);
list.append(e2);
list.append(e3);
is(list[0], e1);
is(list[1], e2);
is(list[2], e3);
is(list.length, 3);
list.remove(e2);
is(list[0], e1);
is(list[1], e3);
is(list[2], undefined);
is(list.length, 2);
// A leak test.
list.expando = list;
]]>
</script>
</window>

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

@ -537,44 +537,19 @@ DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
// We should use JSFunction objects for interface objects, but we need a custom
// hasInstance hook because we have new interface objects on prototype chains of
// old (XPConnect-based) bindings. Because Function.prototype.toString throws if
// passed a non-Function object we also need to provide our own toString method
// for interface objects.
static bool
InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
// reserved slots (e.g. for named constructors). So we define a custom
// funToString ObjectOps member for interface objects.
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned /* indent */)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
if (!args.thisv().isObject()) {
JS_ReportErrorNumber(cx, js::GetErrorMessage, nullptr,
JSMSG_CANT_CONVERT_TO, "null", "object");
return false;
}
JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(thisObj, /* stopAtOuter = */ false));
if (!obj) {
JS_ReportError(cx, "Permission denied to access object");
return false;
}
const js::Class* clasp = js::GetObjectClass(obj);
if (!IsDOMIfaceAndProtoClass(clasp)) {
JS_ReportError(cx, "toString called on incompatible object");
return false;
}
const js::Class* clasp = js::GetObjectClass(aObject);
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
DOMIfaceAndProtoJSClass::FromJSClass(clasp);
JS::Rooted<JSString*> str(cx,
JS_NewStringCopyZ(cx,
ifaceAndProtoJSClass->mToString));
if (!str) {
return false;
}
args.rval().setString(str);
return true;
return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
}
bool
@ -647,15 +622,6 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
}
if (constructorClass) {
// Have to shadow Function.prototype.toString, since that throws
// on things that are not js::FunctionClass.
JS::Rooted<JSFunction*> toString(cx,
JS_DefineFunction(cx, constructor, "toString", InterfaceObjectToString,
0, 0));
if (!toString) {
return nullptr;
}
if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
JSPROP_READONLY)) {
return nullptr;
@ -1570,22 +1536,6 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JSPROP_PERMANENT | JSPROP_READONLY,
desc, cacheOnHolder);
}
if (IdEquals(id, "toString") && !JS_ObjectIsFunction(cx, obj)) {
MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
JS::Rooted<JSFunction*> toString(cx, JS_NewFunction(cx, InterfaceObjectToString, 0, 0, "toString"));
if (!toString) {
return false;
}
cacheOnHolder = true;
FillPropertyDescriptor(desc, wrapper, 0,
JS::ObjectValue(*JS_GetFunctionObject(toString)));
return JS_WrapPropertyDescriptor(cx, desc);
}
} else {
MOZ_ASSERT(IsInterfacePrototype(type));

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

@ -3359,6 +3359,10 @@ void
DeprecationWarning(JSContext* aCx, JSObject* aObject,
nsIDocument::DeprecatedOperations aOperation);
// A callback to perform funToString on an interface object
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned /* indent */);
} // namespace dom
} // namespace mozilla

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

@ -453,7 +453,8 @@ class CGDOMJSClass(CGThing):
nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
mozilla::dom::ObjectToOuterObjectValue /* thisValue */
mozilla::dom::ObjectToOuterObjectValue, /* thisValue */
nullptr, /* funToString */
}
""",
objectMoved=objectMovedHook)
@ -730,7 +731,21 @@ class CGInterfaceObjectJSClass(CGThing):
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
{
nullptr, /* lookupProperty */
nullptr, /* defineProperty */
nullptr, /* hasProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* getOwnPropertyDescriptor */
nullptr, /* deleteProperty */
nullptr, /* watch */
nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
nullptr, /* thisObject */
InterfaceObjectToString, /* funToString */
}
},
eInterface,
${hooks},

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

@ -31,6 +31,15 @@ catch (e) {
ok(false, "Stringifying a DOM interface object shouldn't throw.");
}
try {
eventTargetToString = Function.prototype.toString.call(EventTarget);
is(eventTargetToString, nativeToString,
"Stringifying a DOM interface object via Function.prototype.toString " +
"should return the same string as stringifying a native function.");
}
catch (e) {
ok(false, "Stringifying a DOM interface object shouldn't throw.");
}
</script>
</pre>

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

@ -349,11 +349,15 @@ TypeUtils::ToInternalRequest(const CacheRequest& aIn)
RefPtr<InternalHeaders> internalHeaders =
ToInternalHeaders(aIn.headers(), aIn.headersGuard());
ErrorResult result;
internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
MOZ_ASSERT(!result.Failed());
// Be careful to fill the headers before setting the guard in order to
// correctly re-create the original headers.
internalRequest->Headers()->Fill(*internalHeaders, result);
MOZ_ASSERT(!result.Failed());
internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
MOZ_ASSERT(!result.Failed());
nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
internalRequest->SetBody(stream);

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

@ -303,7 +303,11 @@ FetchDriver::HttpFetch()
// Set the same headers.
nsAutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
bool hasAccept = false;
for (uint32_t i = 0; i < headers.Length(); ++i) {
if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
hasAccept = true;
}
if (headers[i].mValue.IsEmpty()) {
httpChan->SetEmptyRequestHeader(headers[i].mName);
} else {
@ -311,6 +315,12 @@ FetchDriver::HttpFetch()
}
}
if (!hasAccept) {
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
NS_LITERAL_CSTRING("*/*"),
false /* merge */);
}
// Step 2. Set the referrer.
nsAutoString referrer;
mRequest->GetReferrer(referrer);

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

@ -151,13 +151,8 @@ InternalHeaders::Clear()
void
InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
{
// Rather than re-validate all current headers, just require code to set
// this prior to populating the InternalHeaders object. Allow setting immutable
// late, though, as that is pretty much required to have a useful, immutable
// headers object.
if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
aRv.Throw(NS_ERROR_FAILURE);
}
// The guard is only checked during ::Set() and ::Append() in the spec. It
// does not require revalidating headers already set.
mGuard = aGuard;
}

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

@ -1404,11 +1404,11 @@ HTMLMediaElement::CurrentTime() const
return stream->StreamTimeToSeconds(stream->GetCurrentTime());
}
if (mDecoder) {
if (mDefaultPlaybackStartPosition == 0.0 && mDecoder) {
return mDecoder->GetCurrentTime();
}
return 0.0;
return mDefaultPlaybackStartPosition;
}
NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime)
@ -1484,19 +1484,11 @@ HTMLMediaElement::Seek(double aTime,
StopSuspendingAfterFirstFrame();
if (mSrcStream) {
// do nothing since streams aren't seekable; we effectively clamp to
// the current time.
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
// do nothing since media streams have an empty Seekable range.
return;
}
if (!mPlayed) {
LOG(LogLevel::Debug, ("HTMLMediaElement::mPlayed not available."));
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (mCurrentPlayRangeStart != -1.0) {
if (mPlayed && mCurrentPlayRangeStart != -1.0) {
double rangeEndTime = CurrentTime();
LOG(LogLevel::Debug, ("%p Adding \'played\' a range : [%f, %f]", this, mCurrentPlayRangeStart, rangeEndTime));
// Multiple seek without playing, or seek while playing.
@ -1508,15 +1500,14 @@ HTMLMediaElement::Seek(double aTime,
mCurrentPlayRangeStart = -1.0;
}
if (!mDecoder) {
LOG(LogLevel::Debug, ("%p SetCurrentTime(%f) failed: no decoder", this, aTime));
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
mDefaultPlaybackStartPosition = aTime;
return;
}
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
LOG(LogLevel::Debug, ("%p SetCurrentTime(%f) failed: no source", this, aTime));
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
if (!mDecoder) {
// mDecoder must always be set in order to reach this point.
NS_ASSERTION(mDecoder, "SetCurrentTime failed: no decoder");
return;
}
@ -2114,7 +2105,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mMediaStreamTrackListener(nullptr),
mElementInTreeState(ELEMENT_NOT_INTREE),
mHasUserInteraction(false),
mFirstFrameLoaded(false)
mFirstFrameLoaded(false),
mDefaultPlaybackStartPosition(0.0)
{
if (!gMediaElementLog) {
gMediaElementLog = PR_NewLogModule("nsMediaElement");
@ -3440,6 +3432,11 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
// We are a video element playing video so update the screen wakelock
NotifyOwnerDocumentActivityChangedInternal();
}
if (mDefaultPlaybackStartPosition > 0) {
SetCurrentTime(mDefaultPlaybackStartPosition);
mDefaultPlaybackStartPosition = 0.0;
}
}
void HTMLMediaElement::FirstFrameLoaded()

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

@ -1516,6 +1516,11 @@ private:
// True if the first frame has been successfully loaded.
bool mFirstFrameLoaded;
// Media elements also have a default playback start position, which must
// initially be set to zero seconds. This time is used to allow the element to
// be seeked even before the media is loaded.
double mDefaultPlaybackStartPosition;
};
} // namespace dom

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

@ -59,7 +59,7 @@ MediaDocumentStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ct
return mNextStream->OnStartRequest(request, ctxt);
}
return NS_BINDING_ABORTED;
return NS_ERROR_PARSED_DATA_CACHED;
}
NS_IMETHODIMP

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

@ -1986,21 +1986,21 @@ private:
}
size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
nsAutoArrayPtr<char> compressed(new (fallible) char[compressedLength]);
UniqueFreePtr<uint8_t> compressed(
static_cast<uint8_t*>(malloc(compressedLength)));
if (NS_WARN_IF(!compressed)) {
return NS_ERROR_OUT_OF_MEMORY;
}
snappy::RawCompress(reinterpret_cast<const char*>(uncompressed),
uncompressedLength, compressed.get(),
uncompressedLength,
reinterpret_cast<char*>(compressed.get()),
&compressedLength);
std::pair<const void *, int> data(static_cast<void*>(compressed.get()),
int(compressedLength));
std::pair<uint8_t *, int> data(compressed.release(),
int(compressedLength));
// XXX This copies the buffer again... There doesn't appear to be any way to
// preallocate space and write directly to a BlobVariant at the moment.
nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
nsCOMPtr<nsIVariant> result = new mozilla::storage::AdoptedBlobVariant(data);
result.forget(aResult);
return NS_OK;

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

@ -2828,7 +2828,7 @@ ContentParent::RecvGetClipboard(nsTArray<nsCString>&& aTypes,
clipboard->GetData(trans, aWhichClipboard);
nsContentUtils::TransferableToIPCTransferable(trans, aDataTransfer,
nullptr, this);
true, nullptr, this);
return true;
}
@ -5272,6 +5272,7 @@ ContentParent::MaybeInvokeDragSession(TabParent* aParent)
transfer->GetTransferables(lc);
nsContentUtils::TransferablesToIPCTransferables(transferables,
dataTransfers,
false,
nullptr,
this);
uint32_t action;

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

@ -23,6 +23,17 @@ runWithMSE(function(ms, el) {
ok(true, "Receive a sourceopen event");
var audiosb = ms.addSourceBuffer("audio/mp4");
var videosb = ms.addSourceBuffer("video/mp4");
el.addEventListener("error", function(e) {
ok(false, "should not fire '" + e + "' event");
});
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
try {
el.currentTime = 3;
} catch (e) {
ok(false, "should not throw '" + e + "' exception");
}
is(el.currentTime, 3, "currentTime is default playback start position");
is(el.seeking, false, "seek not started with HAVE_NOTHING");
fetchAndLoad(audiosb, 'bipbop/bipbop_audio', ['init'], '.mp4')
.then(fetchAndLoad.bind(null, videosb, 'bipbop/bipbop_video', ['init'], '.mp4'))
.then(once.bind(null, el, 'loadedmetadata'))
@ -30,6 +41,9 @@ runWithMSE(function(ms, el) {
var p = once(el, 'seeking');
el.play();
el.currentTime = 5;
is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
is(el.seeking, true, "seek not started with HAVE_METADATA");
is(el.currentTime, 5, "currentTime is seek position");
return p;
})
.then(function() {

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

@ -134,18 +134,51 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer)
{
RefPtr<PlatformDecoderModule> current = (mEMEPDM && aConfig.mCrypto.mValid)
? mEMEPDM : GetDecoder(aConfig.mMimeType);
bool isEncrypted = mEMEPDM && aConfig.mCrypto.mValid;
if (!current) {
return nullptr;
if (isEncrypted) {
return CreateDecoderWithPDM(mEMEPDM,
aConfig,
aTaskQueue,
aCallback,
aLayersBackend,
aImageContainer);
}
for (auto& current : mCurrentPDMs) {
if (!current->SupportsMimeType(aConfig.mMimeType)) {
continue;
}
RefPtr<MediaDataDecoder> m =
CreateDecoderWithPDM(current,
aConfig,
aTaskQueue,
aCallback,
aLayersBackend,
aImageContainer);
if (m) {
return m.forget();
}
}
NS_WARNING("Unable to create a decoder, no platform found.");
return nullptr;
}
already_AddRefed<MediaDataDecoder>
PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
const TrackInfo& aConfig,
FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer)
{
MOZ_ASSERT(aPDM);
RefPtr<MediaDataDecoder> m;
if (aConfig.GetAsAudioInfo()) {
m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(),
aTaskQueue,
aCallback);
m = aPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(),
aTaskQueue,
aCallback);
return m.forget();
}
@ -165,7 +198,7 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig,
if (H264Converter::IsH264(aConfig)) {
RefPtr<H264Converter> h
= new H264Converter(current,
= new H264Converter(aPDM,
*aConfig.GetAsVideoInfo(),
aLayersBackend,
aImageContainer,
@ -179,11 +212,11 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig,
m = h.forget();
}
} else {
m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
aLayersBackend,
aImageContainer,
aTaskQueue,
callback);
m = aPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
aLayersBackend,
aImageContainer,
aTaskQueue,
callback);
}
if (callbackWrapper && m) {

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

@ -53,6 +53,13 @@ private:
bool StartupPDM(PlatformDecoderModule* aPDM);
// Returns the first PDM in our list supporting the mimetype.
already_AddRefed<PlatformDecoderModule> GetDecoder(const nsACString& aMimeType);
already_AddRefed<MediaDataDecoder>
CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
const TrackInfo& aConfig,
FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer);
// PDM pref caches...
static bool sUseBlankDecoder;

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

@ -214,6 +214,8 @@ public:
// that the format of the next input sample is about to change.
// If video decoder, aConfig will be a VideoInfo object.
// If audio decoder, aConfig will be a AudioInfo object.
// It is not safe to store a reference to this object and the decoder must
// make a copy.
virtual nsresult ConfigurationChanged(const TrackInfo& aConfig)
{
return NS_OK;

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

@ -247,22 +247,30 @@ public:
int32_t size;
NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
const int32_t numFrames = (size / numChannels) / 2;
AudioDataValue* audio = new AudioDataValue[size];
PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), size);
int32_t offset;
NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
#ifdef MOZ_SAMPLE_TYPE_S16
int32_t numSamples = size / 2;
#else
#error We only support 16-bit integer PCM
#endif
const int32_t numFrames = numSamples / numChannels;
AudioDataValue* audio = new AudioDataValue[numSamples];
uint8_t* bufferStart = static_cast<uint8_t*>(aBuffer) + offset;
PodCopy(audio, reinterpret_cast<AudioDataValue*>(bufferStart), numSamples);
int64_t presentationTimeUs;
NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
RefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
aDuration.ToMicroseconds(),
numFrames,
audio,
numChannels,
sampleRate);
RefPtr<AudioData> data = new AudioData(0, presentationTimeUs,
aDuration.ToMicroseconds(),
numFrames,
audio,
numChannels,
sampleRate);
INVOKE_CALLBACK(Output, data);
return NS_OK;
}

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

@ -68,7 +68,8 @@ WMFDecoderModule::Init()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false);
Preferences::AddBoolVarCache(&sIsIntelDecoderEnabled,
"media.webm.intel_decoder.enabled");
sLowLatencyMFTEnabled = Preferences::GetBool("media.wmf.low-latency.enabled", false);
SetNumOfDecoderThreads();
}
@ -139,10 +140,13 @@ CanCreateMFTDecoder(const GUID& aGuid)
if (FAILED(wmf::MFStartup())) {
return false;
}
RefPtr<MFTDecoder> decoder(new MFTDecoder());
bool hasH264 = SUCCEEDED(decoder->Create(aGuid));
bool hasdecoder = false;
{
RefPtr<MFTDecoder> decoder(new MFTDecoder());
hasdecoder = SUCCEEDED(decoder->Create(aGuid));
}
wmf::MFShutdown();
return hasH264;
return hasdecoder;
}
template<const GUID& aGuid>
@ -173,7 +177,7 @@ WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType)
CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>()) {
return true;
}
if (sIsIntelDecoderEnabled) {
if (sIsIntelDecoderEnabled && sDXVAEnabled) {
if (aMimeType.EqualsLiteral("video/webm; codecs=vp8") &&
CanCreateWMFDecoder<CLSID_WebmMfVp8Dec>()) {
return true;

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

@ -232,4 +232,27 @@ WMFMediaDataDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const {
return mMFTManager && mMFTManager->IsHardwareAccelerated(aFailureReason);
}
nsresult
WMFMediaDataDecoder::ConfigurationChanged(const TrackInfo& aConfig)
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethodWithArg<UniquePtr<TrackInfo>&&>(
this,
&WMFMediaDataDecoder::ProcessConfigurationChanged,
aConfig.Clone());
mTaskQueue->Dispatch(runnable.forget());
return NS_OK;
}
void
WMFMediaDataDecoder::ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig)
{
if (mMFTManager) {
mMFTManager->ConfigurationChanged(*aConfig);
}
}
} // namespace mozilla

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

@ -52,6 +52,8 @@ public:
virtual TrackInfo::TrackType GetType() = 0;
virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
protected:
// IMFTransform wrapper that performs the decoding.
RefPtr<MFTDecoder> mDecoder;
@ -81,6 +83,8 @@ public:
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
private:
// Called on the task queue. Inserts the sample into the decoder, and
@ -101,6 +105,10 @@ private:
void ProcessShutdown();
// Called on the task queue. Tell the MFT that the next Input will have a
// different configuration (typically resolution change).
void ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig);
RefPtr<FlushableTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

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

@ -39,7 +39,7 @@ HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
}
HRESULT
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride)
{
// Try to get the default stride from the media type.
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
@ -49,16 +49,11 @@ GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
// Stride attribute not set, calculate it.
GUID subtype = GUID_NULL;
uint32_t width = 0;
uint32_t height = 0;
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, aWidth, (LONG*)(aOutStride));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
return hr;

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

@ -37,7 +37,7 @@ HRESULT
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames);
HRESULT
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride);
GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride);
int32_t
MFOffsetToInt32(const MFOffset& aOffset);

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

@ -73,7 +73,9 @@ WMFVideoMFTManager::WMFVideoMFTManager(
mozilla::layers::LayersBackend aLayersBackend,
mozilla::layers::ImageContainer* aImageContainer,
bool aDXVAEnabled)
: mImageContainer(aImageContainer)
: mVideoInfo(aConfig)
, mVideoStride(0)
, mImageContainer(aImageContainer)
, mDXVAEnabled(aDXVAEnabled)
, mLayersBackend(aLayersBackend)
// mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
@ -252,13 +254,6 @@ WMFVideoMFTManager::InitInternal(bool aForceD3D9)
LOG("Video Decoder initialized, Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
// Just in case ConfigureVideoFrameGeometry() does not set these
mVideoInfo = VideoInfo();
mVideoStride = 0;
mVideoWidth = 0;
mVideoHeight = 0;
mPictureRegion.SetEmpty();
return true;
}
@ -372,26 +367,17 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry()
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL);
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL);
nsIntRect pictureRegion;
hr = GetPictureRegion(mediaType, pictureRegion);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
UINT32 width = 0, height = 0;
hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
uint32_t aspectNum = 0, aspectDenom = 0;
hr = MFGetAttributeRatio(mediaType,
MF_MT_PIXEL_ASPECT_RATIO,
&aspectNum,
&aspectDenom);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
mVideoInfo.mImage.width = width;
mVideoInfo.mImage.height = height;
nsIntRect pictureRegion = mVideoInfo.mImage;
// Calculate and validate the picture region and frame dimensions after
// scaling by the pixel aspect ratio.
nsIntSize frameSize = nsIntSize(width, height);
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
nsIntSize displaySize = nsIntSize(mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
// Video track's frame sizes will overflow. Ignore the video track.
return E_FAIL;
@ -403,18 +389,13 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry()
}
// Success! Save state.
mVideoInfo.mDisplay = displaySize;
GetDefaultStride(mediaType, &mVideoStride);
mVideoWidth = width;
mVideoHeight = height;
mPictureRegion = pictureRegion;
GetDefaultStride(mediaType, width, &mVideoStride);
LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d)",
width, height,
mVideoStride,
mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
displaySize.width, displaySize.height,
aspectNum, aspectDenom);
pictureRegion.x, pictureRegion.y, pictureRegion.width, pictureRegion.height,
mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
return S_OK;
}
@ -456,25 +437,28 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
// i.e., Y, then V, then U.
VideoData::YCbCrBuffer b;
uint32_t videoWidth = mVideoInfo.mImage.width;
uint32_t videoHeight = mVideoInfo.mImage.height;
// Y (Y') plane
b.mPlanes[0].mData = data;
b.mPlanes[0].mStride = stride;
b.mPlanes[0].mHeight = mVideoHeight;
b.mPlanes[0].mWidth = mVideoWidth;
b.mPlanes[0].mHeight = videoHeight;
b.mPlanes[0].mWidth = videoWidth;
b.mPlanes[0].mOffset = 0;
b.mPlanes[0].mSkip = 0;
// The V and U planes are stored 16-row-aligned, so we need to add padding
// to the row heights to ensure the Y'CbCr planes are referenced properly.
uint32_t padding = 0;
if (mVideoHeight % 16 != 0) {
padding = 16 - (mVideoHeight % 16);
if (videoHeight % 16 != 0) {
padding = 16 - (videoHeight % 16);
}
uint32_t y_size = stride * (mVideoHeight + padding);
uint32_t v_size = stride * (mVideoHeight + padding) / 4;
uint32_t y_size = stride * (videoHeight + padding);
uint32_t v_size = stride * (videoHeight + padding) / 4;
uint32_t halfStride = (stride + 1) / 2;
uint32_t halfHeight = (mVideoHeight + 1) / 2;
uint32_t halfWidth = (mVideoWidth + 1) / 2;
uint32_t halfHeight = (videoHeight + 1) / 2;
uint32_t halfWidth = (videoWidth + 1) / 2;
// U plane (Cb)
b.mPlanes[1].mData = data + y_size + v_size;
@ -503,7 +487,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
VideoData::SetVideoDataToImage(image,
mVideoInfo,
b,
mPictureRegion,
mVideoInfo.mImage,
false);
RefPtr<VideoData> v =
@ -515,7 +499,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
image.forget(),
false,
-1,
mPictureRegion);
mVideoInfo.mImage);
v.forget(aOutVideoData);
return S_OK;
@ -536,7 +520,7 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
RefPtr<Image> image;
hr = mDXVA2Manager->CopyToImage(aSample,
mPictureRegion,
mVideoInfo.mImage,
mImageContainer,
getter_AddRefs(image));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
@ -554,7 +538,7 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
image.forget(),
false,
-1,
mPictureRegion);
mVideoInfo.mImage);
NS_ENSURE_TRUE(v, E_FAIL);
v.forget(aOutVideoData);
@ -632,4 +616,11 @@ WMFVideoMFTManager::IsHardwareAccelerated(nsACString& aFailureReason) const
return mDecoder && mUseHwAccel;
}
void
WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
{
MOZ_ASSERT(aConfig.GetAsVideoInfo());
mVideoInfo = *aConfig.GetAsVideoInfo();
}
} // namespace mozilla

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

@ -39,6 +39,8 @@ public:
return TrackInfo::kVideoTrack;
}
void ConfigurationChanged(const TrackInfo& aConfig) override;
private:
bool InitializeDXVA(bool aForceD3D9);
@ -62,9 +64,6 @@ private:
// Video frame geometry.
VideoInfo mVideoInfo;
uint32_t mVideoStride;
uint32_t mVideoWidth;
uint32_t mVideoHeight;
nsIntRect mPictureRegion;
RefPtr<layers::ImageContainer> mImageContainer;
nsAutoPtr<DXVA2Manager> mDXVA2Manager;

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

@ -22,6 +22,7 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM,
FlushableTaskQueue* aVideoTaskQueue,
MediaDataDecoderCallback* aCallback)
: mPDM(aPDM)
, mOriginalConfig(aConfig)
, mCurrentConfig(aConfig)
, mLayersBackend(aLayersBackend)
, mImageContainer(aImageContainer)
@ -53,14 +54,10 @@ H264Converter::Init()
nsresult
H264Converter::Input(MediaRawData* aSample)
{
if (!mNeedAVCC) {
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
return NS_ERROR_FAILURE;
}
} else {
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
return NS_ERROR_FAILURE;
}
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
// We need AVCC content to be able to later parse the SPS.
// This is a no-op if the data is already AVCC.
return NS_ERROR_FAILURE;
}
if (mInitPromiseRequest.Exists()) {
@ -84,6 +81,11 @@ H264Converter::Input(MediaRawData* aSample)
}
NS_ENSURE_SUCCESS(rv, rv);
if (!mNeedAVCC &&
!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
return NS_ERROR_FAILURE;
}
aSample->mExtraData = mCurrentConfig.mExtraData;
return mDecoder->Input(aSample);
@ -138,7 +140,7 @@ H264Converter::CreateDecoder()
}
UpdateConfigFromExtraData(mCurrentConfig.mExtraData);
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
mDecoder = mPDM->CreateVideoDecoder(mNeedAVCC ? mCurrentConfig : mOriginalConfig,
mLayersBackend,
mImageContainer,
mVideoTaskQueue,

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

@ -53,6 +53,7 @@ private:
void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason);
RefPtr<PlatformDecoderModule> mPDM;
const VideoInfo& mOriginalConfig;
VideoInfo mCurrentConfig;
layers::LayersBackend mLayersBackend;
RefPtr<layers::ImageContainer> mImageContainer;

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

@ -768,6 +768,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
tags=capturestream
[test_resume.html]
skip-if = true # bug 1021673
[test_seek_nosrc.html]
[test_seek_out_of_range.html]
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_seek-1.html]

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

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: seek tests</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var SEEK_TIME = 3.5;
var seekStarted = false;
var seekCompleted = false;
var metadata = false;
var v = document.createElement('video');
document.body.appendChild(v);
SimpleTest.registerCleanupFunction(function () {
v.remove();
});
try {
v.currentTime = SEEK_TIME;
} catch (e) {
ok(false, "should not fire '" + e + "' event");
}
is(v.readyState, v.HAVE_NOTHING, "readyState is HAVE_NOTHING");
ok(!v.seeking, "can't be seeking prior src defined");
is(v.currentTime, SEEK_TIME, "currentTime is default playback start position");
once(v, "seeking", function() {
seekStarted = true;
});
once(v, "seeked", function() {
seekCompleted = true;
});
once(v, "loadedmetadata", function() {
metadata = true;
ok(v.seeking, "element is seeking once readyState is HAVE_METADATA");
});
once(v, "ended", function() {
ok(seekStarted, "seek should have started");
ok(seekCompleted, "seek should have completed");
ok(metadata, "loadedmetadata fired");
ok(v.currentTime >= SEEK_TIME, "currentTime should be after seek time");
SimpleTest.finish();
});
v.src = "seek.webm";
v.play();
</script>
</pre>
</body>
</html>

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

@ -177,25 +177,25 @@ AudioNode::DisconnectFromGraph()
DestroyMediaStream();
}
void
AudioNode*
AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv)
{
if (aOutput >= NumberOfOutputs() ||
aInput >= aDestination.NumberOfInputs()) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
return nullptr;
}
if (Context() != aDestination.Context()) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
return nullptr;
}
if (FindIndexOfNodeWithPorts(aDestination.mInputNodes, this, aInput, aOutput) !=
nsTArray<AudioNode::InputNode>::NoIndex) {
// connection already exists.
return;
return &aDestination;
}
// The MediaStreamGraph will handle cycle detection. We don't need to do it
@ -220,6 +220,8 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
// This connection may have connected a panner and a source.
Context()->UpdatePannerSource();
return &aDestination;
}
void

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

@ -89,8 +89,8 @@ public:
return mContext;
}
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv);
virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv);
virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
ErrorResult& aRv);

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

@ -33,13 +33,14 @@ public:
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv) override
virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv) override
{
AudioNode::Connect(aDestination, aOutput, aInput, aRv);
AudioNode* node = AudioNode::Connect(aDestination, aOutput, aInput, aRv);
if (!aRv.Failed()) {
UpdateConnectedStatus();
}
return node;
}
virtual void Connect(AudioParam& aDestination, uint32_t aOutput,

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

@ -24,7 +24,7 @@ enum ChannelInterpretation {
interface AudioNode : EventTarget {
[Throws]
void connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
AudioNode connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
[Throws]
void connect(AudioParam destination, optional unsigned long output = 0);
[Throws]

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

@ -0,0 +1,13 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[ChromeOnly, Constructor]
interface ChromeNodeList : NodeList {
[Throws]
void append(Node aNode);
[Throws]
void remove(Node aNode);
};

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

@ -75,6 +75,7 @@ WEBIDL_FILES = [
'ChannelSplitterNode.webidl',
'CharacterData.webidl',
'ChildNode.webidl',
'ChromeNodeList.webidl',
'ChromeNotifications.webidl',
'ChromeUtils.webidl',
'Client.webidl',

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

@ -59,9 +59,9 @@ CancelChannelRunnable::Run()
}
FetchEvent::FetchEvent(EventTarget* aOwner)
: ExtendableEvent(aOwner)
, mIsReload(false)
, mWaitToRespond(false)
: ExtendableEvent(aOwner)
, mIsReload(false)
, mWaitToRespond(false)
{
}
@ -436,15 +436,6 @@ FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
return;
}
// 4.5.3.2 If the respond-with entered flag is set, then:
// Throw an "InvalidStateError" exception.
// Here we use |mPromise != nullptr| as respond-with enter flag
if (mPromise) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mPromise = &aArg;
RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
StopImmediatePropagation();
mWaitToRespond = true;
@ -452,6 +443,8 @@ FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(),
ir->IsNavigationRequest(), mScriptSpec);
aArg.AppendNativeHandler(handler);
WaitUntil(aArg, aRv);
}
NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
@ -460,8 +453,7 @@ NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent,
mRequest, mPromise)
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent, mRequest)
ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
: Event(aOwner, nullptr, nullptr)

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

@ -103,7 +103,6 @@ class FetchEvent final : public ExtendableEvent
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
RefPtr<Request> mRequest;
nsCString mScriptSpec;
RefPtr<Promise> mPromise;
bool mIsReload;
bool mWaitToRespond;
protected:
@ -150,13 +149,6 @@ public:
void
RespondWith(Promise& aArg, ErrorResult& aRv);
already_AddRefed<Promise>
GetPromise() const
{
RefPtr<Promise> p = mPromise;
return p.forget();
}
already_AddRefed<Promise>
ForwardTo(const nsAString& aUrl);

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

@ -1175,11 +1175,11 @@ private:
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
}
RefPtr<Promise> respondWithPromise = event->GetPromise();
if (respondWithPromise) {
RefPtr<Promise> waitUntilPromise = event->GetPromise();
if (waitUntilPromise) {
RefPtr<KeepAliveHandler> keepAliveHandler =
new KeepAliveHandler(mKeepAliveToken);
respondWithPromise->AppendNativeHandler(keepAliveHandler);
waitUntilPromise->AppendNativeHandler(keepAliveHandler);
}
// 9.8.22 If request is a non-subresource request, then: Invoke Soft Update algorithm

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 87 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 123 B

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

@ -0,0 +1,29 @@
<!DOCTYPE html>
<script>
var width, url, width2, url2;
function maybeReport() {
if (width !== undefined && url !== undefined &&
width2 !== undefined && url2 !== undefined) {
window.parent.postMessage({status: "result",
width: width,
width2: width2,
url: url,
url2: url2}, "*");
}
}
onload = function() {
width = document.querySelector("img").width;
width2 = document.querySelector("img").width;
maybeReport();
};
navigator.serviceWorker.onmessage = function(event) {
if (event.data.suffix == "2") {
url2 = event.data.url;
} else {
url = event.data.url;
}
maybeReport();
};
</script>
<img src="image.png">
<img src="image2.png">

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

@ -0,0 +1,41 @@
function synthesizeImage(suffix) {
// Serve image-20px for the first page, and image-40px for the second page.
return clients.matchAll().then(clients => {
var url = "image-20px.png";
clients.forEach(client => {
if (client.url.indexOf("?new") > 0) {
url = "image-40px.png";
}
client.postMessage({suffix: suffix, url: url});
});
return fetch(url);
}).then(response => {
return response.arrayBuffer();
}).then(ab => {
var headers;
if (suffix == "") {
headers = {
"Content-Type": "image/png",
"Date": "Tue, 1 Jan 1990 01:02:03 GMT",
"Cache-Control": "max-age=1",
};
} else {
headers = {
"Content-Type": "image/png",
"Cache-Control": "no-cache",
};
}
return new Response(ab, {
status: 200,
headers: headers,
});
});
}
self.addEventListener("fetch", function(event) {
if (event.request.url.indexOf("image.png") >= 0) {
event.respondWith(synthesizeImage(""));
} else if (event.request.url.indexOf("image2.png") >= 0) {
event.respondWith(synthesizeImage("2"));
}
});

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

@ -0,0 +1,14 @@
<!DOCTYPE html>
<script>
function ok(v, msg) {
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
function done(reg) {
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("maxage_test.js", {scope: "."});
</script>

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

@ -0,0 +1,12 @@
<!DOCTYPE html>
<script>
navigator.serviceWorker.getRegistration(".").then(function(registration) {
registration.unregister().then(function(success) {
if (success) {
window.parent.postMessage({status: "unregistrationdone"}, "*");
}
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
});
</script>

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

@ -59,6 +59,12 @@ support-files =
fetch/https/clonedresponse/register.html
fetch/https/clonedresponse/unregister.html
fetch/https/clonedresponse/https_test.js
fetch/imagecache-maxage/index.html
fetch/imagecache-maxage/image-20px.png
fetch/imagecache-maxage/image-40px.png
fetch/imagecache-maxage/maxage_test.js
fetch/imagecache-maxage/register.html
fetch/imagecache-maxage/unregister.html
fetch/interrupt.sjs
fetch/origin/index.sjs
fetch/origin/index-to-https.sjs
@ -282,3 +288,4 @@ skip-if = e10s # Bug 1214305
[test_serviceworker_header.html]
[test_openWindow.html]
skip-if = toolkit == "android" || toolkit == "gonk" || e10s
[test_imagecache_max_age.html]

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

@ -0,0 +1,75 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test that the image cache respects a synthesized image's Cache headers</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
var framesLoaded = 0;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/register.html";
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/index.html";
} else if (e.data.status == "result") {
switch (++framesLoaded) {
case 1:
is(e.data.url, "image-20px.png", "Correct url expected");
is(e.data.url2, "image-20px.png", "Correct url expected");
is(e.data.width, 20, "Correct width expected");
is(e.data.width2, 20, "Correct width expected");
// Wait for 100ms so that the image gets expired.
setTimeout(function() {
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/index.html?new"
}, 100);
break;
case 2:
is(e.data.url, "image-40px.png", "Correct url expected");
is(e.data.url2, "image-40px.png", "Correct url expected");
// TODO: Uncomment this check when bug 1217571 gets fixed.
// Currently because of bug 1217571, the QI in imgCacheValidator::OnStartRequest()
// to nsICachingChannel fails, which causes the check below to fail in non-e10s.
//is(e.data.width, 40, "Correct width expected");
//is(e.data.width2, 40, "Correct width expected");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/unregister.html";
break;
default:
ok(false, "This should never happen");
}
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
SimpleTest.finish();
}
};
}
SimpleTest.requestFlakyTimeout("This test needs to simulate the passing of time");
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.serviceWorkers.interception.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

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

@ -116,10 +116,10 @@ function report(testName, success) {
<script type="text/javascript"><![CDATA[
try {
eval("let x = 1;");
var success = false;
var success = true;
}
catch (e) { success = true; }
is(success, true, "JS 1.7 should not work in versionless HTML script tags");
catch (e) { success = false; }
is(success, true, "let should work in versionless HTML script tags");
]]></script>
</pre>
</body>

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

@ -1021,63 +1021,52 @@ nsresult nsHTMLEditor::InsertObject(const char* aType, nsISupports* aObject, boo
{
nsresult rv;
const char* type = aType;
nsAutoCString type(aType);
// Check to see if we can insert an image file
bool insertAsImage = false;
nsCOMPtr<nsIURI> fileURI;
if (0 == nsCRT::strcmp(type, kFileMime))
nsCOMPtr<nsIFile> fileObj;
if (type.EqualsLiteral(kFileMime))
{
nsCOMPtr<nsIFile> fileObj = do_QueryInterface(aObject);
fileObj = do_QueryInterface(aObject);
if (fileObj)
{
rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
nsAutoCString contentType;
rv = mime->GetTypeFromFile(fileObj, contentType);
NS_ENSURE_SUCCESS(rv, rv);
// Accept any image type fed to us
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
if (nsContentUtils::IsFileImage(fileObj, type))
{
insertAsImage = true;
type = contentType.get();
}
else
{
// Reset type.
type.AssignLiteral(kFileMime);
}
}
}
if (0 == nsCRT::strcmp(type, kJPEGImageMime) ||
0 == nsCRT::strcmp(type, kJPGImageMime) ||
0 == nsCRT::strcmp(type, kPNGImageMime) ||
0 == nsCRT::strcmp(type, kGIFImageMime) ||
if (type.EqualsLiteral(kJPEGImageMime) ||
type.EqualsLiteral(kJPGImageMime) ||
type.EqualsLiteral(kPNGImageMime) ||
type.EqualsLiteral(kGIFImageMime) ||
insertAsImage)
{
nsCOMPtr<nsIInputStream> imageStream;
if (insertAsImage) {
NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
fileURI,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->Open2(getter_AddRefs(imageStream));
NS_ENSURE_SUCCESS(rv, rv);
} else {
imageStream = do_QueryInterface(aObject);
NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
}
nsCString imageData;
rv = NS_ConsumeStream(imageStream, UINT32_MAX, imageData);
NS_ENSURE_SUCCESS(rv, rv);
if (insertAsImage)
{
rv = nsContentUtils::SlurpFileToString(fileObj, imageData);
NS_ENSURE_SUCCESS(rv, rv);
}
else
{
nsCOMPtr<nsIInputStream> imageStream = do_QueryInterface(aObject);
NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
rv = imageStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_ConsumeStream(imageStream, UINT32_MAX, imageData);
NS_ENSURE_SUCCESS(rv, rv);
rv = imageStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
}
nsAutoCString data64;
rv = Base64Encode(imageData, data64);

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

@ -1616,7 +1616,9 @@ public:
* marked as needed to be recomposited.
*/
const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; }
const void AddInvalidRegion(const nsIntRegion& aRegion) {
mInvalidRegion.Or(mInvalidRegion, aRegion);
}
/**
* Mark the entirety of the layer's visible region as being invalid.

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

@ -306,9 +306,12 @@ RotatedContentBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
void
BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
{
MOZ_ASSERT(mLoanedDrawTarget);
MOZ_ASSERT(aReturned == mLoanedDrawTarget);
mLoanedDrawTarget->SetTransform(mLoanedTransform);
mLoanedDrawTarget = nullptr;
if (mLoanedDrawTarget) {
mLoanedDrawTarget->SetTransform(mLoanedTransform);
mLoanedDrawTarget = nullptr;
}
aReturned = nullptr;
}

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

@ -148,6 +148,7 @@ LayerManagerComposite::Destroy()
RootLayer()->Destroy();
}
mRoot = nullptr;
mClonedLayerTreeProperties = nullptr;
mDestroyed = true;
}
}
@ -175,8 +176,6 @@ LayerManagerComposite::BeginTransaction()
}
mIsCompositorReady = true;
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
}
void
@ -282,42 +281,11 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
// also to compute invalid regions properly.
mCompositor->SetCompositionTime(aTimeStamp);
if (mRoot && mClonedLayerTreeProperties) {
MOZ_ASSERT(!mTarget);
nsIntRegion invalid =
mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
mClonedLayerTreeProperties = nullptr;
mInvalidRegion.Or(mInvalidRegion, invalid);
} else if (!mTarget) {
mInvalidRegion.Or(mInvalidRegion, mRenderBounds);
}
if (mInvalidRegion.IsEmpty() && !mTarget) {
// Composition requested, but nothing has changed. Don't do any work.
return;
}
// We don't want our debug overlay to cause more frames to happen
// so we will invalidate after we've decided if something changed.
InvalidateDebugOverlay(mRenderBounds);
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
MOZ_ASSERT(!aTimeStamp.IsNull());
// The results of our drawing always go directly into a pixel buffer,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
nsIntRegion opaque;
ApplyOcclusionCulling(mRoot, opaque);
Render();
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
RenderToPresentationSurface();
#endif
mGeometryChanged = false;
UpdateAndRender();
} else {
// Modified layer tree
// Modified the layer tree.
mGeometryChanged = true;
}
@ -330,6 +298,70 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
#endif
}
void
LayerManagerComposite::UpdateAndRender()
{
nsIntRegion invalid;
if (mClonedLayerTreeProperties) {
// We need to compute layer tree differences even if we're not going to
// immediately use the resulting damage area, since ComputeDifferences
// is also responsible for invalidates intermediate surfaces in
// ContainerLayers.
nsIntRegion changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
if (mTarget) {
// Since we're composing to an external target, we're not going to use
// the damage region from layers changes - we want to composite
// everything in the target bounds. Instead we accumulate the layers
// damage region for the next window composite.
mInvalidRegion.Or(mInvalidRegion, changed);
} else {
invalid = Move(changed);
}
}
if (mTarget) {
invalid.Or(invalid, mTargetBounds);
} else {
// If we didn't have a previous layer tree, invalidate the entire render
// area.
if (!mClonedLayerTreeProperties) {
invalid.Or(invalid, mRenderBounds);
}
// Add any additional invalid rects from the window manager or previous
// damage computed during ComposeToTarget().
invalid.Or(invalid, mInvalidRegion);
mInvalidRegion.SetEmpty();
}
// Update cached layer tree information.
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
if (invalid.IsEmpty()) {
// Composition requested, but nothing has changed. Don't do any work.
return;
}
// We don't want our debug overlay to cause more frames to happen
// so we will invalidate after we've decided if something changed.
InvalidateDebugOverlay(mRenderBounds);
// The results of our drawing always go directly into a pixel buffer,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
nsIntRegion opaque;
ApplyOcclusionCulling(mRoot, opaque);
Render(invalid);
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
RenderToPresentationSurface();
#endif
mGeometryChanged = false;
}
already_AddRefed<DrawTarget>
LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize)
{
@ -641,7 +673,7 @@ LayerManagerComposite::PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> a
}
void
LayerManagerComposite::Render()
LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
{
PROFILER_LABEL("LayerManagerComposite", "Render",
js::ProfileEntry::Category::GRAPHICS);
@ -701,8 +733,6 @@ LayerManagerComposite::Render()
}
}
mCompositor->EndFrameForExternalComposition(Matrix());
// Reset the invalid region as compositing is done
mInvalidRegion.SetEmpty();
mLastFrameMissedHWC = false;
return;
} else if (!mTarget && !haveLayerEffects) {
@ -718,15 +748,6 @@ LayerManagerComposite::Render()
}
}
nsIntRegion invalid;
if (mTarget) {
invalid = mTargetBounds;
} else {
invalid = mInvalidRegion;
// Reset the invalid region now that we've begun compositing.
mInvalidRegion.SetEmpty();
}
ParentLayerIntRect clipRect;
Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
Rect actualBounds;
@ -736,10 +757,10 @@ LayerManagerComposite::Render()
if (mRoot->GetClipRect()) {
clipRect = *mRoot->GetClipRect();
Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
mCompositor->BeginFrame(invalid, &rect, bounds, nullptr, &actualBounds);
mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, nullptr, &actualBounds);
} else {
gfx::Rect rect;
mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, &rect, &actualBounds);
clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
}

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

@ -297,10 +297,15 @@ private:
nsIntRegion& aLowPrecisionScreenRegion,
const gfx::Matrix4x4& aTransform);
/**
* Update the invalid region and render it.
*/
void UpdateAndRender();
/**
* Render the current layer tree to the active target.
*/
void Render();
void Render(const nsIntRegion& aInvalidRegion);
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
void RenderToPresentationSurface();
#endif

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

@ -345,10 +345,13 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
layer->SetMaskLayer(nullptr);
}
layer->SetAnimations(common.animations());
layer->SetInvalidRegion(common.invalidRegion());
layer->SetFrameMetrics(common.metrics());
layer->SetDisplayListLog(common.displayListLog().get());
// The updated invalid region is added to the existing one, since we can
// update multiple times before the next composite.
layer->AddInvalidRegion(common.invalidRegion());
nsTArray<RefPtr<Layer>> maskLayers;
for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) {
Layer* maskLayer = cast(common.ancestorMaskLayersParent().ElementAt(i))->AsLayer();

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

@ -294,6 +294,7 @@ private:
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false);
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
DECL_GFX_PREF(Live, "layers.bench.enabled", LayersBenchEnabled, bool, false);

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

@ -1858,16 +1858,19 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
gfxInfo->GetAdapterVendorID(vendorID);
gfxInfo->GetAdapterVendorID2(vendorID2);
if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Unexpected Intel/AMD dual-GPU setup";
return false;
if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) {
return false;
}
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
}
}
}
RefPtr<ID3D11Texture2D> texture;
D3D11_TEXTURE2D_DESC desc;
desc.Width = 32;
desc.Height = 32;
const int texture_size = 32;
desc.Width = texture_size;
desc.Height = texture_size;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format;
@ -1877,7 +1880,17 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
desc.CPUAccessFlags = 0;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
desc.BindFlags = bindflags;
if (FAILED(device->CreateTexture2D(&desc, NULL, getter_AddRefs(texture)))) {
uint32_t color[texture_size * texture_size];
for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) {
color[i] = 0xff00ffff;
}
// We're going to check that sharing actually works with this format
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = color;
data.SysMemPitch = texture_size * 4;
data.SysMemSlicePitch = 0;
if (FAILED(device->CreateTexture2D(&desc, &data, getter_AddRefs(texture)))) {
return false;
}
@ -1908,6 +1921,50 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
return false;
}
// create a staging texture for readback
RefPtr<ID3D11Texture2D> cpuTexture;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
desc.BindFlags = 0;
if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) {
return false;
}
RefPtr<IDXGIKeyedMutex> sharedMutex;
RefPtr<ID3D11DeviceContext> deviceContext;
sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex));
device->GetImmediateContext(getter_AddRefs(deviceContext));
if (FAILED(sharedMutex->AcquireSync(0, 30*1000))) {
gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
// only wait for 30 seconds
return false;
}
// Copy to the cpu texture so that we can readback
deviceContext->CopyResource(cpuTexture, sharedTexture);
D3D11_MAPPED_SUBRESOURCE mapped;
int resultColor = 0;
if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
// read the texture
resultColor = *(int*)mapped.pData;
deviceContext->Unmap(cpuTexture, 0);
} else {
gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
return false;
}
sharedMutex->ReleaseSync(0);
// check that the color we put in is the color we get out
if (resultColor != color[0]) {
// Shared surfaces seem to be broken on dual AMD & Intel HW when using the
// AMD GPU
gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
return false;
}
RefPtr<ID3D11ShaderResourceView> sharedView;
// This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.

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

@ -1,84 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_BMPFileHeaders_h
#define mozilla_image_BMPFileHeaders_h
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
namespace image {
namespace bmp {
// This length is stored in the |bihsize| field of bmp::FileHeader.
struct InfoHeaderLength {
enum {
WIN_V2 = 12,
WIN_V3 = 40,
WIN_V4 = 108,
WIN_V5 = 124,
// OS2_V1 is omitted; it's the same as WIN_V2.
OS2_V2_MIN = 16, // Minimum allowed value for OS2v2.
OS2_V2_MAX = 64, // Maximum allowed value for OS2v2.
};
};
struct FileHeader {
char signature[2]; // String "BM".
uint32_t filesize; // File size; unreliable in practice.
int32_t reserved; // Zero.
uint32_t dataoffset; // Offset to raster data.
// The length of the file header as defined in the BMP spec.
static const size_t LENGTH = 14;
};
struct XYZ {
int32_t x, y, z;
};
struct XYZTriple {
XYZ r, g, b;
};
struct V5InfoHeader {
uint32_t bihsize; // Header size
int32_t width; // Uint16 in OS/2 BMPs
int32_t height; // Uint16 in OS/2 BMPs
uint16_t planes; // =1
uint16_t bpp; // Bits per pixel.
// The rest of the header is not available in WIN_V2/OS2_V1 BMP Files
uint32_t compression; // See Compression for valid values
uint32_t image_size; // (compressed) image size. Can be 0 if
// compression==0
uint32_t xppm; // Pixels per meter, horizontal
uint32_t yppm; // Pixels per meter, vertical
uint32_t colors; // Used Colors
uint32_t important_colors; // Number of important colors. 0=all
uint32_t red_mask; // Bits used for red component
uint32_t green_mask; // Bits used for green component
uint32_t blue_mask; // Bits used for blue component
uint32_t alpha_mask; // Bits used for alpha component
uint32_t color_space; // 0x73524742=LCS_sRGB ...
// These members are unused unless color_space == LCS_CALIBRATED_RGB
XYZTriple white_point; // Logical white point
uint32_t gamma_red; // Red gamma component
uint32_t gamma_green; // Green gamma component
uint32_t gamma_blue; // Blue gamma component
uint32_t intent; // Rendering intent
// These members are unused unless color_space == LCS_PROFILE_*
uint32_t profile_offset; // Offset to profile data in bytes
uint32_t profile_size; // Size of profile data in bytes
uint32_t reserved; // =0
static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
};
} // namespace bmp
} // namespace image
} // namespace mozilla
#endif // mozilla_image_BMPFileHeaders_h

38
image/BMPHeaders.h Normal file
Просмотреть файл

@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_BMPHeaders_h
#define mozilla_image_BMPHeaders_h
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
namespace image {
namespace bmp {
// The length of the file header as defined in the BMP spec.
static const size_t FILE_HEADER_LENGTH = 14;
// This lengths of the info header for the different BMP versions.
struct InfoHeaderLength {
enum {
WIN_V2 = 12,
WIN_V3 = 40,
WIN_V4 = 108,
WIN_V5 = 124,
// OS2_V1 is omitted; it's the same as WIN_V2.
OS2_V2_MIN = 16, // Minimum allowed value for OS2v2.
OS2_V2_MAX = 64, // Maximum allowed value for OS2v2.
WIN_ICO = WIN_V3,
};
};
} // namespace bmp
} // namespace image
} // namespace mozilla
#endif // mozilla_image_BMPHeaders_h

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

@ -106,7 +106,7 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
// Allocate the buffer, which contains scanlines of the original image.
// pad by 15 to handle overreads by the simd code
mRowBuffer = MakeUnique<uint8_t[]>(mOriginalSize.width * sizeof(uint32_t) + 15);
mRowBuffer.reset(new (fallible) uint8_t[mOriginalSize.width * sizeof(uint32_t) + 15]);
if (MOZ_UNLIKELY(!mRowBuffer)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -115,7 +115,7 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
// can store scanlines which are already downscale because our downscaling
// filter is separable.)
mWindowCapacity = mYFilter->max_filter();
mWindow = MakeUnique<uint8_t*[]>(mWindowCapacity);
mWindow.reset(new (fallible) uint8_t*[mWindowCapacity]);
if (MOZ_UNLIKELY(!mWindow)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -124,7 +124,7 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
// pad by 15 to handle overreads by the simd code
const int rowSize = mTargetSize.width * sizeof(uint32_t) + 15;
for (int32_t i = 0; i < mWindowCapacity; ++i) {
mWindow[i] = new uint8_t[rowSize];
mWindow[i] = new (fallible) uint8_t[rowSize];
anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;
}

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

@ -273,15 +273,13 @@ private:
, mLength(0)
{
MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
mData = new (fallible) char[mCapacity];
mData.reset(new (fallible) char[mCapacity]);
}
~Chunk() { delete[] mData; }
Chunk(Chunk&& aOther)
: mCapacity(aOther.mCapacity)
, mLength(aOther.mLength)
, mData(aOther.mData)
, mData(Move(aOther.mData))
{
aOther.mCapacity = aOther.mLength = 0;
aOther.mData = nullptr;
@ -291,7 +289,7 @@ private:
{
mCapacity = aOther.mCapacity;
mLength = aOther.mLength;
mData = aOther.mData;
mData = Move(aOther.mData);
aOther.mCapacity = aOther.mLength = 0;
aOther.mData = nullptr;
return *this;
@ -304,7 +302,7 @@ private:
char* Data() const
{
MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
return mData;
return mData.get();
}
void AddLength(size_t aAdditionalLength)
@ -319,7 +317,7 @@ private:
size_t mCapacity;
size_t mLength;
char* mData;
UniquePtr<char[]> mData;
};
nsresult AppendChunk(Maybe<Chunk>&& aChunk);

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

@ -575,11 +575,11 @@ nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking)
colorHeader.biSizeImage +
maskHeader.biSizeImage;
char* buffer = new char[iconSize];
UniquePtr<char[]> buffer = MakeUnique<char[]>(iconSize);
if (!buffer) {
rv = NS_ERROR_OUT_OF_MEMORY;
} else {
char* whereTo = buffer;
char* whereTo = buffer.get();
int howMuch;
// the data starts with an icon file header
@ -640,7 +640,7 @@ nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking)
iconSize, iconSize, aNonBlocking);
if (NS_SUCCEEDED(rv)) {
uint32_t written;
rv = outStream->Write(buffer, iconSize, &written);
rv = outStream->Write(buffer.get(), iconSize, &written);
if (NS_SUCCEEDED(rv)) {
NS_ADDREF(*_retval = inStream);
}
@ -650,7 +650,6 @@ nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking)
delete maskInfo;
} // if we got mask bits
delete colorInfo;
delete [] buffer;
} // if we allocated the buffer
} // if we got mask size

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

@ -25,28 +25,28 @@
//
// WinBMPv2.
// - First is a 14 byte file header that includes: the magic number ("BM"),
// file size, and offset to the pixel data (|dataoffset|).
// file size, and offset to the pixel data (|mDataOffset|).
// - Next is a 12 byte info header which includes: the info header size
// (bihsize), width, height, number of color planes, and bits-per-pixel
// (|bpp|) which must be 1, 4, 8 or 24.
// - Next is the semi-optional color table, which has length 2^|bpp| and has 3
// bytes per value (BGR). The color table is required if |bpp| is 1, 4, or 8.
// (mBIHSize), width, height, number of color planes, and bits-per-pixel
// (|mBpp|) which must be 1, 4, 8 or 24.
// - Next is the semi-optional color table, which has length 2^|mBpp| and has 3
// bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8.
// - Next is an optional gap.
// - Next is the pixel data, which is pointed to by |dataoffset|.
// - Next is the pixel data, which is pointed to by |mDataOffset|.
//
// WinBMPv3. This is the most widely used version.
// - It changed the info header to 40 bytes by taking the WinBMPv2 info
// header, enlargening its width and height fields, and adding more fields
// including: a compression type (|compression|) and number of colors
// (|colors|).
// including: a compression type (|mCompression|) and number of colors
// (|mNumColors|).
// - The semi-optional color table is now 4 bytes per value (BGR0), and its
// length is |colors|, or 2^|bpp| if |colors| is zero.
// - |compression| can be RGB (i.e. no compression), RLE4 (if bpp==4) or RLE8
// (if bpp==8) values.
// length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero.
// - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or
// RLE8 (if |mBpp|==8) values.
//
// WinBMPv3-NT. A variant of WinBMPv3.
// - It did not change the info header layout from WinBMPv3.
// - |bpp| can now be 16 or 32, in which case |compression| can be RGB or the
// - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the
// new BITFIELDS value; in the latter case an additional 12 bytes of color
// bitfields follow the info header.
//
@ -137,7 +137,8 @@ SetPixel(uint32_t*& aDecoded, uint8_t aRed, uint8_t aGreen,
}
static void
SetPixel(uint32_t*& aDecoded, uint8_t idx, bmp::ColorTableEntry* aColors)
SetPixel(uint32_t*& aDecoded, uint8_t idx,
const UniquePtr<ColorTableEntry[]>& aColors)
{
SetPixel(aDecoded,
aColors[idx].mRed, aColors[idx].mGreen, aColors[idx].mBlue);
@ -150,7 +151,7 @@ SetPixel(uint32_t*& aDecoded, uint8_t idx, bmp::ColorTableEntry* aColors)
/// @param aCount Current count. Is decremented by one or two.
static void
Set4BitPixel(uint32_t*& aDecoded, uint8_t aData, uint32_t& aCount,
bmp::ColorTableEntry* aColors)
const UniquePtr<ColorTableEntry[]>& aColors)
{
uint8_t idx = aData >> 4;
SetPixel(aDecoded, idx, aColors);
@ -171,9 +172,12 @@ GetBMPLog()
return sBMPLog;
}
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
// The length of the mBIHSize field in the info header.
static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
: Decoder(aImage)
, mLexer(Transition::To(State::FILE_HEADER, FileHeader::LENGTH))
, mLexer(Transition::To(aState, aLength))
, mIsWithinICO(false)
, mMayHaveTransparency(false)
, mDoesHaveTransparency(false)
@ -185,53 +189,43 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
, mCurrentPos(0)
, mAbsoluteModeNumPixels(0)
{
memset(&mBFH, 0, sizeof(mBFH));
memset(&mBIH, 0, sizeof(mBIH));
}
// Constructor for normal BMP files.
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
: nsBMPDecoder(aImage, State::FILE_HEADER, FILE_HEADER_LENGTH)
{
}
// Constructor used for WinBMPv3-ICO files, which lack a file header.
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
: nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH)
{
SetIsWithinICO();
// Even though the file header isn't present in this case, the dataOffset
// field is set as if it is, and so we must increment mPreGapLength
// accordingly.
mPreGapLength += FILE_HEADER_LENGTH;
// This is the one piece of data we normally get from a BMP file header, so
// it must be provided via an argument.
mH.mDataOffset = aDataOffset;
}
nsBMPDecoder::~nsBMPDecoder()
{
delete[] mColors;
}
// Obtains the bits per pixel from the internal BIH header.
int32_t
nsBMPDecoder::GetBitsPerPixel() const
{
return mBIH.bpp;
}
// Obtains the width from the internal BIH header.
int32_t
nsBMPDecoder::GetWidth() const
{
return mBIH.width;
}
// Obtains the absolute value of the height from the internal BIH header.
// If it's positive the bitmap is stored bottom to top, otherwise top to bottom.
int32_t
nsBMPDecoder::GetHeight() const
{
return abs(mBIH.height);
}
// Obtains the internal output image buffer.
uint32_t*
nsBMPDecoder::GetImageData()
{
return reinterpret_cast<uint32_t*>(mImageData);
}
// Obtains the size of the compressed image resource.
int32_t
nsBMPDecoder::GetCompressedImageSize() const
{
// In the RGB case image_size might not be set, so compute it manually.
// In the RGB case mImageSize might not be set, so compute it manually.
MOZ_ASSERT(mPixelRowSize != 0);
return mBIH.compression == Compression::RGB
? mPixelRowSize * GetHeight()
: mBIH.image_size;
return mH.mCompression == Compression::RGB
? mPixelRowSize * AbsoluteHeight()
: mH.mImageSize;
}
void
@ -247,7 +241,7 @@ nsBMPDecoder::FinishInternal()
if (!IsMetadataDecode() && HasSize()) {
// Invalidate.
nsIntRect r(0, 0, mBIH.width, GetHeight());
nsIntRect r(0, 0, mH.mWidth, AbsoluteHeight());
PostInvalidation(r);
if (mDoesHaveTransparency) {
@ -400,11 +394,11 @@ nsBMPDecoder::RowBuffer()
return reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer()) + mCurrentPos;
}
// Convert from row (1..height) to absolute line (0..height-1).
int32_t line = (mBIH.height < 0)
? -mBIH.height - mCurrentRow
// Convert from row (1..mHeight) to absolute line (0..mHeight-1).
int32_t line = (mH.mHeight < 0)
? -mH.mHeight - mCurrentRow
: mCurrentRow - 1;
int32_t offset = line * mBIH.width + mCurrentPos;
int32_t offset = line * mH.mWidth + mCurrentPos;
return reinterpret_cast<uint32_t*>(mImageData) + offset;
}
@ -420,7 +414,7 @@ nsBMPDecoder::FinishRow()
Some(invalidRect.mTargetSizeRect));
}
} else {
PostInvalidation(IntRect(0, mCurrentRow, mBIH.width, 1));
PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
}
mCurrentRow--;
}
@ -466,59 +460,49 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
return;
}
// The length of the bihsize field in the info header.
static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
LexerTransition<nsBMPDecoder::State>
nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
mBFH.signature[0] = aData[0];
mBFH.signature[1] = aData[1];
bool signatureOk = mBFH.signature[0] == 'B' && mBFH.signature[1] == 'M';
bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
if (!signatureOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// Nb: this field is unreliable. In Windows BMPs it's the file size, but in
// OS/2 BMPs it's sometimes the size of the file and info headers. It doesn't
// matter because we don't consult it.
mBFH.filesize = LittleEndian::readUint32(aData + 2);
// We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
mBFH.reserved = 0;
mBFH.dataoffset = LittleEndian::readUint32(aData + 10);
mH.mDataOffset = LittleEndian::readUint32(aData + 10);
return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
}
// We read the info header in two steps: (a) read the bihsize field to
// We read the info header in two steps: (a) read the mBIHSize field to
// determine how long the header is; (b) read the rest of the header.
LexerTransition<nsBMPDecoder::State>
nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
mBIH.bihsize = LittleEndian::readUint32(aData);
mH.mBIHSize = LittleEndian::readUint32(aData);
bool bihsizeOk = mBIH.bihsize == InfoHeaderLength::WIN_V2 ||
mBIH.bihsize == InfoHeaderLength::WIN_V3 ||
mBIH.bihsize == InfoHeaderLength::WIN_V4 ||
mBIH.bihsize == InfoHeaderLength::WIN_V5 ||
(mBIH.bihsize >= InfoHeaderLength::OS2_V2_MIN &&
mBIH.bihsize <= InfoHeaderLength::OS2_V2_MAX);
if (!bihsizeOk) {
bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
(mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
if (!bihSizeOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// ICO BMPs must have a WinVMPv3 header. nsICODecoder should have already
// terminated decoding if this isn't the case.
MOZ_ASSERT_IF(mIsWithinICO, mBIH.bihsize == InfoHeaderLength::WIN_V3);
MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3);
return Transition::To(State::INFO_HEADER_REST,
mBIH.bihsize - BIHSIZE_FIELD_LENGTH);
mH.mBIHSize - BIHSIZE_FIELD_LENGTH);
}
LexerTransition<nsBMPDecoder::State>
@ -526,28 +510,26 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
// |width| and |height| may be signed (Windows) or unsigned (OS/2). We just
// |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just
// read as unsigned because in practice that's good enough.
if (mBIH.bihsize == InfoHeaderLength::WIN_V2) {
mBIH.width = LittleEndian::readUint16(aData + 0);
mBIH.height = LittleEndian::readUint16(aData + 2);
mBIH.planes = LittleEndian::readUint16(aData + 4);
mBIH.bpp = LittleEndian::readUint16(aData + 6);
if (mH.mBIHSize == InfoHeaderLength::WIN_V2) {
mH.mWidth = LittleEndian::readUint16(aData + 0);
mH.mHeight = LittleEndian::readUint16(aData + 2);
// We ignore the planes (aData + 4) field; it should always be 1.
mH.mBpp = LittleEndian::readUint16(aData + 6);
} else {
mBIH.width = LittleEndian::readUint32(aData + 0);
mBIH.height = LittleEndian::readUint32(aData + 4);
mBIH.planes = LittleEndian::readUint16(aData + 8);
mBIH.bpp = LittleEndian::readUint16(aData + 10);
mH.mWidth = LittleEndian::readUint32(aData + 0);
mH.mHeight = LittleEndian::readUint32(aData + 4);
// We ignore the planes (aData + 4) field; it should always be 1.
mH.mBpp = LittleEndian::readUint16(aData + 10);
// For OS2-BMPv2 the info header may be as little as 16 bytes, so be
// careful for these fields.
mBIH.compression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
mBIH.image_size = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
mBIH.xppm = aLength >= 24 ? LittleEndian::readUint32(aData + 20) : 0;
mBIH.yppm = aLength >= 28 ? LittleEndian::readUint32(aData + 24) : 0;
mBIH.colors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
mBIH.important_colors
= aLength >= 36 ? LittleEndian::readUint32(aData + 32) : 0;
mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
mH.mImageSize = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
// We ignore the xppm (aData + 20) and yppm (aData + 24) fields.
mH.mNumColors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
// We ignore the important_colors (aData + 36) field.
// For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional
// fields in the info header which we ignore, with the possible exception
@ -557,52 +539,52 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
// Run with NSPR_LOG_MODULES=BMPDecoder:4 set to see this output.
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u\n",
mBIH.bihsize, mBIH.width, mBIH.height, uint32_t(mBIH.bpp),
mBIH.compression, mBIH.colors));
mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp),
mH.mCompression, mH.mNumColors));
// BMPs with negative width are invalid. Also, reject extremely wide images
// to keep the math sane. And reject INT_MIN as a height because you can't
// get its absolute value (because -INT_MIN is one more than INT_MAX).
const int32_t k64KWidth = 0x0000FFFF;
bool sizeOk = 0 <= mBIH.width && mBIH.width <= k64KWidth &&
mBIH.height != INT_MIN;
bool sizeOk = 0 <= mH.mWidth && mH.mWidth <= k64KWidth &&
mH.mHeight != INT_MIN;
if (!sizeOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// Check bpp and compression.
// Check mBpp and mCompression.
bool bppCompressionOk =
(mBIH.compression == Compression::RGB &&
(mBIH.bpp == 1 || mBIH.bpp == 4 || mBIH.bpp == 8 ||
mBIH.bpp == 16 || mBIH.bpp == 24 || mBIH.bpp == 32)) ||
(mBIH.compression == Compression::RLE8 && mBIH.bpp == 8) ||
(mBIH.compression == Compression::RLE4 && mBIH.bpp == 4) ||
(mBIH.compression == Compression::BITFIELDS &&
(mBIH.bpp == 16 || mBIH.bpp == 32));
(mH.mCompression == Compression::RGB &&
(mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 ||
mH.mBpp == 16 || mH.mBpp == 24 || mH.mBpp == 32)) ||
(mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
(mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
(mH.mCompression == Compression::BITFIELDS &&
(mH.mBpp == 16 || mH.mBpp == 32));
if (!bppCompressionOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// Post our size to the superclass.
uint32_t realHeight = GetHeight();
PostSize(mBIH.width, realHeight);
mCurrentRow = realHeight;
uint32_t absHeight = AbsoluteHeight();
PostSize(mH.mWidth, absHeight);
mCurrentRow = absHeight;
// Round it up to the nearest byte count, then pad to 4-byte boundary.
// Compute this even for a metadate decode because GetCompressedImageSize()
// relies on it.
mPixelRowSize = (mBIH.bpp * mBIH.width + 7) / 8;
mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8;
uint32_t surplus = mPixelRowSize % 4;
if (surplus != 0) {
mPixelRowSize += 4 - surplus;
}
size_t bitFieldsLengthStillToRead = 0;
if (mBIH.compression == Compression::BITFIELDS) {
if (mH.mCompression == Compression::BITFIELDS) {
// Need to read bitfields.
if (mBIH.bihsize >= InfoHeaderLength::WIN_V4) {
if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
// Bitfields are present in the info header, so we can read them
// immediately.
mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
@ -611,10 +593,10 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
// ReadBitfields().
bitFieldsLengthStillToRead = BitFields::LENGTH;
}
} else if (mBIH.bpp == 16) {
} else if (mH.mBpp == 16) {
// No bitfields specified; use the default 5-5-5 values.
mBitFields.SetR5G5B5();
} else if (mBIH.bpp == 32) {
} else if (mH.mBpp == 32) {
// No bitfields specified; use the default 8-8-8 values.
mBitFields.SetR8G8B8();
}
@ -647,10 +629,10 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
// Note that RLE-encoded BMPs might be transparent because the 'delta' mode
// can skip pixels and cause implicit transparency.
mMayHaveTransparency =
(mBIH.compression == Compression::RGB && mIsWithinICO && mBIH.bpp == 32) ||
mBIH.compression == Compression::RLE8 ||
mBIH.compression == Compression::RLE4 ||
(mBIH.compression == Compression::BITFIELDS &&
(mH.mCompression == Compression::RGB && mIsWithinICO && mH.mBpp == 32) ||
mH.mCompression == Compression::RLE8 ||
mH.mCompression == Compression::RLE4 ||
(mH.mCompression == Compression::BITFIELDS &&
mBitFields.mAlpha.IsPresent());
if (mMayHaveTransparency) {
PostHasTransparency();
@ -663,19 +645,19 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
}
// Set up the color table, if present; it'll be filled in by ReadColorTable().
if (mBIH.bpp <= 8) {
mNumColors = 1 << mBIH.bpp;
if (0 < mBIH.colors && mBIH.colors < mNumColors) {
mNumColors = mBIH.colors;
if (mH.mBpp <= 8) {
mNumColors = 1 << mH.mBpp;
if (0 < mH.mNumColors && mH.mNumColors < mNumColors) {
mNumColors = mH.mNumColors;
}
// Always allocate and zero 256 entries, even though mNumColors might be
// smaller, because the file might erroneously index past mNumColors.
mColors = new ColorTableEntry[256];
memset(mColors, 0, 256 * sizeof(ColorTableEntry));
mColors = MakeUnique<ColorTableEntry[]>(256);
memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry));
// OS/2 Bitmaps have no padding byte.
mBytesPerColor = (mBIH.bihsize == InfoHeaderLength::WIN_V2) ? 3 : 4;
mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4;
}
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
@ -718,25 +700,25 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
}
// We know how many bytes we've read so far (mPreGapLength) and we know the
// offset of the pixel data (mBFH.dataoffset), so we can determine the length
// offset of the pixel data (mH.mDataOffset), so we can determine the length
// of the gap (possibly zero) between the color table and the pixel data.
//
// If the gap is negative the file must be malformed (e.g. mBFH.dataoffset
// If the gap is negative the file must be malformed (e.g. mH.mDataOffset
// points into the middle of the color palette instead of past the end) and
// we give up.
if (mPreGapLength > mBFH.dataoffset) {
if (mPreGapLength > mH.mDataOffset) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
uint32_t gapLength = mBFH.dataoffset - mPreGapLength;
uint32_t gapLength = mH.mDataOffset - mPreGapLength;
return Transition::To(State::GAP, gapLength);
}
LexerTransition<nsBMPDecoder::State>
nsBMPDecoder::SkipGap()
{
bool hasRLE = mBIH.compression == Compression::RLE8 ||
mBIH.compression == Compression::RLE4;
bool hasRLE = mH.mCompression == Compression::RLE8 ||
mH.mCompression == Compression::RLE4;
return hasRLE
? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH)
: Transition::To(State::PIXEL_ROW, mPixelRowSize);
@ -749,8 +731,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData)
const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
uint32_t* dst = RowBuffer();
uint32_t lpos = mBIH.width;
switch (mBIH.bpp) {
uint32_t lpos = mH.mWidth;
switch (mH.mBpp) {
case 1:
while (lpos > 0) {
int8_t bit;
@ -817,8 +799,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData)
break;
case 32:
if (mBIH.compression == Compression::RGB && mIsWithinICO &&
mBIH.bpp == 32) {
if (mH.mCompression == Compression::RGB && mIsWithinICO &&
mH.mBpp == 32) {
// This is a special case only used for 32bpp WinBMPv3-ICO files, which
// could be in either 0RGB or ARGB format.
while (lpos > 0) {
@ -894,11 +876,11 @@ nsBMPDecoder::ReadRLESegment(const char* aData)
//
// Work around bitmaps that specify too many pixels.
uint32_t pixelsNeeded =
std::min<uint32_t>(mBIH.width - mCurrentPos, byte1);
std::min<uint32_t>(mH.mWidth - mCurrentPos, byte1);
if (pixelsNeeded) {
uint32_t* dst = RowBuffer();
mCurrentPos += pixelsNeeded;
if (mBIH.compression == Compression::RLE8) {
if (mH.mCompression == Compression::RLE8) {
do {
SetPixel(dst, byte2, mColors);
pixelsNeeded --;
@ -934,7 +916,7 @@ nsBMPDecoder::ReadRLESegment(const char* aData)
MOZ_ASSERT(mAbsoluteModeNumPixels == 0);
mAbsoluteModeNumPixels = byte2;
uint32_t length = byte2;
if (mBIH.compression == Compression::RLE4) {
if (mH.mCompression == Compression::RLE4) {
length = (length + 1) / 2; // halve, rounding up
}
if (length & 1) {
@ -959,8 +941,8 @@ nsBMPDecoder::ReadRLEDelta(const char* aData)
// Handle the XDelta.
mCurrentPos += uint8_t(aData[0]);
if (mCurrentPos > mBIH.width) {
mCurrentPos = mBIH.width;
if (mCurrentPos > mH.mWidth) {
mCurrentPos = mH.mWidth;
}
// Handle the Y Delta.
@ -989,7 +971,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
uint32_t n = mAbsoluteModeNumPixels;
mAbsoluteModeNumPixels = 0;
if (mCurrentPos + n > uint32_t(mBIH.width)) {
if (mCurrentPos + n > uint32_t(mH.mWidth)) {
// Bad data. Stop decoding; at least part of the image may have been
// decoded.
return Transition::Terminate(State::SUCCESS);
@ -1000,7 +982,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
uint32_t* dst = RowBuffer();
uint32_t iSrc = 0;
uint32_t* oldPos = dst;
if (mBIH.compression == Compression::RLE8) {
if (mH.mCompression == Compression::RLE8) {
while (n > 0) {
SetPixel(dst, aData[iSrc], mColors);
n--;

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

@ -7,16 +7,43 @@
#ifndef mozilla_image_decoders_nsBMPDecoder_h
#define mozilla_image_decoders_nsBMPDecoder_h
#include "BMPFileHeaders.h"
#include "BMPHeaders.h"
#include "Decoder.h"
#include "gfxColor.h"
#include "StreamingLexer.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace image {
namespace bmp {
/// This struct contains the fields from the file header and info header that
/// we use during decoding. (Excluding bitfields fields, which are kept in
/// BitFields.)
struct Header {
uint32_t mDataOffset; // Offset to raster data.
uint32_t mBIHSize; // Header size.
int32_t mWidth; // Image width.
int32_t mHeight; // Image height.
uint16_t mBpp; // Bits per pixel.
uint32_t mCompression; // See struct Compression for valid values.
uint32_t mImageSize; // (compressed) image size. Can be 0 if
// mCompression==0.
uint32_t mNumColors; // Used colors.
Header()
: mDataOffset(0)
, mBIHSize(0)
, mWidth(0)
, mHeight(0)
, mBpp(0)
, mCompression(0)
, mImageSize(0)
, mNumColors(0)
{}
};
/// An entry in the color table.
struct ColorTableEntry {
uint8_t mRed;
@ -98,23 +125,17 @@ class nsBMPDecoder : public Decoder
public:
~nsBMPDecoder();
/// Obtains the bits per pixel from the internal BIH header.
int32_t GetBitsPerPixel() const;
/// Obtains the width from the internal BIH header.
int32_t GetWidth() const;
/// Obtains the abs-value of the height from the internal BIH header.
int32_t GetHeight() const;
/// Obtains the internal output image buffer.
uint32_t* GetImageData();
uint32_t* GetImageData() { return reinterpret_cast<uint32_t*>(mImageData); }
/// Obtains the length of the internal output image buffer.
size_t GetImageDataLength() const { return mImageDataLength; }
/// Obtains the size of the compressed image resource.
int32_t GetCompressedImageSize() const;
/// Mark this BMP as being within an ICO file.
/// Mark this BMP as being within an ICO file. Only used for testing purposes
/// because the ICO-specific constructor does this marking automatically.
void SetIsWithinICO() { mIsWithinICO = true; }
/// Did the BMP file have alpha data of any kind? (Only use this after the
@ -136,14 +157,6 @@ private:
friend class DecoderFactory;
friend class nsICODecoder;
// Decoders should only be instantiated via DecoderFactory.
// XXX(seth): nsICODecoder is temporarily an exception to this rule.
explicit nsBMPDecoder(RasterImage* aImage);
uint32_t* RowBuffer();
void FinishRow();
enum class State {
FILE_HEADER,
INFO_HEADER_SIZE,
@ -159,6 +172,23 @@ private:
FAILURE
};
// This is the constructor used by DecoderFactory.
explicit nsBMPDecoder(RasterImage* aImage);
// This is the constructor used by nsICODecoder.
// XXX(seth): nsICODecoder is temporarily an exception to the rule that
// decoders should only be instantiated via DecoderFactory.
nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
// Helper constructor called by the other two.
nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
uint32_t* RowBuffer();
void FinishRow();
LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
@ -172,8 +202,7 @@ private:
StreamingLexer<State> mLexer;
bmp::FileHeader mBFH;
bmp::V5InfoHeader mBIH;
bmp::Header mH;
// If the BMP is within an ICO file our treatment of it differs slightly.
bool mIsWithinICO;
@ -190,7 +219,7 @@ private:
uint32_t mNumColors; // The number of used colors, i.e. the number of
// entries in mColors, if it's present.
bmp::ColorTableEntry* mColors; // The color table, if it's present.
UniquePtr<bmp::ColorTableEntry[]> mColors; // The color table, if it's present.
uint32_t mBytesPerColor; // 3 or 4, depending on the format
// The number of bytes prior to the optional gap that have been read. This

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

@ -21,7 +21,7 @@ namespace image {
// Constants.
static const uint32_t ICOHEADERSIZE = 6;
static const uint32_t BITMAPINFOSIZE = 40;
static const uint32_t BITMAPINFOSIZE = bmp::InfoHeaderLength::WIN_ICO;
// ----------------------------------------
// Actual Data Processing
@ -110,53 +110,16 @@ nsICODecoder::GetFinalStateFromContainedDecoder()
MOZ_ASSERT(HasError() || !mCurrentFrame || mCurrentFrame->IsImageComplete());
}
// Returns a buffer filled with the bitmap file header in little endian:
// Signature 2 bytes 'BM'
// FileSize 4 bytes File size in bytes
// reserved 4 bytes unused (=0)
// DataOffset 4 bytes File offset to Raster Data
// Returns true if successful
bool
nsICODecoder::FillBitmapFileHeaderBuffer(int8_t* bfh)
{
memset(bfh, 0, 14);
bfh[0] = 'B';
bfh[1] = 'M';
int32_t dataOffset = 0;
int32_t fileSize = 0;
dataOffset = bmp::FileHeader::LENGTH + BITMAPINFOSIZE;
// The color table is present only if BPP is <= 8
if (mDirEntry.mBitCount <= 8) {
uint16_t numColors = GetNumColors();
if (numColors == (uint16_t)-1) {
return false;
}
dataOffset += 4 * numColors;
fileSize = dataOffset + GetRealWidth() * GetRealHeight();
} else {
fileSize = dataOffset + (mDirEntry.mBitCount * GetRealWidth() *
GetRealHeight()) / 8;
}
NativeEndian::swapToLittleEndianInPlace(&fileSize, 1);
memcpy(bfh + 2, &fileSize, sizeof(fileSize));
NativeEndian::swapToLittleEndianInPlace(&dataOffset, 1);
memcpy(bfh + 10, &dataOffset, sizeof(dataOffset));
return true;
}
// A BMP inside of an ICO has *2 height because of the AND mask
// that follows the actual bitmap. The BMP shouldn't know about
// this difference though.
bool
nsICODecoder::FixBitmapHeight(int8_t* bih)
{
// Get the height from the BMP file information header
int32_t height;
memcpy(&height, bih + 8, sizeof(height));
NativeEndian::swapFromLittleEndianInPlace(&height, 1);
// BMPs can be stored inverted by having a negative height
// Get the height from the BMP file information header.
int32_t height = LittleEndian::readInt32(bih + 8);
// BMPs can be stored inverted by having a negative height.
height = abs(height);
// The bitmap height is by definition * 2 what it should be to account for
@ -176,8 +139,7 @@ nsICODecoder::FixBitmapHeight(int8_t* bih)
}
// Fix the BMP height in the BIH so that the BMP decoder can work properly
NativeEndian::swapToLittleEndianInPlace(&height, 1);
memcpy(bih + 8, &height, sizeof(height));
LittleEndian::writeInt32(bih + 8, height);
return true;
}
@ -186,15 +148,14 @@ nsICODecoder::FixBitmapHeight(int8_t* bih)
bool
nsICODecoder::FixBitmapWidth(int8_t* bih)
{
// Get the width from the BMP file information header
int32_t width;
memcpy(&width, bih + 4, sizeof(width));
NativeEndian::swapFromLittleEndianInPlace(&width, 1);
// Get the width from the BMP file information header.
int32_t width = LittleEndian::readInt32(bih + 4);
if (width > 256) {
return false;
}
// We should always trust the width from the bitmap itself instead of
// We should always trust the width from the bitmap itself instead of
// the ICO width.
if (width == 256) {
mDirEntry.mWidth = 0;
@ -204,28 +165,6 @@ nsICODecoder::FixBitmapWidth(int8_t* bih)
return true;
}
// The BMP information header's bits per pixel should be trusted
// more than what we have. Usually the ICO's BPP is set to 0.
int32_t
nsICODecoder::ReadBPP(const char* aBIH)
{
const int8_t* bih = reinterpret_cast<const int8_t*>(aBIH);
int32_t bitsPerPixel;
memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
NativeEndian::swapFromLittleEndianInPlace(&bitsPerPixel, 1);
return bitsPerPixel;
}
int32_t
nsICODecoder::ReadBIHSize(const char* aBIH)
{
const int8_t* bih = reinterpret_cast<const int8_t*>(aBIH);
int32_t headerSize;
memcpy(&headerSize, bih, sizeof(headerSize));
NativeEndian::swapFromLittleEndianInPlace(&headerSize, 1);
return headerSize;
}
LexerTransition<ICOState>
nsICODecoder::ReadHeader(const char* aData)
{
@ -236,8 +175,7 @@ nsICODecoder::ReadHeader(const char* aData)
mIsCursor = (aData[2] == 2);
// The fifth and sixth bytes specify the number of resources in the file.
mNumIcons =
LittleEndian::readUint16(reinterpret_cast<const uint16_t*>(aData + 4));
mNumIcons = LittleEndian::readUint16(aData + 4);
if (mNumIcons == 0) {
return Transition::Terminate(ICOState::SUCCESS); // Nothing to do.
}
@ -271,19 +209,14 @@ nsICODecoder::ReadDirEntry(const char* aData)
// Read the directory entry.
IconDirEntry e;
memset(&e, 0, sizeof(e));
memcpy(&e.mWidth, aData, sizeof(e.mWidth));
memcpy(&e.mHeight, aData + 1, sizeof(e.mHeight));
memcpy(&e.mColorCount, aData + 2, sizeof(e.mColorCount));
memcpy(&e.mReserved, aData + 3, sizeof(e.mReserved));
memcpy(&e.mPlanes, aData + 4, sizeof(e.mPlanes));
e.mPlanes = LittleEndian::readUint16(&e.mPlanes);
memcpy(&e.mBitCount, aData + 6, sizeof(e.mBitCount));
e.mBitCount = LittleEndian::readUint16(&e.mBitCount);
memcpy(&e.mBytesInRes, aData + 8, sizeof(e.mBytesInRes));
e.mBytesInRes = LittleEndian::readUint32(&e.mBytesInRes);
memcpy(&e.mImageOffset, aData + 12, sizeof(e.mImageOffset));
e.mImageOffset = LittleEndian::readUint32(&e.mImageOffset);
e.mWidth = aData[0];
e.mHeight = aData[1];
e.mColorCount = aData[2];
e.mReserved = aData[3];
e.mPlanes = LittleEndian::readUint16(aData + 4);
e.mBitCount = LittleEndian::readUint16(aData + 6);
e.mBytesInRes = LittleEndian::readUint32(aData + 8);
e.mImageOffset = LittleEndian::readUint32(aData + 12);
// Determine if this is the biggest resource we've seen so far. We always use
// the biggest resource for the intrinsic size, and if we're not downscaling,
@ -389,21 +322,8 @@ nsICODecoder::SniffResource(const char* aData)
ICOState::READ_PNG,
toRead);
} else {
// Create a BMP decoder which will do most of the work for us; the exception
// is the AND mask, which isn't present in standalone BMPs.
nsBMPDecoder* bmpDecoder = new nsBMPDecoder(mImage);
mContainedDecoder = bmpDecoder;
bmpDecoder->SetIsWithinICO();
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
if (mDownscaler) {
mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
}
mContainedDecoder->Init();
// Make sure we have a sane size for the bitmap information header.
int32_t bihSize = ReadBIHSize(aData);
int32_t bihSize = LittleEndian::readUint32(aData);
if (bihSize != static_cast<int32_t>(BITMAPINFOSIZE)) {
return Transition::Terminate(ICOState::FAILURE);
}
@ -439,22 +359,35 @@ nsICODecoder::ReadBIH(const char* aData)
// Buffer the rest of the bitmap information header.
memcpy(mBIHraw + PNGSIGNATURESIZE, aData, BITMAPINFOSIZE - PNGSIGNATURESIZE);
// Extracting the BPP from the BIH header; it should be trusted over the one
// we have from the ICO header.
mBPP = ReadBPP(mBIHraw);
// Extract the BPP from the BIH header; it should be trusted over the one
// we have from the ICO header which is usually set to 0.
mBPP = LittleEndian::readUint16(mBIHraw + 14);
// The ICO format when containing a BMP does not include the 14 byte
// bitmap file header. To use the code of the BMP decoder we need to
// generate this header ourselves and feed it to the BMP decoder.
int8_t bfhBuffer[BMPFILEHEADERSIZE];
if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
return Transition::Terminate(ICOState::FAILURE);
// bitmap file header. So we create the BMP decoder via the constructor that
// tells it to skip this, and pass in the required data (dataOffset) that
// would have been present in the header.
uint32_t dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE;
if (mDirEntry.mBitCount <= 8) {
// The color table is present only if BPP is <= 8.
uint16_t numColors = GetNumColors();
if (numColors == (uint16_t)-1) {
return Transition::Terminate(ICOState::FAILURE);
}
dataOffset += 4 * numColors;
}
if (!WriteToContainedDecoder(reinterpret_cast<const char*>(bfhBuffer),
sizeof(bfhBuffer))) {
return Transition::Terminate(ICOState::FAILURE);
// Create a BMP decoder which will do most of the work for us; the exception
// is the AND mask, which isn't present in standalone BMPs.
RefPtr<nsBMPDecoder> bmpDecoder = new nsBMPDecoder(mImage, dataOffset);
mContainedDecoder = bmpDecoder;
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
if (mDownscaler) {
mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
}
mContainedDecoder->Init();
// Fix the ICO height from the BIH. It needs to be halved so our BMP decoder
// will understand, because the BMP decoder doesn't expect the alpha mask that
@ -473,14 +406,6 @@ nsICODecoder::ReadBIH(const char* aData)
return Transition::Terminate(ICOState::FAILURE);
}
// Sometimes the ICO BPP header field is not filled out so we should trust the
// contained resource over our own information.
// XXX(seth): Is this ever different than the value we obtained from
// ReadBPP() above?
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
mBPP = bmpDecoder->GetBitsPerPixel();
// Check to make sure we have valid color settings.
uint16_t numColors = GetNumColors();
if (numColors == uint16_t(-1)) {

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

@ -87,8 +87,6 @@ private:
// Gets decoder state from the contained decoder so it's visible externally.
void GetFinalStateFromContainedDecoder();
// Creates a bitmap file header buffer, returns true if successful
bool FillBitmapFileHeaderBuffer(int8_t* bfh);
// Fixes the ICO height to match that of the BIH.
// and also fixes the BIH height to be /2 of what it was.
// See definition for explanation.
@ -97,10 +95,6 @@ private:
// Fixes the ICO width to match that of the BIH.
// Returns false if invalid information is contained within.
bool FixBitmapWidth(int8_t* bih);
// Extract bitmap info header size count from BMP information header
int32_t ReadBIHSize(const char* aBIH);
// Extract bit count from BMP information header
int32_t ReadBPP(const char* aBIH);
// Calculates the row size in bytes for the AND mask table
uint32_t CalcAlphaRowSize();
// Obtains the number of colors from the BPP, mBPP must be filled in
@ -120,7 +114,7 @@ private:
StreamingLexer<ICOState, 32> mLexer; // The lexer.
RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
UniquePtr<uint8_t[]> mMaskBuffer; // A temporary buffer for the alpha mask.
char mBIHraw[40]; // The bitmap information header.
char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
IconDirEntry mDirEntry; // The dir entry for the selected resource.
IntSize mBiggestResourceSize; // Used to select the intrinsic size.
IntSize mBiggestResourceHotSpot; // Used to select the intrinsic size.

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

@ -487,9 +487,9 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
mBMPFileHeader.signature[1] = 'M';
if (aVersion == VERSION_3) {
mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V3;
mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V3;
} else { // aVersion == 5
mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V5;
mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V5;
}
// The color table is present only if BPP is <= 8

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

@ -11,7 +11,7 @@
#include "mozilla/UniquePtr.h"
#include "imgIEncoder.h"
#include "BMPFileHeaders.h"
#include "BMPHeaders.h"
#include "nsCOMPtr.h"
@ -23,6 +23,62 @@
{0xbd, 0x16, 0xb0, 0x81, 0xa3, 0Xba, 0x8c, 0x0b} \
}
namespace mozilla {
namespace image {
namespace bmp {
struct FileHeader {
char signature[2]; // String "BM".
uint32_t filesize; // File size.
int32_t reserved; // Zero.
uint32_t dataoffset; // Offset to raster data.
};
struct XYZ {
int32_t x, y, z;
};
struct XYZTriple {
XYZ r, g, b;
};
struct V5InfoHeader {
uint32_t bihsize; // Header size
int32_t width; // Uint16 in OS/2 BMPs
int32_t height; // Uint16 in OS/2 BMPs
uint16_t planes; // =1
uint16_t bpp; // Bits per pixel.
uint32_t compression; // See Compression for valid values
uint32_t image_size; // (compressed) image size. Can be 0 if
// compression==0
uint32_t xppm; // Pixels per meter, horizontal
uint32_t yppm; // Pixels per meter, vertical
uint32_t colors; // Used Colors
uint32_t important_colors; // Number of important colors. 0=all
// The rest of the header is not available in WIN_V3 BMP Files
uint32_t red_mask; // Bits used for red component
uint32_t green_mask; // Bits used for green component
uint32_t blue_mask; // Bits used for blue component
uint32_t alpha_mask; // Bits used for alpha component
uint32_t color_space; // 0x73524742=LCS_sRGB ...
// These members are unused unless color_space == LCS_CALIBRATED_RGB
XYZTriple white_point; // Logical white point
uint32_t gamma_red; // Red gamma component
uint32_t gamma_green; // Green gamma component
uint32_t gamma_blue; // Blue gamma component
uint32_t intent; // Rendering intent
// These members are unused unless color_space == LCS_PROFILE_*
uint32_t profile_offset; // Offset to profile data in bytes
uint32_t profile_size; // Size of profile data in bytes
uint32_t reserved; // =0
static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
};
} // namespace bmp
} // namespace image
} // namespace mozilla
// Provides BMP encoding functionality. Use InitFromData() to do the
// encoding. See that function definition for encoding options.

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

@ -162,10 +162,10 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData,
// Icon files that wrap a BMP file must not include the BITMAPFILEHEADER
// section at the beginning of the encoded BMP data, so we must skip over
// bmp::FileHeader::LENGTH bytes when adding the BMP content to the icon
// bmp::FILE_HEADER_LENGTH bytes when adding the BMP content to the icon
// file.
mICODirEntry.mBytesInRes =
BMPImageBufferSize - bmp::FileHeader::LENGTH + andMaskSize;
BMPImageBufferSize - bmp::FILE_HEADER_LENGTH + andMaskSize;
// Encode the icon headers
EncodeFileHeader();
@ -174,14 +174,14 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData,
char* imageBuffer;
rv = mContainedEncoder->GetImageBuffer(&imageBuffer);
NS_ENSURE_SUCCESS(rv, rv);
memcpy(mImageBufferCurr, imageBuffer + bmp::FileHeader::LENGTH,
BMPImageBufferSize - bmp::FileHeader::LENGTH);
memcpy(mImageBufferCurr, imageBuffer + bmp::FILE_HEADER_LENGTH,
BMPImageBufferSize - bmp::FILE_HEADER_LENGTH);
// We need to fix the BMP height to be *2 for the AND mask
uint32_t fixedHeight = GetRealHeight() * 2;
NativeEndian::swapToLittleEndianInPlace(&fixedHeight, 1);
// The height is stored at an offset of 8 from the DIB header
memcpy(mImageBufferCurr + 8, &fixedHeight, sizeof(fixedHeight));
mImageBufferCurr += BMPImageBufferSize - bmp::FileHeader::LENGTH;
mImageBufferCurr += BMPImageBufferSize - bmp::FILE_HEADER_LENGTH;
// Calculate rowsize in DWORD's
uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up

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

@ -162,19 +162,19 @@ nsJPEGEncoder::InitFromData(const uint8_t* aData,
jpeg_write_scanlines(&cinfo, const_cast<uint8_t**>(&row), 1);
}
} else if (aInputFormat == INPUT_FORMAT_RGBA) {
uint8_t* row = new uint8_t[aWidth * 3];
UniquePtr<uint8_t[]> rowptr = MakeUnique<uint8_t[]>(aWidth * 3);
uint8_t* row = rowptr.get();
while (cinfo.next_scanline < cinfo.image_height) {
ConvertRGBARow(&aData[cinfo.next_scanline * aStride], row, aWidth);
jpeg_write_scanlines(&cinfo, &row, 1);
}
delete[] row;
} else if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
uint8_t* row = new uint8_t[aWidth * 3];
UniquePtr<uint8_t[]> rowptr = MakeUnique<uint8_t[]>(aWidth * 3);
uint8_t* row = rowptr.get();
while (cinfo.next_scanline < cinfo.image_height) {
ConvertHostARGBRow(&aData[cinfo.next_scanline * aStride], row, aWidth);
jpeg_write_scanlines(&cinfo, &row, 1);
}
delete[] row;
}
jpeg_finish_compress(&cinfo);

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

@ -287,22 +287,18 @@ nsPNGEncoder::AddImageFrame(const uint8_t* aData,
if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
// PNG requires RGBA with post-multiplied alpha, so we need to
// convert
uint8_t* row = new uint8_t[aWidth * 4];
UniquePtr<uint8_t[]> row = MakeUnique<uint8_t[]>(aWidth * 4);
for (uint32_t y = 0; y < aHeight; y++) {
ConvertHostARGBRow(&aData[y * aStride], row, aWidth, useTransparency);
png_write_row(mPNG, row);
ConvertHostARGBRow(&aData[y * aStride], row.get(), aWidth, useTransparency);
png_write_row(mPNG, row.get());
}
delete[] row;
} else if (aInputFormat == INPUT_FORMAT_RGBA && !useTransparency) {
// RBGA, but we need to strip the alpha
uint8_t* row = new uint8_t[aWidth * 4];
UniquePtr<uint8_t[]> row = MakeUnique<uint8_t[]>(aWidth * 4);
for (uint32_t y = 0; y < aHeight; y++) {
StripAlpha(&aData[y * aStride], row, aWidth);
png_write_row(mPNG, row);
StripAlpha(&aData[y * aStride], row.get(), aWidth);
png_write_row(mPNG, row.get());
}
delete[] row;
} else if (aInputFormat == INPUT_FORMAT_RGB ||
aInputFormat == INPUT_FORMAT_RGBA) {
// simple RBG(A), no conversion needed

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

@ -323,6 +323,14 @@ typedef bool
typedef bool
(* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
/**
* The type of ObjectOps::funToString. This callback allows an object to
* provide a custom string to use when Function.prototype.toString is invoked on
* that object. A null return value means OOM.
*/
typedef JSString*
(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
/**
* Resolve a lazy property named by id in obj by defining it directly in obj.
* Lazy properties are those reflected from some peer native property space
@ -650,6 +658,7 @@ struct ObjectOps
GetElementsOp getElements;
JSNewEnumerateOp enumerate;
ThisValueOp thisValue;
JSFunToStringOp funToString;
};
#define JS_NULL_OBJECT_OPS \
@ -665,7 +674,7 @@ typedef void (*JSClassInternal)();
struct JSClass {
JS_CLASS_MEMBERS(JSFinalizeOp);
void* reserved[25];
void* reserved[26];
};
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot

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

@ -136,7 +136,7 @@ static const unsigned PushedRetAddr = 0;
static const unsigned PushedFP = 0;
static const unsigned StoredFP = 0;
static const unsigned PostStorePrePopFP = 0;
#elif defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static const unsigned PushedRetAddr = 8;
static const unsigned PushedFP = 24;
static const unsigned StoredFP = 28;
@ -157,7 +157,7 @@ PushRetAddr(MacroAssembler& masm)
{
#if defined(JS_CODEGEN_ARM)
masm.push(lr);
#elif defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.push(ra);
#else
// The x86/x64 call instruction pushes the return address.
@ -221,7 +221,8 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit:
Label* profilingReturn)
{
Register scratch = ABIArgGenerator::NonReturn_VolatileReg0;
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
Register scratch2 = ABIArgGenerator::NonReturn_VolatileReg1;
#endif
@ -245,7 +246,8 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit:
// and the async interrupt exit. Since activation.fp can be read at any
// time and still points to the current frame, be careful to only update
// sp after activation.fp has been repointed to the caller's frame.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
DebugOnly<uint32_t> prePop = masm.currentOffset();
@ -344,6 +346,13 @@ js::GenerateAsmJSFunctionEpilogue(MacroAssembler& masm, unsigned framePushed,
masm.nop();
masm.nop();
masm.nop();
#elif defined(JS_CODEGEN_MIPS64)
masm.nop();
masm.nop();
masm.nop();
masm.nop();
masm.nop();
masm.nop();
#endif
}
@ -566,7 +575,7 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation&
MOZ_ASSERT(offsetInModule < codeRange->end());
uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
void** sp = (void**)state.sp;
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
if (offsetInCodeRange < PushedRetAddr) {
// First instruction of the ARM/MIPS function; the return address is
// still in lr and fp still holds the caller's fp.

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

@ -384,6 +384,17 @@ AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembl
if (!staticLinkData_.relativeLinks.append(link))
return false;
}
#elif defined(JS_CODEGEN_MIPS64)
// On MIPS64 we need to update all the long jumps because they contain an
// absolute adress.
for (size_t i = 0; i < masm.numLongJumps(); i++) {
RelativeLink link(RelativeLink::InstructionImmediate);
link.patchAtOffset = masm.longJump(i);
InstImm* inst = (InstImm*)(code_ + masm.longJump(i));
link.targetOffset = Assembler::ExtractLoad64Value(inst) - (uint64_t)code_;
if (!staticLinkData_.relativeLinks.append(link))
return false;
}
#endif
#if defined(JS_CODEGEN_X64)
@ -826,7 +837,7 @@ AsmJSModule::initHeap(Handle<ArrayBufferObjectMaybeShared*> heap, JSContext* cx)
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code_), heapLength);
}
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
uint32_t heapLength = heap->byteLength();
for (unsigned i = 0; i < heapAccesses_.length(); i++) {
jit::Assembler::UpdateBoundsCheck(heapLength,
@ -1739,6 +1750,9 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
#elif defined(JS_CODEGEN_MIPS32)
Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
#elif defined(JS_CODEGEN_MIPS64)
Instruction* instr = (Instruction*)(callerRetAddr - 6 * sizeof(uint32_t));
void* callee = (void*)Assembler::ExtractLoad64Value(instr);
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();
void* callee = nullptr;
@ -1767,6 +1781,9 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
Assembler::WriteLuiOriInstructions(instr, instr->next(),
ScratchRegister, (uint32_t)newCallee);
instr[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
#elif defined(JS_CODEGEN_MIPS64)
Assembler::WriteLoad64Instructions(instr, ScratchRegister, (uint64_t)newCallee);
instr[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();
#else
@ -1841,6 +1858,18 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
instr[1].makeNop();
instr[2].makeNop();
}
#elif defined(JS_CODEGEN_MIPS64)
Instruction* instr = (Instruction*)jump;
if (enabled) {
Assembler::WriteLoad64Instructions(instr, ScratchRegister, (uint64_t)profilingEpilogue);
instr[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr);
} else {
instr[0].makeNop();
instr[1].makeNop();
instr[2].makeNop();
instr[3].makeNop();
instr[4].makeNop();
}
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();
#else
@ -1881,6 +1910,7 @@ GetCPUID(uint32_t* cpuId)
X64 = 0x2,
ARM = 0x3,
MIPS = 0x4,
MIPS64 = 0x5,
ARCH_BITS = 3
};
@ -1900,6 +1930,10 @@ GetCPUID(uint32_t* cpuId)
MOZ_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
*cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
return true;
#elif defined(JS_CODEGEN_MIPS64)
MOZ_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
*cpuId = MIPS64 | (GetMIPSFlags() << ARCH_BITS);
return true;
#else
return false;
#endif

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

@ -746,7 +746,7 @@ class AsmJSModule
explicit RelativeLink(Kind kind)
{
#if defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
kind_ = kind;
#elif defined(JS_CODEGEN_ARM)
// On ARM, CodeLabels are only used to label raw pointers, so in
@ -757,14 +757,14 @@ class AsmJSModule
}
bool isRawPointerPatch() {
#if defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
return kind_ == RawPointer;
#else
return true;
#endif
}
#ifdef JS_CODEGEN_MIPS32
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
Kind kind_;
#endif
uint32_t patchAtOffset;

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

@ -7055,7 +7055,7 @@ GenerateEntry(ModuleValidator& m, unsigned exportIndex)
// Save the return address if it wasn't already saved by the call insn.
#if defined(JS_CODEGEN_ARM)
masm.push(lr);
#elif defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.push(ra);
#elif defined(JS_CODEGEN_X86)
static const unsigned EntryFrameSize = sizeof(void*);
@ -7067,15 +7067,15 @@ GenerateEntry(ModuleValidator& m, unsigned exportIndex)
masm.PushRegsInMask(NonVolatileRegs);
MOZ_ASSERT(masm.framePushed() == FramePushedAfterSave);
// ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
// ARM and MIPS/MIPS64 have a globally-pinned GlobalReg (x64 uses RIP-relative
// addressing, x86 uses immediates in effective addresses). For the
// AsmJSGlobalRegBias addition, see Assembler-(mips,arm).h.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.movePtr(IntArgReg1, GlobalReg);
masm.addPtr(Imm32(AsmJSGlobalRegBias), GlobalReg);
#endif
// ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
// ARM, MIPS/MIPS64 and x64 have a globally-pinned HeapReg (x86 uses immediates in
// effective addresses). Loading the heap register depends on the global
// register already having been loaded.
masm.loadAsmJSHeapRegisterFromGlobalData();
@ -7384,7 +7384,7 @@ GenerateFFIInterpExit(ModuleValidator& m, const Signature& sig, unsigned exitInd
return !masm.oom() && m.finishGeneratingInterpExit(exitIndex, &begin, &profilingReturn);
}
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static const unsigned MaybeSavedGlobalReg = sizeof(void*);
#else
static const unsigned MaybeSavedGlobalReg = 0;
@ -7428,7 +7428,7 @@ GenerateFFIIonExit(ModuleValidator& m, const Signature& sig, unsigned exitIndex,
m.masm().append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
#elif defined(JS_CODEGEN_X86)
m.masm().append(AsmJSGlobalAccess(masm.movlWithPatch(Imm32(0), callee), globalDataOffset));
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.computeEffectiveAddress(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), callee);
#endif
@ -7464,7 +7464,7 @@ GenerateFFIIonExit(ModuleValidator& m, const Signature& sig, unsigned exitIndex,
// so they must be explicitly preserved. Only save GlobalReg since
// HeapReg must be reloaded (from global data) after the call since the
// heap may change during the FFI call.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
masm.storePtr(GlobalReg, Address(masm.getStackPointer(), ionFrameBytes));
#endif
@ -7580,7 +7580,7 @@ GenerateFFIIonExit(ModuleValidator& m, const Signature& sig, unsigned exitIndex,
}
// Reload the global register since Ion code can clobber any register.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
masm.loadPtr(Address(masm.getStackPointer(), ionFrameBytes), GlobalReg);
#endif
@ -7895,7 +7895,7 @@ GenerateAsyncInterruptExit(ModuleValidator& m, Label* throwLabel)
masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
masm.popFlags(); // after this, nothing that sets conditions
masm.ret(); // pop resumePC into PC
#elif defined(JS_CODEGEN_MIPS32)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
// Reserve space to store resumePC.
masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
// set to zero so we can use masm.framePushed() below.

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

@ -276,7 +276,14 @@ class LifoAlloc
}
MOZ_ALWAYS_INLINE
void* allocInfallible(size_t n) {
void* allocInfallibleOrAssert(size_t n) {
void* result = allocImpl(n);
MOZ_RELEASE_ASSERT(result, "[OOM] Is it really infallible?");
return result;
}
MOZ_ALWAYS_INLINE
void* allocInfallibleOrCrash(size_t n) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (void* result = allocImpl(n))
return result;
@ -284,6 +291,11 @@ class LifoAlloc
return nullptr;
}
MOZ_ALWAYS_INLINE
void* allocInfallible(size_t n) {
return allocInfallibleOrCrash(n);
}
// Ensures that enough space exists to satisfy N bytes worth of
// allocation requests, not necessarily contiguous. Note that this does
// not guarantee a successful single allocation of N bytes.

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

@ -5195,6 +5195,10 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
*/
bool isForDecl = false;
// True if a 'let' token at the head is parsed as an identifier instead of
// as starting a declaration.
bool letIsIdentifier = false;
/* Non-null when isForDecl is true for a 'for (let ...)' statement. */
RootedStaticBlockObject blockObj(context);
@ -5222,19 +5226,38 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
isForDecl = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
pn1 = variables(yieldHandling, PNK_VAR, InForInit);
} else if (tt == TOK_LET || tt == TOK_CONST) {
} else if (tt == TOK_LET || tt == TOK_CONST ||
(tt == TOK_NAME && tokenStream.nextName() == context->names().let)) {
handler.disableSyntaxParser();
bool constDecl = tt == TOK_CONST;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
isForDecl = true;
blockObj = StaticBlockObject::create(context);
if (!blockObj)
return null();
// Initialize the enclosing scope manually for the call to
// |variables| below.
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
nullptr, blockObj, DontHoistVars);
// Check for the backwards-compatibility corner case in sloppy
// mode like |for (let in e)| where the 'let' token should be
// parsed as an identifier.
bool parseDecl;
if (tt == TOK_NAME) {
if (!peekShouldParseLetDeclaration(&parseDecl, TokenStream::Operand))
return null();
letIsIdentifier = !parseDecl;
} else {
parseDecl = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
}
if (parseDecl) {
bool constDecl = tt == TOK_CONST;
isForDecl = true;
blockObj = StaticBlockObject::create(context);
if (!blockObj)
return null();
// Initialize the enclosing scope manually for the call to
// |variables| below.
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
nullptr, blockObj, DontHoistVars);
} else {
pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
}
} else {
// Pass |InProhibited| when parsing an expression so that |in|
// isn't parsed in a RelationalExpression as a binary operator.
@ -5309,9 +5332,17 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
bool isForIn, isForOf;
if (!matchInOrOf(&isForIn, &isForOf))
return null();
// In for-in loops, a 'let' token may be used as an identifier for
// backwards-compatibility reasons, e.g., |for (let in e)|. In for-of
// loops, a 'let' token is never parsed as an identifier. Forbid
// trying to parse a for-of loop if we have parsed a 'let' token as an
// identifier above.
//
// See ES6 13.7.5.1.
if (isForIn)
headKind = PNK_FORIN;
else if (isForOf)
else if (isForOf && !letIsIdentifier)
headKind = PNK_FOROF;
}
@ -5567,12 +5598,12 @@ Parser<SyntaxParseHandler>::forStatement(YieldHandling yieldHandling)
isForDecl = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
lhsNode = variables(yieldHandling, PNK_VAR, InForInit, &simpleForDecl);
}
else if (tt == TOK_CONST || tt == TOK_LET) {
} else if (tt == TOK_CONST || tt == TOK_LET ||
(tt == TOK_NAME && tokenStream.nextName() == context->names().let))
{
JS_ALWAYS_FALSE(abortIfSyntaxParser());
return null();
}
else {
} else {
lhsNode = expr(InProhibited, yieldHandling, TripledotProhibited);
}
if (!lhsNode)
@ -6627,6 +6658,71 @@ Parser<SyntaxParseHandler>::classDefinition(YieldHandling yieldHandling,
return SyntaxParseHandler::NodeFailure;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::shouldParseLetDeclaration(bool* parseDeclOut)
{
// 'let' is a reserved keyword in strict mode and we shouldn't get here.
MOZ_ASSERT(!pc->sc->strict());
TokenKind tt;
*parseDeclOut = false;
if (!tokenStream.peekToken(&tt))
return false;
switch (tt) {
case TOK_NAME:
// |let let| is disallowed per ES6 13.3.1.1.
*parseDeclOut = tokenStream.nextName() != context->names().let;
break;
case TOK_LC:
case TOK_LB:
// A following name is always a declaration.
//
// |let {| and |let [| are destructuring declarations.
*parseDeclOut = true;
break;
case TOK_LP:
// Only parse let blocks for 1.7 and 1.8. Do not expose deprecated let
// blocks to content.
*parseDeclOut = versionNumber() == JSVERSION_1_7 || versionNumber() == JSVERSION_1_8;
break;
default:
break;
}
return true;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::peekShouldParseLetDeclaration(bool* parseDeclOut,
TokenStream::Modifier modifier)
{
*parseDeclOut = false;
#ifdef DEBUG
TokenKind tt;
if (!tokenStream.peekToken(&tt, modifier))
return false;
MOZ_ASSERT(tt == TOK_NAME && tokenStream.nextName() == context->names().let);
#endif
tokenStream.consumeKnownToken(TOK_NAME, modifier);
if (!shouldParseLetDeclaration(parseDeclOut))
return false;
// Unget the TOK_NAME of 'let' if not parsing a declaration.
if (!*parseDeclOut)
tokenStream.ungetToken();
return true;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirectives)
@ -6696,6 +6792,16 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
}
case TOK_NAME: {
// 'let' is a contextual keyword in sloppy node. In strict mode, it is
// always lexed as TOK_LET.
if (tokenStream.currentName() == context->names().let) {
bool parseDecl;
if (!shouldParseLetDeclaration(&parseDecl))
return null();
if (parseDecl)
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
}
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();

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

@ -800,6 +800,15 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
ParseNodeKind headKind);
bool checkForHeadConstInitializers(Node pn1);
// Use when the current token is TOK_NAME and is known to be 'let'.
bool shouldParseLetDeclaration(bool* parseDeclOut);
// Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
// let declaration should be parsed, the TOK_NAME token of 'let' is
// consumed. Otherwise, the current token remains the TOK_NAME token of
// 'let'.
bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
public:
enum FunctionCallBehavior {
PermitAssignmentToFunctionCalls,

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

@ -999,6 +999,11 @@ TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
if (kw->tokentype != TOK_STRICT_RESERVED) {
if (kw->version <= versionNumber()) {
// Treat 'let' as an identifier and contextually a keyword in
// sloppy mode. It is always a keyword in strict mode.
if (kw->tokentype == TOK_LET && !strictMode())
return true;
// Working keyword.
if (ttp) {
*ttp = kw->tokentype;
@ -1006,12 +1011,6 @@ TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
}
return reportError(JSMSG_RESERVED_ID, kw->chars);
}
// The keyword is not in this version. Treat it as an identifier, unless
// it is let which we treat as TOK_STRICT_RESERVED by falling through to
// the code below (ES5 forbids it in strict mode).
if (kw->tokentype != TOK_LET)
return true;
}
// Strict reserved word.

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

@ -365,6 +365,13 @@ class MOZ_STACK_CLASS TokenStream
return currentToken().name();
}
PropertyName* nextName() const {
if (nextToken().type == TOK_YIELD)
return cx->names().yield;
MOZ_ASSERT(nextToken().type == TOK_NAME);
return nextToken().name();
}
bool isCurrentTokenAssignment() const {
return TokenKindIsAssignment(currentToken().type);
}
@ -999,12 +1006,12 @@ class MOZ_STACK_CLASS TokenStream
void updateLineInfoForEOL();
void updateFlagsForEOL();
const Token& nextToken() {
const Token& nextToken() const {
MOZ_ASSERT(hasLookahead());
return tokens[(cursor + 1) & ntokensMask];
}
bool hasLookahead() { return lookahead > 0; }
bool hasLookahead() const { return lookahead > 0; }
// Options used for parsing/tokenizing.
const ReadOnlyCompileOptions& options_;

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