Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-11-21 11:39:17 -05:00
commit 5f5fcba645
626 changed files with 18713 additions and 5636 deletions

View File

@ -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

View File

@ -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;

View File

@ -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));

View File

@ -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));

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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>

View File

@ -1,4 +1,4 @@
{
"revision": "14a570c0af0ad29420a47318576fc365ebf7b10a",
"revision": "89c57a31cebe0d8d94cbce4bcb47788b18f4fe84",
"repo_path": "/integration/gaia-central"
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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]

View File

@ -60,10 +60,6 @@ DEBUGGER_INFO = {
"args": "-q --args"
},
"cgdb": {
"interactive": True,
"args": "-q --args"
},
"cgdb": {
"interactive": True,
"args": "-q --args"

View File

@ -16,6 +16,7 @@ Important Concepts
:maxdepth: 1
build-overview
supported-configurations
Mozconfig Files <mozconfigs>
mozbuild-files
mozbuild-symbols

View 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.

View File

@ -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)
{

View 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()

View File

@ -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

View File

@ -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)

View File

@ -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)
*

View File

@ -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

View File

@ -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.

View File

@ -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
};

View File

@ -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
{

View File

@ -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',

View File

@ -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.

View File

@ -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

View File

@ -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")

View File

@ -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);
}
}

View File

@ -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

View 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>

View File

@ -20,3 +20,4 @@ load 802926-1.html
load 896047-1.html
load 896047-2.html
load 916128-1.html
load 934939-1.html

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View 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);
}

View 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

View File

@ -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',
]

View File

@ -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) {

View File

@ -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);

View File

@ -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) ||

View File

@ -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) {

View File

@ -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());

View File

@ -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

View File

@ -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());
}

View File

@ -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);
},

View File

@ -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)
{

View File

@ -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)
{

View File

@ -668,6 +668,8 @@ public:
void MozSetFileNameArray(const Sequence< nsString >& aFileNames);
HTMLInputElement* GetOwnerNumberControl();
bool MozIsTextField(bool aExcludePassword);
nsIEditor* GetEditor();

View File

@ -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)
{

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

View 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>

View File

@ -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 ],

View File

@ -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]

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -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

View File

@ -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));

View File

@ -94,6 +94,8 @@ protected:
void ResetZoomLevel();
float GetZoomLevel();
void UpdateSizeFromLayout();
enum eModeClasses {
eNone,
eShrinkToFit,

View File

@ -32,6 +32,7 @@ LOCAL_INCLUDES += [
'/caps/include',
'/content/base/src',
'/content/events/src',
'/docshell/base',
'/dom/base',
'/layout/style',
'/xpcom/ds',

View File

@ -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;

View File

@ -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))) {

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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)) ||

View File

@ -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;
}

View File

@ -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"));
}
}

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -1057,7 +1057,7 @@ protected:
{
MOZ_COUNT_CTOR(MediaStreamGraph);
}
~MediaStreamGraph()
virtual ~MediaStreamGraph()
{
MOZ_COUNT_DTOR(MediaStreamGraph);
}

View File

@ -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.
/**

View File

@ -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;
}

View File

@ -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()));
}
}
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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.");
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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.

View 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