mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 17:23:59 +00:00
Merge m-c to fx-team.
This commit is contained in:
commit
5f5fcba645
@ -253,13 +253,6 @@ endif
|
||||
ifdef BUILD_JS
|
||||
js/src/Makefile: subsrcdir := js/src
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
# Incorporate static tier directories into tests. This should be incorporated
|
||||
# into moz.build files someday.
|
||||
check::
|
||||
$(call SUBMAKE,$@,js/src)
|
||||
endif
|
||||
|
||||
ifdef MOZ_PSEUDO_DERECURSE
|
||||
# Interdependencies for parallel export.
|
||||
js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
|
||||
|
@ -99,22 +99,19 @@ LogDocShellState(nsIDocument* aDocumentNode)
|
||||
printf("docshell busy: ");
|
||||
|
||||
nsAutoCString docShellBusy;
|
||||
nsCOMPtr<nsISupports> container = aDocumentNode->GetContainer();
|
||||
if (container) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
||||
uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
|
||||
docShell->GetBusyFlags(&busyFlags);
|
||||
if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)
|
||||
printf("'none'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)
|
||||
printf("'busy'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)
|
||||
printf(", 'before page load'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)
|
||||
printf(", 'page loading'");
|
||||
} else {
|
||||
nsCOMPtr<nsIDocShell> docShell = aDocumentNode->GetDocShell();
|
||||
uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
|
||||
docShell->GetBusyFlags(&busyFlags);
|
||||
if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)
|
||||
printf("'none'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)
|
||||
printf("'busy'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)
|
||||
printf(", 'before page load'");
|
||||
if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)
|
||||
printf(", 'page loading'");
|
||||
|
||||
printf("[failed]");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -132,8 +129,7 @@ static void
|
||||
LogDocShellTree(nsIDocument* aDocumentNode)
|
||||
{
|
||||
if (aDocumentNode->IsActive()) {
|
||||
nsCOMPtr<nsISupports> container = aDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
treeItem->GetParent(getter_AddRefs(parentTreeItem));
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
|
||||
|
@ -200,8 +200,7 @@ nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
|
||||
nsIPresShell* ps = aPresShell;
|
||||
nsIDocument* documentNode = aPresShell->GetDocument();
|
||||
if (documentNode) {
|
||||
nsCOMPtr<nsISupports> container = documentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(documentNode->GetDocShell());
|
||||
if (treeItem) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
|
||||
treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
|
||||
|
@ -394,17 +394,14 @@ nsCoreUtils::GetDocShellFor(nsINode *aNode)
|
||||
if (!aNode)
|
||||
return nullptr;
|
||||
|
||||
nsCOMPtr<nsISupports> container = aNode->OwnerDoc()->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShell> docShell = aNode->OwnerDoc()->GetDocShell();
|
||||
return docShell.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
nsCoreUtils::IsRootDocument(nsIDocument *aDocument)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
||||
do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell();
|
||||
NS_ASSERTION(docShellTreeItem, "No document shell for document!");
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
@ -416,9 +413,7 @@ nsCoreUtils::IsRootDocument(nsIDocument *aDocument)
|
||||
bool
|
||||
nsCoreUtils::IsContentDocument(nsIDocument *aDocument)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
||||
do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell();
|
||||
NS_ASSERTION(docShellTreeItem, "No document shell tree item for document!");
|
||||
|
||||
int32_t contentType;
|
||||
@ -429,8 +424,7 @@ nsCoreUtils::IsContentDocument(nsIDocument *aDocument)
|
||||
bool
|
||||
nsCoreUtils::IsTabDocument(nsIDocument* aDocumentNode)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
treeItem->GetParent(getter_AddRefs(parentTreeItem));
|
||||
|
@ -377,10 +377,8 @@ Accessible::AccessKey() const
|
||||
nsIDocument* document = mContent->GetCurrentDoc();
|
||||
if (!document)
|
||||
return KeyBinding();
|
||||
nsCOMPtr<nsISupports> container = document->GetContainer();
|
||||
if (!container)
|
||||
return KeyBinding();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(document->GetDocShell());
|
||||
if (!treeItem)
|
||||
return KeyBinding();
|
||||
|
||||
@ -1294,9 +1292,7 @@ Accessible::NativeAttributes()
|
||||
nsCoreUtils::GetRoleContent(doc));
|
||||
|
||||
// Allow ARIA live region markup from outer documents to override
|
||||
nsCOMPtr<nsISupports> container = doc->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
||||
do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
|
||||
if (!docShellTreeItem)
|
||||
break;
|
||||
|
||||
|
@ -244,6 +244,16 @@ public:
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if accessible is unavailable.
|
||||
*/
|
||||
bool Unavailable() const
|
||||
{
|
||||
uint64_t state = NativelyUnavailable() ? states::UNAVAILABLE : 0;
|
||||
ApplyARIAState(&state);
|
||||
return state & states::UNAVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the states of accessible, not taking into account ARIA states.
|
||||
* Use State() to get complete set of states.
|
||||
|
@ -688,8 +688,7 @@ DocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame)
|
||||
nsresult
|
||||
DocAccessible::AddEventListeners()
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(mDocumentNode->GetDocShell());
|
||||
|
||||
// We want to add a command observer only if the document is content and has
|
||||
// an editor.
|
||||
@ -721,8 +720,7 @@ DocAccessible::RemoveEventListeners()
|
||||
if (mDocumentNode) {
|
||||
mDocumentNode->RemoveObserver(this);
|
||||
|
||||
nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(mDocumentNode->GetDocShell());
|
||||
NS_ASSERTION(docShellTreeItem, "doc should support nsIDocShellTreeItem.");
|
||||
|
||||
if (docShellTreeItem) {
|
||||
@ -870,7 +868,12 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
|
||||
aAttribute == nsGkAtoms::aria_pressed) {
|
||||
mARIAAttrOldValue = (aModType != nsIDOMMutationEvent::ADDITION) ?
|
||||
nsAccUtils::GetARIAToken(aElement, aAttribute) : nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_disabled ||
|
||||
aAttribute == nsGkAtoms::disabled)
|
||||
mStateBitWasOn = accessible->Unavailable();
|
||||
}
|
||||
|
||||
void
|
||||
@ -938,22 +941,24 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
|
||||
|
||||
// Universal boolean properties that don't require a role. Fire the state
|
||||
// change when disabled or aria-disabled attribute is set.
|
||||
// Note. Checking the XUL or HTML namespace would not seem to gain us
|
||||
// anything, because disabled attribute really is going to mean the same
|
||||
// thing in any namespace.
|
||||
// Note. We use the attribute instead of the disabled state bit because
|
||||
// ARIA's aria-disabled does not affect the disabled state bit.
|
||||
if (aAttribute == nsGkAtoms::disabled ||
|
||||
aAttribute == nsGkAtoms::aria_disabled) {
|
||||
|
||||
// Note. Checking the XUL or HTML namespace would not seem to gain us
|
||||
// anything, because disabled attribute really is going to mean the same
|
||||
// thing in any namespace.
|
||||
|
||||
// Note. We use the attribute instead of the disabled state bit because
|
||||
// ARIA's aria-disabled does not affect the disabled state bit.
|
||||
// Do nothing if state wasn't changed (like @aria-disabled was removed but
|
||||
// @disabled is still presented).
|
||||
if (aAccessible->Unavailable() == mStateBitWasOn)
|
||||
return;
|
||||
|
||||
nsRefPtr<AccEvent> enabledChangeEvent =
|
||||
new AccStateChangeEvent(aAccessible, states::ENABLED);
|
||||
new AccStateChangeEvent(aAccessible, states::ENABLED, mStateBitWasOn);
|
||||
FireDelayedEvent(enabledChangeEvent);
|
||||
|
||||
nsRefPtr<AccEvent> sensitiveChangeEvent =
|
||||
new AccStateChangeEvent(aAccessible, states::SENSITIVE);
|
||||
new AccStateChangeEvent(aAccessible, states::SENSITIVE, mStateBitWasOn);
|
||||
FireDelayedEvent(sensitiveChangeEvent);
|
||||
return;
|
||||
}
|
||||
@ -1987,8 +1992,7 @@ DocAccessible::ShutdownChildrenInSubtree(Accessible* aAccessible)
|
||||
bool
|
||||
DocAccessible::IsLoadEventTarget() const
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem = mDocumentNode->GetDocShell();
|
||||
NS_ASSERTION(treeItem, "No document shell for document!");
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
|
@ -533,10 +533,16 @@ protected:
|
||||
nsCOMPtr<nsIContent> mAnchorJumpElm;
|
||||
|
||||
/**
|
||||
* Keep the ARIA attribute old value that is initialized by
|
||||
* AttributeWillChange and used by AttributeChanged notifications.
|
||||
* A generic state (see items below) before the attribute value was changed.
|
||||
* @see AttributeWillChange and AttributeChanged notifications.
|
||||
*/
|
||||
nsIAtom* mARIAAttrOldValue;
|
||||
union {
|
||||
// ARIA attribute value
|
||||
nsIAtom* mARIAAttrOldValue;
|
||||
|
||||
// True if the accessible state bit was on
|
||||
bool mStateBitWasOn;
|
||||
};
|
||||
|
||||
nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
|
||||
|
||||
|
@ -23,7 +23,7 @@ GetHRESULT(nsresult aResult)
|
||||
case NS_OK:
|
||||
return S_OK;
|
||||
|
||||
case NS_ERROR_INVALID_ARG: case NS_ERROR_INVALID_POINTER:
|
||||
case NS_ERROR_INVALID_ARG:
|
||||
return E_INVALIDARG;
|
||||
|
||||
case NS_ERROR_OUT_OF_MEMORY:
|
||||
|
@ -1959,7 +1959,12 @@ var gA11yEventObserver =
|
||||
var type = eventTypeToString(event.eventType);
|
||||
var info = "Event type: " + type;
|
||||
|
||||
if (event instanceof nsIAccessibleTextChangeEvent) {
|
||||
if (event instanceof nsIAccessibleStateChangeEvent) {
|
||||
var stateStr = statesToString(event.isExtraState ? 0 : event.state,
|
||||
event.isExtraState ? event.state : 0);
|
||||
info += ", state: " + stateStr + ", is enabled: " + event.isEnabled;
|
||||
|
||||
} else if (event instanceof nsIAccessibleTextChangeEvent) {
|
||||
info += ", start: " + event.start + ", length: " + event.length +
|
||||
", " + (event.isInserted ? "inserted" : "removed") +
|
||||
" text: " + event.modifiedText;
|
||||
|
@ -143,18 +143,46 @@
|
||||
new stateChangeChecker(aState, aIsExtraState, true, getNode(aID))
|
||||
];
|
||||
|
||||
this.invoke = function dupeStateChange_invoke()
|
||||
this.invoke = function oppositeStateChange_invoke()
|
||||
{
|
||||
getNode(aID).setAttribute(aAttr, "false");
|
||||
getNode(aID).setAttribute(aAttr, "true");
|
||||
}
|
||||
|
||||
this.getID = function dupeStateChange_getID()
|
||||
this.getID = function oppositeStateChange_getID()
|
||||
{
|
||||
return "opposite state change events";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change concomitant ARIA and native attribute at once.
|
||||
*/
|
||||
function echoingStateChange(aID, aARIAAttr, aAttr, aValue,
|
||||
aState, aIsExtraState, aIsEnabled)
|
||||
{
|
||||
this.eventSeq = [
|
||||
new stateChangeChecker(aState, aIsExtraState, aIsEnabled, getNode(aID))
|
||||
];
|
||||
|
||||
this.invoke = function echoingStateChange_invoke()
|
||||
{
|
||||
if (aValue == null) {
|
||||
getNode(aID).removeAttribute(aARIAAttr);
|
||||
getNode(aID).removeAttribute(aAttr);
|
||||
|
||||
} else {
|
||||
getNode(aID).setAttribute(aARIAAttr, aValue);
|
||||
getNode(aID).setAttribute(aAttr, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
this.getID = function echoingStateChange_getID()
|
||||
{
|
||||
return "enchoing ARIA and native attributes change";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Do tests
|
||||
|
||||
@ -193,6 +221,11 @@
|
||||
gQueue.push(new oppositeStateChange("div", "aria-busy",
|
||||
STATE_BUSY, false));
|
||||
|
||||
gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", "true",
|
||||
EXT_STATE_ENABLED, true, false));
|
||||
gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", null,
|
||||
EXT_STATE_ENABLED, true, true));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -223,6 +256,11 @@
|
||||
title="Fire statechange event whenever checked state is changed not depending on focused state">
|
||||
Bug 788389
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=926812"
|
||||
title="State change event not fired when both disabled and aria-disabled are toggled">
|
||||
Bug 926812
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
@ -242,6 +280,8 @@
|
||||
|
||||
<div id="div"></div>
|
||||
|
||||
<input id="text1">
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "14a570c0af0ad29420a47318576fc365ebf7b10a",
|
||||
"revision": "89c57a31cebe0d8d94cbce4bcb47788b18f4fe84",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ const prefs = new Preferences("datareporting.healthreport.");
|
||||
|
||||
let healthReportWrapper = {
|
||||
init: function () {
|
||||
if (!reporter) {
|
||||
healthReportWrapper.handleInitFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
reporter.onInit().then(healthReportWrapper.refreshPayload,
|
||||
healthReportWrapper.handleInitFailure);
|
||||
|
||||
|
@ -475,8 +475,7 @@ function openCacheEntry(key, cb)
|
||||
},
|
||||
onCacheEntryAvailable: function(entry, isNew, appCache, status) {
|
||||
cb(entry);
|
||||
},
|
||||
get mainThreadOnly() { return true; }
|
||||
}
|
||||
};
|
||||
diskStorage.asyncOpenURI(Services.io.newURI(key, null, null), "", nsICacheStorage.OPEN_READONLY, checkCacheListener);
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ support-files =
|
||||
[browser_privatebrowsing_DownloadLastDirWithCPS.js]
|
||||
[browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
|
||||
[browser_privatebrowsing_aboutSessionRestore.js]
|
||||
# [browser_privatebrowsing_cache.js]
|
||||
# Disabled for too many intermittent failures (bug 895390)
|
||||
[browser_privatebrowsing_cache.js]
|
||||
[browser_privatebrowsing_certexceptionsui.js]
|
||||
[browser_privatebrowsing_concurrent.js]
|
||||
[browser_privatebrowsing_cookieacceptdialog.js]
|
||||
|
@ -60,10 +60,6 @@ DEBUGGER_INFO = {
|
||||
"args": "-q --args"
|
||||
},
|
||||
|
||||
"cgdb": {
|
||||
"interactive": True,
|
||||
"args": "-q --args"
|
||||
},
|
||||
"cgdb": {
|
||||
"interactive": True,
|
||||
"args": "-q --args"
|
||||
|
@ -16,6 +16,7 @@ Important Concepts
|
||||
:maxdepth: 1
|
||||
|
||||
build-overview
|
||||
supported-configurations
|
||||
Mozconfig Files <mozconfigs>
|
||||
mozbuild-files
|
||||
mozbuild-symbols
|
||||
|
55
build/docs/supported-configurations.rst
Normal file
55
build/docs/supported-configurations.rst
Normal file
@ -0,0 +1,55 @@
|
||||
.. _build_supported_configurations:
|
||||
|
||||
========================
|
||||
Supported Configurations
|
||||
========================
|
||||
|
||||
This page attempts to document supported build configurations.
|
||||
|
||||
Windows
|
||||
=======
|
||||
|
||||
We support building on Windows XP and newer operating systems using
|
||||
Visual Studio 2010 and newer.
|
||||
|
||||
The following are not fully supported by Mozilla (but may work):
|
||||
|
||||
* Building without the latest *MozillaBuild* Windows development
|
||||
environment
|
||||
* Building with Mingw or any other non-Visual Studio toolchain.
|
||||
|
||||
OS X
|
||||
====
|
||||
|
||||
We support building on OS X 10.6 and newer with the OS X 10.6 SDK.
|
||||
|
||||
The tree should build with the following OS X releases and SDK versions:
|
||||
|
||||
* 10.6 Snow Leopard
|
||||
* 10.7 Lion
|
||||
* 10.8 Mountain Lion
|
||||
* 10.9 Mavericks
|
||||
|
||||
The tree requires building with Clang 3.3 and newer. This corresponds to
|
||||
version of 4.2 of Apple's Clang that ships with Xcode. This corresponds
|
||||
to Xcode 4.6 and newer. Xcode 4.6 only runs on OS X 10.7.4 and newer.
|
||||
So, OS X 10.6 users will need to install a non-Apple toolchain. Running
|
||||
``mach bootstrap`` should install an appropriate toolchain from Homebrew
|
||||
or MacPorts automatically.
|
||||
|
||||
The tree should build with GCC 4.4 and newer on OS X. However, this
|
||||
build configuration isn't as widely used (and differs from what Mozilla
|
||||
uses to produce OS X builds), so it's recommended to stick with Clang.
|
||||
|
||||
Linux
|
||||
=====
|
||||
|
||||
Linux 2.6 and later kernels are supported.
|
||||
|
||||
Most distributions are supported as long as the proper package
|
||||
dependencies are in place. Running ``mach bootstrap`` should install
|
||||
packages for popular Linux distributions. ``configure`` will typically
|
||||
detect missing dependencies and inform you how to disable features to
|
||||
work around unsatisfied dependencies.
|
||||
|
||||
Clang 3.3 or GCC 4.4 is required to build the tree.
|
@ -27,8 +27,10 @@
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "mozilla/dom/URL.h"
|
||||
|
||||
nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
|
||||
using mozilla::dom::IsChromeURI;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -371,14 +373,6 @@ nsChromeRegistry::FlushSkinCaches()
|
||||
NS_CHROME_FLUSH_SKINS_TOPIC, nullptr);
|
||||
}
|
||||
|
||||
static bool IsChromeURI(nsIURI* aURI)
|
||||
{
|
||||
bool isChrome=false;
|
||||
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXXbsmedberg: move this to windowmediator
|
||||
nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
|
||||
{
|
||||
|
159
config/check_vanilla_allocations.py
Normal file
159
config/check_vanilla_allocations.py
Normal file
@ -0,0 +1,159 @@
|
||||
# vim: set ts=8 sts=4 et sw=4 tw=79:
|
||||
# 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/.
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# All heap allocations in SpiderMonkey must go through js_malloc, js_calloc,
|
||||
# js_realloc, and js_free. This is so that any embedder who uses a custom
|
||||
# allocator (by defining JS_USE_CUSTOM_ALLOCATOR) will see all heap allocation
|
||||
# go through that custom allocator.
|
||||
#
|
||||
# Therefore, the presence of any calls to "vanilla" allocation/free functions
|
||||
# (e.g. malloc(), free()) is a bug.
|
||||
#
|
||||
# This script checks for the presence of such disallowed vanilla
|
||||
# allocation/free function in SpiderMonkey when it's built as a library. It
|
||||
# relies on |nm| from the GNU binutils, and so only works on Linux, but one
|
||||
# platform is good enough to catch almost all violations.
|
||||
#
|
||||
# This checking is only 100% reliable in a JS_USE_CUSTOM_ALLOCATOR build in
|
||||
# which the default definitions of js_malloc et al (in Utility.h) -- which call
|
||||
# malloc et al -- are replaced with empty definitions. This is because the
|
||||
# presence and possible inlining of the default js_malloc et al can cause
|
||||
# malloc/calloc/realloc/free calls show up in unpredictable places.
|
||||
#
|
||||
# Unfortunately, that configuration cannot be tested on Mozilla's standard
|
||||
# testing infrastructure. Instead, by default this script only tests that none
|
||||
# of the other vanilla allocation/free functions (operator new, memalign, etc)
|
||||
# are present. If given the --aggressive flag, it will also check for
|
||||
# malloc/calloc/realloc/free.
|
||||
#
|
||||
# Note: We don't check for |operator delete| and |operator delete[]|. These
|
||||
# can be present somehow due to virtual destructors, but this is not too
|
||||
# because vanilla delete/delete[] calls don't make sense without corresponding
|
||||
# vanilla new/new[] calls, and any explicit calls will be caught by Valgrind's
|
||||
# mismatched alloc/free checking.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# The obvious way to implement this script is to search for occurrences of
|
||||
# malloc et al, succeed if none are found, and fail is some are found.
|
||||
# However, "none are found" does not necessarily mean "none are present" --
|
||||
# this script could be buggy. (Or the output format of |nm| might change in
|
||||
# the future.)
|
||||
#
|
||||
# So jsutil.cpp deliberately contains a (never-called) function that contains a
|
||||
# single use of all the vanilla allocation/free functions. And this script
|
||||
# fails if it (a) finds uses of those functions in files other than jsutil.cpp,
|
||||
# *or* (b) fails to find them in jsutil.cpp.
|
||||
|
||||
# Tracks overall success of the test.
|
||||
has_failed = False
|
||||
|
||||
|
||||
def fail(msg):
|
||||
print('TEST-UNEXPECTED-FAIL | check_vanilla_allocations.py |', msg)
|
||||
global has_failed
|
||||
has_failed = True
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--aggressive', action='store_true',
|
||||
help='also check for malloc, calloc, realloc and free')
|
||||
parser.add_argument('file', type=str,
|
||||
help='name of the file to check')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Run |nm|. Options:
|
||||
# -u: show only undefined symbols
|
||||
# -C: demangle symbol names
|
||||
# -l: show a filename and line number for each undefined symbol
|
||||
cmd = ['nm', '-u', '-C', '-l', args.file]
|
||||
lines = subprocess.check_output(cmd, universal_newlines=True,
|
||||
stderr=subprocess.PIPE).split('\n')
|
||||
|
||||
# alloc_fns contains all the vanilla allocation/free functions that we look
|
||||
# for. Regexp chars are escaped appropriately.
|
||||
|
||||
alloc_fns = [
|
||||
# Matches |operator new(unsigned T)|, where |T| is |int| or |long|.
|
||||
r'operator new\(unsigned',
|
||||
|
||||
# Matches |operator new[](unsigned T)|, where |T| is |int| or |long|.
|
||||
r'operator new\[\]\(unsigned',
|
||||
|
||||
r'memalign',
|
||||
# These two aren't available on all Linux configurations.
|
||||
#r'posix_memalign',
|
||||
#r'aligned_alloc',
|
||||
r'valloc',
|
||||
r'strdup'
|
||||
]
|
||||
|
||||
if args.aggressive:
|
||||
alloc_fns += [
|
||||
r'malloc',
|
||||
r'calloc',
|
||||
r'realloc',
|
||||
r'free'
|
||||
]
|
||||
|
||||
# This is like alloc_fns, but regexp chars are not escaped.
|
||||
alloc_fns_unescaped = [fn.translate(None, r'\\') for fn in alloc_fns]
|
||||
|
||||
# This regexp matches the relevant lines in the output of |nm|, which look
|
||||
# like the following.
|
||||
#
|
||||
# U malloc /path/to/objdir/dist/include/js/Utility.h:142
|
||||
#
|
||||
alloc_fns_re = r'U (' + r'|'.join(alloc_fns) + r').*\/([\w\.]+):(\d+)$'
|
||||
|
||||
# This tracks which allocation/free functions have been seen in jsutil.cpp.
|
||||
jsutil_cpp = set([])
|
||||
|
||||
for line in lines:
|
||||
m = re.search(alloc_fns_re, line)
|
||||
if m is None:
|
||||
continue
|
||||
|
||||
fn = m.group(1)
|
||||
filename = m.group(2)
|
||||
linenum = m.group(3)
|
||||
if filename == 'jsutil.cpp':
|
||||
jsutil_cpp.add(fn)
|
||||
else:
|
||||
# An allocation is present in a non-special file. Fail!
|
||||
fail("'" + fn + "' present at " + filename + ':' + linenum)
|
||||
|
||||
|
||||
# Check that all functions we expect are used in jsutil.cpp. (This will
|
||||
# fail if the function-detection code breaks at any point.)
|
||||
for fn in alloc_fns_unescaped:
|
||||
if fn not in jsutil_cpp:
|
||||
fail("'" + fn + "' isn't used as expected in jsutil.cpp")
|
||||
else:
|
||||
jsutil_cpp.remove(fn)
|
||||
|
||||
# This should never happen, but check just in case.
|
||||
if jsutil_cpp:
|
||||
fail('unexpected allocation fns used in jsutil.cpp: ' +
|
||||
', '.join(jsutil_cpp))
|
||||
|
||||
if has_failed:
|
||||
sys.exit(1)
|
||||
|
||||
print('TEST-PASS | check_vanilla_allocations.py | ok')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -1,80 +0,0 @@
|
||||
# /bin/bash
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# We must avoid using the vanilla new/new[] operators (and consequently, the
|
||||
# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why.
|
||||
#
|
||||
# This script:
|
||||
# - Detects if any of the vanilla new/new[] operators are used in a file.
|
||||
# Its exit code is 1 if it found some, and 0 if it didn't.
|
||||
# - Doesn't detect delete/delete[] because it appears they can be present
|
||||
# somehow due to virtual destructors, but this is ok because vanilla
|
||||
# delete/delete[] calls don't make sense without corresponding new/new[]
|
||||
# calls, and any explicit calls will be caught by Valgrind's mismatched
|
||||
# alloc/free checking.
|
||||
# - Doesn't detect the 'nothrow' variants, which are ok but probably still
|
||||
# best avoided.
|
||||
# - Is designed to only run on Linux (though it may also work on Mac); one
|
||||
# platform will be enough to catch any violations.
|
||||
#
|
||||
# If this script fails:
|
||||
# - You need to find the uses of vanilla new/delete and replace them with
|
||||
# {js::OffTheBooks,JSContext,JSRuntime}::{new_,/array_new}.
|
||||
# - Run this script on each of the .o files, that should narrow it down.
|
||||
# - After that, one way to find them is to run 'objdump -r -C' on the
|
||||
# relevant .o files. For example, you might search for 'operator new' and
|
||||
# find a record like this:
|
||||
#
|
||||
# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
|
||||
# OFFSET TYPE VALUE
|
||||
# 00000009 R_386_PC32 __i686.get_pc_thunk.bx
|
||||
# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_
|
||||
# 0000001b R_386_PLT32 operator new(unsigned int)
|
||||
# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int)
|
||||
# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool()
|
||||
# 00000052 R_386_PLT32 operator delete(void*)
|
||||
#
|
||||
# This says that vanilla 'new' and 'delete' are both used in
|
||||
# JSC::ExecutablePool::create(unsigned int). This doesn't always work,
|
||||
# though. (Nb: use 'c++filt' to demangle names like
|
||||
# _ZN3JSC14ExecutablePool6createEj.)
|
||||
#
|
||||
# If that doesn't work, use grep.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
if [ -z $1 ] ; then
|
||||
echo "usage: find_vanilla_new_calls <file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=$1
|
||||
|
||||
if [ ! -f $file ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpfile1=`mktemp`
|
||||
tmpfile2=`mktemp`
|
||||
nm -C $file > $tmpfile1
|
||||
|
||||
# Need to double-escape '[' and ']' to stop grep from interpreting them
|
||||
# specially.
|
||||
grep '^operator new(unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep '^operator new(unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
grep '^operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep '^operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
rm -f $tmpfile1
|
||||
|
||||
if [ -s $tmpfile2 ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below"
|
||||
cat $tmpfile2
|
||||
echo
|
||||
rm -f $tmpfile2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "TEST-PASS | find_vanilla_new_calls | ok"
|
||||
echo
|
||||
|
||||
exit 0
|
22
configure.in
22
configure.in
@ -3942,6 +3942,7 @@ MOZ_OPUS=1
|
||||
MOZ_WEBM=1
|
||||
MOZ_DIRECTSHOW=
|
||||
MOZ_WMF=
|
||||
MOZ_FMP4=
|
||||
MOZ_WEBRTC=1
|
||||
MOZ_PEERCONNECTION=
|
||||
MOZ_SRTP=
|
||||
@ -5275,6 +5276,26 @@ if test -n "$MOZ_WMF"; then
|
||||
MOZ_CUBEB=1
|
||||
fi;
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Built-in fragmented MP4 support.
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_WMF"; then
|
||||
dnl Enable fragmented MP4 parser on Windows by default.
|
||||
dnl We will also need to enable it on other platforms as we implement
|
||||
dnl platform decoder support there too.
|
||||
MOZ_FMP4=1
|
||||
fi
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(fmp4,
|
||||
[ --disable-fmp4 Disable support for in built Fragmented MP4 parsing],
|
||||
MOZ_FMP4=,
|
||||
MOZ_FMP4=1)
|
||||
|
||||
if test -n "$MOZ_FMP4"; then
|
||||
AC_DEFINE(MOZ_FMP4)
|
||||
fi;
|
||||
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable media plugin support
|
||||
dnl ========================================================
|
||||
@ -8627,6 +8648,7 @@ AC_SUBST(MOZ_TREMOR)
|
||||
AC_SUBST(MOZ_OPUS)
|
||||
AC_SUBST(MOZ_WEBM)
|
||||
AC_SUBST(MOZ_WMF)
|
||||
AC_SUBST(MOZ_FMP4)
|
||||
AC_SUBST(MOZ_DIRECTSHOW)
|
||||
AC_SUBST(MOZ_MEDIA_PLUGINS)
|
||||
AC_SUBST(MOZ_APPLEMEDIA)
|
||||
|
@ -1886,6 +1886,15 @@ public:
|
||||
*/
|
||||
static bool IsSubDocumentTabbable(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Returns if aNode ignores user focus.
|
||||
*
|
||||
* @param aNode node to test
|
||||
*
|
||||
* @return Whether the node ignores user focus.
|
||||
*/
|
||||
static bool IsUserFocusIgnored(nsINode* aNode);
|
||||
|
||||
/**
|
||||
* Flushes the layout tree (recursively)
|
||||
*
|
||||
|
@ -34,8 +34,8 @@ enum nsLinkState {
|
||||
|
||||
// IID for the nsIContent interface
|
||||
#define NS_ICONTENT_IID \
|
||||
{ 0x976f4cd1, 0xbdfc, 0x4a1e, \
|
||||
{ 0x82, 0x46, 0x1c, 0x13, 0x9c, 0xd3, 0x73, 0x7f } }
|
||||
{ 0x34117ca3, 0x45d0, 0x479e, \
|
||||
{ 0x91, 0x30, 0x54, 0x49, 0xa9, 0x5f, 0x25, 0x99 } }
|
||||
|
||||
/**
|
||||
* A node of content in a document's content model. This interface
|
||||
@ -557,12 +557,8 @@ public:
|
||||
* > 0 can be tabbed to in the order specified by this value
|
||||
* @return whether the content is focusable via mouse, kbd or script.
|
||||
*/
|
||||
virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false)
|
||||
{
|
||||
if (aTabIndex)
|
||||
*aTabIndex = -1; // Default, not tabbable
|
||||
return false;
|
||||
}
|
||||
bool IsFocusable(int32_t* aTabIndex = nullptr, bool aWithMouse = false);
|
||||
virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse);
|
||||
|
||||
/**
|
||||
* The method focuses (or activates) element that accesskey is bound to. It is
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsPropertyTable.h" // for member
|
||||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/dom/DocumentBinding.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "Units.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsClassHashtable.h"
|
||||
@ -28,6 +29,8 @@ class imgIRequest;
|
||||
class nsAString;
|
||||
class nsBindingManager;
|
||||
class nsCSSStyleSheet;
|
||||
class nsIDocShell;
|
||||
class nsDocShell;
|
||||
class nsDOMNavigationTiming;
|
||||
class nsDOMTouchList;
|
||||
class nsEventStates;
|
||||
@ -1150,22 +1153,23 @@ public:
|
||||
* Set the container (docshell) for this document. Virtual so that
|
||||
* docshell can call it.
|
||||
*/
|
||||
virtual void SetContainer(nsISupports *aContainer);
|
||||
virtual void SetContainer(nsDocShell* aContainer);
|
||||
|
||||
/**
|
||||
* Get the container (docshell) for this document.
|
||||
*/
|
||||
already_AddRefed<nsISupports> GetContainer() const
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = do_QueryReferent(mDocumentContainer);
|
||||
return container.forget();
|
||||
}
|
||||
virtual nsISupports* GetContainer() const;
|
||||
|
||||
/**
|
||||
* Get the container's load context for this document.
|
||||
*/
|
||||
nsILoadContext* GetLoadContext() const;
|
||||
|
||||
/**
|
||||
* Get docshell the for this document.
|
||||
*/
|
||||
nsIDocShell* GetDocShell() const;
|
||||
|
||||
/**
|
||||
* Set and get XML declaration. If aVersion is null there is no declaration.
|
||||
* aStandalone takes values -1, 0 and 1 indicating respectively that there
|
||||
@ -1526,7 +1530,7 @@ public:
|
||||
void SetDisplayDocument(nsIDocument* aDisplayDocument)
|
||||
{
|
||||
NS_PRECONDITION(!GetShell() &&
|
||||
!nsCOMPtr<nsISupports>(GetContainer()) &&
|
||||
!GetContainer() &&
|
||||
!GetWindow(),
|
||||
"Shouldn't set mDisplayDocument on documents that already "
|
||||
"have a presentation or a docshell or a window");
|
||||
@ -1696,7 +1700,7 @@ public:
|
||||
* @param aCloneContainer The container for the clone document.
|
||||
*/
|
||||
virtual already_AddRefed<nsIDocument>
|
||||
CreateStaticClone(nsISupports* aCloneContainer);
|
||||
CreateStaticClone(nsIDocShell* aCloneContainer);
|
||||
|
||||
/**
|
||||
* If this document is a static clone, this returns the original
|
||||
@ -2227,7 +2231,7 @@ protected:
|
||||
|
||||
nsWeakPtr mDocumentLoadGroup;
|
||||
|
||||
nsWeakPtr mDocumentContainer;
|
||||
mozilla::WeakPtr<nsDocShell> mDocumentContainer;
|
||||
|
||||
nsCString mCharacterSet;
|
||||
int32_t mCharacterSetSource;
|
||||
@ -2390,6 +2394,14 @@ protected:
|
||||
// caches.
|
||||
bool mDidDocumentOpen;
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* This is true while FlushPendingLinkUpdates executes. Calls to
|
||||
* [Un]RegisterPendingLinkUpdate will assert when this is true.
|
||||
*/
|
||||
bool mIsLinkUpdateRegistrationsForbidden;
|
||||
#endif
|
||||
|
||||
// The document's script global object, the object from which the
|
||||
// document can get its script context and scope. This is the
|
||||
// *inner* window object.
|
||||
|
@ -16,7 +16,7 @@ interface nsIGlobalObject;
|
||||
interface nsIInputStream;
|
||||
interface nsIDOMBlob;
|
||||
|
||||
[scriptable, builtinclass, uuid(ac97e161-9f1d-4163-adc9-e9a59e18682c)]
|
||||
[scriptable, builtinclass, uuid(5ced7e7a-e2c3-4563-a57d-31b97ce64dc5)]
|
||||
interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
|
||||
// event handler attributes
|
||||
};
|
||||
|
@ -838,6 +838,33 @@ nsIContent::AttrValueIs(int32_t aNameSpaceID,
|
||||
AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse)
|
||||
{
|
||||
bool focusable = IsFocusableInternal(aTabIndex, aWithMouse);
|
||||
// Ensure that the return value and aTabIndex are consistent in the case
|
||||
// we're in userfocusignored context.
|
||||
if (focusable || (aTabIndex && *aTabIndex != -1)) {
|
||||
if (nsContentUtils::IsUserFocusIgnored(this)) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return focusable;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
|
||||
{
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1; // Default, not tabbable
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsAttrValue*
|
||||
FragmentOrElement::DoGetClasses() const
|
||||
{
|
||||
|
@ -201,6 +201,7 @@ LOCAL_INCLUDES += [
|
||||
'/content/xslt/src/xpath',
|
||||
'/content/xul/content/src',
|
||||
'/content/xul/document/src',
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
'/dom/ipc',
|
||||
'/dom/workers',
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGenericHTMLFrameElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "nsHtml5Module.h"
|
||||
@ -378,6 +379,9 @@ nsContentUtils::Init()
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ADDREF(sSecurityManager);
|
||||
|
||||
// Getting the first context can trigger GC, so do this non-lazily.
|
||||
sXPConnect->InitSafeJSContext();
|
||||
|
||||
rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
|
||||
if (NS_FAILED(rv)) {
|
||||
// This makes life easier, but we can live without it.
|
||||
@ -387,7 +391,7 @@ nsContentUtils::Init()
|
||||
|
||||
rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -2622,10 +2626,7 @@ nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
|
||||
uint32_t appType = nsIDocShell::APP_TYPE_UNKNOWN;
|
||||
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aLoadingDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
||||
do_QueryInterface(container);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aLoadingDocument->GetDocShell();
|
||||
if (docShellTreeItem) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
|
||||
@ -3153,8 +3154,7 @@ nsContentUtils::IsChromeDoc(nsIDocument *aDocument)
|
||||
bool
|
||||
nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(aDoc->GetDocShell());
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
|
||||
if (docShellAsItem) {
|
||||
docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
|
||||
@ -3235,8 +3235,7 @@ nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument)
|
||||
return IsInChromeDocshell(aDocument->GetDisplayDocument());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> docContainer = aDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(docContainer));
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShell(aDocument->GetDocShell());
|
||||
int32_t itemType = nsIDocShellTreeItem::typeContent;
|
||||
if (docShell) {
|
||||
docShell->GetItemType(&itemType);
|
||||
@ -4976,8 +4975,7 @@ nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
|
||||
#ifdef MOZ_XUL
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm && aDocument) {
|
||||
nsCOMPtr<nsISupports> container = aDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellToHide = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell();
|
||||
if (docShellToHide)
|
||||
pm->HidePopupsInDocShell(docShellToHide);
|
||||
}
|
||||
@ -5877,8 +5875,7 @@ nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> container = subDoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShell> docShell = subDoc->GetDocShell();
|
||||
if (!docShell) {
|
||||
return false;
|
||||
}
|
||||
@ -5898,6 +5895,30 @@ nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
|
||||
return !zombieViewer;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsUserFocusIgnored(nsINode* aNode)
|
||||
{
|
||||
if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if our mozbrowser iframe ancestors has ignoreuserfocus attribute.
|
||||
while (aNode) {
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aNode);
|
||||
if (browserFrame &&
|
||||
aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::ignoreuserfocus) &&
|
||||
browserFrame->GetReallyIsBrowserOrApp()) {
|
||||
return true;
|
||||
}
|
||||
nsPIDOMWindow* win = aNode->OwnerDoc()->GetWindow();
|
||||
if (win) {
|
||||
aNode = win->GetFrameElementInternal();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
|
||||
{
|
||||
@ -5988,8 +6009,7 @@ nsContentUtils::FindPresShellForDocument(const nsIDocument* aDoc)
|
||||
return shell;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> container = doc->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
|
||||
while (docShellTreeItem) {
|
||||
// We may be in a display:none subdocument, or we may not have a presshell
|
||||
// created yet.
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "nsDocument.h"
|
||||
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Util.h"
|
||||
@ -33,7 +34,7 @@
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
@ -2203,7 +2204,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
||||
nsIScriptSecurityManager *securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
if (securityManager) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
|
||||
if (!docShell && aLoadGroup) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> cbs;
|
||||
@ -2699,7 +2700,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
|
||||
// ----- Enforce frame-ancestor policy on any applied policies
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
bool safeAncestry = false;
|
||||
|
||||
@ -2930,7 +2931,7 @@ nsresult
|
||||
nsDocument::GetAllowPlugins(bool * aAllowPlugins)
|
||||
{
|
||||
// First, we ask our docshell if it allows plugins.
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
|
||||
if (docShell) {
|
||||
docShell->GetAllowPlugins(aAllowPlugins);
|
||||
@ -3398,7 +3399,7 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
|
||||
if (aHeaderField == nsGkAtoms::refresh) {
|
||||
// We get into this code before we have a script global yet, so get to
|
||||
// our container via mDocumentContainer.
|
||||
nsCOMPtr<nsIRefreshURI> refresher = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
|
||||
if (refresher) {
|
||||
// Note: using mDocumentURI instead of mBaseURI here, for consistency
|
||||
// (used to just use the current URI of our webnavigation, but that
|
||||
@ -3479,7 +3480,7 @@ nsDocument::doCreateShell(nsPresContext* aContext,
|
||||
mPresShell = shell;
|
||||
|
||||
// Make sure to never paint if we belong to an invisible DocShell.
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell && docShell->IsInvisible())
|
||||
shell->SetNeverPainting(true);
|
||||
|
||||
@ -4212,29 +4213,41 @@ NotifyActivityChanged(nsIContent *aContent, void *aUnused)
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::SetContainer(nsISupports* aContainer)
|
||||
nsIDocument::SetContainer(nsDocShell* aContainer)
|
||||
{
|
||||
mDocumentContainer = do_GetWeakReference(aContainer);
|
||||
EnumerateFreezableElements(NotifyActivityChanged, nullptr);
|
||||
// Get the Docshell
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer);
|
||||
if (docShell) {
|
||||
int32_t itemType;
|
||||
docShell->GetItemType(&itemType);
|
||||
// check itemtype
|
||||
if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||
// check if same type root
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
|
||||
docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
|
||||
NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
|
||||
if (aContainer) {
|
||||
mDocumentContainer = aContainer->asWeakPtr();
|
||||
} else {
|
||||
mDocumentContainer = WeakPtr<nsDocShell>();
|
||||
}
|
||||
|
||||
if (sameTypeRoot == docShell) {
|
||||
static_cast<nsDocument*>(this)->SetIsTopLevelContentDocument(true);
|
||||
}
|
||||
EnumerateFreezableElements(NotifyActivityChanged, nullptr);
|
||||
if (!aContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Docshell
|
||||
int32_t itemType;
|
||||
aContainer->GetItemType(&itemType);
|
||||
// check itemtype
|
||||
if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||
// check if same type root
|
||||
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
|
||||
aContainer->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
|
||||
NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
|
||||
|
||||
if (sameTypeRoot == aContainer) {
|
||||
static_cast<nsDocument*>(this)->SetIsTopLevelContentDocument(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsIDocument::GetContainer() const
|
||||
{
|
||||
return static_cast<nsIDocShell*>(mDocumentContainer);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
||||
{
|
||||
@ -4292,7 +4305,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
||||
#endif
|
||||
|
||||
if (mAllowDNSPrefetch) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIWebNavigation> webNav =
|
||||
@ -4391,8 +4404,7 @@ nsDocument::GetWindowInternal() const
|
||||
// the docshell, the outer window might be still obtainable from the it.
|
||||
nsCOMPtr<nsPIDOMWindow> win;
|
||||
if (mRemovedFromDocShell) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> requestor =
|
||||
do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIInterfaceRequestor> requestor(mDocumentContainer);
|
||||
if (requestor) {
|
||||
// The docshell returns the outer window we are done.
|
||||
win = do_GetInterface(requestor);
|
||||
@ -7819,7 +7831,7 @@ nsDocument::GetLayoutHistoryState() const
|
||||
if (!mScriptGlobalObject) {
|
||||
state = mLayoutHistoryState;
|
||||
} else {
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocumentContainer));
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
docShell->GetLayoutHistoryState(getter_AddRefs(state));
|
||||
}
|
||||
@ -8340,7 +8352,7 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
||||
|
||||
// |mDocumentContainer| is the container of the document that is being
|
||||
// created and not the original container. See CreateStaticClone function().
|
||||
nsCOMPtr<nsIDocumentLoader> docLoader = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocumentLoader> docLoader(mDocumentContainer);
|
||||
if (docLoader) {
|
||||
docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
}
|
||||
@ -8353,8 +8365,7 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
||||
clone->ResetToURI(uri, loadGroup, NodePrincipal());
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsISupports> container = GetContainer();
|
||||
clone->SetContainer(container);
|
||||
clone->SetContainer(mDocumentContainer);
|
||||
}
|
||||
|
||||
// Set scripting object
|
||||
@ -8832,6 +8843,7 @@ nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
|
||||
void
|
||||
nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
|
||||
{
|
||||
MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
|
||||
mLinksToUpdate.PutEntry(aLink);
|
||||
mHasLinksToUpdate = true;
|
||||
}
|
||||
@ -8839,6 +8851,7 @@ nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
|
||||
void
|
||||
nsIDocument::UnregisterPendingLinkUpdate(Link* aLink)
|
||||
{
|
||||
MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
|
||||
if (!mHasLinksToUpdate)
|
||||
return;
|
||||
|
||||
@ -8855,28 +8868,32 @@ EnumeratePendingLinkUpdates(nsPtrHashKey<Link>* aEntry, void* aData)
|
||||
void
|
||||
nsIDocument::FlushPendingLinkUpdates()
|
||||
{
|
||||
MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
|
||||
if (!mHasLinksToUpdate)
|
||||
return;
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
#ifdef DEBUG
|
||||
AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden);
|
||||
mIsLinkUpdateRegistrationsForbidden = true;
|
||||
#endif
|
||||
mLinksToUpdate.EnumerateEntries(EnumeratePendingLinkUpdates, nullptr);
|
||||
mLinksToUpdate.Clear();
|
||||
mHasLinksToUpdate = false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument>
|
||||
nsIDocument::CreateStaticClone(nsISupports* aCloneContainer)
|
||||
nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(this);
|
||||
NS_ENSURE_TRUE(domDoc, nullptr);
|
||||
mCreatingStaticClone = true;
|
||||
|
||||
// Make document use different container during cloning.
|
||||
nsCOMPtr<nsISupports> originalContainer = GetContainer();
|
||||
SetContainer(aCloneContainer);
|
||||
nsRefPtr<nsDocShell> originalShell = mDocumentContainer.get();
|
||||
SetContainer(static_cast<nsDocShell*>(aCloneContainer));
|
||||
nsCOMPtr<nsIDOMNode> clonedNode;
|
||||
nsresult rv = domDoc->CloneNode(true, 1, getter_AddRefs(clonedNode));
|
||||
SetContainer(originalContainer);
|
||||
SetContainer(originalShell);
|
||||
|
||||
nsCOMPtr<nsIDocument> clonedDoc;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -10182,8 +10199,7 @@ nsDocument::FullScreenStackTop()
|
||||
static bool
|
||||
IsInActiveTab(nsIDocument* aDoc)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIDocShell> docshell = aDoc->GetDocShell();
|
||||
if (!docshell) {
|
||||
return false;
|
||||
}
|
||||
@ -10194,12 +10210,8 @@ IsInActiveTab(nsIDocument* aDoc)
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(container);
|
||||
if (!dsti) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
dsti->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
docshell->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
if (!rootItem) {
|
||||
return false;
|
||||
}
|
||||
@ -10544,7 +10556,7 @@ nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure)
|
||||
|
||||
// Ensure that all ancestor <iframe> elements have the allowfullscreen
|
||||
// boolean attribute set.
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
bool allowed = false;
|
||||
if (docShell) {
|
||||
docShell->GetFullscreenAllowed(&allowed);
|
||||
@ -10858,7 +10870,7 @@ nsDocument::ShouldLockPointer(Element* aElement, Element* aCurrentLock,
|
||||
|
||||
// Check if the element is in a document with a docshell.
|
||||
nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
|
||||
if (!nsCOMPtr<nsISupports>(ownerDoc->GetContainer())) {
|
||||
if (!ownerDoc->GetContainer()) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindow> ownerWindow = ownerDoc->GetWindow();
|
||||
@ -11429,12 +11441,13 @@ nsIDocument::SetContentTypeInternal(const nsACString& aType)
|
||||
nsILoadContext*
|
||||
nsIDocument::GetLoadContext() const
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = GetContainer();
|
||||
if (container) {
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
|
||||
return loadContext;
|
||||
}
|
||||
return nullptr;
|
||||
return mDocumentContainer;
|
||||
}
|
||||
|
||||
nsIDocShell*
|
||||
nsIDocument::GetDocShell() const
|
||||
{
|
||||
return mDocumentContainer;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -433,6 +433,7 @@ GK_ATOM(_if, "if")
|
||||
GK_ATOM(iframe, "iframe")
|
||||
GK_ATOM(ignorecase, "ignorecase")
|
||||
GK_ATOM(ignorekeys, "ignorekeys")
|
||||
GK_ATOM(ignoreuserfocus, "ignoreuserfocus")
|
||||
GK_ATOM(ilayer, "ilayer")
|
||||
GK_ATOM(image, "image")
|
||||
GK_ATOM(imageClickedPoint, "image-clicked-point")
|
||||
@ -719,7 +720,9 @@ GK_ATOM(onheld, "onheld")
|
||||
GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
|
||||
GK_ATOM(onholding, "onholding")
|
||||
GK_ATOM(oniccchange, "oniccchange")
|
||||
GK_ATOM(oniccdetected, "oniccdetected")
|
||||
GK_ATOM(oniccinfochange, "oniccinfochange")
|
||||
GK_ATOM(oniccundetected, "oniccundetected")
|
||||
GK_ATOM(onincoming, "onincoming")
|
||||
GK_ATOM(oninput, "oninput")
|
||||
GK_ATOM(oninvalid, "oninvalid")
|
||||
@ -1757,6 +1760,18 @@ GK_ATOM(onMozEdgeUIStarted, "onMozEdgeUIStarted")
|
||||
GK_ATOM(onMozEdgeUICanceled, "onMozEdgeUICanceled")
|
||||
GK_ATOM(onMozEdgeUICompleted, "onMozEdgeUICompleted")
|
||||
|
||||
// Pointer events
|
||||
GK_ATOM(onpointerdown, "onpointerdown")
|
||||
GK_ATOM(onpointermove, "onpointermove")
|
||||
GK_ATOM(onpointerup, "onpointerup")
|
||||
GK_ATOM(onpointercancel, "onpointercancel")
|
||||
GK_ATOM(onpointerover, "onpointerover")
|
||||
GK_ATOM(onpointerout, "onpointerout")
|
||||
GK_ATOM(onpointerenter, "onpointerenter")
|
||||
GK_ATOM(onpointerleave, "onpointerleave")
|
||||
GK_ATOM(ongotpointercapture, "ongotpointercapture")
|
||||
GK_ATOM(onlostpointercapture, "onlostpointercapture")
|
||||
|
||||
// orientation support
|
||||
GK_ATOM(ondevicemotion, "ondevicemotion")
|
||||
GK_ATOM(ondeviceorientation, "ondeviceorientation")
|
||||
|
@ -1331,15 +1331,15 @@ AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode)
|
||||
static nsresult
|
||||
CheckForOutdatedParent(nsINode* aParent, nsINode* aNode)
|
||||
{
|
||||
if (JSObject* existingObj = aNode->GetWrapper()) {
|
||||
if (JSObject* existingObjUnrooted = aNode->GetWrapper()) {
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JSObject*> existingObj(cx, existingObjUnrooted);
|
||||
nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
if (js::GetGlobalForObjectCrossCompartment(existingObj) !=
|
||||
global->GetGlobalJSObject()) {
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JSObject*> rooted(cx, existingObj);
|
||||
nsresult rv = ReparentWrapper(cx, rooted);
|
||||
nsresult rv = ReparentWrapper(cx, existingObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
@ -1359,8 +1359,7 @@ nsTreeSanitizer::Sanitize(nsIDocument* aDocument)
|
||||
// here that notifies / does not notify or that fires mutation events if
|
||||
// in tree.
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsISupports> container = aDocument->GetContainer();
|
||||
NS_PRECONDITION(!container, "The document is in a shell.");
|
||||
NS_PRECONDITION(!aDocument->GetContainer(), "The document is in a shell.");
|
||||
nsRefPtr<mozilla::dom::Element> root = aDocument->GetRootElement();
|
||||
NS_PRECONDITION(root->IsHTML(nsGkAtoms::html), "Not HTML root.");
|
||||
#endif
|
||||
|
8
content/canvas/crashtests/934939-1.html
Normal file
8
content/canvas/crashtests/934939-1.html
Normal file
@ -0,0 +1,8 @@
|
||||
<script type="text/javascript">
|
||||
function run() {
|
||||
var cx = canvas.getContext("2d");
|
||||
canvas.toDataURL("image/png");
|
||||
}
|
||||
</script>
|
||||
<body onload="run()">
|
||||
<canvas width="1" height="65536" id="canvas"></canvas>
|
@ -20,3 +20,4 @@ load 802926-1.html
|
||||
load 896047-1.html
|
||||
load 896047-2.html
|
||||
load 916128-1.html
|
||||
load 934939-1.html
|
||||
|
@ -1069,12 +1069,10 @@ CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
|
||||
if (!data) {
|
||||
if (!data || data->GetSize() != IntSize(mWidth, mHeight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data->GetSize() == IntSize(mWidth, mHeight));
|
||||
|
||||
*aImageBuffer = SurfaceToPackedBGRA(data);
|
||||
*aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
}
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// Microsoft's API Name hackery sucks
|
||||
#undef CreateEvent
|
||||
|
||||
class nsEventTargetChainItem;
|
||||
class nsIDOMEvent;
|
||||
class nsIScriptGlobalObject;
|
||||
|
@ -293,6 +293,48 @@ EVENT(mozpointerlockerror,
|
||||
NS_POINTERLOCKERROR,
|
||||
EventNameType_HTML,
|
||||
NS_EVENT)
|
||||
|
||||
EVENT(pointerdown,
|
||||
NS_POINTER_DOWN,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointermove,
|
||||
NS_POINTER_MOVE,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointerup,
|
||||
NS_POINTER_UP,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointercancel,
|
||||
NS_POINTER_CANCEL,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointerover,
|
||||
NS_POINTER_OVER,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointerout,
|
||||
NS_POINTER_OUT,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointerenter,
|
||||
NS_POINTER_ENTER,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(pointerleave,
|
||||
NS_POINTER_LEAVE,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(gotpointercapture,
|
||||
NS_POINTER_GOT_CAPTURE,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
EVENT(lostpointercapture,
|
||||
NS_POINTER_LOST_CAPTURE,
|
||||
EventNameType_All,
|
||||
NS_POINTER_EVENT)
|
||||
|
||||
// Not supported yet; probably never because "wheel" is a better idea.
|
||||
// EVENT(mousewheel)
|
||||
EVENT(pause,
|
||||
|
150
content/events/src/PointerEvent.cpp
Normal file
150
content/events/src/PointerEvent.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Portions Copyright 2013 Microsoft Open Technologies, Inc. */
|
||||
|
||||
#include "PointerEvent.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
PointerEvent::PointerEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetPointerEvent* aEvent)
|
||||
: nsDOMMouseEvent(aOwner, aPresContext, aEvent ? aEvent : new WidgetPointerEvent(false, 0, nullptr))
|
||||
{
|
||||
NS_ASSERTION(mEvent->eventStructType == NS_POINTER_EVENT, "event type mismatch NS_POINTER_EVENT");
|
||||
|
||||
WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
|
||||
if (aEvent) {
|
||||
mEventIsInternal = false;
|
||||
} else {
|
||||
mEventIsInternal = true;
|
||||
mEvent->time = PR_Now();
|
||||
mEvent->refPoint.x = mEvent->refPoint.y = 0;
|
||||
mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ConvertStringToPointerType(const nsAString& aPointerTypeArg)
|
||||
{
|
||||
if (aPointerTypeArg.EqualsLiteral("mouse")) {
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
|
||||
}
|
||||
if (aPointerTypeArg.EqualsLiteral("pen")) {
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_PEN;
|
||||
}
|
||||
if (aPointerTypeArg.EqualsLiteral("touch")) {
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
}
|
||||
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
|
||||
}
|
||||
|
||||
//static
|
||||
already_AddRefed<PointerEvent>
|
||||
PointerEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const mozilla::dom::PointerEventInit& aParam,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsRefPtr<PointerEvent> e = new PointerEvent(t, nullptr, nullptr);
|
||||
bool trusted = e->Init(t);
|
||||
|
||||
aRv = e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mDetail, aParam.mScreenX,
|
||||
aParam.mScreenY, aParam.mClientX, aParam.mClientY,
|
||||
aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
|
||||
aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WidgetPointerEvent* widgetEvent = e->mEvent->AsPointerEvent();
|
||||
widgetEvent->pointerId = aParam.mPointerId;
|
||||
widgetEvent->width = aParam.mWidth;
|
||||
widgetEvent->height = aParam.mHeight;
|
||||
widgetEvent->pressure = aParam.mPressure;
|
||||
widgetEvent->tiltX = aParam.mTiltX;
|
||||
widgetEvent->tiltY = aParam.mTiltY;
|
||||
widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
|
||||
widgetEvent->isPrimary = aParam.mIsPrimary;
|
||||
widgetEvent->buttons = aParam.mButtons;
|
||||
|
||||
e->SetTrusted(trusted);
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PointerEvent::GetPointerType(nsAString& aPointerType)
|
||||
{
|
||||
switch (mEvent->AsPointerEvent()->inputSource) {
|
||||
case nsIDOMMouseEvent::MOZ_SOURCE_MOUSE:
|
||||
aPointerType.AssignLiteral("mouse");
|
||||
break;
|
||||
case nsIDOMMouseEvent::MOZ_SOURCE_PEN:
|
||||
aPointerType.AssignLiteral("pen");
|
||||
break;
|
||||
case nsIDOMMouseEvent::MOZ_SOURCE_TOUCH:
|
||||
aPointerType.AssignLiteral("touch");
|
||||
break;
|
||||
case nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN:
|
||||
aPointerType.AssignLiteral("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PointerEvent::PointerId()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->pointerId;
|
||||
}
|
||||
|
||||
int32_t PointerEvent::Width()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->width;
|
||||
}
|
||||
|
||||
int32_t PointerEvent::Height()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->height;
|
||||
}
|
||||
|
||||
int32_t PointerEvent::Pressure()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->pressure;
|
||||
}
|
||||
|
||||
int32_t PointerEvent::TiltX()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->tiltX;
|
||||
}
|
||||
|
||||
int32_t PointerEvent::TiltY()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->tiltY;
|
||||
}
|
||||
|
||||
bool PointerEvent::IsPrimary()
|
||||
{
|
||||
return mEvent->AsPointerEvent()->isPrimary;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsresult NS_NewDOMPointerEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetPointerEvent *aEvent)
|
||||
{
|
||||
dom::PointerEvent *it = new dom::PointerEvent(aOwner, aPresContext, aEvent);
|
||||
return CallQueryInterface(it, aInstancePtrResult);
|
||||
}
|
50
content/events/src/PointerEvent.h
Normal file
50
content/events/src/PointerEvent.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* 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/.
|
||||
*
|
||||
* Portions Copyright 2013 Microsoft Open Technologies, Inc. */
|
||||
|
||||
#ifndef PointerEvent_h__
|
||||
#define PointerEvent_h__
|
||||
|
||||
#include "nsDOMMouseEvent.h"
|
||||
#include "mozilla/dom/PointerEventBinding.h"
|
||||
|
||||
class nsPresContext;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PointerEvent : public nsDOMMouseEvent
|
||||
{
|
||||
public:
|
||||
PointerEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetPointerEvent* aEvent);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
|
||||
{
|
||||
return mozilla::dom::PointerEventBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
static already_AddRefed<PointerEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const PointerEventInit& aParam,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
int32_t PointerId();
|
||||
int32_t Width();
|
||||
int32_t Height();
|
||||
int32_t Pressure();
|
||||
int32_t TiltX();
|
||||
int32_t TiltY();
|
||||
bool IsPrimary();
|
||||
void GetPointerType(nsAString& aPointerType);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'PointerEvent.h',
|
||||
'Touch.h',
|
||||
]
|
||||
|
||||
@ -57,6 +58,7 @@ UNIFIED_SOURCES += [
|
||||
'nsIMEStateManager.cpp',
|
||||
'nsPaintRequest.cpp',
|
||||
'nsPrivateTextRange.cpp',
|
||||
'PointerEvent.cpp',
|
||||
'TextComposition.cpp',
|
||||
'Touch.cpp',
|
||||
]
|
||||
|
@ -145,6 +145,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEvent)
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
|
||||
break;
|
||||
case NS_DRAG_EVENT: {
|
||||
@ -182,6 +183,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
|
||||
cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
|
||||
break;
|
||||
@ -738,6 +740,21 @@ nsDOMEvent::DuplicatePrivateData()
|
||||
newEvent = touchEvent;
|
||||
break;
|
||||
}
|
||||
case NS_POINTER_EVENT:
|
||||
{
|
||||
WidgetPointerEvent* oldPointerEvent = mEvent->AsPointerEvent();
|
||||
WidgetPointerEvent* pointerEvent =
|
||||
new WidgetPointerEvent(false, msg, nullptr,
|
||||
oldPointerEvent->pointerId,
|
||||
oldPointerEvent->width,
|
||||
oldPointerEvent->height,
|
||||
oldPointerEvent->tiltX,
|
||||
oldPointerEvent->tiltY,
|
||||
oldPointerEvent->isPrimary);
|
||||
pointerEvent->buttons = oldPointerEvent->buttons;
|
||||
newEvent = pointerEvent;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
NS_WARNING("Unknown event type!!!");
|
||||
@ -1022,6 +1039,7 @@ nsDOMEvent::GetScreenCoords(nsPresContext* aPresContext,
|
||||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
|
||||
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
aEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
aEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
aEvent->eventStructType != NS_TOUCH_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
|
||||
@ -1081,6 +1099,7 @@ nsDOMEvent::GetClientCoords(nsPresContext* aPresContext,
|
||||
aEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
aEvent->eventStructType != NS_TOUCH_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
|
||||
!aPresContext ||
|
||||
!aEvent->AsGUIEvent()->widget) {
|
||||
|
@ -62,6 +62,7 @@ nsDOMMouseEvent::InitMouseEvent(const nsAString & aType, bool aCanBubble, bool a
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT: {
|
||||
WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
|
||||
mouseEventBase->relatedTarget = aRelatedTarget;
|
||||
@ -115,6 +116,7 @@ nsDOMMouseEvent::InitMouseEvent(const nsAString& aType,
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
mEvent->AsInputEvent()->modifiers = modifiers;
|
||||
return NS_OK;
|
||||
@ -145,6 +147,7 @@ nsDOMMouseEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
e->mEvent->AsMouseEventBase()->buttons = aParam.mButtons;
|
||||
break;
|
||||
@ -192,6 +195,7 @@ nsDOMMouseEvent::Button()
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
return mEvent->AsMouseEventBase()->button;
|
||||
default:
|
||||
@ -217,6 +221,7 @@ nsDOMMouseEvent::Buttons()
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
return mEvent->AsMouseEventBase()->buttons;
|
||||
default:
|
||||
@ -242,6 +247,7 @@ nsDOMMouseEvent::GetRelatedTarget()
|
||||
case NS_MOUSE_SCROLL_EVENT:
|
||||
case NS_WHEEL_EVENT:
|
||||
case NS_DRAG_EVENT:
|
||||
case NS_POINTER_EVENT:
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
relatedTarget =
|
||||
do_QueryInterface(mEvent->AsMouseEventBase()->relatedTarget);
|
||||
|
@ -119,6 +119,7 @@ nsDOMUIEvent::GetMovementPoint()
|
||||
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
mEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
mEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
mEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
|
||||
!mEvent->AsGUIEvent()->widget) {
|
||||
return nsIntPoint(0, 0);
|
||||
@ -300,6 +301,7 @@ nsDOMUIEvent::GetLayerPoint() const
|
||||
(mEvent->eventStructType != NS_MOUSE_EVENT &&
|
||||
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
mEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
mEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
mEvent->eventStructType != NS_TOUCH_EVENT &&
|
||||
mEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
aEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
|
||||
return nsIntPoint(0, 0);
|
||||
}
|
||||
@ -71,6 +72,7 @@ public:
|
||||
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
aEvent->eventStructType != NS_WHEEL_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_POINTER_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
|
||||
!aPresContext ||
|
||||
!aEvent->AsGUIEvent()->widget) {
|
||||
|
@ -739,6 +739,9 @@ nsEventDispatcher::CreateEvent(mozilla::dom::EventTarget* aOwner,
|
||||
case NS_SIMPLE_GESTURE_EVENT:
|
||||
return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsSimpleGestureEvent());
|
||||
case NS_POINTER_EVENT:
|
||||
return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsPointerEvent());
|
||||
case NS_TOUCH_EVENT:
|
||||
return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext,
|
||||
aEvent->AsTouchEvent());
|
||||
|
@ -3221,6 +3221,10 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
if (!suppressBlur) {
|
||||
suppressBlur = nsContentUtils::IsUserFocusIgnored(activeContent);
|
||||
}
|
||||
|
||||
nsIFrame* currFrame = mCurrentTarget;
|
||||
|
||||
// When a root content which isn't editable but has an editable HTML
|
||||
|
@ -5,6 +5,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIMEStateManager.h"
|
||||
|
||||
#include "HTMLInputElement.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISupports.h"
|
||||
@ -35,6 +37,7 @@
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
// nsTextStateManager notifies widget of any text and selection changes
|
||||
@ -457,8 +460,22 @@ nsIMEStateManager::SetIMEState(const IMEState &aState,
|
||||
(aContent->Tag() == nsGkAtoms::input ||
|
||||
aContent->Tag() == nsGkAtoms::textarea)) {
|
||||
if (aContent->Tag() != nsGkAtoms::textarea) {
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
|
||||
context.mHTMLInputType);
|
||||
// <input type=number> has an anonymous <input type=text> descendant
|
||||
// that gets focus whenever anyone tries to focus the number control. We
|
||||
// need to check if aContent is one of those anonymous text controls and,
|
||||
// if so, use the number control instead:
|
||||
nsIContent* content = aContent;
|
||||
HTMLInputElement* inputElement =
|
||||
HTMLInputElement::FromContentOrNull(aContent);
|
||||
if (inputElement) {
|
||||
HTMLInputElement* ownerNumberControl =
|
||||
inputElement->GetOwnerNumberControl();
|
||||
if (ownerNumberControl) {
|
||||
content = ownerNumberControl; // an <input type=number>
|
||||
}
|
||||
}
|
||||
content->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
|
||||
context.mHTMLInputType);
|
||||
} else {
|
||||
context.mHTMLInputType.Assign(nsGkAtoms::textarea->GetUTF16String());
|
||||
}
|
||||
|
@ -171,6 +171,10 @@ const kEventConstructors = {
|
||||
return new HashChangeEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
IccChangeEvent: { create: function (aName, aProps) {
|
||||
return new IccChangeEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
IDBVersionChangeEvent: { create: function (aName, aProps) {
|
||||
return new IDBVersionChangeEvent(aName, aProps);
|
||||
},
|
||||
|
@ -369,6 +369,10 @@ public:
|
||||
return mNetworkState;
|
||||
}
|
||||
|
||||
// Called by the media decoder object, on the main thread,
|
||||
// when the connection between Rtsp server and client gets lost.
|
||||
void ResetConnectionState() MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
// XPCOM GetPreload() is OK
|
||||
void SetPreload(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -993,9 +993,7 @@ UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
|
||||
nsIURI* docURI = aDoc->GetDocumentURI();
|
||||
NS_PRECONDITION(docURI, "docURI is null");
|
||||
|
||||
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
|
||||
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
|
||||
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
|
||||
|
||||
@ -1046,8 +1044,7 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
prefValue->SetAsAString(unicodePath);
|
||||
|
||||
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
|
||||
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
|
||||
return contentPrefService->Set(spec, CPS_PREF_NAME, prefValue, loadContext, nullptr);
|
||||
}
|
||||
|
||||
@ -2061,7 +2058,7 @@ HTMLInputElement::ApplyStep(int32_t aStep)
|
||||
|
||||
Decimal value = GetValueAsDecimal();
|
||||
if (value.isNaN()) {
|
||||
return NS_OK;
|
||||
value = 0;
|
||||
}
|
||||
|
||||
Decimal minimum = GetMinimum();
|
||||
@ -2244,6 +2241,21 @@ HTMLInputElement::MozIsTextField(bool aExcludePassword)
|
||||
return IsSingleLineTextControl(aExcludePassword);
|
||||
}
|
||||
|
||||
HTMLInputElement*
|
||||
HTMLInputElement::GetOwnerNumberControl()
|
||||
{
|
||||
if (IsInNativeAnonymousSubtree() &&
|
||||
mType == NS_FORM_INPUT_TEXT &&
|
||||
GetParent() && GetParent()->GetParent()) {
|
||||
HTMLInputElement* grandparent =
|
||||
HTMLInputElement::FromContentOrNull(GetParent()->GetParent());
|
||||
if (grandparent && grandparent->mType == NS_FORM_INPUT_NUMBER) {
|
||||
return grandparent;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
|
||||
{
|
||||
|
@ -668,6 +668,8 @@ public:
|
||||
|
||||
void MozSetFileNameArray(const Sequence< nsString >& aFileNames);
|
||||
|
||||
HTMLInputElement* GetOwnerNumberControl();
|
||||
|
||||
bool MozIsTextField(bool aExcludePassword);
|
||||
|
||||
nsIEditor* GetEditor();
|
||||
|
@ -1083,12 +1083,9 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
}
|
||||
|
||||
// Check if media is allowed for the docshell.
|
||||
nsCOMPtr<nsISupports> container = OwnerDoc()->GetContainer();
|
||||
if (container) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
||||
if (docShell && !docShell->GetAllowMedia()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDocShell> docShell = OwnerDoc()->GetDocShell();
|
||||
if (docShell && !docShell->GetAllowMedia()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
@ -2068,6 +2065,19 @@ void HTMLMediaElement::SetPlayedOrSeeked(bool aValue)
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::ResetConnectionState()
|
||||
{
|
||||
mBegun = false;
|
||||
SetCurrentTime(0);
|
||||
FireTimeUpdate(false);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
|
||||
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
|
||||
AddRemoveSelfReference();
|
||||
ChangeDelayLoadStatus(false);
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::Play(ErrorResult& aRv)
|
||||
{
|
||||
|
@ -558,7 +558,7 @@ public:
|
||||
bool aNotify) MOZ_OVERRIDE;
|
||||
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
bool aNotify) MOZ_OVERRIDE;
|
||||
virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false) MOZ_OVERRIDE
|
||||
virtual bool IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse) MOZ_OVERRIDE
|
||||
{
|
||||
bool isFocusable = false;
|
||||
IsHTMLFocusable(aWithMouse, &isFocusable, aTabIndex);
|
||||
|
@ -323,6 +323,21 @@ nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGenericHTMLFrameElement::BrowserFramesEnabled()
|
||||
{
|
||||
static bool sMozBrowserFramesEnabled = false;
|
||||
static bool sBoolVarCacheInitialized = false;
|
||||
|
||||
if (!sBoolVarCacheInitialized) {
|
||||
sBoolVarCacheInitialized = true;
|
||||
Preferences::AddBoolVarCache(&sMozBrowserFramesEnabled,
|
||||
"dom.mozBrowserFramesEnabled");
|
||||
}
|
||||
|
||||
return sMozBrowserFramesEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this frame element really is a mozbrowser or mozapp. (It
|
||||
* needs to have the right attributes, and its creator must have the right
|
||||
@ -334,7 +349,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut)
|
||||
*aOut = false;
|
||||
|
||||
// Fail if browser frames are globally disabled.
|
||||
if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
|
||||
if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
|
||||
void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aError);
|
||||
|
||||
static bool BrowserFramesEnabled();
|
||||
protected:
|
||||
// This doesn't really ensure a frame loade in all cases, only when
|
||||
// it makes sense.
|
||||
|
10
content/html/content/test/file_ignoreuserfocus.html
Normal file
10
content/html/content/test/file_ignoreuserfocus.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<map name=a>
|
||||
<area shape=rect coords=0,0,100,100 href=#fail>
|
||||
</map>
|
||||
<img usemap=#a src=image.png>
|
||||
<input><iframe></iframe>
|
||||
</body>
|
||||
</html>
|
@ -169,7 +169,7 @@ function checkStepDown()
|
||||
[ '10', '2', '0', '4', '10', '0', false ],
|
||||
[ '10', '2', '0', '4', '5', '0', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '-1', false ],
|
||||
// With step = 'any'.
|
||||
[ '0', 'any', null, null, 1, null, true ],
|
||||
[ '0', 'ANY', null, null, 1, null, true ],
|
||||
@ -304,7 +304,7 @@ function checkStepDown()
|
||||
[ '1970-03-08', '3', '1970-02-01', '1970-02-07', 15, '1970-02-01', false ],
|
||||
[ '1970-01-10', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '1969-12-31', false ],
|
||||
// With step = 'any'.
|
||||
[ '2012-01-01', 'any', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'ANY', null, null, 1, null, true ],
|
||||
@ -368,7 +368,7 @@ function checkStepDown()
|
||||
[ '17:22', '180', '17:00', '17:20', 15, '17:00', false ],
|
||||
[ '17:22', '180', '17:10', '17:20', 2, '17:16', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '23:59', false ],
|
||||
// With step = 'any'.
|
||||
[ '17:26', 'any', null, null, 1, null, true ],
|
||||
[ '17:26', 'ANY', null, null, 1, null, true ],
|
||||
@ -484,7 +484,7 @@ function checkStepUp()
|
||||
[ '-3', '2', '-6', '-2', null, '-2', false ],
|
||||
[ '-3', '2', '-6', '-1', null, '-2', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '1', false ],
|
||||
// With step = 'any'.
|
||||
[ '0', 'any', null, null, 1, null, true ],
|
||||
[ '0', 'ANY', null, null, 1, null, true ],
|
||||
@ -619,7 +619,7 @@ function checkStepUp()
|
||||
[ '1970-01-01', '3', '1970-02-01', '1970-02-07', 15, '1970-02-07', false ],
|
||||
[ '1970-01-01', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '1970-01-02', false ],
|
||||
// With step = 'any'.
|
||||
[ '2012-01-01', 'any', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'ANY', null, null, 1, null, true ],
|
||||
@ -683,7 +683,7 @@ function checkStepUp()
|
||||
[ '17:22', '180', '17:00', '17:20', 15, '17:22', false ],
|
||||
[ '17:22', '180', '17:10', '17:20', 2, '17:22', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
[ '', null, null, null, null, '00:01', false ],
|
||||
// With step = 'any'.
|
||||
[ '17:26', 'any', null, null, 1, null, true ],
|
||||
[ '17:26', 'ANY', null, null, 1, null, true ],
|
||||
|
@ -154,6 +154,7 @@ support-files =
|
||||
reflect.js
|
||||
wakelock.ogg
|
||||
wakelock.ogv
|
||||
file_ignoreuserfocus.html
|
||||
|
||||
[test_a_text.html]
|
||||
[test_anchor_href_cache_invalidation.html]
|
||||
@ -416,3 +417,4 @@ support-files =
|
||||
[test_undoManager.html]
|
||||
[test_video_wakelock.html]
|
||||
[test_input_files_not_nsIFile.html]
|
||||
[test_ignoreuserfocus.html]
|
||||
|
146
content/html/content/test/test_ignoreuserfocus.html
Normal file
146
content/html/content/test/test_ignoreuserfocus.html
Normal file
@ -0,0 +1,146 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Copied from EventUtils.js, but we want *ToWindow methods.
|
||||
function synthesizeMouseAtPoint(left, top, aEvent, aWindow) {
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
var defaultPrevented = false;
|
||||
if (utils) {
|
||||
var button = aEvent.button || 0;
|
||||
var clickCount = aEvent.clickCount || 1;
|
||||
var modifiers = _parseModifiers(aEvent);
|
||||
var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0;
|
||||
var inputSource = ("inputSource" in aEvent) ? aEvent.inputSource : 0;
|
||||
|
||||
if (("type" in aEvent) && aEvent.type) {
|
||||
defaultPrevented = utils.sendMouseEventToWindow(aEvent.type, left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
}
|
||||
else {
|
||||
utils.sendMouseEventToWindow("mousedown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
utils.sendMouseEventToWindow("mouseup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var witness = document.createElement("input");
|
||||
witness.setAttribute("type", "text");
|
||||
var witness2 = document.createElement("input");
|
||||
witness2.setAttribute("type", "text");
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozbrowser", "true");
|
||||
iframe.setAttribute("ignoreuserfocus", "true");
|
||||
iframe.setAttribute("height", "500px");
|
||||
iframe.setAttribute("src", "file_ignoreuserfocus.html");
|
||||
|
||||
iframe.addEventListener('load', function (e) {
|
||||
// Get privileged iframe because mozbrowser iframe is not same origin
|
||||
// with the parent. We need to access its content through the wrapper.
|
||||
var privilegedIframe = SpecialPowers.wrap(iframe);
|
||||
privilegedIframe.contentWindow.addEventListener("MozAfterPaint", function afterPaint(e) {
|
||||
privilegedIframe.contentWindow.removeEventListener("MozAfterPaint", afterPaint);
|
||||
|
||||
privilegedIframe.contentWindow.addEventListener("focus",
|
||||
function(e) {
|
||||
ok(!iframe.hasAttribute("ignoreuserfocus"), "Shouldn't get a focus event in ignoreuserfocus iframe!");
|
||||
},
|
||||
true);
|
||||
privilegedIframe.contentWindow.addEventListener("blur",
|
||||
function(e) {
|
||||
ok(!iframe.hasAttribute("ignoreuserfocus"), "Shouldn't get a blur event in ignoreuserfocus iframe!");
|
||||
},
|
||||
true);
|
||||
|
||||
// Sanity check
|
||||
witness.focus();
|
||||
is(document.activeElement, witness, "witness should have the focus");
|
||||
|
||||
iframe.focus();
|
||||
isnot(document.activeElement, iframe, "[explicit iframe.focus()] iframe should not get the focus");
|
||||
|
||||
iframe.removeAttribute("ignoreuserfocus");
|
||||
iframe.focus();
|
||||
is(document.activeElement, iframe, "[explicit iframe.focus()] iframe should get the focus");
|
||||
|
||||
iframe.setAttribute("ignoreuserfocus", "true");
|
||||
|
||||
// Test the case when iframe contains <input> and .focus()
|
||||
// is called and explicit focus using mouse
|
||||
witness.focus();
|
||||
|
||||
var innerInput = privilegedIframe.contentDocument.getElementsByTagName("input")[0];
|
||||
innerInput.focus();
|
||||
isnot(document.activeElement, iframe, "[explicit innerInput.focus()] iframe should not have the focus");
|
||||
|
||||
var iframeWindow = SpecialPowers.unwrap(privilegedIframe.contentWindow);
|
||||
witness.focus();
|
||||
synthesizeMouseAtCenter(innerInput, {}, iframeWindow);
|
||||
is(document.activeElement, witness, "[synthesize mouse click] witness should have the focus");
|
||||
|
||||
// Test the case when iframe contains <iframe> and .focus()
|
||||
// is called and explicit focus using mouse
|
||||
witness.focus();
|
||||
|
||||
var innerIframe = privilegedIframe.contentDocument.getElementsByTagName("iframe")[0];
|
||||
innerIframe.focus();
|
||||
isnot(document.activeElement, iframe, "[explicit innerIframe.focus()] iframe should not have the focus");
|
||||
|
||||
witness.focus();
|
||||
synthesizeMouseAtCenter(innerIframe, {}, iframeWindow);
|
||||
is(document.activeElement, witness, "[synthesize mouse click inner iframe] witness should have the focus");
|
||||
|
||||
// Test the case when iframe contains <area> and .focus()
|
||||
// is called and explicit focus using mouse
|
||||
witness.focus();
|
||||
|
||||
// Wait for paint to setup frame for area. Currently the area frame
|
||||
// map is reset for each paint. If we are in the middle of a paint
|
||||
// then the area will not be focusable.
|
||||
privilegedIframe.contentWindow.addEventListener("MozAfterPaint", function afterPaintArea(e) {
|
||||
privilegedIframe.contentWindow.removeEventListener("MozAfterPaint", afterPaintArea);
|
||||
var innerArea = privilegedIframe.contentDocument.getElementsByTagName("area")[0];
|
||||
innerArea.focus();
|
||||
isnot(document.activeElement, iframe, "[explicit innerArea.focus()] iframe should not have the focus");
|
||||
|
||||
witness.focus();
|
||||
synthesizeMouseAtCenter(innerArea, {}, iframeWindow);
|
||||
is(document.activeElement, witness, "[synthesize mouse click] witness should have the focus");
|
||||
|
||||
// Test tabindex
|
||||
witness.focus();
|
||||
is(document.activeElement, witness, "witness should have the focus");
|
||||
synthesizeKey("VK_TAB", {});
|
||||
isnot(document.activeElement, iframe, "[synthesize tab key] iframe should not have the focus");
|
||||
is(document.activeElement, witness2, "witness2 should have the focus");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.body.appendChild(witness);
|
||||
document.body.appendChild(iframe);
|
||||
document.body.appendChild(witness2);
|
||||
}
|
||||
addEventListener("load", function() {
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.mozBrowserFramesEnabled", true]
|
||||
]
|
||||
}, runTest);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
18
content/html/document/reftests/bug917595-1-ref.html
Normal file
18
content/html/document/reftests/bug917595-1-ref.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('MozReftestInvalidate',
|
||||
() => document.documentElement.removeAttribute('class'),
|
||||
false);
|
||||
</script>
|
||||
<body>
|
||||
<iframe src="bug917595-unrotated.jpg" scrolling="no" marginwidth="0" marginheight="0"></iframe>
|
||||
</body>
|
||||
</html>
|
BIN
content/html/document/reftests/bug917595-exif-rotated.jpg
Normal file
BIN
content/html/document/reftests/bug917595-exif-rotated.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
18
content/html/document/reftests/bug917595-iframe-1.html
Normal file
18
content/html/document/reftests/bug917595-iframe-1.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('MozReftestInvalidate',
|
||||
() => document.documentElement.removeAttribute('class'),
|
||||
false);
|
||||
</script>
|
||||
<body>
|
||||
<iframe src="bug917595-exif-rotated.jpg" scrolling="no" marginwidth="0" marginheight="0"></iframe>
|
||||
</body>
|
||||
</html>
|
BIN
content/html/document/reftests/bug917595-pixel-rotated.jpg
Normal file
BIN
content/html/document/reftests/bug917595-pixel-rotated.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
content/html/document/reftests/bug917595-unrotated.jpg
Normal file
BIN
content/html/document/reftests/bug917595-unrotated.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
@ -3,3 +3,10 @@
|
||||
|
||||
== bug448564-4a.html bug448564-4b.html
|
||||
== bug502168-1_malformed.html bug502168-1_well-formed.html
|
||||
|
||||
# Test that image documents taken into account CSS properties like
|
||||
# image-orientation when determining the size of the image.
|
||||
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
|
||||
# The vast majority of the fuzziness comes from Linux and WinXP.)
|
||||
fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html
|
||||
fuzzy(2,446) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nsRect.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIDocumentInlines.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "nsIDOMKeyEvent.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "imgILoader.h"
|
||||
@ -209,6 +211,7 @@ ImageDocument::Destroy()
|
||||
if (mImageContent) {
|
||||
// Remove our event listener from the image content.
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(mImageContent);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
|
||||
|
||||
// Break reference cycle with mImageContent, if we have one
|
||||
@ -253,6 +256,7 @@ ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
|
||||
|
||||
target = do_QueryInterface(mImageContent);
|
||||
target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
|
||||
target->AddEventListener(NS_LITERAL_STRING("click"), this, false);
|
||||
}
|
||||
|
||||
@ -509,8 +513,11 @@ ImageDocument::SetModeClass(eModeClasses mode)
|
||||
nsresult
|
||||
ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
|
||||
{
|
||||
// Styles have not yet been applied, so we don't know the final size. For now,
|
||||
// default to the image's intrinsic size.
|
||||
aImage->GetWidth(&mImageWidth);
|
||||
aImage->GetHeight(&mImageHeight);
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing);
|
||||
nsContentUtils::AddScriptRunner(runnable);
|
||||
@ -573,11 +580,44 @@ ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
|
||||
else if (mImageIsOverflowing) {
|
||||
ShrinkToFit();
|
||||
}
|
||||
} else if (eventType.EqualsLiteral("load")) {
|
||||
UpdateSizeFromLayout();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageDocument::UpdateSizeFromLayout()
|
||||
{
|
||||
// Pull an updated size from the content frame to account for any size
|
||||
// change due to CSS properties like |image-orientation|.
|
||||
Element* contentElement = mImageContent->AsElement();
|
||||
if (!contentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* contentFrame = contentElement->GetPrimaryFrame(Flush_Frames);
|
||||
if (!contentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntSize oldSize(mImageWidth, mImageHeight);
|
||||
IntrinsicSize newSize = contentFrame->GetIntrinsicSize();
|
||||
|
||||
if (newSize.width.GetUnit() == eStyleUnit_Coord) {
|
||||
mImageWidth = nsPresContext::AppUnitsToFloatCSSPixels(newSize.width.GetCoordValue());
|
||||
}
|
||||
if (newSize.height.GetUnit() == eStyleUnit_Coord) {
|
||||
mImageHeight = nsPresContext::AppUnitsToFloatCSSPixels(newSize.height.GetCoordValue());
|
||||
}
|
||||
|
||||
// Ensure that our information about overflow is up-to-date if needed.
|
||||
if (mImageWidth != oldSize.width || mImageHeight != oldSize.height) {
|
||||
CheckOverflowing(false);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageDocument::CreateSyntheticDocument()
|
||||
{
|
||||
@ -724,7 +764,7 @@ ImageDocument::UpdateTitleAndCharset()
|
||||
void
|
||||
ImageDocument::ResetZoomLevel()
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
if (nsContentUtils::IsChildOfSameType(this)) {
|
||||
return;
|
||||
@ -743,7 +783,7 @@ float
|
||||
ImageDocument::GetZoomLevel()
|
||||
{
|
||||
float zoomLevel = mOriginalZoomLevel;
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIContentViewer> cv;
|
||||
docShell->GetContentViewer(getter_AddRefs(cv));
|
||||
|
@ -94,6 +94,8 @@ protected:
|
||||
void ResetZoomLevel();
|
||||
float GetZoomLevel();
|
||||
|
||||
void UpdateSizeFromLayout();
|
||||
|
||||
enum eModeClasses {
|
||||
eNone,
|
||||
eShrinkToFit,
|
||||
|
@ -32,6 +32,7 @@ LOCAL_INCLUDES += [
|
||||
'/caps/include',
|
||||
'/content/base/src',
|
||||
'/content/events/src',
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
'/layout/style',
|
||||
'/xpcom/ds',
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIMarkupDocumentViewer.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
@ -1362,7 +1362,7 @@ nsHTMLDocument::Open(JSContext* cx,
|
||||
}
|
||||
|
||||
// check whether we're in the middle of unload. If so, ignore this call.
|
||||
nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocumentContainer);
|
||||
nsCOMPtr<nsIDocShell> shell(mDocumentContainer);
|
||||
if (!shell) {
|
||||
// We won't be able to create a parser anyway.
|
||||
nsCOMPtr<nsIDocument> ret = this;
|
||||
|
@ -815,7 +815,7 @@ nsMathMLElement::SetIncrementScriptLevel(bool aIncrementScriptLevel,
|
||||
}
|
||||
|
||||
bool
|
||||
nsMathMLElement::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
|
||||
nsMathMLElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (IsLink(getter_AddRefs(uri))) {
|
||||
|
@ -80,8 +80,7 @@ public:
|
||||
return mIncrementScriptLevel;
|
||||
}
|
||||
|
||||
virtual bool IsFocusable(int32_t *aTabIndex = nullptr,
|
||||
bool aWithMouse = false) MOZ_OVERRIDE;
|
||||
virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) MOZ_OVERRIDE;
|
||||
virtual bool IsLink(nsIURI** aURI) const MOZ_OVERRIDE;
|
||||
virtual void GetLinkTarget(nsAString& aTarget) MOZ_OVERRIDE;
|
||||
virtual already_AddRefed<nsIURI> GetHrefURI() const MOZ_OVERRIDE;
|
||||
|
@ -9,12 +9,6 @@
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AudioNodeStream.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
// Forward declaration for mResamplerMap
|
||||
typedef struct SpeexResamplerState_ SpeexResamplerState;
|
||||
|
||||
|
@ -10,12 +10,6 @@
|
||||
#include "mozilla/dom/AudioNodeBinding.h"
|
||||
#include "AudioSegment.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
@ -61,6 +61,10 @@
|
||||
#include "AppleDecoder.h"
|
||||
#include "AppleMP3Reader.h"
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
@ -298,6 +302,15 @@ IsDirectShowSupportedType(const nsACString& aType)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
static bool
|
||||
IsMP4SupportedType(const nsACString& aType)
|
||||
{
|
||||
return Preferences::GetBool("media.fragmented-mp4.exposed", false) &&
|
||||
MP4Decoder::GetSupportedCodecs(aType, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
static const char * const gAppleMP3Types[] = {
|
||||
"audio/mp3",
|
||||
@ -445,30 +458,35 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
return CANPLAY_YES;
|
||||
}
|
||||
|
||||
/* static */
|
||||
// Instantiates but does not initialize decoder.
|
||||
static
|
||||
already_AddRefed<MediaDecoder>
|
||||
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
{
|
||||
nsRefPtr<MediaDecoder> decoder;
|
||||
|
||||
#ifdef MOZ_GSTREAMER
|
||||
if (IsGStreamerSupportedType(aType)) {
|
||||
decoder = new GStreamerDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_RAW
|
||||
if (IsRawType(aType)) {
|
||||
decoder = new RawDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_OGG
|
||||
if (IsOggType(aType)) {
|
||||
decoder = new OggDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(aType)) {
|
||||
decoder = new WaveDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
@ -489,22 +507,26 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
}
|
||||
}
|
||||
decoder = new MediaOmxDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
if (IsRtspSupportedType(aType)) {
|
||||
decoder = new RtspOmxDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_MEDIA_PLUGINS
|
||||
if (MediaDecoder::IsMediaPluginsEnabled() &&
|
||||
GetMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
||||
decoder = new MediaPluginDecoder(aType);
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
if (IsWebMType(aType)) {
|
||||
decoder = new WebMDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
@ -512,21 +534,40 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
// "media.directshow.preferred" won't be honored.
|
||||
if (IsDirectShowSupportedType(aType)) {
|
||||
decoder = new DirectShowDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
if (IsMP4SupportedType(aType)) {
|
||||
decoder = new MP4Decoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
if (IsWMFSupportedType(aType)) {
|
||||
decoder = new WMFDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(aType)) {
|
||||
decoder = new AppleDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
|
||||
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MediaDecoder>
|
||||
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
{
|
||||
nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
|
||||
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
|
||||
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
@ -579,6 +620,11 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
||||
decoderReader = new DirectShowReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
if (IsMP4SupportedType(aType)) {
|
||||
decoderReader = new MP4Reader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
if (IsWMFSupportedType(aType)) {
|
||||
decoderReader = new WMFReader(aDecoder);
|
||||
@ -615,6 +661,9 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
||||
#ifdef MOZ_MEDIA_PLUGINS
|
||||
(MediaDecoder::IsMediaPluginsEnabled() && IsMediaPluginsType(aType)) ||
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
IsMP4SupportedType(aType) ||
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
(IsWMFSupportedType(aType) &&
|
||||
Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) ||
|
||||
|
@ -26,9 +26,9 @@ namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gMediaCacheLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaCacheLog, type, msg)
|
||||
#define CACHE_LOG(type, msg) PR_LOG(gMediaCacheLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define CACHE_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
// Readahead blocks for non-seekable streams will be limited to this
|
||||
@ -935,7 +935,7 @@ MediaCache::FreeBlock(int32_t aBlock)
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("Released block %d", aBlock));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Released block %d", aBlock));
|
||||
|
||||
for (uint32_t i = 0; i < block->mOwners.Length(); ++i) {
|
||||
BlockOwner* bo = &block->mOwners[i];
|
||||
@ -1101,20 +1101,20 @@ MediaCache::Update()
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// We successfully copied the file data.
|
||||
LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)",
|
||||
blockIndex, destinationBlockIndex));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)",
|
||||
blockIndex, destinationBlockIndex));
|
||||
// Swapping the block metadata here lets us maintain the
|
||||
// correct positions in the linked lists
|
||||
SwapBlocks(blockIndex, destinationBlockIndex);
|
||||
//Free the overflowing block even if the copy failed.
|
||||
LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)", blockIndex));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)", blockIndex));
|
||||
FreeBlock(blockIndex);
|
||||
}
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("Could not trim cache block %d (destination %d, predicted next use %f, latest predicted use for overflow %f",
|
||||
blockIndex, destinationBlockIndex,
|
||||
PredictNextUse(now, destinationBlockIndex).ToSeconds(),
|
||||
latestPredictedUseForOverflow.ToSeconds()));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Could not trim cache block %d (destination %d, predicted next use %f, latest predicted use for overflow %f",
|
||||
blockIndex, destinationBlockIndex,
|
||||
PredictNextUse(now, destinationBlockIndex).ToSeconds(),
|
||||
latestPredictedUseForOverflow.ToSeconds()));
|
||||
}
|
||||
}
|
||||
// Try chopping back the array of cache entries and the cache file.
|
||||
@ -1194,29 +1194,29 @@ MediaCache::Update()
|
||||
// advertised with Content-Length, and we may as well keep reading.
|
||||
// But we don't want to seek to the end of the stream if we're not
|
||||
// already there.
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p at end of stream", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p at end of stream", stream));
|
||||
enableReading = !stream->mCacheSuspended &&
|
||||
stream->mStreamLength == stream->mChannelOffset;
|
||||
} else if (desiredOffset < stream->mStreamOffset) {
|
||||
// We're reading to try to catch up to where the current stream
|
||||
// reader wants to be. Better not stop.
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p catching up", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p catching up", stream));
|
||||
enableReading = true;
|
||||
} else if (desiredOffset < stream->mStreamOffset + BLOCK_SIZE) {
|
||||
// The stream reader is waiting for us, or nearly so. Better feed it.
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p feeding reader", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p feeding reader", stream));
|
||||
enableReading = true;
|
||||
} else if (!stream->mIsTransportSeekable &&
|
||||
nonSeekableReadaheadBlockCount >= maxBlocks*NONSEEKABLE_READAHEAD_MAX) {
|
||||
// This stream is not seekable and there are already too many blocks
|
||||
// being cached for readahead for nonseekable streams (which we can't
|
||||
// free). So stop reading ahead now.
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p throttling non-seekable readahead", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p throttling non-seekable readahead", stream));
|
||||
enableReading = false;
|
||||
} else if (mIndex.Length() > uint32_t(maxBlocks)) {
|
||||
// We're in the process of bringing the cache size back to the
|
||||
// desired limit, so don't bring in more data yet
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p throttling to reduce cache size", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p throttling to reduce cache size", stream));
|
||||
enableReading = false;
|
||||
} else {
|
||||
TimeDuration predictedNewDataUse = PredictNextUseForIncomingData(stream);
|
||||
@ -1224,21 +1224,21 @@ MediaCache::Update()
|
||||
if (stream->mCacheSuspended &&
|
||||
predictedNewDataUse.ToMilliseconds() > CACHE_POWERSAVE_WAKEUP_LOW_THRESHOLD_MS) {
|
||||
// Don't need data for a while, so don't bother waking up the stream
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p avoiding wakeup since more data is not needed", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p avoiding wakeup since more data is not needed", stream));
|
||||
enableReading = false;
|
||||
} else if (freeBlockCount > 0) {
|
||||
// Free blocks in the cache, so keep reading
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p reading since there are free blocks", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p reading since there are free blocks", stream));
|
||||
enableReading = true;
|
||||
} else if (latestNextUse <= TimeDuration(0)) {
|
||||
// No reusable blocks, so can't read anything
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p throttling due to no reusable blocks", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p throttling due to no reusable blocks", stream));
|
||||
enableReading = false;
|
||||
} else {
|
||||
// Read ahead if the data we expect to read is more valuable than
|
||||
// the least valuable block in the main part of the cache
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p predict next data in %f, current worst block is %f",
|
||||
stream, predictedNewDataUse.ToSeconds(), latestNextUse.ToSeconds()));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p predict next data in %f, current worst block is %f",
|
||||
stream, predictedNewDataUse.ToSeconds(), latestNextUse.ToSeconds()));
|
||||
enableReading = predictedNewDataUse < latestNextUse;
|
||||
}
|
||||
}
|
||||
@ -1252,8 +1252,8 @@ MediaCache::Update()
|
||||
// This block is already going to be read by the other stream.
|
||||
// So don't try to read it from this stream as well.
|
||||
enableReading = false;
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p waiting on same block (%lld) from stream %p",
|
||||
stream, desiredOffset/BLOCK_SIZE, other));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p waiting on same block (%lld) from stream %p",
|
||||
stream, desiredOffset/BLOCK_SIZE, other));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1316,17 +1316,17 @@ MediaCache::Update()
|
||||
switch (actions[i]) {
|
||||
case SEEK:
|
||||
case SEEK_AND_RESUME:
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p CacheSeek to %lld (resume=%d)", stream,
|
||||
(long long)stream->mChannelOffset, actions[i] == SEEK_AND_RESUME));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p CacheSeek to %lld (resume=%d)", stream,
|
||||
(long long)stream->mChannelOffset, actions[i] == SEEK_AND_RESUME));
|
||||
rv = stream->mClient->CacheClientSeek(stream->mChannelOffset,
|
||||
actions[i] == SEEK_AND_RESUME);
|
||||
break;
|
||||
case RESUME:
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream));
|
||||
rv = stream->mClient->CacheClientResume();
|
||||
break;
|
||||
case SUSPEND:
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream));
|
||||
rv = stream->mClient->CacheClientSuspend();
|
||||
break;
|
||||
default:
|
||||
@ -1447,8 +1447,8 @@ MediaCache::AllocateAndWriteBlock(MediaCacheStream* aStream, const void* aData,
|
||||
if (stream->mBlocks[streamBlockIndex] >= 0) {
|
||||
// We no longer want to own this block
|
||||
int32_t globalBlockIndex = stream->mBlocks[streamBlockIndex];
|
||||
LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
globalBlockIndex, stream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
globalBlockIndex, stream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
RemoveBlockOwner(globalBlockIndex, stream);
|
||||
}
|
||||
}
|
||||
@ -1461,8 +1461,8 @@ MediaCache::AllocateAndWriteBlock(MediaCacheStream* aStream, const void* aData,
|
||||
FreeBlock(blockIndex);
|
||||
|
||||
Block* block = &mIndex[blockIndex];
|
||||
LOG(PR_LOG_DEBUG, ("Allocated block %d to stream %p block %d(%lld)",
|
||||
blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Allocated block %d to stream %p block %d(%lld)",
|
||||
blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
|
||||
mFreeBlocks.RemoveBlock(blockIndex);
|
||||
|
||||
@ -1496,8 +1496,8 @@ MediaCache::AllocateAndWriteBlock(MediaCacheStream* aStream, const void* aData,
|
||||
|
||||
nsresult rv = mFileCache->WriteBlock(blockIndex, reinterpret_cast<const uint8_t*>(aData));
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
|
||||
FreeBlock(blockIndex);
|
||||
}
|
||||
}
|
||||
@ -1513,7 +1513,7 @@ MediaCache::OpenStream(MediaCacheStream* aStream)
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p opened", aStream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p opened", aStream));
|
||||
mStreams.AppendElement(aStream);
|
||||
aStream->mResourceID = AllocateResourceID();
|
||||
|
||||
@ -1527,7 +1527,7 @@ MediaCache::ReleaseStream(MediaCacheStream* aStream)
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p closed", aStream));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p closed", aStream));
|
||||
mStreams.RemoveElement(aStream);
|
||||
}
|
||||
|
||||
@ -1543,8 +1543,8 @@ MediaCache::ReleaseStreamBlocks(MediaCacheStream* aStream)
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
int32_t blockIndex = aStream->mBlocks[i];
|
||||
if (blockIndex >= 0) {
|
||||
LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
blockIndex, aStream, i, (long long)i*BLOCK_SIZE));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Released block %d from stream %p block %d(%lld)",
|
||||
blockIndex, aStream, i, (long long)i*BLOCK_SIZE));
|
||||
RemoveBlockOwner(blockIndex, aStream);
|
||||
}
|
||||
}
|
||||
@ -1712,8 +1712,8 @@ MediaCacheStream::NotifyDataReceived(int64_t aSize, const char* aData,
|
||||
int64_t size = aSize;
|
||||
const char* data = aData;
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p DataReceived at %lld count=%lld",
|
||||
this, (long long)mChannelOffset, (long long)aSize));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p DataReceived at %lld count=%lld",
|
||||
this, (long long)mChannelOffset, (long long)aSize));
|
||||
|
||||
// We process the data one block (or part of a block) at a time
|
||||
while (size > 0) {
|
||||
@ -1780,12 +1780,12 @@ MediaCacheStream::FlushPartialBlockInternal(bool aNotifyAll)
|
||||
|
||||
int32_t blockOffset = int32_t(mChannelOffset%BLOCK_SIZE);
|
||||
if (blockOffset > 0) {
|
||||
LOG(PR_LOG_DEBUG,
|
||||
("Stream %p writing partial block: [%d] bytes; "
|
||||
"mStreamOffset [%lld] mChannelOffset[%lld] mStreamLength [%lld] "
|
||||
"notifying: [%s]",
|
||||
this, blockOffset, mStreamOffset, mChannelOffset, mStreamLength,
|
||||
aNotifyAll ? "yes" : "no"));
|
||||
CACHE_LOG(PR_LOG_DEBUG,
|
||||
("Stream %p writing partial block: [%d] bytes; "
|
||||
"mStreamOffset [%lld] mChannelOffset[%lld] mStreamLength [%lld] "
|
||||
"notifying: [%s]",
|
||||
this, blockOffset, mStreamOffset, mChannelOffset, mStreamLength,
|
||||
aNotifyAll ? "yes" : "no"));
|
||||
|
||||
// Write back the partial block
|
||||
memset(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset, 0,
|
||||
@ -2107,7 +2107,7 @@ MediaCacheStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("Stream %p Seek to %lld", this, (long long)mStreamOffset));
|
||||
CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Seek to %lld", this, (long long)mStreamOffset));
|
||||
gMediaCache->NoteSeek(this, oldOffset);
|
||||
|
||||
gMediaCache->QueueUpdate();
|
||||
@ -2221,8 +2221,8 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
||||
// have changed
|
||||
gMediaCache->QueueUpdate();
|
||||
}
|
||||
LOG(PR_LOG_DEBUG,
|
||||
("Stream %p Read at %lld count=%d", this, (long long)(mStreamOffset-count), count));
|
||||
CACHE_LOG(PR_LOG_DEBUG,
|
||||
("Stream %p Read at %lld count=%d", this, (long long)(mStreamOffset-count), count));
|
||||
*aBytes = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ static const int64_t CAN_PLAY_THROUGH_MARGIN = 1;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define DECODER_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
class MediaMemoryTracker
|
||||
@ -251,8 +251,8 @@ void MediaDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
LOG(PR_LOG_DEBUG, ("MediaDecoder::RecreateDecodedStream this=%p aStartTimeUSecs=%lld!",
|
||||
this, (long long)aStartTimeUSecs));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoder::RecreateDecodedStream this=%p aStartTimeUSecs=%lld!",
|
||||
this, (long long)aStartTimeUSecs));
|
||||
|
||||
DestroyDecodedStream();
|
||||
|
||||
@ -296,8 +296,8 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
LOG(PR_LOG_DEBUG, ("MediaDecoder::AddOutputStream this=%p aStream=%p!",
|
||||
this, aStream));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoder::AddOutputStream this=%p aStream=%p!",
|
||||
this, aStream));
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
@ -459,7 +459,7 @@ nsresult MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
|
||||
|
||||
nsresult rv = mResource->Open(aStreamListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -476,7 +476,7 @@ nsresult MediaDecoder::Load(nsIStreamListener** aStreamListener,
|
||||
|
||||
mDecoderStateMachine = CreateStateMachine();
|
||||
if (!mDecoderStateMachine) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to create state machine!", this));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to create state machine!", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -491,7 +491,7 @@ nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
|
||||
MediaDecoder* cloneDonor = static_cast<MediaDecoder*>(aCloneDonor);
|
||||
if (NS_FAILED(mDecoderStateMachine->Init(cloneDonor ?
|
||||
cloneDonor->mDecoderStateMachine : nullptr))) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to init state machine!", this));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to init state machine!", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
{
|
||||
@ -814,6 +814,23 @@ void MediaDecoder::ResourceLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::ResetConnectionState()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mShuttingDown)
|
||||
return;
|
||||
|
||||
if (mOwner) {
|
||||
// Notify the media element that connection gets lost.
|
||||
mOwner->ResetConnectionState();
|
||||
}
|
||||
|
||||
// Since we have notified the media element the connection
|
||||
// lost event, the decoder will be reloaded when user tries
|
||||
// to play the Rtsp streaming next time.
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void MediaDecoder::NetworkError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -1252,7 +1269,7 @@ void MediaDecoder::DurationChanged()
|
||||
UpdatePlaybackRate();
|
||||
|
||||
if (mOwner && oldDuration != mDuration && !IsInfinite()) {
|
||||
LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration));
|
||||
mOwner->DispatchEvent(NS_LITERAL_STRING("durationchange"));
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +247,9 @@ public:
|
||||
MediaDecoder();
|
||||
virtual ~MediaDecoder();
|
||||
|
||||
// Reset the decoder and notify the media element that
|
||||
// server connection is closed.
|
||||
virtual void ResetConnectionState();
|
||||
// Create a new decoder of the same type as this one.
|
||||
// Subclasses must implement this.
|
||||
virtual MediaDecoder* Clone() = 0;
|
||||
|
@ -139,6 +139,10 @@ public:
|
||||
// Called by the media decoder and the video frame to get the
|
||||
// ImageContainer containing the video data.
|
||||
virtual VideoFrameContainer* GetVideoFrameContainer() = 0;
|
||||
|
||||
// Called by the media decoder object, on the main thread,
|
||||
// when the connection between Rtsp server and client gets lost.
|
||||
virtual void ResetConnectionState() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ static_assert(PlanarYCbCrImage::MAX_DIMENSION < UINT32_MAX / PlanarYCbCrImage::M
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#ifdef SEEK_LOGGING
|
||||
#define SEEK_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#else
|
||||
#define SEEK_LOG(type, msg)
|
||||
#endif
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define DECODER_LOG(type, msg)
|
||||
#define SEEK_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
@ -466,12 +466,14 @@ VideoData* MediaDecoderReader::FindStartTime(int64_t& aOutStartTime)
|
||||
videoData = DecodeToFirstVideoData();
|
||||
if (videoData) {
|
||||
videoStartTime = videoData->mTime;
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::FindStartTime() video=%lld", videoStartTime));
|
||||
}
|
||||
}
|
||||
if (HasAudio()) {
|
||||
AudioData* audioData = DecodeToFirstAudioData();
|
||||
if (audioData) {
|
||||
audioStartTime = audioData->mTime;
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::FindStartTime() audio=%lld", audioStartTime));
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +487,7 @@ VideoData* MediaDecoderReader::FindStartTime(int64_t& aOutStartTime)
|
||||
|
||||
nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) Begin", aTarget));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) Begin", aTarget));
|
||||
|
||||
// Decode forward to the target frame. Start with video, if we have it.
|
||||
if (HasVideo()) {
|
||||
@ -529,7 +531,7 @@ nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
|
||||
}
|
||||
|
||||
if (HasAudio()) {
|
||||
@ -609,7 +611,7 @@ nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
|
||||
}
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) End", aTarget));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) End", aTarget));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ using namespace mozilla::dom;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define DECODER_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
// Wait this number of seconds when buffering, then leave and play
|
||||
@ -287,7 +287,7 @@ void StateMachineTracker::CleanupGlobalStateMachine()
|
||||
"State machine ref count must be > 0");
|
||||
mStateMachineCount--;
|
||||
if (mStateMachineCount == 0) {
|
||||
LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
|
||||
NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
@ -506,7 +506,7 @@ void MediaDecoderStateMachine::DecodeThreadRun()
|
||||
NS_FAILED(DecodeMetadata())) {
|
||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||
"Should be in shutdown state if metadata loading fails.");
|
||||
LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
|
||||
while (mState != DECODER_STATE_SHUTDOWN &&
|
||||
@ -522,7 +522,7 @@ void MediaDecoderStateMachine::DecodeThreadRun()
|
||||
if (NS_FAILED(DecodeMetadata())) {
|
||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||
"Should be in shutdown state if metadata loading fails.");
|
||||
LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
} else if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
|
||||
mDecoder->GetReentrantMonitor().Wait();
|
||||
@ -537,7 +537,7 @@ void MediaDecoderStateMachine::DecodeThreadRun()
|
||||
}
|
||||
|
||||
mDecodeThreadIdle = true;
|
||||
LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
|
||||
}
|
||||
|
||||
mReader->OnDecodeThreadFinish();
|
||||
@ -567,8 +567,8 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
|
||||
return;
|
||||
if (audioWrittenOffset.value() < frameOffset.value()) {
|
||||
// Write silence to catch up
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream",
|
||||
mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value())));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream",
|
||||
mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value())));
|
||||
AudioSegment silence;
|
||||
silence.InsertNullDataAtStart(frameOffset.value() - audioWrittenOffset.value());
|
||||
aStream->mAudioFramesWritten += silence.GetDuration();
|
||||
@ -597,8 +597,8 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
|
||||
channels.AppendElement(bufferData + i*aAudio->mFrames + offset);
|
||||
}
|
||||
aOutput->AppendFrames(buffer.forget(), channels, aAudio->mFrames);
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld",
|
||||
mDecoder.get(), aAudio->mFrames - int32_t(offset), aAudio->mTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld",
|
||||
mDecoder.get(), aAudio->mFrames - int32_t(offset), aAudio->mTime));
|
||||
aStream->mAudioFramesWritten += aAudio->mFrames - int32_t(offset);
|
||||
}
|
||||
|
||||
@ -684,9 +684,9 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
for (uint32_t i = 0; i < video.Length(); ++i) {
|
||||
VideoData* v = video[i];
|
||||
if (stream->mNextVideoTime + mStartTime < v->mTime) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream %p for %lld ms",
|
||||
mDecoder.get(), mediaStream,
|
||||
v->mTime - (stream->mNextVideoTime + mStartTime)));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream %p for %lld ms",
|
||||
mDecoder.get(), mediaStream,
|
||||
v->mTime - (stream->mNextVideoTime + mStartTime)));
|
||||
// Write last video frame to catch up. mLastVideoImage can be null here
|
||||
// which is fine, it just means there's no video.
|
||||
WriteVideoToMediaStream(stream->mLastVideoImage,
|
||||
@ -695,9 +695,9 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
stream->mNextVideoTime = v->mTime - mStartTime;
|
||||
}
|
||||
if (stream->mNextVideoTime + mStartTime < v->GetEndTime()) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream %p for %lld ms",
|
||||
mDecoder.get(), v->mTime, mediaStream,
|
||||
v->GetEndTime() - (stream->mNextVideoTime + mStartTime)));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream %p for %lld ms",
|
||||
mDecoder.get(), v->mTime, mediaStream,
|
||||
v->GetEndTime() - (stream->mNextVideoTime + mStartTime)));
|
||||
WriteVideoToMediaStream(v->mImage,
|
||||
v->GetEndTime() - (stream->mNextVideoTime + mStartTime), v->mDisplay,
|
||||
&output);
|
||||
@ -705,8 +705,8 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
stream->mLastVideoImage = v->mImage;
|
||||
stream->mLastVideoImageDisplaySize = v->mDisplay;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
|
||||
mDecoder.get(), v->mTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
|
||||
mDecoder.get(), v->mTime));
|
||||
}
|
||||
}
|
||||
if (output.GetDuration() > 0) {
|
||||
@ -814,7 +814,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
||||
|
||||
void MediaDecoderStateMachine::DecodeLoop()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
|
||||
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
@ -889,7 +889,7 @@ void MediaDecoderStateMachine::DecodeLoop()
|
||||
!HasLowUndecodedData())
|
||||
{
|
||||
skipToNextKeyframe = true;
|
||||
LOG(PR_LOG_DEBUG, ("%p Skipping video decode to the next keyframe", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Skipping video decode to the next keyframe", mDecoder.get()));
|
||||
}
|
||||
|
||||
// Video decode.
|
||||
@ -922,9 +922,9 @@ void MediaDecoderStateMachine::DecodeLoop()
|
||||
std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), AMPLE_AUDIO_USECS);
|
||||
ampleAudioThreshold = std::max(THRESHOLD_FACTOR * lowAudioThreshold,
|
||||
ampleAudioThreshold);
|
||||
LOG(PR_LOG_DEBUG,
|
||||
("Slow video decode, set lowAudioThreshold=%lld ampleAudioThreshold=%lld",
|
||||
lowAudioThreshold, ampleAudioThreshold));
|
||||
DECODER_LOG(PR_LOG_DEBUG,
|
||||
("Slow video decode, set lowAudioThreshold=%lld ampleAudioThreshold=%lld",
|
||||
lowAudioThreshold, ampleAudioThreshold));
|
||||
}
|
||||
}
|
||||
|
||||
@ -990,7 +990,7 @@ void MediaDecoderStateMachine::DecodeLoop()
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("%p Exiting DecodeLoop", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Exiting DecodeLoop", mDecoder.get()));
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsPlaying()
|
||||
@ -1026,7 +1026,7 @@ static void WriteSilence(AudioStream* aStream, uint32_t aFrames)
|
||||
void MediaDecoderStateMachine::AudioLoop()
|
||||
{
|
||||
NS_ASSERTION(OnAudioThread(), "Should be on audio thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p Begun audio thread/loop", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Begun audio thread/loop", mDecoder.get()));
|
||||
int64_t audioDuration = 0;
|
||||
int64_t audioStartTime = -1;
|
||||
uint32_t channels, rate;
|
||||
@ -1164,8 +1164,8 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
// hardware so that the next audio chunk begins playback at the correct
|
||||
// time.
|
||||
missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of silence",
|
||||
mDecoder.get(), int32_t(missingFrames.value())));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of silence",
|
||||
mDecoder.get(), int32_t(missingFrames.value())));
|
||||
framesWritten = PlaySilence(static_cast<uint32_t>(missingFrames.value()),
|
||||
channels, playedFrames.value());
|
||||
} else {
|
||||
@ -1220,7 +1220,7 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(PR_LOG_DEBUG, ("%p Reached audio stream end.", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Reached audio stream end.", mDecoder.get()));
|
||||
{
|
||||
// Must hold lock while shutting down and anulling the audio stream to prevent
|
||||
// state machine thread trying to use it while we're destroying it.
|
||||
@ -1236,7 +1236,7 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
}
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("%p Audio stream finished playing, audio thread exit", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Audio stream finished playing, audio thread exit", mDecoder.get()));
|
||||
}
|
||||
|
||||
uint32_t MediaDecoderStateMachine::PlaySilence(uint32_t aFrames,
|
||||
@ -1271,8 +1271,8 @@ uint32_t MediaDecoderStateMachine::PlayFromAudioQueue(uint64_t aFrameOffset,
|
||||
int64_t offset = -1;
|
||||
uint32_t frames = 0;
|
||||
if (!PR_GetEnv("MOZ_QUIET")) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of data to stream for AudioData at %lld",
|
||||
mDecoder.get(), audio->mFrames, audio->mTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of data to stream for AudioData at %lld",
|
||||
mDecoder.get(), audio->mFrames, audio->mTime));
|
||||
}
|
||||
mAudioStream->Write(audio->mAudioData,
|
||||
audio->mFrames);
|
||||
@ -1303,7 +1303,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
||||
|
||||
void MediaDecoderStateMachine::StopPlayback()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p StopPlayback()", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p StopPlayback()", mDecoder.get()));
|
||||
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
@ -1321,7 +1321,7 @@ void MediaDecoderStateMachine::StopPlayback()
|
||||
|
||||
void MediaDecoderStateMachine::StartPlayback()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p StartPlayback()", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p StartPlayback()", mDecoder.get()));
|
||||
|
||||
NS_ASSERTION(!IsPlaying(), "Shouldn't be playing when StartPlayback() is called");
|
||||
AssertCurrentThreadInMonitor();
|
||||
@ -1535,7 +1535,7 @@ void MediaDecoderStateMachine::Shutdown()
|
||||
|
||||
// Change state before issuing shutdown request to threads so those
|
||||
// threads can start exiting cleanly during the Shutdown call.
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN", mDecoder.get()));
|
||||
ScheduleStateMachine();
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
@ -1577,7 +1577,7 @@ void MediaDecoderStateMachine::Play()
|
||||
// when the state machine notices the decoder's state change to PLAYING.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mState == DECODER_STATE_BUFFERING) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get()));
|
||||
mState = DECODER_STATE_DECODING;
|
||||
mDecodeStartTime = TimeStamp::Now();
|
||||
}
|
||||
@ -1652,7 +1652,7 @@ void MediaDecoderStateMachine::Seek(double aTime)
|
||||
mSeekTime = std::min(mSeekTime, mEndTime);
|
||||
mSeekTime = std::max(mStartTime, mSeekTime);
|
||||
mBasePosition = mSeekTime - mStartTime;
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %f)", mDecoder.get(), aTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %f)", mDecoder.get(), aTime));
|
||||
mState = DECODER_STATE_SEEKING;
|
||||
if (mDecoder->GetDecodedStream()) {
|
||||
mDecoder->RecreateDecodedStream(mSeekTime - mStartTime);
|
||||
@ -1675,7 +1675,7 @@ void MediaDecoderStateMachine::StopDecodeThread()
|
||||
mStopDecodeThread = true;
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
if (mDecodeThread) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder.get()));
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
mDecodeThread->Shutdown();
|
||||
@ -1704,7 +1704,7 @@ void MediaDecoderStateMachine::StopAudioThread()
|
||||
mStopAudioThread = true;
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
if (mAudioThread) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Shutdown audio thread", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Shutdown audio thread", mDecoder.get()));
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
mAudioThread->Shutdown();
|
||||
@ -1801,7 +1801,7 @@ MediaDecoderStateMachine::StartAudioThread()
|
||||
nullptr,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
return rv;
|
||||
}
|
||||
@ -1884,7 +1884,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
NS_ASSERTION(mState == DECODER_STATE_DECODING_METADATA,
|
||||
"Only call when in metadata decoding state");
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoding Media Headers", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoding Media Headers", mDecoder.get()));
|
||||
nsresult res;
|
||||
MediaInfo info;
|
||||
MetadataTags* tags;
|
||||
@ -1935,10 +1935,10 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
"Active seekable media should have end time");
|
||||
MOZ_ASSERT(!(mMediaSeekable && mTransportSeekable) ||
|
||||
GetDuration() != -1, "Seekable media should have duration");
|
||||
LOG(PR_LOG_DEBUG, ("%p Media goes from %lld to %lld (duration %lld)"
|
||||
" transportSeekable=%d, mediaSeekable=%d",
|
||||
mDecoder.get(), mStartTime, mEndTime, GetDuration(),
|
||||
mTransportSeekable, mMediaSeekable));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Media goes from %lld to %lld (duration %lld)"
|
||||
" transportSeekable=%d, mediaSeekable=%d",
|
||||
mDecoder.get(), mStartTime, mEndTime, GetDuration(),
|
||||
mTransportSeekable, mMediaSeekable));
|
||||
|
||||
// Inform the element that we've loaded the metadata and the first frame,
|
||||
// setting the default framebuffer size for audioavailable events. Also,
|
||||
@ -1963,7 +1963,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
NS_DispatchToMainThread(metadataLoadedEvent, NS_DISPATCH_NORMAL);
|
||||
|
||||
if (mState == DECODER_STATE_DECODING_METADATA) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING_METADATA to DECODING", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING_METADATA to DECODING", mDecoder.get()));
|
||||
StartDecoding();
|
||||
}
|
||||
|
||||
@ -2068,8 +2068,8 @@ void MediaDecoderStateMachine::DecodeSeek()
|
||||
}
|
||||
|
||||
// Try to decode another frame to detect if we're at the end...
|
||||
LOG(PR_LOG_DEBUG, ("%p Seek completed, mCurrentFrameTime=%lld\n",
|
||||
mDecoder.get(), mCurrentFrameTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Seek completed, mCurrentFrameTime=%lld\n",
|
||||
mDecoder.get(), mCurrentFrameTime));
|
||||
|
||||
// Change state to DECODING or COMPLETED now. SeekingStopped will
|
||||
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
@ -2081,13 +2081,13 @@ void MediaDecoderStateMachine::DecodeSeek()
|
||||
// Seeked to end of media, move to COMPLETED state. Note we don't do
|
||||
// this if we're playing a live stream, since the end of media will advance
|
||||
// once we download more data!
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
|
||||
mDecoder.get(), seekTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
|
||||
mDecoder.get(), seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStoppedAtEnd);
|
||||
mState = DECODER_STATE_COMPLETED;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING",
|
||||
mDecoder.get(), seekTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING",
|
||||
mDecoder.get(), seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStopped);
|
||||
StartDecoding();
|
||||
}
|
||||
@ -2278,19 +2278,19 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
!mDecoder->IsDataCachedToEndOfResource() &&
|
||||
!resource->IsSuspended())
|
||||
{
|
||||
LOG(PR_LOG_DEBUG,
|
||||
("%p Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mDecoder.get(),
|
||||
mBufferingWait,
|
||||
mBufferingWait - elapsed.ToSeconds(),
|
||||
(mQuickBuffering ? "(quick exit)" : "")));
|
||||
DECODER_LOG(PR_LOG_DEBUG,
|
||||
("%p Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mDecoder.get(),
|
||||
mBufferingWait,
|
||||
mBufferingWait - elapsed.ToSeconds(),
|
||||
(mQuickBuffering ? "(quick exit)" : "")));
|
||||
ScheduleStateMachine(USECS_PER_S);
|
||||
return NS_OK;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get()));
|
||||
LOG(PR_LOG_DEBUG, ("%p Buffered for %.3lfs",
|
||||
mDecoder.get(),
|
||||
(now - mBufferingStart).ToSeconds()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Buffered for %.3lfs",
|
||||
mDecoder.get(),
|
||||
(now - mBufferingStart).ToSeconds()));
|
||||
StartDecoding();
|
||||
}
|
||||
|
||||
@ -2377,8 +2377,8 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
|
||||
}
|
||||
|
||||
if (!PR_GetEnv("MOZ_QUIET")) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder playing video frame %lld",
|
||||
mDecoder.get(), aData->mTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing video frame %lld",
|
||||
mDecoder.get(), aData->mTime));
|
||||
}
|
||||
|
||||
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
|
||||
@ -2487,10 +2487,10 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
currentFrame = frame;
|
||||
#ifdef PR_LOGGING
|
||||
if (!PR_GetEnv("MOZ_QUIET")) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime));
|
||||
if (droppedFrames++) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)",
|
||||
mDecoder.get(), frame->mTime, droppedFrames - 1));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)",
|
||||
mDecoder.get(), frame->mTime, droppedFrames - 1));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2632,7 +2632,7 @@ VideoData* MediaDecoderStateMachine::FindStartTime()
|
||||
// first actual audio frame we have, we'll inject silence during playback
|
||||
// to ensure the audio starts at the correct time.
|
||||
mAudioStartTime = mStartTime;
|
||||
LOG(PR_LOG_DEBUG, ("%p Media start time is %lld", mDecoder.get(), mStartTime));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Media start time is %lld", mDecoder.get(), mStartTime));
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -2693,15 +2693,15 @@ void MediaDecoderStateMachine::StartBuffering()
|
||||
// the element we're buffering or not.
|
||||
UpdateReadyState();
|
||||
mState = DECODER_STATE_BUFFERING;
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING to BUFFERING, decoded for %.3lfs",
|
||||
mDecoder.get(), decodeDuration.ToSeconds()));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING to BUFFERING, decoded for %.3lfs",
|
||||
mDecoder.get(), decodeDuration.ToSeconds()));
|
||||
#ifdef PR_LOGGING
|
||||
MediaDecoder::Statistics stats = mDecoder->GetStatistics();
|
||||
#endif
|
||||
LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
|
||||
mDecoder.get(),
|
||||
stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
|
||||
stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"));
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
|
||||
mDecoder.get(),
|
||||
stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
|
||||
stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"));
|
||||
}
|
||||
|
||||
nsresult MediaDecoderStateMachine::GetBuffered(dom::TimeRanges* aBuffered) {
|
||||
|
@ -33,13 +33,13 @@
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gMediaResourceLog;
|
||||
#define LOG(msg, ...) PR_LOG(gMediaResourceLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
#define RESOURCE_LOG(msg, ...) PR_LOG(gMediaResourceLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
// Debug logging macro with object pointer and class name.
|
||||
#define CMLOG(msg, ...) \
|
||||
LOG("%p [ChannelMediaResource]: " msg, this, ##__VA_ARGS__)
|
||||
RESOURCE_LOG("%p [ChannelMediaResource]: " msg, this, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(msg, ...)
|
||||
#define RESOURCE_LOG(msg, ...)
|
||||
#define CMLOG(msg, ...)
|
||||
#endif
|
||||
|
||||
@ -475,10 +475,10 @@ ChannelMediaResource::CopySegmentToCache(nsIInputStream *aInStream,
|
||||
closure->mResource->mDecoder->NotifyDataArrived(aFromSegment, aCount, closure->mResource->mOffset);
|
||||
|
||||
// Keep track of where we're up to.
|
||||
LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "
|
||||
"[%d] bytes for decoder[%p]",
|
||||
closure->mResource, closure->mResource->mOffset, aCount,
|
||||
closure->mResource->mDecoder);
|
||||
RESOURCE_LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "
|
||||
"[%d] bytes for decoder[%p]",
|
||||
closure->mResource, closure->mResource->mOffset, aCount,
|
||||
closure->mResource->mDecoder);
|
||||
closure->mResource->mOffset += aCount;
|
||||
|
||||
closure->mResource->mCacheStream.NotifyDataReceived(aCount, aFromSegment,
|
||||
|
@ -32,6 +32,9 @@ namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gMediaStreamGraphLog;
|
||||
#define STREAM_LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define STREAM_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -39,6 +42,14 @@ PRLogModuleInfo* gMediaStreamGraphLog;
|
||||
*/
|
||||
static MediaStreamGraphImpl* gGraph;
|
||||
|
||||
MediaStreamGraphImpl::~MediaStreamGraphImpl()
|
||||
{
|
||||
NS_ASSERTION(IsEmpty(),
|
||||
"All streams should have been destroyed by messages from the main thread");
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this));
|
||||
}
|
||||
|
||||
|
||||
StreamTime
|
||||
MediaStreamGraphImpl::GetDesiredBufferEnd(MediaStream* aStream)
|
||||
{
|
||||
@ -52,7 +63,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
|
||||
{
|
||||
if (aStream->mFinished)
|
||||
return;
|
||||
LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
|
||||
aStream->mFinished = true;
|
||||
// Force at least one more iteration of the control loop, since we rely
|
||||
// on UpdateCurrentTime to notify our listeners once the stream end
|
||||
@ -65,7 +76,7 @@ MediaStreamGraphImpl::AddStream(MediaStream* aStream)
|
||||
{
|
||||
aStream->mBufferStartTime = mCurrentTime;
|
||||
*mStreams.AppendElement() = already_AddRefed<MediaStream>(aStream);
|
||||
LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph", aStream));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph", aStream));
|
||||
}
|
||||
|
||||
void
|
||||
@ -86,7 +97,7 @@ MediaStreamGraphImpl::RemoveStream(MediaStream* aStream)
|
||||
// This unrefs the stream, probably destroying it
|
||||
mStreams.RemoveElement(aStream);
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("Removing media stream %p from the graph", aStream));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Removing media stream %p from the graph", aStream));
|
||||
}
|
||||
|
||||
void
|
||||
@ -120,16 +131,16 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
StreamTime t =
|
||||
GraphTimeToStreamTime(aStream, mStateComputedTime) +
|
||||
(aDesiredUpToTime - mStateComputedTime);
|
||||
LOG(PR_LOG_DEBUG+1, ("Calling NotifyPull aStream=%p t=%f current end=%f", aStream,
|
||||
MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Calling NotifyPull aStream=%p t=%f current end=%f", aStream,
|
||||
MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
if (t > aStream->mBuffer.GetEnd()) {
|
||||
*aEnsureNextIteration = true;
|
||||
#ifdef DEBUG
|
||||
if (aStream->mListeners.Length() == 0) {
|
||||
LOG(PR_LOG_ERROR, ("No listeners in NotifyPull aStream=%p desired=%f current end=%f",
|
||||
aStream, MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
STREAM_LOG(PR_LOG_ERROR, ("No listeners in NotifyPull aStream=%p desired=%f current end=%f",
|
||||
aStream, MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
aStream->DumpTrackInfo();
|
||||
}
|
||||
#endif
|
||||
@ -155,9 +166,9 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
}
|
||||
if (data->mCommands & SourceMediaStream::TRACK_CREATE) {
|
||||
MediaSegment* segment = data->mData.forget();
|
||||
LOG(PR_LOG_DEBUG, ("SourceMediaStream %p creating track %d, rate %d, start %lld, initial end %lld",
|
||||
aStream, data->mID, data->mRate, int64_t(data->mStart),
|
||||
int64_t(segment->GetDuration())));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("SourceMediaStream %p creating track %d, rate %d, start %lld, initial end %lld",
|
||||
aStream, data->mID, data->mRate, int64_t(data->mStart),
|
||||
int64_t(segment->GetDuration())));
|
||||
aStream->mBuffer.AddTrack(data->mID, data->mRate, data->mStart, segment);
|
||||
// The track has taken ownership of data->mData, so let's replace
|
||||
// data->mData with an empty clone.
|
||||
@ -165,10 +176,10 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
data->mCommands &= ~SourceMediaStream::TRACK_CREATE;
|
||||
} else if (data->mData->GetDuration() > 0) {
|
||||
MediaSegment* dest = aStream->mBuffer.FindTrack(data->mID)->GetSegment();
|
||||
LOG(PR_LOG_DEBUG+1, ("SourceMediaStream %p track %d, advancing end from %lld to %lld",
|
||||
aStream, data->mID,
|
||||
int64_t(dest->GetDuration()),
|
||||
int64_t(dest->GetDuration() + data->mData->GetDuration())));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("SourceMediaStream %p track %d, advancing end from %lld to %lld",
|
||||
aStream, data->mID,
|
||||
int64_t(dest->GetDuration()),
|
||||
int64_t(dest->GetDuration() + data->mData->GetDuration())));
|
||||
dest->AppendFrom(data->mData);
|
||||
}
|
||||
if (data->mCommands & SourceMediaStream::TRACK_END) {
|
||||
@ -322,27 +333,27 @@ MediaStreamGraphImpl::UpdateCurrentTime()
|
||||
SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime;
|
||||
|
||||
mCurrentTimeStamp = now;
|
||||
LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)",
|
||||
MediaTimeToSeconds(nextCurrentTime),
|
||||
(now - mInitialTimeStamp).ToSeconds(),
|
||||
MediaTimeToSeconds(mStateComputedTime)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)",
|
||||
MediaTimeToSeconds(nextCurrentTime),
|
||||
(now - mInitialTimeStamp).ToSeconds(),
|
||||
MediaTimeToSeconds(mStateComputedTime)));
|
||||
} else {
|
||||
prevCurrentTime = mCurrentTime;
|
||||
nextCurrentTime = mCurrentTime + MEDIA_GRAPH_TARGET_PERIOD_MS;
|
||||
LOG(PR_LOG_DEBUG+1, ("Updating offline current time to %f (mStateComputedTime %f)",
|
||||
MediaTimeToSeconds(nextCurrentTime),
|
||||
MediaTimeToSeconds(mStateComputedTime)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Updating offline current time to %f (mStateComputedTime %f)",
|
||||
MediaTimeToSeconds(nextCurrentTime),
|
||||
MediaTimeToSeconds(mStateComputedTime)));
|
||||
}
|
||||
|
||||
if (mStateComputedTime < nextCurrentTime) {
|
||||
LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
|
||||
STREAM_LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
|
||||
nextCurrentTime = mStateComputedTime;
|
||||
}
|
||||
|
||||
if (prevCurrentTime >= nextCurrentTime) {
|
||||
NS_ASSERTION(prevCurrentTime == nextCurrentTime, "Time can't go backwards!");
|
||||
// This could happen due to low clock resolution, maybe?
|
||||
LOG(PR_LOG_DEBUG, ("Time did not advance"));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Time did not advance"));
|
||||
// There's not much left to do here, but the code below that notifies
|
||||
// listeners that streams have ended still needs to run.
|
||||
}
|
||||
@ -386,9 +397,9 @@ MediaStreamGraphImpl::UpdateCurrentTime()
|
||||
if (stream->mFinished && !stream->mNotifiedFinished) {
|
||||
streamsReadyToFinish.AppendElement(stream);
|
||||
}
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p bufferStartTime=%f blockedTime=%f",
|
||||
stream, MediaTimeToSeconds(stream->mBufferStartTime),
|
||||
MediaTimeToSeconds(blockedTime)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p bufferStartTime=%f blockedTime=%f",
|
||||
stream, MediaTimeToSeconds(stream->mBufferStartTime),
|
||||
MediaTimeToSeconds(blockedTime)));
|
||||
}
|
||||
|
||||
mCurrentTime = nextCurrentTime;
|
||||
@ -422,19 +433,19 @@ MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream, GraphTime aTime,
|
||||
INCLUDE_TRAILING_BLOCKED_INTERVAL);
|
||||
#ifdef DEBUG
|
||||
if (bufferEnd < mCurrentTime) {
|
||||
LOG(PR_LOG_ERROR, ("MediaStream %p underrun, "
|
||||
"bufferEnd %f < mCurrentTime %f (%lld < %lld), Streamtime %lld",
|
||||
aStream, MediaTimeToSeconds(bufferEnd), MediaTimeToSeconds(mCurrentTime),
|
||||
bufferEnd, mCurrentTime, aStream->GetBufferEnd()));
|
||||
STREAM_LOG(PR_LOG_ERROR, ("MediaStream %p underrun, "
|
||||
"bufferEnd %f < mCurrentTime %f (%lld < %lld), Streamtime %lld",
|
||||
aStream, MediaTimeToSeconds(bufferEnd), MediaTimeToSeconds(mCurrentTime),
|
||||
bufferEnd, mCurrentTime, aStream->GetBufferEnd()));
|
||||
aStream->DumpTrackInfo();
|
||||
NS_ASSERTION(bufferEnd >= mCurrentTime, "Buffer underran");
|
||||
}
|
||||
#endif
|
||||
// We should block after bufferEnd.
|
||||
if (bufferEnd <= aTime) {
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p will block due to data underrun, "
|
||||
"bufferEnd %f",
|
||||
aStream, MediaTimeToSeconds(bufferEnd)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p will block due to data underrun, "
|
||||
"bufferEnd %f",
|
||||
aStream, MediaTimeToSeconds(bufferEnd)));
|
||||
return true;
|
||||
}
|
||||
// We should keep blocking if we're currently blocked and we don't have
|
||||
@ -443,9 +454,9 @@ MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream, GraphTime aTime,
|
||||
// but we might as well remain unblocked and play the data we've got while
|
||||
// we can.
|
||||
if (bufferEnd <= aEndBlockingDecisions && aStream->mBlocked.GetBefore(aTime)) {
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p will block due to speculative data underrun, "
|
||||
"bufferEnd %f",
|
||||
aStream, MediaTimeToSeconds(bufferEnd)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p will block due to speculative data underrun, "
|
||||
"bufferEnd %f",
|
||||
aStream, MediaTimeToSeconds(bufferEnd)));
|
||||
return true;
|
||||
}
|
||||
// Reconsider decisions at bufferEnd
|
||||
@ -573,8 +584,8 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions)
|
||||
{
|
||||
bool blockingDecisionsWillChange = false;
|
||||
|
||||
LOG(PR_LOG_DEBUG+1, ("Media graph %p computing blocking for time %f",
|
||||
this, MediaTimeToSeconds(mStateComputedTime)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Media graph %p computing blocking for time %f",
|
||||
this, MediaTimeToSeconds(mStateComputedTime)));
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
MediaStream* stream = mStreams[i];
|
||||
if (!stream->mInBlockingSet) {
|
||||
@ -600,9 +611,9 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions)
|
||||
blockingDecisionsWillChange = true;
|
||||
}
|
||||
}
|
||||
LOG(PR_LOG_DEBUG+1, ("Media graph %p computed blocking for interval %f to %f",
|
||||
this, MediaTimeToSeconds(mStateComputedTime),
|
||||
MediaTimeToSeconds(aEndBlockingDecisions)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Media graph %p computed blocking for interval %f to %f",
|
||||
this, MediaTimeToSeconds(mStateComputedTime),
|
||||
MediaTimeToSeconds(aEndBlockingDecisions)));
|
||||
mStateComputedTime = aEndBlockingDecisions;
|
||||
|
||||
if (blockingDecisionsWillChange) {
|
||||
@ -676,15 +687,15 @@ MediaStreamGraphImpl::RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams
|
||||
if (stream->mFinished) {
|
||||
GraphTime endTime = StreamTimeToGraphTime(stream, stream->GetBufferEnd());
|
||||
if (endTime <= aTime) {
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p is blocked due to being finished", stream));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p is blocked due to being finished", stream));
|
||||
// We'll block indefinitely
|
||||
MarkStreamBlocking(stream);
|
||||
*aEnd = aEndBlockingDecisions;
|
||||
continue;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)",
|
||||
stream, MediaTimeToSeconds(stream->GetBufferEnd()),
|
||||
MediaTimeToSeconds(endTime)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)",
|
||||
stream, MediaTimeToSeconds(stream->GetBufferEnd()),
|
||||
MediaTimeToSeconds(endTime)));
|
||||
*aEnd = std::min(*aEnd, endTime);
|
||||
}
|
||||
}
|
||||
@ -693,7 +704,7 @@ MediaStreamGraphImpl::RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams
|
||||
bool explicitBlock = stream->mExplicitBlockerCount.GetAt(aTime, &end) > 0;
|
||||
*aEnd = std::min(*aEnd, end);
|
||||
if (explicitBlock) {
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p is blocked due to explicit blocker", stream));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p is blocked due to explicit blocker", stream));
|
||||
MarkStreamBlocking(stream);
|
||||
continue;
|
||||
}
|
||||
@ -833,8 +844,8 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream,
|
||||
TimeToTicksRoundDown(track->GetRate(), audioOutput.mBlockedAudioTime);
|
||||
|
||||
output.InsertNullDataAtStart(endTicks - startTicks);
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing blocking-silence samples for %f to %f",
|
||||
aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(end)));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing blocking-silence samples for %f to %f",
|
||||
aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(end)));
|
||||
} else {
|
||||
TrackTicks startTicks =
|
||||
track->TimeToTicksRoundDown(GraphTimeToStreamTime(aStream, t));
|
||||
@ -854,9 +865,9 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream,
|
||||
NS_ASSERTION(endTicks == sliceEnd || track->IsEnded(),
|
||||
"Ran out of data but track not ended?");
|
||||
output.ApplyVolume(volume);
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing samples for %f to %f (samples %lld to %lld)",
|
||||
aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(end),
|
||||
startTicks, endTicks));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing samples for %f to %f (samples %lld to %lld)",
|
||||
aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(end),
|
||||
startTicks, endTicks));
|
||||
}
|
||||
// Need unique id for stream & track - and we want it to match the inserter
|
||||
output.WriteTo(LATENCY_STREAM_ID(aStream, track->GetID()),
|
||||
@ -912,9 +923,9 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||
if (!frame || *frame == aStream->mLastPlayedVideoFrame)
|
||||
return;
|
||||
|
||||
LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing video frame %p (%dx%d)",
|
||||
aStream, frame->GetImage(), frame->GetIntrinsicSize().width,
|
||||
frame->GetIntrinsicSize().height));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing video frame %p (%dx%d)",
|
||||
aStream, frame->GetImage(), frame->GetIntrinsicSize().width,
|
||||
frame->GetIntrinsicSize().height));
|
||||
GraphTime startTime = StreamTimeToGraphTime(aStream,
|
||||
track->TicksToTimeRoundDown(start), INCLUDE_TRAILING_BLOCKED_INTERVAL);
|
||||
TimeStamp targetTime = mCurrentTimeStamp +
|
||||
@ -1220,7 +1231,7 @@ MediaStreamGraphImpl::RunThread()
|
||||
if (finalUpdate) {
|
||||
// Enter shutdown mode. The stable-state handler will detect this
|
||||
// and complete shutdown. Destroy any streams immediately.
|
||||
LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p waiting for main thread cleanup", this));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p waiting for main thread cleanup", this));
|
||||
// Commit to shutting down this graph object.
|
||||
mLifecycleState = LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP;
|
||||
// No need to Destroy streams here. The main-thread owner of each
|
||||
@ -1240,17 +1251,17 @@ MediaStreamGraphImpl::RunThread()
|
||||
// least once a minute, if we need to wake up at all
|
||||
timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
|
||||
timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
|
||||
LOG(PR_LOG_DEBUG+1, ("Waiting for next iteration; at %f, timeout=%f",
|
||||
(now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Waiting for next iteration; at %f, timeout=%f",
|
||||
(now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
|
||||
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
|
||||
} else {
|
||||
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
|
||||
}
|
||||
if (timeout > 0) {
|
||||
mMonitor.Wait(timeout);
|
||||
LOG(PR_LOG_DEBUG+1, ("Resuming after timeout; at %f, elapsed=%f",
|
||||
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
|
||||
(TimeStamp::Now() - now).ToSeconds()));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("Resuming after timeout; at %f, elapsed=%f",
|
||||
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
|
||||
(TimeStamp::Now() - now).ToSeconds()));
|
||||
}
|
||||
}
|
||||
mWaitState = WAITSTATE_RUNNING;
|
||||
@ -1289,7 +1300,7 @@ MediaStreamGraphImpl::ShutdownThreads()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
|
||||
// mGraph's thread is not running so it's OK to do whatever here
|
||||
LOG(PR_LOG_DEBUG, ("Stopping threads for MediaStreamGraph %p", this));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Stopping threads for MediaStreamGraph %p", this));
|
||||
|
||||
if (mThread) {
|
||||
mThread->Shutdown();
|
||||
@ -1301,7 +1312,7 @@ void
|
||||
MediaStreamGraphImpl::ForceShutDown()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
|
||||
LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p ForceShutdown", this));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p ForceShutdown", this));
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mForceShutDown = true;
|
||||
@ -1475,7 +1486,7 @@ MediaStreamGraphImpl::RunInStableState()
|
||||
if (mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP && IsEmpty()) {
|
||||
// Complete shutdown. First, ensure that this graph is no longer used.
|
||||
// A new graph graph will be created if one is needed.
|
||||
LOG(PR_LOG_DEBUG, ("Disconnecting MediaStreamGraph %p", this));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Disconnecting MediaStreamGraph %p", this));
|
||||
if (this == gGraph) {
|
||||
// null out gGraph if that's the graph being shut down
|
||||
gGraph = nullptr;
|
||||
@ -2196,8 +2207,8 @@ SourceMediaStream::GetBufferedTicks(TrackID aID)
|
||||
void
|
||||
MediaInputPort::Init()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph",
|
||||
this, mSource, mDest));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph",
|
||||
this, mSource, mDest));
|
||||
mSource->AddConsumer(this);
|
||||
mDest->AddInput(this);
|
||||
// mPortCount decremented via MediaInputPort::Destroy's message
|
||||
@ -2415,7 +2426,7 @@ MediaStreamGraph::GetInstance()
|
||||
}
|
||||
|
||||
gGraph = new MediaStreamGraphImpl(true);
|
||||
LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
|
||||
}
|
||||
|
||||
return gGraph;
|
||||
|
@ -1057,7 +1057,7 @@ protected:
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaStreamGraph);
|
||||
}
|
||||
~MediaStreamGraph()
|
||||
virtual ~MediaStreamGraph()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaStreamGraph);
|
||||
}
|
||||
|
@ -19,13 +19,6 @@ namespace mozilla {
|
||||
template <typename T>
|
||||
class LinkedList;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaStreamGraphLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Assume we can run an iteration of the MediaStreamGraph loop in this much time
|
||||
* or less.
|
||||
@ -120,12 +113,7 @@ public:
|
||||
* implement OfflineAudioContext. They do not support MediaStream inputs.
|
||||
*/
|
||||
explicit MediaStreamGraphImpl(bool aRealtime);
|
||||
~MediaStreamGraphImpl()
|
||||
{
|
||||
NS_ASSERTION(IsEmpty(),
|
||||
"All streams should have been destroyed by messages from the main thread");
|
||||
LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this));
|
||||
}
|
||||
virtual ~MediaStreamGraphImpl();
|
||||
|
||||
// Main thread only.
|
||||
/**
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gRtspMediaResourceLog;
|
||||
#define LOG(msg, ...) PR_LOG(gRtspMediaResourceLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
#define RTSP_LOG(msg, ...) PR_LOG(gRtspMediaResourceLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
// Debug logging macro with object pointer and class name.
|
||||
#define RTSPMLOG(msg, ...) \
|
||||
LOG("%p [RtspMediaResource]: " msg, this, ##__VA_ARGS__)
|
||||
RTSP_LOG("%p [RtspMediaResource]: " msg, this, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(msg, ...)
|
||||
#define RTSP_LOG(msg, ...)
|
||||
#define RTSPMLOG(msg, ...)
|
||||
#endif
|
||||
|
||||
@ -72,6 +72,7 @@ public:
|
||||
void Start() {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
mIsStarted = true;
|
||||
mFrameType = 0;
|
||||
}
|
||||
void Stop() {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
@ -444,6 +445,9 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
|
||||
nsIStreamingProtocolMetaData *meta)
|
||||
{
|
||||
if (mIsConnected) {
|
||||
for (uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
|
||||
mTrackBuffer[i]->Start();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -523,9 +527,19 @@ RtspMediaResource::OnDisconnected(uint8_t aTrackIdx, nsresult aReason)
|
||||
mTrackBuffer[i]->Reset();
|
||||
}
|
||||
|
||||
if (aReason == NS_ERROR_CONNECTION_REFUSED) {
|
||||
if (aReason == NS_ERROR_NOT_INITIALIZED ||
|
||||
aReason == NS_ERROR_CONNECTION_REFUSED ||
|
||||
aReason == NS_ERROR_NOT_CONNECTED) {
|
||||
|
||||
RTSPMLOG("Error in OnDisconnected 0x%x", aReason);
|
||||
|
||||
mDecoder->NetworkError();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Resetting the decoder and media element when the connection
|
||||
// between Rtsp client and server goes down.
|
||||
mDecoder->ResetConnectionState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -11,23 +11,23 @@ namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaStreamGraphLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#define STREAM_LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define STREAM_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
StreamBuffer::DumpTrackInfo() const
|
||||
{
|
||||
LOG(PR_LOG_ALWAYS, ("DumpTracks: mTracksKnownTime %lld", mTracksKnownTime));
|
||||
STREAM_LOG(PR_LOG_ALWAYS, ("DumpTracks: mTracksKnownTime %lld", mTracksKnownTime));
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (track->IsEnded()) {
|
||||
LOG(PR_LOG_ALWAYS, ("Track[%d] %d: ended", i, track->GetID()));
|
||||
STREAM_LOG(PR_LOG_ALWAYS, ("Track[%d] %d: ended", i, track->GetID()));
|
||||
} else {
|
||||
LOG(PR_LOG_ALWAYS, ("Track[%d] %d: %lld", i, track->GetID(),
|
||||
track->GetEndTimeRoundDown()));
|
||||
STREAM_LOG(PR_LOG_ALWAYS, ("Track[%d] %d: %lld", i, track->GetID(),
|
||||
track->GetEndTimeRoundDown()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#define STREAM_LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#define STREAM_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -178,9 +178,9 @@ protected:
|
||||
segment->AppendNullData(outputStart);
|
||||
StreamBuffer::Track* track =
|
||||
&mBuffer.AddTrack(id, rate, outputStart, segment.forget());
|
||||
LOG(PR_LOG_DEBUG, ("TrackUnionStream %p adding track %d for input stream %p track %d, start ticks %lld",
|
||||
this, id, aPort->GetSource(), aTrack->GetID(),
|
||||
(long long)outputStart));
|
||||
STREAM_LOG(PR_LOG_DEBUG, ("TrackUnionStream %p adding track %d for input stream %p track %d, start ticks %lld",
|
||||
this, id, aPort->GetSource(), aTrack->GetID(),
|
||||
(long long)outputStart));
|
||||
|
||||
TrackMapEntry* map = mTrackMap.AppendElement();
|
||||
map->mEndOfConsumedInputTicks = 0;
|
||||
@ -253,8 +253,8 @@ protected:
|
||||
if (interval.mInputIsBlocked) {
|
||||
// Maybe the input track ended?
|
||||
segment->AppendNullData(ticks);
|
||||
LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of null data to track %d",
|
||||
this, (long long)ticks, outputTrack->GetID()));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of null data to track %d",
|
||||
this, (long long)ticks, outputTrack->GetID()));
|
||||
} else {
|
||||
// Figuring out which samples to use from the input stream is tricky
|
||||
// because its start time and our start time may differ by a fraction
|
||||
@ -322,9 +322,9 @@ protected:
|
||||
std::min(inputTrackEndPoint, inputStartTicks),
|
||||
std::min(inputTrackEndPoint, inputEndTicks));
|
||||
}
|
||||
LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
|
||||
this, (long long)(std::min(inputTrackEndPoint, inputEndTicks) - std::min(inputTrackEndPoint, inputStartTicks)),
|
||||
outputTrack->GetID()));
|
||||
STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
|
||||
this, (long long)(std::min(inputTrackEndPoint, inputEndTicks) - std::min(inputTrackEndPoint, inputStartTicks)),
|
||||
outputTrack->GetID()));
|
||||
}
|
||||
ApplyTrackDisabling(outputTrack->GetID(), segment);
|
||||
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
|
||||
|
@ -30,9 +30,9 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(WebVTTListener)
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gTextTrackLog;
|
||||
# define LOG(...) PR_LOG(gTextTrackLog, PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
# define VTT_LOG(...) PR_LOG(gTextTrackLog, PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#else
|
||||
# define LOG(msg)
|
||||
# define VTT_LOG(msg)
|
||||
#endif
|
||||
|
||||
WebVTTListener::WebVTTListener(HTMLTrackElement* aElement)
|
||||
@ -44,12 +44,12 @@ WebVTTListener::WebVTTListener(HTMLTrackElement* aElement)
|
||||
gTextTrackLog = PR_NewLogModule("TextTrack");
|
||||
}
|
||||
#endif
|
||||
LOG("WebVTTListener created.");
|
||||
VTT_LOG("WebVTTListener created.");
|
||||
}
|
||||
|
||||
WebVTTListener::~WebVTTListener()
|
||||
{
|
||||
LOG("WebVTTListener destroyed.");
|
||||
VTT_LOG("WebVTTListener destroyed.");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -124,7 +124,7 @@ WebVTTListener::ParseChunk(nsIInputStream* aInStream, void* aClosure,
|
||||
WebVTTListener* listener = static_cast<WebVTTListener*>(aClosure);
|
||||
|
||||
if (NS_FAILED(listener->mParserWrapper->Parse(buffer))) {
|
||||
LOG("Unable to parse chunk of WEBVTT text. Aborting.");
|
||||
VTT_LOG("Unable to parse chunk of WEBVTT text. Aborting.");
|
||||
*aWriteCount = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -127,6 +127,10 @@ OpusTrackEncoder::~OpusTrackEncoder()
|
||||
if (mEncoder) {
|
||||
opus_encoder_destroy(mEncoder);
|
||||
}
|
||||
if (mResampler) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -324,6 +328,7 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
mDoneEncoding = true;
|
||||
if (mResampler) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
mResampler = nullptr;
|
||||
}
|
||||
LOG("[Opus] Done encoding.");
|
||||
}
|
||||
|
225
content/media/fmp4/BlankDecoderModule.cpp
Normal file
225
content/media/fmp4/BlankDecoderModule.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "MediaDecoderReader.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "nsRect.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Decoder that uses a passed in object's Create function to create blank
|
||||
// MediaData objects.
|
||||
template<class BlankMediaDataCreator>
|
||||
class BlankMediaDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
BlankMediaDataDecoder(BlankMediaDataCreator* aCreator)
|
||||
: mCreator(aCreator),
|
||||
mNextDTS(-1),
|
||||
mNextOffset(-1)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual DecoderStatus Input(const uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
Microseconds aDTS,
|
||||
Microseconds aPTS,
|
||||
int64_t aOffsetInStream) MOZ_OVERRIDE
|
||||
{
|
||||
// Accepts input, and outputs on the second input, using the difference
|
||||
// in DTS as the duration.
|
||||
if (mOutput) {
|
||||
return DECODE_STATUS_NOT_ACCEPTING;
|
||||
}
|
||||
if (mNextDTS != -1 && mNextOffset != -1) {
|
||||
Microseconds duration = aDTS - mNextDTS;
|
||||
mOutput = mCreator->Create(mNextDTS, duration, mNextOffset);
|
||||
}
|
||||
|
||||
mNextDTS = aDTS;
|
||||
mNextOffset = aOffsetInStream;
|
||||
return DECODE_STATUS_OK;
|
||||
}
|
||||
|
||||
virtual DecoderStatus Output(nsAutoPtr<MediaData>& aOutData) MOZ_OVERRIDE
|
||||
{
|
||||
if (!mOutput) {
|
||||
return DECODE_STATUS_NEED_MORE_INPUT;
|
||||
}
|
||||
aOutData = mOutput.forget();
|
||||
return DECODE_STATUS_OK;
|
||||
}
|
||||
|
||||
virtual DecoderStatus Flush() MOZ_OVERRIDE {
|
||||
return DECODE_STATUS_OK;
|
||||
}
|
||||
private:
|
||||
nsAutoPtr<BlankMediaDataCreator> mCreator;
|
||||
Microseconds mNextDTS;
|
||||
int64_t mNextOffset;
|
||||
nsAutoPtr<MediaData> mOutput;
|
||||
bool mHasInput;
|
||||
};
|
||||
|
||||
static const uint32_t sFrameWidth = 320;
|
||||
static const uint32_t sFrameHeight = 240;
|
||||
|
||||
class BlankVideoDataCreator {
|
||||
public:
|
||||
BlankVideoDataCreator(layers::ImageContainer* aImageContainer)
|
||||
: mImageContainer(aImageContainer)
|
||||
{
|
||||
mInfo.mDisplay = nsIntSize(sFrameWidth, sFrameHeight);
|
||||
mPicture = nsIntRect(0, 0, sFrameWidth, sFrameHeight);
|
||||
}
|
||||
|
||||
MediaData* Create(Microseconds aDTS,
|
||||
Microseconds aDuration,
|
||||
int64_t aOffsetInStream)
|
||||
{
|
||||
// Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
|
||||
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
|
||||
// 2x2 subsampled. Have the data pointers of each frame point to the
|
||||
// first plane, they'll always be zero'd memory anyway.
|
||||
uint8_t* frame = new uint8_t[sFrameWidth * sFrameHeight];
|
||||
memset(frame, 0, sFrameWidth * sFrameHeight);
|
||||
VideoData::YCbCrBuffer buffer;
|
||||
|
||||
// Y plane.
|
||||
buffer.mPlanes[0].mData = frame;
|
||||
buffer.mPlanes[0].mStride = sFrameWidth;
|
||||
buffer.mPlanes[0].mHeight = sFrameHeight;
|
||||
buffer.mPlanes[0].mWidth = sFrameWidth;
|
||||
buffer.mPlanes[0].mOffset = 0;
|
||||
buffer.mPlanes[0].mSkip = 0;
|
||||
|
||||
// Cb plane.
|
||||
buffer.mPlanes[1].mData = frame;
|
||||
buffer.mPlanes[1].mStride = sFrameWidth / 2;
|
||||
buffer.mPlanes[1].mHeight = sFrameHeight / 2;
|
||||
buffer.mPlanes[1].mWidth = sFrameWidth / 2;
|
||||
buffer.mPlanes[1].mOffset = 0;
|
||||
buffer.mPlanes[1].mSkip = 0;
|
||||
|
||||
// Cr plane.
|
||||
buffer.mPlanes[2].mData = frame;
|
||||
buffer.mPlanes[2].mStride = sFrameWidth / 2;
|
||||
buffer.mPlanes[2].mHeight = sFrameHeight / 2;
|
||||
buffer.mPlanes[2].mWidth = sFrameWidth / 2;
|
||||
buffer.mPlanes[2].mOffset = 0;
|
||||
buffer.mPlanes[2].mSkip = 0;
|
||||
|
||||
return VideoData::Create(mInfo,
|
||||
mImageContainer,
|
||||
nullptr,
|
||||
aOffsetInStream,
|
||||
aDTS,
|
||||
aDuration,
|
||||
buffer,
|
||||
true,
|
||||
aDTS,
|
||||
mPicture);
|
||||
}
|
||||
private:
|
||||
VideoInfo mInfo;
|
||||
nsIntRect mPicture;
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
};
|
||||
|
||||
|
||||
class BlankAudioDataCreator {
|
||||
public:
|
||||
BlankAudioDataCreator(uint32_t aChannelCount,
|
||||
uint32_t aSampleRate,
|
||||
uint16_t aBitsPerSample)
|
||||
: mFrameSum(0),
|
||||
mChannelCount(aChannelCount),
|
||||
mSampleRate(aSampleRate),
|
||||
mBitsPerSample(aBitsPerSample)
|
||||
{
|
||||
}
|
||||
|
||||
MediaData* Create(Microseconds aDTS,
|
||||
Microseconds aDuration,
|
||||
int64_t aOffsetInStream)
|
||||
{
|
||||
// Convert duration to frames. We add 1 to duration to account for
|
||||
// rounding errors, so we get a consistent tone.
|
||||
CheckedInt64 frames = UsecsToFrames(aDuration+1, mSampleRate);
|
||||
if (!frames.isValid() ||
|
||||
!mChannelCount ||
|
||||
!mSampleRate ||
|
||||
frames.value() > (UINT32_MAX / mChannelCount)) {
|
||||
return nullptr;
|
||||
}
|
||||
AudioDataValue* samples = new AudioDataValue[frames.value() * mChannelCount];
|
||||
// Fill the sound buffer with an A4 tone.
|
||||
static const float pi = 3.14159265f;
|
||||
static const float noteHz = 440.0f;
|
||||
for (int i = 0; i < frames.value(); i++) {
|
||||
float f = sin(2 * pi * noteHz * mFrameSum / mSampleRate);
|
||||
for (unsigned c = 0; c < mChannelCount; c++) {
|
||||
samples[i * mChannelCount + c] = AudioDataValue(f);
|
||||
}
|
||||
mFrameSum++;
|
||||
}
|
||||
return new AudioData(aOffsetInStream,
|
||||
aDTS,
|
||||
aDuration,
|
||||
uint32_t(frames.value()),
|
||||
samples,
|
||||
mChannelCount);
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t mFrameSum;
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mSampleRate;
|
||||
uint16_t mBitsPerSample;
|
||||
};
|
||||
|
||||
class BlankDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer) MOZ_OVERRIDE {
|
||||
BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aImageContainer);
|
||||
return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder);
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount,
|
||||
uint32_t aSampleRate,
|
||||
uint16_t aBitsPerSample,
|
||||
const uint8_t* aUserData,
|
||||
uint32_t aUserDataLength) MOZ_OVERRIDE {
|
||||
BlankAudioDataCreator* decoder = new BlankAudioDataCreator(aChannelCount,
|
||||
aSampleRate,
|
||||
aBitsPerSample);
|
||||
return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder);
|
||||
}
|
||||
};
|
||||
|
||||
PlatformDecoderModule* CreateBlankDecoderModule()
|
||||
{
|
||||
return new BlankDecoderModule();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
90
content/media/fmp4/MP4Decoder.cpp
Normal file
90
content/media/fmp4/MP4Decoder.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "MP4Decoder.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "WinUtils.h"
|
||||
using namespace mozilla::widget;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
|
||||
{
|
||||
return new MediaDecoderStateMachine(this, new MP4Reader(this));
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Decoder::GetSupportedCodecs(const nsACString& aType,
|
||||
char const *const ** aCodecList)
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// AAC in M4A.
|
||||
static char const *const aacAudioCodecs[] = {
|
||||
"mp4a.40.2", // AAC-LC
|
||||
// TODO: AAC-HE ?
|
||||
nullptr
|
||||
};
|
||||
if (aType.EqualsASCII("audio/mp4") ||
|
||||
aType.EqualsASCII("audio/x-m4a")) {
|
||||
if (aCodecList) {
|
||||
*aCodecList = aacAudioCodecs;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// H.264 + AAC in MP4.
|
||||
static char const *const h264Codecs[] = {
|
||||
"avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0
|
||||
"avc1.42001E", // H.264 Baseline Profile Level 3.0
|
||||
"avc1.58A01E", // H.264 Extended Profile Level 3.0
|
||||
"avc1.4D401E", // H.264 Main Profile Level 3.0
|
||||
"avc1.64001E", // H.264 High Profile Level 3.0
|
||||
"avc1.64001F", // H.264 High Profile Level 3.1
|
||||
"mp4a.40.2", // AAC-LC
|
||||
// TODO: There must be more profiles here?
|
||||
nullptr
|
||||
};
|
||||
if (aType.EqualsASCII("video/mp4")) {
|
||||
if (aCodecList) {
|
||||
*aCodecList = h264Codecs;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
HavePlatformMPEGDecoders()
|
||||
{
|
||||
return
|
||||
Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") ||
|
||||
#ifdef XP_WIN
|
||||
// We have H.264/AAC platform decoders on Windows Vista and up.
|
||||
WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION ||
|
||||
#endif
|
||||
// TODO: Other platforms...
|
||||
false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MP4Decoder::IsEnabled()
|
||||
{
|
||||
return HavePlatformMPEGDecoders() &&
|
||||
Preferences::GetBool("media.fragmented-mp4.enabled");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
41
content/media/fmp4/MP4Decoder.h
Normal file
41
content/media/fmp4/MP4Decoder.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
#if !defined(MP4Decoder_h_)
|
||||
#define MP4Decoder_h_
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Decoder that uses a bundled MP4 demuxer and platform decoders to play MP4.
|
||||
class MP4Decoder : public MediaDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
virtual MediaDecoder* Clone() {
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new MP4Decoder();
|
||||
}
|
||||
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine();
|
||||
|
||||
// Returns true if aType is a MIME type that we can render with the
|
||||
// a MP4 platform decoder backend. If aCodecList is non null,
|
||||
// it is filled with a (static const) null-terminated list of strings
|
||||
// denoting the codecs we'll playback.
|
||||
static bool GetSupportedCodecs(const nsACString& aType,
|
||||
char const *const ** aCodecList);
|
||||
|
||||
// Returns true if the MP4 backend is preffed on, and we're running on a
|
||||
// platform that is likely to have decoders for the contained formats.
|
||||
static bool IsEnabled();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
393
content/media/fmp4/MP4Reader.cpp
Normal file
393
content/media/fmp4/MP4Reader.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "MP4Reader.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/Streams.h"
|
||||
#include "nsSize.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Layers.h"
|
||||
|
||||
using mozilla::layers::Image;
|
||||
using mozilla::layers::LayerManager;
|
||||
using mozilla::layers::LayersBackend;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* GetDemuxerLog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("MP4Demuxer");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
#define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#else
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
using namespace mp4_demuxer;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Uncomment to enable verbose per-sample logging.
|
||||
//#define LOG_SAMPLE_DECODE 1
|
||||
|
||||
class MP4Stream : public mp4_demuxer::Stream {
|
||||
public:
|
||||
|
||||
MP4Stream(MediaResource* aResource)
|
||||
: mResource(aResource)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MP4Stream);
|
||||
MOZ_ASSERT(aResource);
|
||||
}
|
||||
~MP4Stream() {
|
||||
MOZ_COUNT_DTOR(MP4Stream);
|
||||
}
|
||||
|
||||
virtual bool ReadAt(int64_t aOffset,
|
||||
uint8_t* aBuffer,
|
||||
uint32_t aCount,
|
||||
uint32_t* aBytesRead) MOZ_OVERRIDE {
|
||||
uint32_t sum = 0;
|
||||
do {
|
||||
uint32_t offset = aOffset + sum;
|
||||
char* buffer = reinterpret_cast<char*>(aBuffer + sum);
|
||||
uint32_t toRead = aCount - sum;
|
||||
uint32_t bytesRead = 0;
|
||||
nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
sum += bytesRead;
|
||||
} while (sum < aCount);
|
||||
*aBytesRead = sum;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual int64_t Length() const MOZ_OVERRIDE {
|
||||
return mResource->GetLength();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<MediaResource> mResource;
|
||||
};
|
||||
|
||||
MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder),
|
||||
mLayersBackendType(layers::LAYERS_NONE),
|
||||
mHasAudio(false),
|
||||
mHasVideo(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MP4Reader);
|
||||
}
|
||||
|
||||
MP4Reader::~MP4Reader()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MP4Reader);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
mMP4Stream = new MP4Stream(mDecoder->GetResource());
|
||||
mDemuxer = new MP4Demuxer(mMP4Stream);
|
||||
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
|
||||
if (IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
|
||||
// Extract the layer manager backend type so that platform decoders
|
||||
// can determine whether it's worthwhile using hardware accelerated
|
||||
// video decoding.
|
||||
MediaDecoderOwner* owner = mDecoder->GetOwner();
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
|
||||
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
||||
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
|
||||
|
||||
nsRefPtr<LayerManager> layerManager =
|
||||
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
|
||||
NS_ENSURE_TRUE(layerManager, NS_ERROR_FAILURE);
|
||||
|
||||
mLayersBackendType = layerManager->GetBackendType();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
bool ok = mDemuxer->Init();
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
||||
|
||||
mInfo.mAudio.mHasAudio = mHasAudio = mDemuxer->HasAudio();
|
||||
if (mHasAudio) {
|
||||
const AudioDecoderConfig& config = mDemuxer->AudioConfig();
|
||||
mInfo.mAudio.mRate = config.samples_per_second();
|
||||
mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(config.channel_layout());
|
||||
mAudioDecoder = mPlatform->CreateAudioDecoder(mInfo.mAudio.mChannels,
|
||||
mInfo.mAudio.mRate,
|
||||
config.bits_per_channel(),
|
||||
config.extra_data(),
|
||||
config.extra_data_size());
|
||||
NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo();
|
||||
if (mHasVideo) {
|
||||
const VideoDecoderConfig& config = mDemuxer->VideoConfig();
|
||||
IntSize sz = config.natural_size();
|
||||
mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height());
|
||||
|
||||
mVideoDecoder = mPlatform->CreateVideoDecoder(mLayersBackendType,
|
||||
mDecoder->GetImageContainer());
|
||||
NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
Microseconds duration = mDemuxer->Duration();
|
||||
if (duration != -1) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->SetMediaDuration(duration);
|
||||
}
|
||||
// We can seek if we get a duration *and* the reader reports that it's
|
||||
// seekable.
|
||||
if (!mDemuxer->CanSeek()) {
|
||||
mDecoder->SetMediaSeekable(false);
|
||||
}
|
||||
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::HasAudio()
|
||||
{
|
||||
return mHasAudio;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::HasVideo()
|
||||
{
|
||||
return mHasVideo;
|
||||
}
|
||||
|
||||
MP4SampleQueue&
|
||||
MP4Reader::SampleQueue(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(aTrack == kAudio || aTrack == kVideo);
|
||||
return (aTrack == kAudio) ? mCompressedAudioQueue
|
||||
: mCompressedVideoQueue;
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
MP4Reader::Decoder(mp4_demuxer::TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(aTrack == kAudio || aTrack == kVideo);
|
||||
return (aTrack == kAudio) ? mAudioDecoder
|
||||
: mVideoDecoder;
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
MP4Reader::PopSample(TrackType aTrack)
|
||||
{
|
||||
// Unfortunately the demuxer outputs in the order samples appear in the
|
||||
// media, not on a per stream basis. We cache the samples we get from
|
||||
// streams other than the one we want.
|
||||
MP4SampleQueue& sampleQueue = SampleQueue(aTrack);
|
||||
while (sampleQueue.empty()) {
|
||||
nsAutoPtr<MP4Sample> sample;
|
||||
bool eos = false;
|
||||
bool ok = mDemuxer->Demux(&sample, &eos);
|
||||
if (!ok || eos) {
|
||||
MOZ_ASSERT(!sample);
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(sample);
|
||||
MP4Sample* s = sample.forget();
|
||||
SampleQueue(s->type).push_back(s);
|
||||
}
|
||||
MOZ_ASSERT(!sampleQueue.empty());
|
||||
MP4Sample* sample = sampleQueue.front();
|
||||
sampleQueue.pop_front();
|
||||
return sample;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::Decode(TrackType aTrack, nsAutoPtr<MediaData>& aOutData)
|
||||
{
|
||||
MP4SampleQueue& sampleQueue = SampleQueue(aTrack);
|
||||
MediaDataDecoder* decoder = Decoder(aTrack);
|
||||
|
||||
MOZ_ASSERT(decoder);
|
||||
|
||||
// Loop until we hit a return condition; we produce samples, or hit an error.
|
||||
while (true) {
|
||||
DecoderStatus status = decoder->Output(aOutData);
|
||||
if (status == DECODE_STATUS_OK) {
|
||||
MOZ_ASSERT(aOutData);
|
||||
return true;
|
||||
}
|
||||
// |aOutData| should only be non-null in success case.
|
||||
MOZ_ASSERT(!aOutData);
|
||||
|
||||
if (status == DECODE_STATUS_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status == DECODE_STATUS_NEED_MORE_INPUT) {
|
||||
// We need to push more data from the demuxer into the decoder.
|
||||
// Now loop back and try to extract output again.
|
||||
nsAutoPtr<MP4Sample> compressed;
|
||||
do {
|
||||
compressed = PopSample(aTrack);
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know there are no more
|
||||
// frames coming.
|
||||
return false;
|
||||
}
|
||||
const std::vector<uint8_t>* data = compressed->data;
|
||||
status = decoder->Input(&data->front(),
|
||||
data->size(),
|
||||
compressed->decode_timestamp,
|
||||
compressed->composition_timestamp,
|
||||
compressed->byte_offset);
|
||||
} while (status == DECODE_STATUS_OK);
|
||||
if (status == DECODE_STATUS_NOT_ACCEPTING) {
|
||||
// Decoder should now be able to produce an output.
|
||||
SampleQueue(aTrack).push_front(compressed.forget());
|
||||
continue;
|
||||
}
|
||||
LOG("MP4Reader decode failure. track=%d status=%d\n", aTrack, status);
|
||||
return false;
|
||||
} else {
|
||||
LOG("MP4Reader unexpected error. track=%d status=%d\n", aTrack, status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::DecodeAudioData()
|
||||
{
|
||||
MOZ_ASSERT(mHasAudio && mPlatform && mAudioDecoder);
|
||||
nsAutoPtr<MediaData> audio;
|
||||
bool ok = Decode(kAudio, audio);
|
||||
if (ok && audio && audio->mType == MediaData::AUDIO_SAMPLES) {
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("DecodeAudioData time=%lld dur=%lld", audio->mTime, audio->mDuration);
|
||||
#endif
|
||||
mAudioQueue.Push(static_cast<AudioData*>(audio.forget()));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed)
|
||||
{
|
||||
MOZ_ASSERT(mVideoDecoder);
|
||||
|
||||
// Purge the current decoder's state.
|
||||
mVideoDecoder->Flush();
|
||||
|
||||
// Loop until we reach the next keyframe after the threshold.
|
||||
while (true) {
|
||||
nsAutoPtr<MP4Sample> compressed(PopSample(kVideo));
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know.
|
||||
return false;
|
||||
}
|
||||
parsed++;
|
||||
if (!compressed->is_sync_point ||
|
||||
compressed->composition_timestamp < aTimeThreshold) {
|
||||
continue;
|
||||
}
|
||||
mCompressedVideoQueue.push_front(compressed.forget());
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
uint32_t parsed = 0, decoded = 0;
|
||||
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
|
||||
|
||||
MOZ_ASSERT(mHasVideo && mPlatform && mVideoDecoder);
|
||||
|
||||
if (aKeyframeSkip) {
|
||||
bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
|
||||
if (!ok) {
|
||||
NS_WARNING("Failed to skip demux up to next keyframe");
|
||||
return false;
|
||||
}
|
||||
aKeyframeSkip = false;
|
||||
}
|
||||
|
||||
nsAutoPtr<MediaData> data;
|
||||
bool ok = Decode(kVideo, data);
|
||||
MOZ_ASSERT(!data || data->mType == MediaData::VIDEO_FRAME);
|
||||
if (ok && data) {
|
||||
parsed++;
|
||||
if (data->mTime < aTimeThreshold) {
|
||||
// Skip frame, it's too late to be displayed.
|
||||
return true;
|
||||
}
|
||||
decoded++;
|
||||
VideoData* video = static_cast<VideoData*>(data.forget());
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("DecodeVideoData time=%lld dur=%lld", video->mTime, video->mDuration);
|
||||
#endif
|
||||
mVideoQueue.Push(video);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::Seek(int64_t aTime,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
int64_t aCurrentTime)
|
||||
{
|
||||
if (!mDemuxer->CanSeek()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::OnDecodeThreadStart()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread.");
|
||||
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mPlatform);
|
||||
mPlatform->OnDecodeThreadStart();
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::OnDecodeThreadFinish()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread.");
|
||||
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mPlatform);
|
||||
mPlatform->OnDecodeThreadFinish();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
88
content/media/fmp4/MP4Reader.h
Normal file
88
content/media/fmp4/MP4Reader.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(MP4Reader_h_)
|
||||
#define MP4Reader_h_
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/box_definitions.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class TimeRanges;
|
||||
}
|
||||
|
||||
typedef std::deque<mp4_demuxer::MP4Sample*> MP4SampleQueue;
|
||||
|
||||
class MP4Stream;
|
||||
|
||||
class MP4Reader : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
MP4Reader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
virtual ~MP4Reader();
|
||||
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool DecodeAudioData() MOZ_OVERRIDE;
|
||||
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasAudio() MOZ_OVERRIDE;
|
||||
virtual bool HasVideo() MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Seek(int64_t aTime,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
int64_t aCurrentTime) MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnDecodeThreadStart() MOZ_OVERRIDE;
|
||||
virtual void OnDecodeThreadFinish() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
MP4SampleQueue& SampleQueue(mp4_demuxer::TrackType aTrack);
|
||||
|
||||
// Blocks until the demuxer produces an sample of specified type.
|
||||
// Returns nullptr on error on EOS. Caller must delete sample.
|
||||
mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack);
|
||||
|
||||
bool Decode(mp4_demuxer::TrackType aTrack,
|
||||
nsAutoPtr<MediaData>& aOutData);
|
||||
|
||||
MediaDataDecoder* Decoder(mp4_demuxer::TrackType aTrack);
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
|
||||
nsAutoPtr<MP4Stream> mMP4Stream;
|
||||
nsAutoPtr<PlatformDecoderModule> mPlatform;
|
||||
nsAutoPtr<MediaDataDecoder> mVideoDecoder;
|
||||
nsAutoPtr<MediaDataDecoder> mAudioDecoder;
|
||||
|
||||
MP4SampleQueue mCompressedAudioQueue;
|
||||
MP4SampleQueue mCompressedVideoQueue;
|
||||
|
||||
layers::LayersBackend mLayersBackendType;
|
||||
|
||||
bool mHasAudio;
|
||||
bool mHasVideo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
7
content/media/fmp4/Makefile.in
Normal file
7
content/media/fmp4/Makefile.in
Normal file
@ -0,0 +1,7 @@
|
||||
# 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/.
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
OS_CXXFLAGS += -DNOMINMAX
|
||||
endif
|
43
content/media/fmp4/PlatformDecoderModule.cpp
Normal file
43
content/media/fmp4/PlatformDecoderModule.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "PlatformDecoderModule.h"
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
#endif
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern PlatformDecoderModule* CreateBlankDecoderModule();
|
||||
|
||||
/* static */
|
||||
PlatformDecoderModule*
|
||||
PlatformDecoderModule::Create()
|
||||
{
|
||||
if (Preferences::GetBool("media.fragmented-mp4.use-blank-decoder")) {
|
||||
return CreateBlankDecoderModule();
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
|
||||
if (NS_SUCCEEDED(m->Init())) {
|
||||
return m.forget();
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
PlatformDecoderModule::OnDecodeThreadStart()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PlatformDecoderModule::OnDecodeThreadFinish()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
84
content/media/fmp4/PlatformDecoderModule.h
Normal file
84
content/media/fmp4/PlatformDecoderModule.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(PlatformDecoderModule_h_)
|
||||
#define PlatformDecoderModule_h_
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class ImageContainer;
|
||||
}
|
||||
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
enum DecoderStatus {
|
||||
DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time.
|
||||
DECODE_STATUS_NEED_MORE_INPUT, // Nothing in pipeline to produce output with at this time.
|
||||
DECODE_STATUS_OK,
|
||||
DECODE_STATUS_ERROR
|
||||
};
|
||||
|
||||
class MediaDataDecoder {
|
||||
public:
|
||||
virtual ~MediaDataDecoder() {};
|
||||
|
||||
virtual nsresult Shutdown() = 0;
|
||||
|
||||
// Returns true if future decodes may produce output, or false
|
||||
// on end of segment.
|
||||
// Inserts data into the decoder's pipeline.
|
||||
virtual DecoderStatus Input(const uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
Microseconds aDTS,
|
||||
Microseconds aPTS,
|
||||
int64_t aOffsetInStream) = 0;
|
||||
|
||||
// Blocks until decoded sample is produced by the deoder.
|
||||
virtual DecoderStatus Output(nsAutoPtr<MediaData>& aOutData) = 0;
|
||||
|
||||
virtual DecoderStatus Flush() = 0;
|
||||
};
|
||||
|
||||
class PlatformDecoderModule {
|
||||
public:
|
||||
|
||||
// Creates the appropriate PlatformDecoderModule for this platform.
|
||||
// Caller is responsible for deleting this instance. It's safe to have
|
||||
// multiple PlatformDecoderModules alive at the same time.
|
||||
// There is one PlatformDecoderModule's created per media decoder.
|
||||
static PlatformDecoderModule* Create();
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
virtual nsresult Shutdown() = 0;
|
||||
|
||||
// TODO: Parameters for codec type.
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer) = 0;
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount,
|
||||
uint32_t aSampleRate,
|
||||
uint16_t aBitsPerSample,
|
||||
const uint8_t* aUserData,
|
||||
uint32_t aUserDataLength) = 0;
|
||||
|
||||
// Platform decoders can override these. Base implementation does nothing.
|
||||
virtual void OnDecodeThreadStart();
|
||||
virtual void OnDecodeThreadFinish();
|
||||
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
27
content/media/fmp4/demuxer/LICENSE
Normal file
27
content/media/fmp4/demuxer/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
content/media/fmp4/demuxer/Streams.h
Normal file
21
content/media/fmp4/demuxer/Streams.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mp4_demuxer {
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
|
||||
// Returns true on success, false on failure.
|
||||
// Writes number of bytes read into out_bytes_read, or 0 on EOS.
|
||||
// Returns true on EOS.
|
||||
virtual bool ReadAt(int64_t offset,
|
||||
uint8_t* buffer,
|
||||
uint32_t count,
|
||||
uint32_t* out_bytes_read) = 0;
|
||||
|
||||
virtual int64_t Length() const = 0;
|
||||
};
|
||||
|
||||
} // namespace mp4_demuxer
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user