merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2013-11-07 16:01:27 +01:00
commit e36218e529
253 changed files with 3246 additions and 8329 deletions

View File

@ -17,13 +17,16 @@ export TOPLEVEL_BUILD := 1
default::
ifdef COMPILE_ENVIRONMENT
include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
endif
include $(topsrcdir)/config/config.mk
ifndef LIBXUL_SDK
ifdef COMPILE_ENVIRONMENT
BUILD_JS = 1
endif
endif
GARBAGE_DIRS += dist _javagen _profile staticlib
DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
config/autoconf.mk \
@ -35,7 +38,7 @@ ifndef MOZ_PROFILE_USE
# We need to explicitly put backend.RecursiveMakeBackend here
# otherwise the rule in rules.mk doesn't run early enough.
libs binaries export tools:: CLOBBER $(topsrcdir)/configure config.status backend.RecursiveMakeBackend
ifndef LIBXUL_SDK
ifdef BUILD_JS
libs binaries export tools:: js-config-status
endif
endif
@ -69,7 +72,7 @@ config.status: $(topsrcdir)/configure
backend.RecursiveMakeBackend:
@echo "Build configuration changed. Regenerating backend."
./config.status
$(PYTHON) config.status
Makefile: backend.RecursiveMakeBackend
@$(TOUCH) $@
@ -78,7 +81,7 @@ include backend.RecursiveMakeBackend.pp
default:: backend.RecursiveMakeBackend
ifndef LIBXUL_SDK
ifdef BUILD_JS
.PHONY: js-config-status
js-config-status:
$(call SUBMAKE,backend.RecursiveMakeBackend,js/src,1)
@ -92,7 +95,7 @@ install_manifest_depends = \
backend.RecursiveMakeBackend \
$(NULL)
ifndef LIBXUL_SDK
ifdef BUILD_JS
install_manifest_depends += js-config-status
endif
@ -101,12 +104,12 @@ install-manifests: $(addprefix install-dist-,$(install_manifests))
.PHONY: $(addprefix install-dist-,$(install_manifests))
$(addprefix install-dist-,$(install_manifests)): install-dist-%: $(install_manifest_depends)
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$* $(if $(LIBXUL_SDK),,js/src/_build_manifests/install/dist_$*))
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$* $(if $(BUILD_JS),js/src/_build_manifests/install/dist_$*))
.PHONY: install-tests
install-manifests: install-tests
install-tests: $(install_manifest_depends)
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests js/src/_build_manifests/install/tests)
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests $(if $(BUILD_JS),js/src/_build_manifests/install/tests))
# _tests should be purged during cleaning. However, we don't want it purged
@ -142,7 +145,7 @@ include $(topsrcdir)/testing/testsuite-targets.mk
endif
default all::
$(call BUILDSTATUS,TIERS export $(if $(MOZ_PSEUDO_DERECURSE),compile )libs tools)
$(call BUILDSTATUS,TIERS export $(if $(COMPILE_ENVIRONMENT),$(if $(MOZ_PSEUDO_DERECURSE),compile ))libs tools)
include $(topsrcdir)/config/rules.mk
@ -247,7 +250,7 @@ scheck::
@relcount=`find $(DIST)/bin -name "*.so" | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo "FAILED: R_386_PC32 relocations detected in a shared library. Did you use a system header without adding it to config/system-headers?"; exit 1; else echo "PASSED"; fi
endif
ifndef LIBXUL_SDK
ifdef BUILD_JS
js/src/Makefile: subsrcdir := js/src
ifdef ENABLE_TESTS

View File

@ -13,7 +13,7 @@ interface nsIAccessible;
* A cross-platform interface that supports hyperlink-specific properties and
* methods. Anchors, image maps, xul:labels with class="text-link" implement this interface.
*/
[scriptable, uuid(38c60bfa-6040-4bfe-93f2-acd6a909bb60)]
[scriptable, uuid(883643d4-93a5-4f32-922c-6f06e01363c1)]
interface nsIAccessibleHyperLink : nsISupports
{
/**
@ -38,16 +38,6 @@ interface nsIAccessibleHyperLink : nsISupports
*/
readonly attribute boolean valid;
/**
* Determines whether the element currently has the focus, e. g. after
* returning from the destination page.
*
* @note ARIA links can only be focused if they have the tabindex
* attribute set. Also, state_focused should then be set on the accessible
* for this link.
*/
readonly attribute boolean selected;
/**
* The numbber of anchors within this Hyperlink. Is normally 1 for anchors.
* This anchor is, for example, the visible output of the html:a tag.

View File

@ -2425,21 +2425,6 @@ Accessible::GetValid(bool *aValid)
return NS_OK;
}
// readonly attribute boolean nsIAccessibleHyperLink::selected
NS_IMETHODIMP
Accessible::GetSelected(bool *aSelected)
{
NS_ENSURE_ARG_POINTER(aSelected);
*aSelected = false;
if (IsDefunct())
return NS_ERROR_FAILURE;
*aSelected = IsLinkSelected();
return NS_OK;
}
void
Accessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
uint32_t aLength)
@ -2779,14 +2764,6 @@ Accessible::EndOffset()
return hyperText ? (hyperText->GetChildOffset(this) + 1) : 0;
}
bool
Accessible::IsLinkSelected()
{
NS_PRECONDITION(IsLink(),
"IsLinkSelected() called on something that is not a hyper link!");
return FocusMgr()->IsFocused(this);
}
uint32_t
Accessible::AnchorCount()
{

View File

@ -629,11 +629,6 @@ public:
return (0 == (State() & mozilla::a11y::states::INVALID));
}
/**
* Return true if the link currently has the focus.
*/
bool IsLinkSelected();
/**
* Return the number of anchors within the link.
*/

View File

@ -735,6 +735,12 @@ var Input = {
case 'swipeleft1':
this.moveCursor('movePrevious', 'Simple', 'gesture');
break;
case 'swipeup1':
this.contextAction('backward');
break;
case 'swipedown1':
this.contextAction('forward');
break;
case 'exploreend1':
this.activateCurrent(null, true);
break;
@ -859,6 +865,12 @@ var Input = {
origin: 'top', inputType: aInputType});
},
contextAction: function contextAction(aDirection) {
// XXX: For now, the only supported context action is adjusting a range.
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
mm.sendAsyncMessage('AccessFu:AdjustRange', {direction: aDirection});
},
moveByGranularity: function moveByGranularity(aDetails) {
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;

View File

@ -331,6 +331,23 @@ function scroll(aMessage) {
}
}
function adjustRange(aMessage) {
function sendUpDownKey(aAccessible) {
let evt = content.document.createEvent('KeyboardEvent');
let keycode = aMessage.json.direction == 'forward' ?
content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP;
evt.initKeyEvent(
"keypress", false, true, null, false, false, false, false, keycode, 0);
if (aAccessible.DOMNode) {
aAccessible.DOMNode.dispatchEvent(evt);
}
}
let position = Utils.getVirtualCursor(content.document).position;
if (!forwardToChild(aMessage, adjustRange, position)) {
sendUpDownKey(position);
}
}
addMessageListener(
'AccessFu:Start',
function(m) {
@ -344,6 +361,7 @@ addMessageListener(
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:ContextMenu', activateContextMenu);
addMessageListener('AccessFu:Scroll', scroll);
addMessageListener('AccessFu:AdjustRange', adjustRange);
addMessageListener('AccessFu:MoveCaret', moveCaret);
addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);

View File

@ -21,9 +21,6 @@ function focusLink(aID, aSelectedAfter)
this.invoke = function focusLink_invoke()
{
is(this.accessible.selected, false,
"Wrong selected state before focus for ID " + prettyName(aID) + "!");
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE : 0);
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
testStates(aID, expectedStates, 0, unexpectedStates, 0);
@ -33,9 +30,6 @@ function focusLink(aID, aSelectedAfter)
this.finalCheck = function focusLink_finalCheck()
{
is(this.accessible.selected, aSelectedAfter,
"Wrong seleccted state after focus for ID " + prettyName(aID) + "!");
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
testStates(aID, expectedStates, 0, unexpectedStates, 0);

View File

@ -113,7 +113,7 @@ AB_CD = $(MOZ_UI_LOCALE)
AB := $(firstword $(subst -, ,$(AB_CD)))
clean clobber repackage::
clean clobber::
rm -rf $(DIST)/$(APP_NAME).app
ifdef LIBXUL_SDK
@ -128,19 +128,16 @@ libs-preqs = \
$(NULL)
.PHONY: repackage
tools repackage:: $(libs-preqs)
libs:: $(libs-preqs)
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
sed -e "s/%MOZ_APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MOZ_APP_NAME%/$(MOZ_APP_NAME)/" -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" -e "s/%APP_BINARY%/$(APP_BINARY)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist
sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
$(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign
rm -rf $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
ln -s $(abspath $(DIST)/bin) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY)
rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks
else
$(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
endif
cp -RL $(srcdir)/b2g.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns
printf "APPLMOZB" > $(DIST)/$(APP_NAME).app/Contents/PkgInfo

View File

@ -57,11 +57,6 @@ libs::
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
$(LOCALE_SRCDIR)/existing-profile-defaults.js > $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \
fi
install::
@if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
$(LOCALE_SRCDIR)/existing-profile-defaults.js > $(DESTDIR)$(mozappdir)/defaults/existing-profile-defaults.js; \
fi
NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD))

View File

@ -120,8 +120,10 @@ endif #}
ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH)))
ifdef COMPILE_ENVIRONMENT
libs::
cp -p $(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
endif
GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)
@ -160,7 +162,7 @@ AB_CD = $(MOZ_UI_LOCALE)
AB := $(firstword $(subst -, ,$(AB_CD)))
clean clobber repackage::
clean clobber::
$(RM) -r $(dist_dest)
ifdef LIBXUL_SDK
@ -171,17 +173,19 @@ endif
MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/config/buildid)
.PHONY: repackage
tools repackage:: $(PROGRAM)
libs:: $(PROGRAM)
$(MKDIR) -p $(dist_dest)/Contents/MacOS
$(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/" -e "s/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
sed -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a $(DIST)/bin/ $(dist_dest)/Contents/$(APPFILES)
rm -rf $(dist_dest)/Contents/$(APPFILES)
ln -s $(abspath $(DIST)/bin) $(dist_dest)/Contents/$(APPFILES)
ifdef LIBXUL_SDK
$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS
endif
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo

View File

@ -120,14 +120,6 @@ libs:: $(addprefix generic/profile/,$(PROFILE_FILES))
libs:: $(call MERGE_FILES,$(addprefix profile/chrome/,$(PROFILE_CHROME)))
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile/chrome
install:: $(DESTDIR)$(mozappdir)/defaults/profile/bookmarks.html ;
install:: $(addprefix generic/profile/,$(PROFILE_FILES))
$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/defaults/profile
install:: $(call MERGE_FILES,$(addprefix profile/chrome/,$(PROFILE_CHROME)))
$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/defaults/profile/chrome
# metro build calls back here for search engine plugins
searchplugins: $(addprefix $(FINAL_TARGET)/searchplugins/,$(SEARCHPLUGINS))
.PHONY: searchplugins

View File

@ -292,7 +292,9 @@ var ContextUI = {
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "URLChanged":
this.displayNavbar();
if (aEvent.target == Browser.selectedBrowser) {
this.displayNavbar();
}
break;
case "MozEdgeUIStarted":
this._onEdgeUIStarted(aEvent);

View File

@ -4,6 +4,3 @@
export::
$(NSINSTALL) $(srcdir)/resources.pri $(DIST)/bin
install::
$(NSINSTALL) $(srcdir)/resources.pri $(DIST)/bin

View File

@ -40,9 +40,10 @@ test-ctors$(DLL_SUFFIX): DT_TYPE=INIT
GARBAGE += test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX) test-array$(DLL_SUFFIX).bak test-ctors$(DLL_SUFFIX).bak
ifndef CROSS_COMPILE
ifdef COMPILE_ENVIRONMENT
libs:: test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX)
ifndef CROSS_COMPILE
dummy: dummy.$(OBJ_SUFFIX)
$(CC) -o $@ $^ $(LDFLAGS)
@ -53,5 +54,6 @@ libs:: dummy
GARBAGE += dummy
endif
endif
test.$(OBJ_SUFFIX): CFLAGS := -O0

View File

@ -9,10 +9,12 @@
MOZ_LIBSTDCXX_HOST_VERSION =
ifndef CROSS_COMPILE
ifdef COMPILE_ENVIRONMENT
ifdef USE_ELF_DYNSTR_GC
export:: elf-dynstr-gc
endif
endif
endif
# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
# a recursive rule for finding nsinstall and the Perl scripts.
@ -27,6 +29,7 @@ endif
include $(topsrcdir)/config/config.mk
ifneq (WINNT,$(HOST_OS_ARCH))
ifdef COMPILE_ENVIRONMENT
# Ensure nsinstall is atomically created
nsinstall$(HOST_BIN_SUFFIX): $(HOST_PROGRAM)
cp $^ $@.tmp
@ -37,6 +40,7 @@ NSINSTALL_DEST := $(DIST)/bin
NSINSTALL_TARGET := export
INSTALL_TARGETS += NSINSTALL
endif
endif
HEADERS_FILES = \
$(DEPTH)/mozilla-config.h \
@ -111,9 +115,6 @@ GARBAGE += $(STL_WRAPPERS_SENTINEL)
GARBAGE_DIRS += stl_wrappers
endif
install::
$(SYSINSTALL) $(IFLAGS1) $(DEPTH)/mozilla-config.h $(DESTDIR)$(includedir)
GARBAGE += \
$(FINAL_LINK_COMPS) $(FINAL_LINK_LIBS) $(FINAL_LINK_COMP_NAMES) buildid $(srcdir)/*.pyc *.pyc

View File

@ -622,8 +622,13 @@ endif
endif
# Default location of include files
ifndef LIBXUL_SDK
IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser
IDL_PARSER_CACHE_DIR = $(DEPTH)/xpcom/idl-parser
else
IDL_PARSER_DIR = $(LIBXUL_SDK)/sdk/bin
IDL_PARSER_CACHE_DIR = $(LIBXUL_SDK)/sdk/bin
endif
SDK_LIB_DIR = $(DIST)/sdk/lib
SDK_BIN_DIR = $(DIST)/sdk/bin

View File

@ -49,6 +49,10 @@ idlprocess := $(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_C
$(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
$(dist_include_dir) $(idl_xpt_dir) $(idl_deps_dir)
ifdef LIBXUL_SDK
idlprocess += -I$(LIBXUL_SDK)/idl
endif
xpidl_modules := @xpidl_modules@
@xpidl_rules@

View File

@ -112,6 +112,7 @@ ifeq ($(CURRENT_TIER),export)
$(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
endif
ifdef COMPILE_ENVIRONMENT
ifneq (,$(filter libs binaries,$(CURRENT_TIER)))
# When doing a "libs" build, target_libs.mk ensures the interesting dependency data
# is available in the "binaries" stamp. Once recursion is done, aggregate all that
@ -139,6 +140,8 @@ endif
DIST_GARBAGE += binaries-deps.mk binaries-deps
endif
else
# Don't recurse if MAKELEVEL is NO_RECURSE_MAKELEVEL as defined above, but
@ -209,6 +212,8 @@ endif
endif
endif
ifdef COMPILE_ENVIRONMENT
# Aggregate all dependency files relevant to a binaries build except in
# the mozilla top-level directory.
ifneq (_.,$(recurse_targets)_$(DEPTH))
@ -227,4 +232,6 @@ ifneq (_.,$(recurse_targets)_$(DEPTH))
@$(if $(or $(recurse_targets),$^),$(call py_action,link_deps,-o binaries --group-all $(if $(want_abspaths),--abspaths )--topsrcdir $(topsrcdir) --topobjdir $(DEPTH) --dist $(DIST) $(ALL_DEP_FILES)))
endif
endif
endif # ifdef MOZ_PSEUDO_DERECURSE

View File

@ -122,6 +122,7 @@ endif
endif
ifdef CPP_UNIT_TESTS
ifdef COMPILE_ENVIRONMENT
# Compile the tests to $(DIST)/bin. Make lots of niceties available by default
# through TestHarness.h, by modifying the list of includes and the libs against
@ -153,6 +154,7 @@ cppunittests-remote:
echo "please prepare your host with environment variables for TEST_DEVICE"; \
fi
endif # COMPILE_ENVIRONMENT
endif # CPP_UNIT_TESTS
.PHONY: check
@ -303,6 +305,7 @@ EXCLUDED_OBJS := $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.$(OBJ_SUFFIX))
SIMPLE_PROGRAMS :=
endif
ifdef COMPILE_ENVIRONMENT
ifndef TARGETS
TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS)
endif
@ -328,6 +331,19 @@ ifndef HOST_OBJS
_HOST_OBJS = $(HOST_COBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
HOST_OBJS = $(strip $(_HOST_OBJS))
endif
else
LIBRARY :=
SHARED_LIBRARY :=
IMPORT_LIBRARY :=
REAL_LIBRARY :=
PROGRAM :=
SIMPLE_PROGRAMS :=
HOST_LIBRARY :=
HOST_PROGRAM :=
HOST_SIMPLE_PROGRAMS :=
SDK_BINARY := $(filter %.py,$(SDK_BINARY))
SDK_LIBRARY :=
endif
ALL_TRASH = \
$(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \
@ -613,7 +629,9 @@ ifndef SUPPRESS_DEFAULT_RULES
default all::
$(MAKE) export
ifdef MOZ_PSEUDO_DERECURSE
ifdef COMPILE_ENVIRONMENT
$(MAKE) compile
endif
endif
$(MAKE) libs
$(MAKE) tools
@ -642,11 +660,13 @@ HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX),$(HOST_LIBS))
GLOBAL_DEPS += Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
##############################################
ifdef COMPILE_ENVIRONMENT
OBJ_TARGETS = $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)
compile:: $(OBJ_TARGETS)
include $(topsrcdir)/config/makefiles/target_libs.mk
include $(topsrcdir)/config/makefiles/target_binaries.mk
endif
ifdef IS_TOOL_DIR
# One would think "tools:: libs" would work, but it turns out that combined with
@ -1353,7 +1373,7 @@ PP_TARGETS += DIST_CHROME_FILES
endif
ifneq ($(XPI_PKGNAME),)
tools realchrome::
libs realchrome::
ifdef STRIP_XPI
ifndef MOZ_DEBUG
@echo "Stripping $(XPI_PKGNAME) package directory..."
@ -1392,7 +1412,7 @@ ifndef XPI_NAME
$(error XPI_NAME must be set for INSTALL_EXTENSION_ID)
endif
tools::
libs::
$(RM) -r "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
$(NSINSTALL) -D "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
$(call copy_dir,$(FINAL_TARGET),$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID))

View File

@ -2498,9 +2498,10 @@ esac
if test -z "$COMPILE_ENVIRONMENT"; then
SKIP_COMPILER_CHECKS=1
SKIP_LIBRARY_CHECKS=1
else
MOZ_COMPILER_OPTS
fi
MOZ_COMPILER_OPTS
if test -z "$SKIP_COMPILER_CHECKS"; then
dnl Checks for typedefs, structures, and compiler characteristics.
dnl ========================================================
@ -3928,7 +3929,6 @@ MOZ_SAMPLE_TYPE_FLOAT32=
MOZ_SAMPLE_TYPE_S16=
MOZ_OPUS=1
MOZ_WEBM=1
MOZ_DASH=
MOZ_DIRECTSHOW=
MOZ_WMF=
MOZ_WEBRTC=1
@ -7179,7 +7179,7 @@ if test "$USE_ELF_HACK" = 1; then
esac
fi
if test -n "$USE_ELF_HACK"; then
if test -n "$COMPILE_ENVIRONMENT" -a -n "$USE_ELF_HACK"; then
dnl PT_GNU_RELRO segment makes the dynamic linker set a read-only flag on
dnl memory addresses it maps to. The result is that by the time elfhack
dnl kicks in, it is not possible to apply relocations because of that,
@ -7882,7 +7882,9 @@ AC_SUBST(MOZ_PIXMAN_CFLAGS)
AC_SUBST(MOZ_PIXMAN_LIBS)
# Check for headers defining standard int types.
MOZ_CHECK_HEADERS(stdint.h inttypes.h sys/int_types.h)
if test -n "$COMPILE_ENVIRONMENT"; then
MOZ_CHECK_HEADERS(stdint.h inttypes.h sys/int_types.h)
fi
if test "$MOZ_TREE_CAIRO"; then
MOZ_CAIRO_CFLAGS='-I$(LIBXUL_DIST)/include/cairo'
@ -8638,7 +8640,6 @@ AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)
AC_SUBST(MOZ_OPUS)
AC_SUBST(MOZ_WEBM)
AC_SUBST(MOZ_DASH)
AC_SUBST(MOZ_WMF)
AC_SUBST(MOZ_DIRECTSHOW)
AC_SUBST(MOZ_MEDIA_PLUGINS)
@ -8669,6 +8670,7 @@ AC_SUBST(MOZ_FOLD_LIBS)
AC_SUBST(MOZ_ENABLE_SZIP)
AC_SUBST(MOZ_SZIP_FLAGS)
if test -n "$COMPILE_ENVIRONMENT"; then
AC_MSG_CHECKING([for posix_fallocate])
AC_TRY_LINK([#define _XOPEN_SOURCE 600
#include <fcntl.h>],
@ -8684,7 +8686,6 @@ else
fi
dnl Check for missing components
if test "$COMPILE_ENVIRONMENT"; then
if test "$MOZ_X11"; then
if test "$WITHOUT_X11"; then
AC_MSG_ERROR([--without-x specified and MOZ_X11 still defined])

View File

@ -9,6 +9,7 @@ interface nsIDOMDOMStringList;
interface nsIDOMWindow;
interface nsIDocShell;
interface nsIContent;
interface nsIPrincipal;
/**
* Message managers provide a way for chrome-privileged JS code to
@ -156,14 +157,15 @@ interface nsIMessageListener : nsISupports
* receiveMessage is called with one parameter, which has the following
* properties:
* {
* target: %the target of the message. Either an element owning
* the message manager, or message manager itself if no
* element owns it%
* name: %message name%,
* sync: %true or false%.
* data: %structured clone of the sent message data%,
* json: %same as .data, deprecated%,
* objects: %named table of jsvals/objects, or null%
* target: %the target of the message. Either an element owning
* the message manager, or message manager itself if no
* element owns it%
* name: %message name%,
* sync: %true or false%.
* data: %structured clone of the sent message data%,
* json: %same as .data, deprecated%,
* objects: %named table of jsvals/objects, or null%
* principal: %principal for the window app
* }
*
* Each listener is invoked with its own copy of the message
@ -231,7 +233,7 @@ interface nsIMessageListenerManager : nsISupports
* messages that are only delivered to its one parent-process message
* manager.
*/
[scriptable, builtinclass, uuid(7f23767d-0f39-40c1-a22d-d3ab8a481f9d)]
[scriptable, builtinclass, uuid(d6b0d851-43e6-426d-9f13-054bc0198175)]
interface nsIMessageSender : nsIMessageListenerManager
{
/**
@ -252,7 +254,8 @@ interface nsIMessageSender : nsIMessageListenerManager
[implicit_jscontext, optional_argc]
void sendAsyncMessage([optional] in AString messageName,
[optional] in jsval obj,
[optional] in jsval objects);
[optional] in jsval objects,
[optional] in nsIPrincipal principal);
};
/**
@ -289,7 +292,7 @@ interface nsIMessageBroadcaster : nsIMessageListenerManager
nsIMessageListenerManager getChildAt(in unsigned long aIndex);
};
[scriptable, builtinclass, uuid(79eeb70f-58e3-4d32-b46f-106f42ada12b)]
[scriptable, builtinclass, uuid(7fda0941-9dcc-448b-bd39-16373c5b4003)]
interface nsISyncMessageSender : nsIMessageSender
{
/**
@ -300,7 +303,8 @@ interface nsISyncMessageSender : nsIMessageSender
[implicit_jscontext, optional_argc]
jsval sendSyncMessage([optional] in AString messageName,
[optional] in jsval obj,
[optional] in jsval objects);
[optional] in jsval objects,
[optional] in nsIPrincipal principal);
/**
* Like |sendSyncMessage()|, except re-entrant. New RPC messages may be
@ -314,7 +318,8 @@ interface nsISyncMessageSender : nsIMessageSender
[implicit_jscontext, optional_argc]
jsval sendRpcMessage([optional] in AString messageName,
[optional] in jsval obj,
[optional] in jsval objects);
[optional] in jsval objects,
[optional] in nsIPrincipal principal);
};
[scriptable, builtinclass, uuid(894ff2d4-39a3-4df8-9d76-8ee329975488)]

View File

@ -2215,8 +2215,10 @@ public:
nsFrameLoader* aFrameLoader,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
: mRuntime(js::GetRuntime(aCx)), mFrameLoader(aFrameLoader), mMessage(aMessage), mCpows(aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: mRuntime(js::GetRuntime(aCx)), mFrameLoader(aFrameLoader)
, mMessage(aMessage), mCpows(aCpows), mPrincipal(aPrincipal)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
@ -2249,7 +2251,7 @@ public:
nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
mm->ReceiveMessage(static_cast<EventTarget*>(tabChild), mMessage,
false, &data, &cpows, nullptr);
false, &data, &cpows, mPrincipal, nullptr);
}
return NS_OK;
}
@ -2259,13 +2261,15 @@ public:
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
bool
nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
TabParent* tabParent = mRemoteBrowser;
if (tabParent) {
@ -2278,11 +2282,14 @@ nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows);
return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
aPrincipal);
}
if (mChildMessageManager) {
nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage, aData, aCpows);
nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
aData, aCpows,
aPrincipal);
NS_DispatchToCurrentThread(ev);
return true;
}

View File

@ -184,7 +184,8 @@ public:
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;

View File

@ -500,28 +500,33 @@ NS_IMETHODIMP
nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, true);
return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
aRetval, true);
}
NS_IMETHODIMP
nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, false);
return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
aRetval, false);
}
nsresult
nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval,
@ -556,7 +561,8 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
InfallibleTArray<nsString> retval;
sSendingSyncMessage |= aIsSync;
bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects, &retval, aIsSync);
bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
aPrincipal, &retval, aIsSync);
if (aIsSync) {
sSendingSyncMessage = false;
}
@ -591,19 +597,20 @@ nsresult
nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
if (mIsBroadcaster) {
int32_t len = mChildManagers.Count();
for (int32_t i = 0; i < len; ++i) {
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows);
DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
}
return NS_OK;
}
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows)) {
if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -613,6 +620,7 @@ nsresult
nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc)
{
@ -632,7 +640,8 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects);
return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
aPrincipal);
}
@ -642,10 +651,12 @@ NS_IMETHODIMP
nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx,
aArgc);
}
@ -658,7 +669,8 @@ nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, aCx,
aArgc);
}
NS_IMETHODIMP
@ -841,6 +853,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
bool aIsSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal)
{
AutoSafeJSContext ctx;
@ -926,6 +939,42 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "objects", cpowsv, nullptr, nullptr, JSPROP_ENUMERATE);
// message.principal == null
if (!aPrincipal) {
JS::Rooted<JS::Value> nullValue(ctx);
JS_DefineProperty(ctx, param, "principal", nullValue, nullptr, nullptr, JSPROP_ENUMERATE);
}
// message.principal = { appId: <id>, origin: <origin>, isInBrowserElement: <something> }
else {
JS::Rooted<JSObject*> principalObj(ctx,
JS_NewObject(ctx, nullptr, nullptr, nullptr));
uint32_t appId;
nsresult rv = aPrincipal->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> appIdValue(ctx, INT_TO_JSVAL(appId));
JS_DefineProperty(ctx, principalObj, "appId", appIdValue, nullptr, nullptr, JSPROP_ENUMERATE);
nsCString origin;
rv = aPrincipal->GetOrigin(getter_Copies(origin));
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSString*> originValue(ctx, JS_InternString(ctx, origin.get()));
JS_DefineProperty(ctx, principalObj, "origin", STRING_TO_JSVAL(originValue), nullptr, nullptr, JSPROP_ENUMERATE);
bool browser;
rv = aPrincipal->GetIsInBrowserElement(&browser);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> browserValue(ctx, BOOLEAN_TO_JSVAL(browser));
JS_DefineProperty(ctx, principalObj, "isInBrowserElement", browserValue, nullptr, nullptr, JSPROP_ENUMERATE);
JS::RootedValue principalValue(ctx, JS::ObjectValue(*principalObj));
JS_DefineProperty(ctx, param, "principal", principalValue, nullptr, nullptr, JSPROP_ENUMERATE);
}
JS::Rooted<JS::Value> thisValue(ctx, JS::UndefinedValue());
JS::Rooted<JS::Value> funval(ctx);
@ -981,7 +1030,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
aIsSync, aCloneData,
aCpows,
aCpows, aPrincipal,
aJSONRetVal) : NS_OK;
}
@ -1452,10 +1501,12 @@ public:
nsAsyncMessageToSameProcessChild(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: mRuntime(js::GetRuntime(aCx)),
mMessage(aMessage),
mCpows(aCpows)
mCpows(aCpows),
mPrincipal(aPrincipal)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
@ -1485,7 +1536,7 @@ public:
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
false, &data, &cpows, nullptr);
false, &data, &cpows, mPrincipal, nullptr);
}
return NS_OK;
}
@ -1494,6 +1545,7 @@ public:
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
@ -1515,10 +1567,12 @@ public:
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows);
new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
aPrincipal);
NS_DispatchToCurrentThread(ev);
return true;
}
@ -1562,6 +1616,7 @@ public:
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync) MOZ_OVERRIDE
{
@ -1579,15 +1634,18 @@ public:
return false;
}
if (aIsSync) {
return cc->SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal);
return cc->SendSyncMessage(nsString(aMessage), data, cpows, aPrincipal,
aJSONRetVal);
}
return cc->CallRpcMessage(nsString(aMessage), data, cpows, aJSONRetVal);
return cc->CallRpcMessage(nsString(aMessage), data, cpows, aPrincipal,
aJSONRetVal);
}
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows) MOZ_OVERRIDE
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
@ -1602,7 +1660,7 @@ public:
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return cc->SendAsyncMessage(nsString(aMessage), data, cpows);
return cc->SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal);
}
};
@ -1614,10 +1672,12 @@ public:
nsAsyncMessageToSameProcessParent(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: mRuntime(js::GetRuntime(aCx)),
mMessage(aMessage),
mCpows(aCpows)
mCpows(aCpows),
mPrincipal(aPrincipal)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
@ -1651,7 +1711,7 @@ public:
nsRefPtr<nsFrameMessageManager> ppm =
nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
mMessage, false, &data, &cpows, nullptr);
mMessage, false, &data, &cpows, mPrincipal, nullptr);
}
return NS_OK;
}
@ -1660,6 +1720,7 @@ public:
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
/**
@ -1681,6 +1742,7 @@ public:
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync) MOZ_OVERRIDE
{
@ -1697,7 +1759,7 @@ public:
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
true, &aData, &cpows, aJSONRetVal);
true, &aData, &cpows, aPrincipal, aJSONRetVal);
}
return true;
}
@ -1705,13 +1767,14 @@ public:
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
}
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows);
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;

View File

@ -61,6 +61,7 @@ public:
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync)
{
@ -70,7 +71,8 @@ public:
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
return true;
}
@ -218,7 +220,7 @@ public:
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
bool aIsSync, const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
CpowHolder* aCpows, nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal);
void AddChildManager(nsFrameMessageManager* aManager,
@ -239,12 +241,14 @@ public:
nsresult DispatchAsyncMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc);
nsresult DispatchAsyncMessageInternal(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal);
void RemoveFromParent();
nsFrameMessageManager* GetParentManager() { return mParentManager; }
void SetParentManager(nsFrameMessageManager* aParent)
@ -268,6 +272,7 @@ private:
nsresult SendMessage(const nsAString& aMessageName,
const JS::Value& aJSON,
const JS::Value& aObjects,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval,

View File

@ -30,6 +30,7 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync)
{
@ -43,7 +44,8 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
if (mChromeMessageManager) {
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aJSONRetVal);
mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aPrincipal,
aJSONRetVal);
}
return true;
}
@ -55,11 +57,13 @@ public:
nsInProcessTabChildGlobal* aTabChild,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: mRuntime(js::GetRuntime(aCx)),
mTabChild(aTabChild),
mMessage(aMessage),
mCpows(aCpows),
mPrincipal(aPrincipal),
mRun(false)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
@ -95,7 +99,8 @@ public:
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data, &cpows, nullptr);
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data, &cpows,
mPrincipal, nullptr);
}
return NS_OK;
}
@ -105,6 +110,7 @@ public:
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
nsCOMPtr<nsIPrincipal> mPrincipal;
// True if this runnable has already been called. This can happen if DoSendSyncMessage
// is called while waiting for an asynchronous message send.
bool mRun;
@ -114,10 +120,11 @@ bool
nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows);
new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
mASyncMessages.AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;

View File

@ -43,23 +43,27 @@ public:
NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote,
aPrincipal, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD SendRpcMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
aPrincipal, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
@ -83,12 +87,14 @@ public:
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
NS_IMETHOD AddEventListener(const nsAString& aType,

View File

@ -2,3 +2,4 @@
[test_bug357450.js]
[test_copypaste.xul]
[test_messagemanager_principal.html]

View File

@ -0,0 +1,94 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Principal in MessageManager</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
var permManager = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
SimpleTest.waitForExplicitFinish();
const childFrameURL =
"data:text/html,<!DOCTYPE HTML><html><body></body></html>";
function childFrameScript() {
"use strict";
addMessageListener("test:ipcMessage", function(message) {
sendAsyncMessage(message.name, "principal: " + (message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "principal.appId: " +
("appId" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "principal.origin: " +
("origin" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "principal.isInBrowserElement: " +
("isInBrowserElement" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "DONE");
});
}
function runTests() {
ok("Browser prefs set.");
let iframe = document.createElement("iframe");
SpecialPowers.wrap(iframe).mozbrowser = true;
iframe.id = "iframe";
iframe.src = childFrameURL;
iframe.addEventListener("mozbrowserloadend", function() {
ok(true, "Got iframe load event.");
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.addMessageListener("test:ipcMessage", function(message) {
// We need to wrap to access message.json, and unwrap to do the
// identity check.
var msg = SpecialPowers.unwrap(SpecialPowers.wrap(message).json);
if (/OK$/.exec(msg)) {
ok(true, msg);
} else if(/KO$/.exec(msg)) {
ok(true, false);
} else if (/DONE/.exec(msg)) {
permManager.removeFromPrincipal(window.document.nodePrincipal, "browser",
Ci.nsIPermissionManager.ALLOW_ACTION);
SimpleTest.finish();
}
});
mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
false);
mm.sendAsyncMessage("test:ipcMessage", 42, null, window.document.nodePrincipal);
});
document.body.appendChild(iframe);
}
addEventListener("load", function() {
info("Got load event.");
permManager.addFromPrincipal(window.document.nodePrincipal, "browser",
Ci.nsIPermissionManager.ALLOW_ACTION);
SpecialPowers.pushPrefEnv({
"set": [
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});
</script>
</body>
</html>

View File

@ -211,7 +211,8 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
int32_t index = Index();
uint32_t mask = HTMLSelectElement::SET_DISABLED;
if (aValue) {
bool defaultSelected = aValue;
if (defaultSelected) {
mask |= HTMLSelectElement::IS_SELECTED;
}
@ -227,8 +228,10 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
// Now reset our members; when we finish the attr set we'll end up with the
// rigt selected state.
mIsInSetDefaultSelected = inSetDefaultSelected;
mSelectedChanged = false;
// mIsSelected doesn't matter while mSelectedChanged is false
// mIsSelected has already been set by SetOptionsSelectedByIndex.
// Possibly more than once; make sure our mSelectedChanged state is
// set correctly.
mSelectedChanged = mIsSelected != defaultSelected;
return NS_OK;
}

View File

@ -402,6 +402,7 @@ support-files =
[test_object_attributes_reflection.html]
[test_object_plugin_nav.html]
[test_ol_attributes_reflection.html]
[test_option_defaultSelected.html]
[test_param_attributes_reflection.html]
[test_q_attributes_reflection.html]
[test_restore_from_parser_fragment.html]

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=927796
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 927796</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=927796">Mozilla Bug 927796</a>
<p id="display">
<select id="s1">
<option selected>one</option>
<option>two</option>
</select>
<select id="s2" size="5">
<option selected>one</option>
<option>two</option>
</select>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 927796 **/
var s1 = $("s1");
s1.options[0].defaultSelected = false;
is(s1.options[0].selected, true,
"First option in combobox should still be selected");
is(s1.options[1].selected, false,
"Second option in combobox should not be selected");
var s2 = $("s2");
s2.options[0].defaultSelected = false;
is(s2.options[0].selected, false,
"First option in listbox should not be selected");
is(s2.options[1].selected, false,
"Second option in listbox should not be selected");
</script>
</body>
</html>

View File

@ -129,14 +129,6 @@ public:
return NS_ERROR_FAILURE;
}
#ifdef MOZ_DASH
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
MediaByteRange const &aByteRange)
{
return NS_ERROR_FAILURE;
}
#endif
virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
{
aRanges.AppendElement(MediaByteRange(0, mLength));

View File

@ -49,9 +49,6 @@
#include "RtspOmxDecoder.h"
#include "RtspOmxReader.h"
#endif
#ifdef MOZ_DASH
#include "DASHDecoder.h"
#endif
#ifdef MOZ_WMF
#include "WMFDecoder.h"
#include "WMFReader.h"
@ -285,24 +282,6 @@ IsMediaPluginsType(const nsACString& aType)
}
#endif
#ifdef MOZ_DASH
/* static */
static const char* const gDASHMPDTypes[2] = {
"application/dash+xml",
nullptr
};
static bool
IsDASHMPDType(const nsACString& aType)
{
if (!MediaDecoder::IsDASHEnabled()) {
return false;
}
return CodecListContains(gDASHMPDTypes, aType);
}
#endif
#ifdef MOZ_WMF
static bool
IsWMFSupportedType(const nsACString& aType)
@ -399,13 +378,6 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
result = CANPLAY_YES;
}
#endif
#ifdef MOZ_DASH
if (IsDASHMPDType(nsDependentCString(aMIMEType))) {
// DASH manifest uses WebM codecs only.
codecList = gWebMCodecs;
result = CANPLAY_YES;
}
#endif
#ifdef MOZ_GSTREAMER
if (GStreamerDecoder::CanHandleMediaType(nsDependentCString(aMIMEType),
aHaveRequestedCodecs ? &aRequestedCodecs : nullptr)) {
@ -530,11 +502,6 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
decoder = new WebMDecoder();
}
#endif
#ifdef MOZ_DASH
if (IsDASHMPDType(aType)) {
decoder = new DASHDecoder();
}
#endif
#ifdef MOZ_DIRECTSHOW
// Note: DirectShow decoder must come before WMFDecoder, else the pref
// "media.directshow.preferred" won't be honored.
@ -616,9 +583,6 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
if (IsAppleMediaSupportedType(aType)) {
decoderReader = new AppleMP3Reader(aDecoder);
} else
#endif
#ifdef MOZ_DASH
// The DASH decoder is not supported.
#endif
if (false) {} // dummy if to take care of the dangling else
@ -640,9 +604,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
#ifdef MOZ_WEBM
IsWebMType(aType) ||
#endif
#ifdef MOZ_DASH
IsDASHMPDType(aType) ||
#endif
#ifdef MOZ_GSTREAMER
IsGStreamerSupportedType(aType) ||
#endif

View File

@ -1739,14 +1739,6 @@ MediaDecoder::IsMediaPluginsEnabled()
}
#endif
#ifdef MOZ_DASH
bool
MediaDecoder::IsDASHEnabled()
{
return Preferences::GetBool("media.dash.enabled");
}
#endif
#ifdef MOZ_WMF
bool
MediaDecoder::IsWMFEnabled()

View File

@ -787,10 +787,6 @@ public:
static bool IsMediaPluginsEnabled();
#endif
#ifdef MOZ_DASH
static bool IsDASHEnabled();
#endif
#ifdef MOZ_WMF
static bool IsWMFEnabled();
#endif

View File

@ -488,11 +488,6 @@ public:
// or an un-recoverable read error has occured.
virtual bool DecodeAudioData() = 0;
#ifdef MOZ_DASH
// Steps to carry out at the start of the |DecodeLoop|.
virtual void PrepareToDecode() { }
#endif
// Reads and decodes one video frame. Packets with a timestamp less
// than aTimeThreshold will be decoded (unless they're not keyframes
// and aKeyframeSkip is true), but will not be added to the queue.

View File

@ -853,10 +853,6 @@ void MediaDecoderStateMachine::DecodeLoop()
!mStopDecodeThread &&
(videoPlaying || audioPlaying))
{
#ifdef MOZ_DASH
mReader->PrepareToDecode();
#endif
// We don't want to consider skipping to the next keyframe if we've
// only just started up the decode loop, so wait until we've decoded
// some frames before enabling the keyframe skip logic on video.

View File

@ -59,12 +59,6 @@ ChannelMediaResource::ChannelMediaResource(MediaDecoder* aDecoder,
mLock("ChannelMediaResource.mLock"),
mIgnoreResume(false),
mSeekingForMetadata(false),
#ifdef MOZ_DASH
mByteRangeDownloads(false),
mByteRangeFirstOpen(true),
mSeekOffsetMonitor("media.dashseekmonitor"),
mSeekOffset(-1),
#endif
mIsTransportSeekable(true)
{
#ifdef PR_LOGGING
@ -417,16 +411,6 @@ ChannelMediaResource::OnStopRequest(nsIRequest* aRequest, nsresult aStatus)
mChannelStatistics->Stop();
}
#ifdef MOZ_DASH
// If we were loading a byte range, notify decoder and return.
// Skip this for unterminated byte range requests, e.g. seeking for whole
// file downloads.
if (mByteRangeDownloads) {
mDecoder->NotifyDownloadEnded(aStatus);
return NS_OK;
}
#endif
// Note that aStatus might have succeeded --- this might be a normal close
// --- even in situations where the server cut us off because we were
// suspended. So we need to "reopen on error" in that case too. The only
@ -490,18 +474,6 @@ ChannelMediaResource::CopySegmentToCache(nsIInputStream *aInStream,
closure->mResource->mDecoder->NotifyDataArrived(aFromSegment, aCount, closure->mResource->mOffset);
#ifdef MOZ_DASH
// For byte range downloads controlled by |DASHDecoder|, there are cases in
// which the reader's offset is different enough from the channel offset that
// |MediaCache| requests a |CacheClientSeek| to the reader's offset. This
// can happen between calls to |CopySegmentToCache|. To avoid copying at
// incorrect offsets, ensure |MediaCache| copies to the location that
// |ChannelMediaResource| expects.
if (closure->mResource->mByteRangeDownloads) {
closure->mResource->mCacheStream.NotifyDataStarted(closure->mResource->mOffset);
}
#endif
// Keep track of where we're up to.
LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "
"[%d] bytes for decoder[%p]",
@ -548,39 +520,6 @@ ChannelMediaResource::OnDataAvailable(nsIRequest* aRequest,
return NS_OK;
}
#ifdef MOZ_DASH
/* |OpenByteRange|
* For terminated byte range requests, use this function.
* Callback is |MediaDecoder|::|NotifyByteRangeDownloaded|().
* See |CacheClientSeek| also.
*/
nsresult
ChannelMediaResource::OpenByteRange(nsIStreamListener** aStreamListener,
MediaByteRange const & aByteRange)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
mByteRangeDownloads = true;
mByteRange = aByteRange;
// OpenByteRange may be called multiple times; same URL, different ranges.
// For the first call using this URL, forward to Open for some init.
if (mByteRangeFirstOpen) {
mByteRangeFirstOpen = false;
return Open(aStreamListener);
}
// For subsequent calls, ensure channel is recreated with correct byte range.
CloseChannel();
nsresult rv = RecreateChannel();
NS_ENSURE_SUCCESS(rv, rv);
return OpenChannel(aStreamListener);
}
#endif
nsresult ChannelMediaResource::Open(nsIStreamListener **aStreamListener)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@ -832,13 +771,6 @@ nsresult ChannelMediaResource::Seek(int32_t aWhence, int64_t aOffset)
CMLOG("Seek requested for aOffset [%lld] for decoder [%p]",
aOffset, mDecoder);
#ifdef MOZ_DASH
// Remember |aOffset|, because Media Cache may request a diff offset later.
if (mByteRangeDownloads) {
ReentrantMonitorAutoEnter mon(mSeekOffsetMonitor);
mSeekOffset = aOffset;
}
#endif
return mCacheStream.Seek(aWhence, aOffset);
}
@ -1045,22 +977,7 @@ ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
CMLOG("CacheClientSeek requested for aOffset [%lld] for decoder [%p]",
aOffset, mDecoder);
#ifndef MOZ_DASH
CloseChannel();
#else
// |CloseChannel| immediately for non-byte-range downloads.
if (!mByteRangeDownloads) {
CloseChannel();
} else if (mChannel) {
// Only close byte range channels if they are not in pending state.
bool isPending = false;
nsresult rv = mChannel->IsPending(&isPending);
NS_ENSURE_SUCCESS(rv, rv);
if (!isPending) {
CloseChannel();
}
}
#endif
if (aResume) {
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
@ -1068,85 +985,6 @@ ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
--mSuspendCount;
}
#ifdef MOZ_DASH // Note: For chunked downloads, e.g. DASH, we need to determine which chunk
// contains the requested offset, |mOffset|. This is either previously
// requested in |Seek| or updated to the most recent bytes downloaded.
// So the process below is:
// 1 - Query decoder for chunk containing desired offset, |mOffset|.
// Return silently if the offset is not available; suggests decoder is
// yet to get range information.
// Return with NetworkError for all other errors.
//
// 2 - Adjust |mByteRange|.mStart to |aOffset|, requested by media cache.
// For seeking, the media cache always requests the start of the cache
// block, so we need to adjust the first chunk of a seek.
// E.g. For "DASH-WebM On Demand" this means the first chunk after
// seeking will most likely be larger than the subsegment (cluster).
//
// 3 - Call |OpenByteRange| requesting |mByteRange| bytes.
if (mByteRangeDownloads) {
// Query decoder for chunk containing desired offset.
nsresult rv;
{
ReentrantMonitorAutoEnter mon(mSeekOffsetMonitor);
// Only continue with seek request if a prior call to |Seek| was made.
// If |Seek| was not called previously, it means the media cache is
// seeking on its own.
// E.g. For those WebM files which are encoded with cues at the end of
// the file, when the cues are parsed, the reader and media cache
// automatically return to the first offset not downloaded, normally the
// first byte after init data. This results in |MediaCache| requesting
// |aOffset| = 0 (aligning to the start of the cache block. Ignore this
// and let |DASHDecoder| decide which bytes to download and when.
if (mSeekOffset >= 0) {
rv = mDecoder->GetByteRangeForSeek(mSeekOffset, mByteRange);
// Cache may try to seek from the next uncached byte: this offset may
// be after the byte range being seeked, i.e. the range containing
// |mSeekOffset|, which is the offset actually requested by the reader.
// This case means that the seeked range is already cached. For byte
// range downloads, we do not permit the cache to request bytes outside
// the seeked range. Instead, the decoder is responsible for
// controlling the sequence of byte range downloads. As such, return
// silently, and do NOT request a new download.
if (NS_SUCCEEDED(rv) && !mByteRange.IsNull() &&
aOffset > mByteRange.mEnd) {
rv = NS_ERROR_NOT_AVAILABLE;
mByteRange.Clear();
}
mSeekOffset = -1;
} else if (mByteRange.mStart <= aOffset && aOffset <= mByteRange.mEnd) {
CMLOG("Trying to resume download at offset [%lld].", aOffset);
rv = NS_OK;
} else {
CMLOG("MediaCache [%p] trying to seek independently to offset [%lld].",
&mCacheStream, aOffset);
rv = NS_ERROR_NOT_AVAILABLE;
}
}
if (rv == NS_ERROR_NOT_AVAILABLE) {
// Decoder will not make byte ranges available for non-active streams, or
// if range information is not yet available, or for metadata bytes if
// they have already been downloaded and read. In all cases, it is ok to
// return silently and assume that the decoder will request the correct
// byte range when range information becomes available.
CMLOG("Byte range not available for decoder [%p]; returning "
"silently.", mDecoder);
return NS_OK;
} else if (NS_FAILED(rv) || mByteRange.IsNull()) {
// Decoder reported an error we don't want to handle here; just return.
CMLOG("Error getting byte range: seek offset[%lld] cache offset[%lld] "
"decoder[%p]", mSeekOffset, aOffset, mDecoder);
mDecoder->NetworkError();
CloseChannel();
return rv;
}
// Adjust the byte range to start where the media cache requested.
mByteRange.mStart = mOffset = aOffset;
return OpenByteRange(nullptr, mByteRange);
}
#endif
mOffset = aOffset;
if (mSuspendCount > 0) {

View File

@ -7,9 +7,6 @@
#define MediaResource_h_
#include "mozilla/Mutex.h"
#ifdef MOZ_DASH
#include "mozilla/ReentrantMonitor.h"
#endif
#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsIStreamingProtocolController.h"
@ -362,19 +359,6 @@ public:
*/
virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
#ifdef MOZ_DASH
/**
* Open the stream using a specific byte range only. Creates a stream
* listener and returns it in aStreamListener; this listener needs to be
* notified of incoming data. Byte range is specified in aByteRange.
*/
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
MediaByteRange const &aByteRange)
{
return Open(aStreamListener);
}
#endif
/**
* Fills aRanges with MediaByteRanges representing the data which is cached
* in the media cache. Stream should be pinned during call and while
@ -522,10 +506,6 @@ public:
// Main thread
virtual nsresult Open(nsIStreamListener** aStreamListener);
#ifdef MOZ_DASH
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
MediaByteRange const & aByteRange);
#endif
virtual nsresult Close();
virtual void Suspend(bool aCloseImmediately);
virtual void Resume();
@ -667,20 +647,6 @@ protected:
// Start and end offset of the bytes to be requested.
MediaByteRange mByteRange;
#ifdef MOZ_DASH
// True if resource was opened with a byte rage request.
bool mByteRangeDownloads;
// Set to false once first byte range request has been made.
bool mByteRangeFirstOpen;
// For byte range requests, set to the offset requested in |Seek|.
// Used in |CacheClientSeek| to find the originally requested byte range.
// Read/Write on multiple threads; use |mSeekMonitor|.
ReentrantMonitor mSeekOffsetMonitor;
int64_t mSeekOffset;
#endif
// True if the stream can seek into unbuffered ranged, i.e. if the
// connection supports byte range requests.
bool mIsTransportSeekable;

File diff suppressed because it is too large Load Diff

View File

@ -1,412 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for info on DASH interaction with the media engine.*/
#if !defined(DASHDecoder_h_)
#define DASHDecoder_h_
#include "nsTArray.h"
#include "nsIURI.h"
#include "nsITimer.h"
#include "MediaDecoder.h"
#include "DASHReader.h"
namespace mozilla {
namespace net {
class IMPDManager;
class nsDASHMPDParser;
class Representation;
}// net
class DASHRepDecoder;
class DASHDecoder : public MediaDecoder
{
public:
typedef class mozilla::net::IMPDManager IMPDManager;
typedef class mozilla::net::nsDASHMPDParser nsDASHMPDParser;
typedef class mozilla::net::Representation Representation;
// XXX Arbitrary max file size for MPD. 50MB seems generously large.
static const uint32_t DASH_MAX_MPD_SIZE = 50*1024*1024;
DASHDecoder();
~DASHDecoder();
MediaDecoder* Clone() MOZ_OVERRIDE {
if (!IsDASHEnabled()) {
return nullptr;
}
return new DASHDecoder();
}
// Creates a single state machine for all stream decoders.
// Called from Load on the main thread only.
MediaDecoderStateMachine* CreateStateMachine();
// Loads the MPD from the network and subsequently loads the media streams.
// Called from the main thread only.
virtual nsresult Load(nsIStreamListener** aListener,
MediaDecoder* aCloneDonor) MOZ_OVERRIDE;
// Notifies download of MPD file has ended.
// Called on the main thread only.
void NotifyDownloadEnded(nsresult aStatus);
// Notification from |DASHReader| that a seek has occurred in
// |aSubsegmentIdx|. Passes notification onto subdecoder which downloaded
// the subsegment already, if download is in the past. Otherwise, it returns.
void NotifySeekInVideoSubsegment(int32_t aRepDecoderIdx,
int32_t aSubsegmentIdx);
void NotifySeekInAudioSubsegment(int32_t aSubsegmentIdx);
// Notifies that a byte range download has ended. As per the DASH spec, this
// allows for stream switching at the boundaries of the byte ranges.
// Called on the main thread only.
void NotifyDownloadEnded(DASHRepDecoder* aRepDecoder,
nsresult aStatus,
int32_t const aSubsegmentIdx);
// Notification from an |MediaDecoderReader| class that metadata has been
// read. Declared here to allow overloading.
void OnReadMetadataCompleted() MOZ_OVERRIDE { }
// Seeks to aTime in seconds
nsresult Seek(double aTime) MOZ_OVERRIDE;
// Notification from |DASHRepDecoder| that a metadata has been read.
// |DASHDecoder| will initiate load of data bytes for active audio/video
// decoders. Called on the decode thread.
void OnReadMetadataCompleted(DASHRepDecoder* aRepDecoder);
// Returns true if all subsegments from current decode position are
// downloaded. Must be in monitor. Call from any thread.
bool IsDataCachedToEndOfResource() MOZ_OVERRIDE;
// Refers to downloading data bytes, i.e. non metadata.
// Returns true if |aRepDecoder| is an active audio or video sub decoder AND
// if metadata for all audio or video decoders has been read.
// Could be called from any thread; enters decoder monitor.
bool IsDecoderAllowedToDownloadData(DASHRepDecoder* aRepDecoder);
// Refers to downloading data bytes during SEEKING.
// Returns true if |aRepDecoder| is the active audio sub decoder, OR if
// it is a video decoder and is allowed to download this subsegment.
// Returns false if there is still some metadata to download.
// Could be called from any thread; enters decoder monitor.
bool IsDecoderAllowedToDownloadSubsegment(DASHRepDecoder* aRepDecoder,
int32_t const aSubsegmentIdx);
// Determines if rep/sub decoders should be switched, and if so switches
// them. Notifies |DASHReader| if and when it should switch readers.
// Returns a pointer to the new active decoder.
// Called on the main thread.
nsresult PossiblySwitchDecoder(DASHRepDecoder* aRepDecoder);
// Sets the byte range index for audio|video downloads. Will only increment
// for current active decoders. Could be called from any thread.
// Requires monitor because of write to |mAudioSubsegmentIdx| or
// |mVideoSubsegmentIdx|.
void SetSubsegmentIndex(DASHRepDecoder* aRepDecoder,
int32_t aSubsegmentIdx);
// Suspend any media downloads that are in progress. Called by the
// media element when it is sent to the bfcache, or when we need
// to throttle the download. Call on the main thread only. This can
// be called multiple times, there's an internal "suspend count".
void Suspend() MOZ_OVERRIDE;
// Resume any media downloads that have been suspended. Called by the
// media element when it is restored from the bfcache, or when we need
// to stop throttling the download. Call on the main thread only.
// The download will only actually resume once as many Resume calls
// have been made as Suspend calls. When aForceBuffering is true,
// we force the decoder to go into buffering state before resuming
// playback.
void Resume(bool aForceBuffering) MOZ_OVERRIDE;
private:
// Increments the byte range index for audio|video downloads. Will only
// increment for current active decoders. Could be called from any thread.
// Requires monitor because of write to |mAudioSubsegmentIdx| or
// |mVideoSubsegmentIdx|.
void IncrementSubsegmentIndex(DASHRepDecoder* aRepDecoder)
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (aRepDecoder == AudioRepDecoder()) {
mAudioSubsegmentIdx++;
} else if (aRepDecoder == VideoRepDecoder()) {
mVideoSubsegmentIdx++;
}
}
public:
// Gets the byte range index for audio|video downloads. Will only increment
// for current active decoders. Could be called from any thread. Will enter
// monitor for read access off the decode thread.
int32_t GetSubsegmentIndex(DASHRepDecoder* aRepDecoder)
{
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
if (aRepDecoder == AudioRepDecoder()) {
return mAudioSubsegmentIdx;
} else if (aRepDecoder == VideoRepDecoder()) {
return mVideoSubsegmentIdx;
}
return (-1);
}
// Returns the total number of subsegments that have been loaded. Will enter
// monitor for read access off the decode thread.
uint32_t GetNumSubsegmentLoads() {
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
return mVideoSubsegmentLoads.Length();
}
// Returns the index of the rep decoder used to load a subsegment. Will enter
// monitor for read access off the decode thread.
int32_t GetRepIdxForVideoSubsegmentLoad(int32_t aSubsegmentIdx)
{
NS_ASSERTION(0 <= aSubsegmentIdx, "Subsegment index should not be negative.");
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
if ((uint32_t)aSubsegmentIdx < mVideoSubsegmentLoads.Length()) {
return mVideoSubsegmentLoads[aSubsegmentIdx];
} else {
// If it hasn't been downloaded yet, use the lowest bitrate decoder.
return 0;
}
}
// Returns the index of the rep decoder used to load a subsegment, after a
// seek. Called on the decode thread, and will block if the subsegment
// previous to the one specified has not yet been loaded. This ensures that
// |DASHDecoder| has had a chance to determine which decoder should load the
// next subsegment, in the case where |DASHRepReader|::|DecodeToTarget| has
// read all the data for the current subsegment from the cache, and needs to
// know which reader (including itself) to use next.
int32_t GetRepIdxForVideoSubsegmentLoadAfterSeek(int32_t aSubsegmentIndex);
int32_t GetSwitchCountAtVideoSubsegment(int32_t aSubsegmentIdx)
{
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
NS_ASSERTION(0 <= aSubsegmentIdx, "Subsegment index should not be negative.");
if (aSubsegmentIdx == 0) {
// Do the zeroeth switch next.
return 0;
}
int32_t switchCount = 0;
for (uint32_t i = 1;
i < mVideoSubsegmentLoads.Length() &&
i <= (uint32_t)aSubsegmentIdx;
i++) {
if (mVideoSubsegmentLoads[i-1] != mVideoSubsegmentLoads[i]) {
switchCount++;
}
}
return switchCount;
}
// The actual playback rate computation. The monitor must be held.
// XXX Computes playback for the current video rep decoder only.
double ComputePlaybackRate(bool* aReliable) MOZ_OVERRIDE;
// Something has changed that could affect the computed playback rate,
// so recompute it. The monitor must be held. Will be forwarded to current
// audio and video rep decoders.
void UpdatePlaybackRate() MOZ_OVERRIDE;
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Forwarded to sub-decoders. Must be called with the decoder monitor held.
void StopProgressUpdates() MOZ_OVERRIDE;
// Allow updating the bytes downloaded for progress notifications.
// Forwarded to sub-decoders. Must be called with the decoder monitor held.
void StartProgressUpdates() MOZ_OVERRIDE;
// Used to estimate rates of data passing through the decoder's channel.
// Records activity starting on the channel. The monitor must be held.
virtual void NotifyPlaybackStarted() MOZ_OVERRIDE;
// Used to estimate rates of data passing through the decoder's channel.
// Records activity stopping on the channel. The monitor must be held.
virtual void NotifyPlaybackStopped() MOZ_OVERRIDE;
// Return statistics. This is used for progress events and other things.
// This can be called from any thread. It's only a snapshot of the
// current state, since other threads might be changing the state
// at any time.
// XXX Stats are calculated based on the current video rep decoder, with the
// exception of download rate, which is based on all video downloads.
virtual Statistics GetStatistics() MOZ_OVERRIDE;
// Drop reference to state machine and tell sub-decoders to do the same.
// Only called during shutdown dance, on main thread only.
void ReleaseStateMachine();
// Overridden to forward |Shutdown| to sub-decoders.
// Called on the main thread only.
void Shutdown();
// Called by sub-decoders when load has been aborted. Will notify media
// element only once. Called on the main thread only.
void LoadAborted();
// Notifies the element that decoding has failed. On main thread, call is
// forwarded to |MediaDecoder|::|Error| immediately. On other threads,
// a call is dispatched for execution on the main thread.
void DecodeError();
private:
// Reads the MPD data from resource to a byte stream.
// Called on the MPD reader thread.
void ReadMPDBuffer();
// Called when MPD data is completely read.
// On the main thread.
void OnReadMPDBufferCompleted();
// Parses the copied MPD byte stream.
// On the main thread: DOM APIs complain when off the main thread.
nsresult ParseMPDBuffer();
// Creates the sub-decoders for a |Representation|, i.e. media streams.
// On the main thread.
nsresult CreateRepDecoders();
// Creates audio/video decoders for individual |Representation|s.
// On the main thread.
nsresult CreateAudioRepDecoder(nsIURI* aUrl, Representation const * aRep);
nsresult CreateVideoRepDecoder(nsIURI* aUrl, Representation const * aRep);
// Get audio sub-decoder for current audio |Representation|. Will return
// nullptr for out of range indexes.
// Enters monitor for read access off the decode thread.
// XXX Note: Although an array of audio decoders is provided, audio stream
// switching is not yet supported.
DASHRepDecoder* AudioRepDecoder() {
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
if (0 == mAudioRepDecoders.Length()) {
return nullptr;
}
NS_ENSURE_TRUE((uint32_t)mAudioRepDecoderIdx < mAudioRepDecoders.Length(),
nullptr);
if (mAudioRepDecoderIdx < 0) {
return nullptr;
} else {
return mAudioRepDecoders[mAudioRepDecoderIdx];
}
}
// Get video sub-decoder for current video |Representation|. Will return
// nullptr for out of range indexes.
// Enters monitor for read access off the decode thread.
DASHRepDecoder* VideoRepDecoder() {
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
if (0 == mVideoRepDecoders.Length()) {
return nullptr;
}
NS_ENSURE_TRUE((uint32_t)mVideoRepDecoderIdx < mVideoRepDecoders.Length(),
nullptr);
if (mVideoRepDecoderIdx < 0) {
return nullptr;
} else {
return mVideoRepDecoders[mVideoRepDecoderIdx];
}
}
// Creates audio/video resources for individual |Representation|s.
// On the main thread.
MediaResource* CreateAudioSubResource(nsIURI* aUrl,
MediaDecoder* aAudioDecoder);
MediaResource* CreateVideoSubResource(nsIURI* aUrl,
MediaDecoder* aVideoDecoder);
// Creates an http channel for a |Representation|.
// On the main thread.
nsresult CreateSubChannel(nsIURI* aUrl, nsIChannel** aChannel);
// Loads the media |Representations|, i.e. the media streams.
// On the main thread.
nsresult LoadRepresentations();
// True when media element has already been notified of an aborted load.
bool mNotifiedLoadAborted;
// Ptr for the MPD data.
nsAutoArrayPtr<char> mBuffer;
// Length of the MPD data.
uint32_t mBufferLength;
// Ptr to the MPD Reader thread.
nsCOMPtr<nsIThread> mMPDReaderThread;
// Document Principal.
nsCOMPtr<nsIPrincipal> mPrincipal;
// MPD Manager provides access to the MPD information.
nsAutoPtr<IMPDManager> mMPDManager;
// Main reader object; manages all sub-readers for |Representation|s. Owned by
// state machine; destroyed in state machine's destructor.
DASHReader* mDASHReader;
// Sub-decoder vars. Note: For all following members, the decode monitor
// should be held for write access on decode thread, and all read/write off
// the decode thread.
// Index of the video |AdaptationSet|.
int32_t mVideoAdaptSetIdx;
// Indexes for the current audio and video decoders.
int32_t mAudioRepDecoderIdx;
int32_t mVideoRepDecoderIdx;
// Array of pointers for the |Representation|s in the audio/video
// |AdaptationSet|.
nsTArray<nsRefPtr<DASHRepDecoder> > mAudioRepDecoders;
nsTArray<nsRefPtr<DASHRepDecoder> > mVideoRepDecoders;
// Current index of subsegments downloaded for audio/video decoder.
int32_t mAudioSubsegmentIdx;
int32_t mVideoSubsegmentIdx;
// Count for the number of readers which have called |OnReadMetadataCompleted|.
// Initialised to 0; incremented for every decoder which has |Load| called;
// and decremented for every call to |OnReadMetadataCompleted|. When it is
// zero again, all metadata has been read for audio or video, and data bytes
// can be downloaded.
uint32_t mAudioMetadataReadCount;
uint32_t mVideoMetadataReadCount;
// Array records the index of the decoder/Representation which loaded each
// subsegment.
nsTArray<int32_t> mVideoSubsegmentLoads;
// True when Seek is called; will block any downloads until
// |NotifySeekInSubsegment| is called, which will set it to false, and will
// start a new series of downloads from the seeked subsegment.
bool mSeeking;
// Mutex for statistics.
Mutex mStatisticsLock;
// Stores snapshot statistics, such as download rate, for the audio|video
// data streams. |mStatisticsLock| must be locked for access.
nsRefPtr<MediaChannelStatistics> mAudioStatistics;
nsRefPtr<MediaChannelStatistics> mVideoStatistics;
};
} // namespace mozilla
#endif

View File

@ -1,674 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for info on DASH interaction with the media engine.*/
#include "mozilla/dom/TimeRanges.h"
#include "VideoFrameContainer.h"
#include "AbstractMediaDecoder.h"
#include "DASHReader.h"
#include "DASHDecoder.h"
#include <algorithm>
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* gDASHReaderLog;
#define LOG(msg, ...) PR_LOG(gDASHReaderLog, PR_LOG_DEBUG, \
("%p [DASHReader] " msg, this, __VA_ARGS__))
#define LOG1(msg) PR_LOG(gDASHReaderLog, PR_LOG_DEBUG, \
("%p [DASHReader] " msg, this))
#else
#define LOG(msg, ...)
#define LOG1(msg)
#endif
DASHReader::DASHReader(AbstractMediaDecoder* aDecoder) :
MediaDecoderReader(aDecoder),
mReadMetadataMonitor("media.dashreader.readmetadata"),
mReadyToReadMetadata(false),
mDecoderIsShuttingDown(false),
mAudioReader(this),
mVideoReader(this),
mAudioReaders(this),
mVideoReaders(this),
mSwitchVideoReaders(false),
mSwitchCount(-1)
{
MOZ_COUNT_CTOR(DASHReader);
#ifdef PR_LOGGING
if (!gDASHReaderLog) {
gDASHReaderLog = PR_NewLogModule("DASHReader");
}
#endif
}
DASHReader::~DASHReader()
{
MOZ_COUNT_DTOR(DASHReader);
}
nsresult
DASHReader::ResetDecode()
{
MediaDecoderReader::ResetDecode();
nsresult rv;
for (uint i = 0; i < mAudioReaders.Length(); i++) {
rv = mAudioReaders[i]->ResetDecode();
NS_ENSURE_SUCCESS(rv, rv);
}
for (uint i = 0; i < mVideoReaders.Length(); i++) {
rv = mVideoReaders[i]->ResetDecode();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
DASHReader::Init(MediaDecoderReader* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ASSERTION(mAudioReaders.Length() != 0 && mVideoReaders.Length() != 0,
"Audio and video readers should exist already.");
nsresult rv;
for (uint i = 0; i < mAudioReaders.Length(); i++) {
rv = mAudioReaders[i]->Init(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
}
for (uint i = 0; i < mVideoReaders.Length(); i++) {
rv = mVideoReaders[i]->Init(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
void
DASHReader::AddAudioReader(DASHRepReader* aAudioReader)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE_VOID(aAudioReader);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mAudioReaders.AppendElement(aAudioReader);
// XXX For now, just pick the first reader to be default.
if (!mAudioReader)
mAudioReader = aAudioReader;
}
void
DASHReader::AddVideoReader(DASHRepReader* aVideoReader)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE_VOID(aVideoReader);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mVideoReaders.AppendElement(aVideoReader);
// XXX For now, just pick the first reader to be default.
if (!mVideoReader)
mVideoReader = aVideoReader;
}
bool
DASHReader::HasAudio()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return mAudioReader ? mAudioReader->HasAudio() : false;
}
bool
DASHReader::HasVideo()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return mVideoReader ? mVideoReader->HasVideo() : false;
}
int64_t
DASHReader::VideoQueueMemoryInUse()
{
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
return VideoQueueMemoryInUse();
}
int64_t
DASHReader::AudioQueueMemoryInUse()
{
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
return AudioQueueMemoryInUse();
}
bool
DASHReader::DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
if (mVideoReader) {
return mVideoReader->DecodeVideoFrame(aKeyframeSkip, aTimeThreshold);
} else {
return false;
}
}
bool
DASHReader::DecodeAudioData()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return (mAudioReader ? mAudioReader->DecodeAudioData() : false);
}
nsresult
DASHReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// Wait for MPD to be parsed and child readers created.
LOG1("Waiting for metadata download.");
nsresult rv = WaitForMetadata();
// If we get an abort, return silently; the decoder is shutting down.
if (NS_ERROR_ABORT == rv) {
return NS_OK;
}
// Verify no other errors before continuing.
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(aTags, "Called with null MetadataTags**.");
*aTags = nullptr;
// Get metadata from child readers.
MediaInfo audioInfo, videoInfo;
// Read metadata for all video streams.
for (uint i = 0; i < mVideoReaders.Length(); i++) {
// Use an nsAutoPtr here to ensure |tags| memory does not leak.
nsAutoPtr<HTMLMediaElement::MetadataTags> tags;
rv = mVideoReaders[i]->ReadMetadata(&videoInfo, getter_Transfers(tags));
NS_ENSURE_SUCCESS(rv, rv);
// Use metadata from current video sub reader to populate aInfo.
if (mVideoReaders[i] == mVideoReader) {
mInfo.mVideo = videoInfo.mVideo;
}
}
// Read metadata for audio stream.
// Note: Getting metadata tags from audio reader only for now.
// XXX Audio stream switching not yet supported.
if (mAudioReader) {
rv = mAudioReader->ReadMetadata(&audioInfo, aTags);
NS_ENSURE_SUCCESS(rv, rv);
mInfo.mAudio = audioInfo.mAudio;
}
*aInfo = mInfo;
return NS_OK;
}
nsresult
DASHReader::Seek(int64_t aTime,
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
NS_ENSURE_SUCCESS(ResetDecode(), NS_ERROR_FAILURE);
LOG("Seeking to [%.2fs]", aTime/1000000.0);
nsresult rv;
DASHDecoder* dashDecoder = static_cast<DASHDecoder*>(mDecoder);
if (mAudioReader) {
int64_t subsegmentIdx = -1;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
subsegmentIdx = mAudioReader->GetSubsegmentForSeekTime(aTime);
NS_ENSURE_TRUE(0 <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE);
}
dashDecoder->NotifySeekInAudioSubsegment(subsegmentIdx);
rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mVideoReader) {
// Determine the video subsegment we're seeking to.
int32_t subsegmentIdx = -1;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
subsegmentIdx = mVideoReader->GetSubsegmentForSeekTime(aTime);
NS_ENSURE_TRUE(0 <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE);
}
LOG("Seek to [%.2fs] found in video subsegment [%d]",
aTime/1000000.0, subsegmentIdx);
// Determine if/which video reader previously downloaded this subsegment.
int32_t readerIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(subsegmentIdx);
dashDecoder->NotifySeekInVideoSubsegment(readerIdx, subsegmentIdx);
if (0 <= readerIdx) {
NS_ENSURE_TRUE(readerIdx < mVideoReaders.Length(),
NS_ERROR_ILLEGAL_VALUE);
// Switch to this reader and do the Seek.
DASHRepReader* fromReader = mVideoReader;
DASHRepReader* toReader = mVideoReaders[readerIdx];
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (fromReader != toReader) {
LOG("Switching video readers now from [%p] to [%p] for a seek to "
"[%.2fs] in subsegment [%d]",
fromReader, toReader, aTime/1000000.0, subsegmentIdx);
mVideoReader = toReader;
}
}
rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
if (NS_FAILED(rv)) {
NS_ENSURE_SUCCESS(rv, rv);
}
// Go back to the appropriate count in the switching history, and setup
// this main reader and the sub readers for the next switch (if any).
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mSwitchCount = dashDecoder->GetSwitchCountAtVideoSubsegment(subsegmentIdx);
LOG("After mVideoReader->Seek() mSwitchCount %d", mSwitchCount);
NS_ENSURE_TRUE(0 <= mSwitchCount, NS_ERROR_ILLEGAL_VALUE);
NS_ENSURE_TRUE(mSwitchCount <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE);
}
} else {
LOG("Error getting rep idx for video subsegment [%d]",
subsegmentIdx);
}
}
return NS_OK;
}
nsresult
DASHReader::GetBuffered(TimeRanges* aBuffered,
int64_t aStartTime)
{
NS_ENSURE_ARG(aBuffered);
MediaResource* resource = nullptr;
AbstractMediaDecoder* decoder = nullptr;
TimeRanges audioBuffered, videoBuffered;
uint32_t audioRangeCount = 0, videoRangeCount = 0;
bool audioCachedAtEnd = false, videoCachedAtEnd = false;
nsresult rv = NS_OK;
// Get all audio and video buffered ranges. Include inactive streams, since
// we may have carried out a seek and future subsegments may be in currently
// inactive decoders.
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
for (uint32_t i = 0; i < mAudioReaders.Length(); i++) {
decoder = mAudioReaders[i]->GetDecoder();
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
resource = decoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
resource->Pin();
rv = mAudioReaders[i]->GetBuffered(&audioBuffered, aStartTime);
NS_ENSURE_SUCCESS(rv, rv);
// If data was cached at the end, then the final timestamp refers to the
// end of the data. Use this later to extend end time if necessary.
if (!audioCachedAtEnd) {
audioCachedAtEnd = mAudioReaders[i]->IsDataCachedAtEndOfSubsegments();
}
resource->Unpin();
}
for (uint32_t i = 0; i < mVideoReaders.Length(); i++) {
decoder = mVideoReaders[i]->GetDecoder();
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
resource = decoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
resource->Pin();
rv = mVideoReaders[i]->GetBuffered(&videoBuffered, aStartTime);
NS_ENSURE_SUCCESS(rv, rv);
// If data was cached at the end, then the final timestamp refers to the
// end of the data. Use this later to extend end time if necessary.
if (!videoCachedAtEnd) {
videoCachedAtEnd = mVideoReaders[i]->IsDataCachedAtEndOfSubsegments();
}
resource->Unpin();
}
audioBuffered.Normalize();
videoBuffered.Normalize();
rv = audioBuffered.GetLength(&audioRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
rv = videoBuffered.GetLength(&videoRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef PR_LOGGING
double start = 0, end = 0;
for (uint32_t i = 0; i < audioRangeCount; i++) {
rv = audioBuffered.Start(i, &start);
NS_ENSURE_SUCCESS(rv, rv);
rv = audioBuffered.End(i, &end);
NS_ENSURE_SUCCESS(rv, rv);
LOG("audioBuffered[%d] = (%f, %f)",
i, start, end);
}
for (uint32_t i = 0; i < videoRangeCount; i++) {
rv = videoBuffered.Start(i, &start);
NS_ENSURE_SUCCESS(rv, rv);
rv = videoBuffered.End(i, &end);
NS_ENSURE_SUCCESS(rv, rv);
LOG("videoBuffered[%d] = (%f, %f)",
i, start, end);
}
#endif
// If audio and video are cached to the end of their subsegments, extend the
// end time of the shorter of the two. Presentation of the shorter stream
// will stop at the end, while the other continues until the combined
// playback is complete.
// Note: Only in cases where the shorter stream is fully cached, and the
// longer stream is partially cached, but with more time buffered than the
// shorter stream.
//
// Audio ========|
// 20
// Video ============|----|
// 30 40
// Combo ============| <----- End time EXTENDED.
//
// For example, audio is fully cached to 20s, but video is partially cached
// to 30s, full duration 40s. In this case, the buffered end time should be
// extended to the video's end time.
//
// Audio =================|
// 40
// Video ========|----|
// 20 30
// Combo ========| <------ End time NOT EXTENDED.
//
// Conversely, if the longer stream is fully cached, but the shorter one is
// not, no extension of end time should occur - we should consider the
// partially cached, shorter end time to be the end time of the combined
// stream
if (audioCachedAtEnd || videoCachedAtEnd) {
NS_ENSURE_TRUE(audioRangeCount, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(videoRangeCount, NS_ERROR_FAILURE);
double audioEndTime = 0, videoEndTime = 0;
// Get end time of the last range of buffered audio.
audioEndTime = audioBuffered.GetFinalEndTime();
NS_ENSURE_TRUE(audioEndTime > 0, NS_ERROR_ILLEGAL_VALUE);
// Get end time of the last range of buffered video.
videoEndTime = videoBuffered.GetFinalEndTime();
NS_ENSURE_TRUE(videoEndTime > 0, NS_ERROR_ILLEGAL_VALUE);
// API for TimeRanges requires extending through adding and normalizing.
if (videoCachedAtEnd && audioEndTime > videoEndTime) {
videoBuffered.Add(videoEndTime, audioEndTime);
videoBuffered.Normalize();
LOG("videoBuffered extended to %f", audioEndTime);
} else if (audioCachedAtEnd && videoEndTime > audioEndTime) {
audioBuffered.Add(audioEndTime, videoEndTime);
audioBuffered.Normalize();
LOG("audioBuffered extended to %f", videoEndTime);
}
}
// Calculate intersecting ranges for video and audio.
if (!mAudioReaders.IsEmpty() && !mVideoReaders.IsEmpty()) {
for (uint32_t i = 0; i < audioRangeCount; i++) {
// |A|udio, |V|ideo, |I|ntersect.
double startA, startV, startI;
double endA, endV, endI;
rv = audioBuffered.Start(i, &startA);
NS_ENSURE_SUCCESS(rv, rv);
rv = audioBuffered.End(i, &endA);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t j = 0; j < videoRangeCount; j++) {
rv = videoBuffered.Start(i, &startV);
NS_ENSURE_SUCCESS(rv, rv);
rv = videoBuffered.End(i, &endV);
NS_ENSURE_SUCCESS(rv, rv);
// If video block is before audio block, compare next video block.
if (startA > endV) {
continue;
// If video block is after audio block, all of them are; compare next
// audio block.
} else if (endA < startV) {
break;
}
// Calculate intersections of current audio and video blocks.
startI = (startA > startV) ? startA : startV;
endI = (endA > endV) ? endV : endA;
aBuffered->Add(startI, endI);
}
}
} else if (!mAudioReaders.IsEmpty()) {
*aBuffered = audioBuffered;
} else if (!mVideoReaders.IsEmpty()) {
*aBuffered = videoBuffered;
} else {
return NS_ERROR_NOT_INITIALIZED;
}
return NS_OK;
}
VideoData*
DASHReader::FindStartTime(int64_t& aOutStartTime)
{
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or decode thread.");
// Extract the start times of the bitstreams in order to calculate
// the duration.
int64_t videoStartTime = INT64_MAX;
int64_t audioStartTime = INT64_MAX;
VideoData* videoData = nullptr;
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
if (HasVideo()) {
// Forward to video reader.
videoData = mVideoReader->DecodeToFirstVideoData();
if (videoData) {
videoStartTime = videoData->mTime;
}
}
if (HasAudio()) {
// Forward to audio reader.
AudioData* audioData = mAudioReader->DecodeToFirstAudioData();
if (audioData) {
audioStartTime = audioData->mTime;
}
}
int64_t startTime = std::min(videoStartTime, audioStartTime);
if (startTime != INT64_MAX) {
aOutStartTime = startTime;
}
return videoData;
}
MediaQueue<AudioData>&
DASHReader::AudioQueue()
{
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
NS_ASSERTION(mAudioReader, "mAudioReader is NULL!");
return mAudioQueue;
}
MediaQueue<VideoData>&
DASHReader::VideoQueue()
{
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
NS_ASSERTION(mVideoReader, "mVideoReader is NULL!");
return mVideoQueue;
}
void
DASHReader::RequestVideoReaderSwitch(uint32_t aFromReaderIdx,
uint32_t aToReaderIdx,
uint32_t aSubsegmentIdx)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(aFromReaderIdx < mVideoReaders.Length(),
"From index is greater than number of video readers!");
NS_ASSERTION(aToReaderIdx < mVideoReaders.Length(),
"To index is greater than number of video readers!");
NS_ASSERTION(aToReaderIdx != aFromReaderIdx,
"Don't request switches to same reader!");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
if (mSwitchCount < 0) {
mSwitchCount = 0;
}
DASHRepReader* fromReader = mVideoReaders[aFromReaderIdx];
DASHRepReader* toReader = mVideoReaders[aToReaderIdx];
LOG("Switch requested from reader [%d] [%p] to reader [%d] [%p] "
"at subsegment[%d].",
aFromReaderIdx, fromReader, aToReaderIdx, toReader, aSubsegmentIdx);
// Append the subsegment index to the list of pending switches.
for (uint32_t i = 0; i < mSwitchToVideoSubsegmentIndexes.Length(); i++) {
if (mSwitchToVideoSubsegmentIndexes[i] == aSubsegmentIdx) {
// A backwards |Seek| has changed the switching history; delete from
// this point on.
mSwitchToVideoSubsegmentIndexes.TruncateLength(i);
break;
}
}
mSwitchToVideoSubsegmentIndexes.AppendElement(aSubsegmentIdx);
// Tell the SWITCH FROM reader when it should stop reading.
fromReader->RequestSwitchAtSubsegment(aSubsegmentIdx, toReader);
// Tell the SWITCH TO reader to seek to the correct offset.
toReader->RequestSeekToSubsegment(aSubsegmentIdx);
mSwitchVideoReaders = true;
}
void
DASHReader::PossiblySwitchVideoReaders()
{
NS_ASSERTION(mDecoder, "Decoder should not be null");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// Flag to switch streams is set in |RequestVideoReaderSwitch|.
if (!mSwitchVideoReaders) {
return;
}
// Only switch if we reached a switch access point.
NS_ENSURE_TRUE_VOID(0 <= mSwitchCount);
NS_ENSURE_TRUE_VOID((uint32_t)mSwitchCount < mSwitchToVideoSubsegmentIndexes.Length());
uint32_t switchIdx = mSwitchToVideoSubsegmentIndexes[mSwitchCount];
if (!mVideoReader->HasReachedSubsegment(switchIdx)) {
return;
}
// Get Representation index to switch to.
DASHDecoder* dashDecoder = static_cast<DASHDecoder*>(mDecoder);
int32_t toReaderIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(switchIdx);
NS_ENSURE_TRUE_VOID(0 <= toReaderIdx);
NS_ENSURE_TRUE_VOID((uint32_t)toReaderIdx < mVideoReaders.Length());
DASHRepReader* fromReader = mVideoReader;
DASHRepReader* toReader = mVideoReaders[toReaderIdx];
NS_ENSURE_TRUE_VOID(fromReader != toReader);
LOG("Switching video readers now from [%p] to [%p] at subsegment [%d]: "
"mSwitchCount [%d].",
fromReader, toReader, switchIdx, mSwitchCount);
// Switch readers while in the monitor.
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mVideoReader = toReader;
// Prep readers for next switch, also while in monitor.
if ((uint32_t)++mSwitchCount < mSwitchToVideoSubsegmentIndexes.Length()) {
// Get the subsegment at which to switch.
switchIdx = mSwitchToVideoSubsegmentIndexes[mSwitchCount];
// Update from and to reader ptrs for next switch.
fromReader = toReader;
toReaderIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(switchIdx);
toReader = mVideoReaders[toReaderIdx];
NS_ENSURE_TRUE_VOID((uint32_t)toReaderIdx < mVideoReaders.Length());
NS_ENSURE_TRUE_VOID(fromReader != toReader);
// Tell the SWITCH FROM reader when it should stop reading.
fromReader->RequestSwitchAtSubsegment(switchIdx, toReader);
// Tell the SWITCH TO reader to seek to the correct offset.
toReader->RequestSeekToSubsegment(switchIdx);
} else {
// If there are no more pending switches, unset the switch readers flag.
mSwitchVideoReaders = false;
}
}
void
DASHReader::PrepareToDecode()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// Flag to switch streams is set by |DASHDecoder|.
if (!mSwitchVideoReaders) {
return;
}
PossiblySwitchVideoReaders();
// Prepare each sub reader for decoding: includes seeking to the correct
// offset if a seek was previously requested.
for (uint32_t i = 0; i < mVideoReaders.Length(); i++) {
mVideoReaders[i]->PrepareToDecode();
}
}
DASHRepReader*
DASHReader::GetReaderForSubsegment(uint32_t aSubsegmentIdx)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
DASHDecoder* dashDecoder = static_cast<DASHDecoder*>(mDecoder);
int32_t repIdx =
dashDecoder->GetRepIdxForVideoSubsegmentLoadAfterSeek((int32_t)aSubsegmentIdx);
if (0 <= repIdx && repIdx < mVideoReaders.Length()) {
return mVideoReaders[repIdx];
} else {
return nullptr;
}
}
} // namespace mozilla

View File

@ -1,303 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for comments on DASH object interaction
*/
#if !defined(DASHReader_h_)
#define DASHReader_h_
#include "VideoUtils.h"
#include "MediaDecoderReader.h"
#include "DASHRepReader.h"
namespace mozilla {
class DASHRepReader;
class DASHReader : public MediaDecoderReader
{
public:
DASHReader(AbstractMediaDecoder* aDecoder);
~DASHReader();
nsresult ResetDecode() MOZ_OVERRIDE;
// Adds a pointer to a audio/video reader for a media |Representation|.
// Called on the main thread only.
void AddAudioReader(DASHRepReader* aAudioReader);
void AddVideoReader(DASHRepReader* aVideoReader);
// Waits for metadata bytes to be downloaded, then reads and parses them.
// Called on the decode thread only.
nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) MOZ_OVERRIDE;
// Waits for |ReadyToReadMetadata| or |NotifyDecoderShuttingDown|
// notification, whichever comes first. Ensures no attempt to read metadata
// during |DASHDecoder|::|Shutdown|. Called on decode thread only.
nsresult WaitForMetadata() {
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
ReentrantMonitorAutoEnter mon(mReadMetadataMonitor);
while (true) {
// Abort if the decoder has started shutting down.
if (mDecoderIsShuttingDown) {
return NS_ERROR_ABORT;
} else if (mReadyToReadMetadata) {
break;
}
mon.Wait();
}
return NS_OK;
}
// Called on the main thread by |DASHDecoder| to notify that metadata bytes
// have been downloaded.
void ReadyToReadMetadata() {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mReadMetadataMonitor);
mReadyToReadMetadata = true;
mon.NotifyAll();
}
// Called on the main thread by |DASHDecoder| when it starts Shutdown. Will
// wake metadata monitor if waiting for a silent return from |ReadMetadata|.
void NotifyDecoderShuttingDown() {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter metadataMon(mReadMetadataMonitor);
mDecoderIsShuttingDown = true;
// Notify |ReadMetadata| of the shutdown if it's waiting.
metadataMon.NotifyAll();
}
// Audio/video status are dependent on the presence of audio/video readers.
// Call on decode thread only.
bool HasAudio() MOZ_OVERRIDE;
bool HasVideo() MOZ_OVERRIDE;
// Returns references to the audio/video queues of sub-readers. Called on
// decode, state machine and audio threads.
MediaQueue<AudioData>& AudioQueue() MOZ_OVERRIDE;
MediaQueue<VideoData>& VideoQueue() MOZ_OVERRIDE;
// Called from MediaDecoderStateMachine on the main thread.
nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
// Used by |MediaMemoryReporter|.
int64_t VideoQueueMemoryInUse() MOZ_OVERRIDE;
int64_t AudioQueueMemoryInUse() MOZ_OVERRIDE;
// Called on the decode thread, at the start of the decode loop, before
// |DecodeVideoFrame|. Carries out video reader switch if previously
// requested, and tells sub-readers to |PrepareToDecode|.
void PrepareToDecode() MOZ_OVERRIDE;
// Called on the decode thread.
bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) MOZ_OVERRIDE;
bool DecodeAudioData() MOZ_OVERRIDE;
// Converts seek time to byte offset. Called on the decode thread only.
nsresult Seek(int64_t aTime,
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
// Called by state machine on multiple threads.
nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE;
// Called on the state machine or decode threads.
VideoData* FindStartTime(int64_t& aOutStartTime) MOZ_OVERRIDE;
// Prepares for an upcoming switch of video readers. Called by
// |DASHDecoder| when it has switched download streams. Sets the index of
// the reader to switch TO and the index of the subsegment to switch AT
// (start offset). (Note: Subsegment boundaries are switch access points for
// DASH-WebM). Called on the main thread. Must be in the decode monitor.
void RequestVideoReaderSwitch(uint32_t aFromReaderIdx,
uint32_t aToReaderIdx,
uint32_t aSubsegmentIdx);
// Returns a pointer to the reader which should be used for the specified
// subsegment. Called on the decode thread only.
DASHRepReader* GetReaderForSubsegment(uint32_t aSubsegmentIdx);
private:
// Switches video subreaders if a stream-switch flag has been set, and the
// current reader has read up to the switching subsegment (start offset).
// Called on the decode thread only.
void PossiblySwitchVideoReaders();
// Monitor and booleans used to wait for metadata bytes to be downloaded, and
// skip reading metadata if |DASHDecoder|'s shutdown is in progress.
ReentrantMonitor mReadMetadataMonitor;
bool mReadyToReadMetadata;
bool mDecoderIsShuttingDown;
// Wrapper class protecting accesses to sub-readers. Asserts that the
// decoder monitor has been entered for write access on all threads and read
// access on all threads that are not the decode thread. Read access on the
// decode thread does not need to be protected.
class MonitoredSubReader
{
public:
// Main constructor takes a pointer to the owning |DASHReader| to verify
// correct entry into the decoder's |ReentrantMonitor|.
MonitoredSubReader(DASHReader* aReader) :
mReader(aReader),
mSubReader(nullptr)
{
MOZ_COUNT_CTOR(DASHReader::MonitoredSubReader);
NS_ASSERTION(mReader, "Reader is null!");
}
// Note: |mSubReader|'s refcount will be decremented in this destructor.
~MonitoredSubReader()
{
MOZ_COUNT_DTOR(DASHReader::MonitoredSubReader);
}
// Override '=' to always assert thread is "in monitor" for writes/changes
// to |mSubReader|.
MonitoredSubReader& operator=(DASHRepReader* rhs)
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
mSubReader = rhs;
return *this;
}
// Override '*' to assert threads other than the decode thread are "in
// monitor" for ptr reads.
operator DASHRepReader*() const
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
if (!mReader->GetDecoder()->OnDecodeThread()) {
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
}
return mSubReader;
}
// Override '->' to assert threads other than the decode thread are "in
// monitor" for |mSubReader| function calls.
DASHRepReader* operator->() const
{
return *this;
}
private:
// Pointer to |DASHReader| object which owns this |MonitoredSubReader|.
DASHReader* mReader;
// Ref ptr to the sub reader.
nsRefPtr<DASHRepReader> mSubReader;
};
// Wrapped ref ptrs to current sub-readers of individual media
// |Representation|s. Decoder monitor must be entered for write access on all
// threads and read access on all threads that are not the decode thread.
// Read access on the decode thread does not need to be protected.
// Note: |MonitoredSubReader| class will assert correct monitor use.
MonitoredSubReader mAudioReader;
MonitoredSubReader mVideoReader;
// Wrapper class protecting accesses to sub-reader list. Asserts that the
// decoder monitor has been entered for write access on all threads and read
// access on all threads that are not the decode thread. Read access on the
// decode thread does not need to be protected.
// Note: Elems accessed via operator[] are not protected with monitor
// assertion checks once obtained.
class MonitoredSubReaderList
{
public:
// Main constructor takes a pointer to the owning |DASHReader| to verify
// correct entry into the decoder's |ReentrantMonitor|.
MonitoredSubReaderList(DASHReader* aReader) :
mReader(aReader)
{
MOZ_COUNT_CTOR(DASHReader::MonitoredSubReaderList);
NS_ASSERTION(mReader, "Reader is null!");
}
// Note: Elements in |mSubReaderList| will have their refcounts decremented
// in this destructor.
~MonitoredSubReaderList()
{
MOZ_COUNT_DTOR(DASHReader::MonitoredSubReaderList);
}
// Returns Length of |mSubReaderList| array. Will assert threads other than
// the decode thread are "in monitor".
uint32_t Length() const
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
if (!mReader->GetDecoder()->OnDecodeThread()) {
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
}
return mSubReaderList.Length();
}
// Returns true if |mSubReaderList| is empty. Will assert that threads
// other than the decode thread are "in monitor".
bool IsEmpty() const
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
if (!mReader->GetDecoder()->OnDecodeThread()) {
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
}
return mSubReaderList.IsEmpty();
}
// Override '[]' to assert threads other than the decode thread are "in
// monitor" for accessing individual elems. Note: elems returned do not
// have monitor assertions builtin like |MonitoredSubReader| objects.
nsRefPtr<DASHRepReader>& operator[](uint32_t i)
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
if (!mReader->GetDecoder()->OnDecodeThread()) {
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
}
return mSubReaderList[i];
}
// Appends a reader to the end of |mSubReaderList|. Will always assert that
// the thread is "in monitor".
void
AppendElement(DASHRepReader* aReader)
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
mSubReaderList.AppendElement(aReader);
}
private:
// Pointer to |DASHReader| object which owns this |MonitoredSubReader|.
DASHReader* mReader;
// Ref ptrs to the sub readers.
nsTArray<nsRefPtr<DASHRepReader> > mSubReaderList;
};
// Ref ptrs to all sub-readers of individual media |Representation|s.
// Decoder monitor must be entered for write access on all threads and read
// access on all threads that are not the decode thread. Read acces on the
// decode thread does not need to be protected.
MonitoredSubReaderList mAudioReaders;
MonitoredSubReaderList mVideoReaders;
// When true, indicates that we should switch reader. Must be in the monitor
// for write access and read access off the decode thread.
bool mSwitchVideoReaders;
// Indicates the subsegment index at which the reader should switch. Must be
// in the monitor for write access and read access off the decode thread.
nsTArray<uint32_t> mSwitchToVideoSubsegmentIndexes;
// Counts the number of switches that have taken place. Must be in the
// monitor for write access and read access off the decode thread.
int32_t mSwitchCount;
};
} // namespace mozilla
#endif

View File

@ -1,517 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for info on DASH interaction with the media engine.*/
#include "prlog.h"
#include "VideoUtils.h"
#include "SegmentBase.h"
#include "MediaDecoderStateMachine.h"
#include "DASHReader.h"
#include "MediaResource.h"
#include "DASHRepDecoder.h"
#include "WebMReader.h"
#include <algorithm>
namespace mozilla {
#ifdef PR_LOGGING
extern PRLogModuleInfo* gMediaDecoderLog;
#define LOG(msg, ...) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \
("%p [DASHRepDecoder] " msg, this, __VA_ARGS__))
#define LOG1(msg) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \
("%p [DASHRepDecoder] " msg, this))
#else
#define LOG(msg, ...)
#define LOG1(msg)
#endif
MediaDecoderStateMachine*
DASHRepDecoder::CreateStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Do not create; just return current state machine.
return mDecoderStateMachine;
}
nsresult
DASHRepDecoder::SetStateMachine(MediaDecoderStateMachine* aSM)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
mDecoderStateMachine = aSM;
return NS_OK;
}
void
DASHRepDecoder::SetResource(MediaResource* aResource)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
mResource = aResource;
}
void
DASHRepDecoder::SetMPDRepresentation(Representation const * aRep)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
mMPDRepresentation = aRep;
}
void
DASHRepDecoder::SetReader(WebMReader* aReader)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
mReader = aReader;
}
nsresult
DASHRepDecoder::Load(nsIStreamListener** aListener,
MediaDecoder* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE(mMPDRepresentation, NS_ERROR_NOT_INITIALIZED);
// Get init range and index range from MPD.
SegmentBase const * segmentBase = mMPDRepresentation->GetSegmentBase();
NS_ENSURE_TRUE(segmentBase, NS_ERROR_NULL_POINTER);
// Get and set init range.
segmentBase->GetInitRange(&mInitByteRange.mStart, &mInitByteRange.mEnd);
NS_ENSURE_TRUE(!mInitByteRange.IsNull(), NS_ERROR_NOT_INITIALIZED);
mReader->SetInitByteRange(mInitByteRange);
// Get and set index range.
segmentBase->GetIndexRange(&mIndexByteRange.mStart, &mIndexByteRange.mEnd);
NS_ENSURE_TRUE(!mIndexByteRange.IsNull(), NS_ERROR_NOT_INITIALIZED);
mReader->SetIndexByteRange(mIndexByteRange);
// Determine byte range to Open.
// For small deltas between init and index ranges, we need to bundle the byte
// range requests together in order to deal with |MediaCache|'s control of
// seeking (see |MediaCache|::|Update|). |MediaCache| will not initiate a
// |ChannelMediaResource|::|CacheClientSeek| for the INDEX byte range if the
// delta between it and the INIT byte ranges is less than
// |SEEK_VS_READ_THRESHOLD|. To get around this, request all metadata bytes
// now so |MediaCache| can assume the bytes are en route.
int64_t delta = std::max(mIndexByteRange.mStart, mInitByteRange.mStart)
- std::min(mIndexByteRange.mEnd, mInitByteRange.mEnd);
MediaByteRange byteRange;
if (delta <= SEEK_VS_READ_THRESHOLD) {
byteRange.mStart = std::min(mIndexByteRange.mStart, mInitByteRange.mStart);
byteRange.mEnd = std::max(mIndexByteRange.mEnd, mInitByteRange.mEnd);
// Loading everything in one chunk .
mMetadataChunkCount = 1;
} else {
byteRange = mInitByteRange;
// Loading in two chunks: init and index.
mMetadataChunkCount = 2;
}
mCurrentByteRange = byteRange;
return mResource->OpenByteRange(nullptr, byteRange);
}
void
DASHRepDecoder::NotifyDownloadEnded(nsresult aStatus)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (!mMainDecoder) {
if (!mShuttingDown) {
LOG("Error! Main Decoder is null before shutdown: mMainDecoder [%p] ",
mMainDecoder.get());
DecodeError();
}
return;
}
if (NS_SUCCEEDED(aStatus)) {
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// Decrement counter as metadata chunks are downloaded.
// Note: Reader gets next chunk download via |ChannelMediaResource|:|Seek|.
if (mMetadataChunkCount > 0) {
LOG("Metadata chunk [%d] downloaded: range requested [%lld - %lld] "
"subsegmentIdx [%d]",
mMetadataChunkCount,
mCurrentByteRange.mStart, mCurrentByteRange.mEnd, mSubsegmentIdx);
mMetadataChunkCount--;
} else {
LOG("Byte range downloaded: status [%x] range requested [%lld - %lld] "
"subsegmentIdx [%d]",
aStatus, mCurrentByteRange.mStart, mCurrentByteRange.mEnd,
mSubsegmentIdx);
if ((uint32_t)mSubsegmentIdx == mByteRanges.Length()-1) {
mResource->NotifyLastByteRange();
}
// Notify main decoder that a DATA byte range is downloaded.
mMainDecoder->NotifyDownloadEnded(this, aStatus, mSubsegmentIdx);
}
} else if (aStatus == NS_BINDING_ABORTED) {
LOG("Media download has been cancelled by the user: aStatus [%x].",
aStatus);
if (mMainDecoder) {
mMainDecoder->LoadAborted();
}
return;
} else if (aStatus != NS_BASE_STREAM_CLOSED) {
LOG("Network error trying to download MPD: aStatus [%x].", aStatus);
NetworkError();
}
}
void
DASHRepDecoder::OnReadMetadataCompleted()
{
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
// If shutting down, just return silently.
if (mShuttingDown) {
LOG1("Shutting down! Ignoring OnReadMetadataCompleted().");
return;
}
LOG1("Metadata has been read.");
// Metadata loaded and read for this stream; ok to populate byte ranges.
nsresult rv = PopulateByteRanges();
if (NS_FAILED(rv) || mByteRanges.IsEmpty()) {
LOG("Error populating byte ranges [%x]", rv);
DecodeError();
return;
}
mMainDecoder->OnReadMetadataCompleted(this);
}
nsresult
DASHRepDecoder::PopulateByteRanges()
{
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
// Should not be called during shutdown.
NS_ENSURE_FALSE(mShuttingDown, NS_ERROR_UNEXPECTED);
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (!mByteRanges.IsEmpty()) {
return NS_OK;
}
NS_ENSURE_TRUE(mReader, NS_ERROR_NULL_POINTER);
LOG1("Populating byte range array.");
return mReader->GetSubsegmentByteRanges(mByteRanges);
}
void
DASHRepDecoder::LoadNextByteRange()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(mResource, "Error: resource is reported as null!");
// Return silently if shutting down.
if (mShuttingDown) {
LOG1("Shutting down! Ignoring LoadNextByteRange().");
return;
}
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
NS_ASSERTION(mMainDecoder, "Error: main decoder is null!");
NS_ASSERTION(mMainDecoder->IsDecoderAllowedToDownloadData(this),
"Should not be called on non-active decoders!");
// Cannot have empty byte ranges.
if (mByteRanges.IsEmpty()) {
LOG1("Error getting list of subsegment byte ranges.");
DecodeError();
return;
}
// Get byte range for subsegment.
int32_t subsegmentIdx = mMainDecoder->GetSubsegmentIndex(this);
NS_ASSERTION(0 <= subsegmentIdx,
"Subsegment index should be >= 0 for active decoders");
if (subsegmentIdx >= 0 && (uint32_t)subsegmentIdx < mByteRanges.Length()) {
mCurrentByteRange = mByteRanges[subsegmentIdx];
mSubsegmentIdx = subsegmentIdx;
} else {
mCurrentByteRange.Clear();
mSubsegmentIdx = -1;
LOG("End of subsegments: index [%d] out of range.", subsegmentIdx);
return;
}
// Request a seek for the first reader. Required so that the reader is
// primed to start here, and will block subsequent subsegment seeks unless
// the subsegment has been read.
if (subsegmentIdx == 0) {
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mReader->RequestSeekToSubsegment(0);
}
// Query resource for cached ranges; only download if it's not there.
if (IsSubsegmentCached(mSubsegmentIdx)) {
LOG("Subsegment [%d] bytes [%lld] to [%lld] already cached. No need to "
"download.", mSubsegmentIdx,
mCurrentByteRange.mStart, mCurrentByteRange.mEnd);
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &DASHRepDecoder::DoNotifyDownloadEnded);
nsresult rv = NS_DispatchToMainThread(event);
if (NS_FAILED(rv)) {
LOG("Error notifying subsegment [%d] cached: rv[0x%x].",
mSubsegmentIdx, rv);
NetworkError();
}
return;
}
// Open byte range corresponding to subsegment.
nsresult rv = mResource->OpenByteRange(nullptr, mCurrentByteRange);
if (NS_FAILED(rv)) {
LOG("Error opening byte range [%lld - %lld]: subsegmentIdx [%d] rv [%x].",
mCurrentByteRange.mStart, mCurrentByteRange.mEnd, mSubsegmentIdx, rv);
NetworkError();
return;
}
}
bool
DASHRepDecoder::IsSubsegmentCached(int32_t aSubsegmentIdx)
{
GetReentrantMonitor().AssertCurrentThreadIn();
MediaByteRange byteRange = mByteRanges[aSubsegmentIdx];
int64_t start = mResource->GetNextCachedData(byteRange.mStart);
int64_t end = mResource->GetCachedDataEnd(byteRange.mStart);
return (start == byteRange.mStart &&
end >= byteRange.mEnd);
}
void
DASHRepDecoder::DoNotifyDownloadEnded()
{
NotifyDownloadEnded(NS_OK);
}
nsresult
DASHRepDecoder::GetByteRangeForSeek(int64_t const aOffset,
MediaByteRange& aByteRange)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Only check data ranges if they're available and if this decoder is active,
// i.e. inactive rep decoders should only load metadata.
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
for (uint32_t i = 0; i < mByteRanges.Length(); i++) {
NS_ENSURE_FALSE(mByteRanges[i].IsNull(), NS_ERROR_NOT_INITIALIZED);
// Check if |aOffset| lies within the current data range.
if (mByteRanges[i].mStart <= aOffset && aOffset <= mByteRanges[i].mEnd) {
if (mMainDecoder->IsDecoderAllowedToDownloadSubsegment(this, i)) {
mCurrentByteRange = aByteRange = mByteRanges[i];
mSubsegmentIdx = i;
// XXX Hack: should be setting subsegment outside this function, but
// need to review seeking for multiple switches anyhow.
mMainDecoder->SetSubsegmentIndex(this, i);
LOG("Getting DATA range [%d] for seek offset [%lld]: "
"bytes [%lld] to [%lld]",
i, aOffset, aByteRange.mStart, aByteRange.mEnd);
return NS_OK;
}
break;
}
}
// Don't allow metadata downloads once they're loaded and byte ranges have
// been populated.
bool canDownloadMetadata = mByteRanges.IsEmpty();
if (canDownloadMetadata) {
// Check metadata ranges; init range.
if (mInitByteRange.mStart <= aOffset && aOffset <= mInitByteRange.mEnd) {
mCurrentByteRange = aByteRange = mInitByteRange;
mSubsegmentIdx = 0;
LOG("Getting INIT range for seek offset [%lld]: bytes [%lld] to "
"[%lld]", aOffset, aByteRange.mStart, aByteRange.mEnd);
return NS_OK;
}
// ... index range.
if (mIndexByteRange.mStart <= aOffset && aOffset <= mIndexByteRange.mEnd) {
mCurrentByteRange = aByteRange = mIndexByteRange;
mSubsegmentIdx = 0;
LOG("Getting INDEXES range for seek offset [%lld]: bytes [%lld] to "
"[%lld]", aOffset, aByteRange.mStart, aByteRange.mEnd);
return NS_OK;
}
} else {
LOG1("Metadata should be read; inhibiting further metadata downloads.");
}
// If no byte range is found by this stage, clear the parameter and return.
aByteRange.Clear();
if (mByteRanges.IsEmpty() || !canDownloadMetadata) {
// Assume mByteRanges will be populated after metadata is read.
LOG("Data ranges not populated [%s]; metadata download restricted [%s]: "
"offset[%lld].",
(mByteRanges.IsEmpty() ? "yes" : "no"),
(canDownloadMetadata ? "no" : "yes"), aOffset);
return NS_ERROR_NOT_AVAILABLE;
} else {
// Cannot seek to an unknown offset.
// XXX Revisit this for dynamic MPD profiles if MPD is regularly updated.
LOG("Error! Offset [%lld] is in an unknown range!", aOffset);
return NS_ERROR_ILLEGAL_VALUE;
}
}
void
DASHRepDecoder::PrepareForSwitch()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Ensure that the media cache writes any data held in its partial block.
mResource->FlushCache();
}
void
DASHRepDecoder::NetworkError()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (mMainDecoder) { mMainDecoder->NetworkError(); }
}
void
DASHRepDecoder::SetDuration(double aDuration)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (mMainDecoder) { mMainDecoder->SetDuration(aDuration); }
}
void
DASHRepDecoder::SetInfinite(bool aInfinite)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (mMainDecoder) { mMainDecoder->SetInfinite(aInfinite); }
}
void
DASHRepDecoder::SetMediaSeekable(bool aMediaSeekable)
{
NS_ASSERTION(NS_IsMainThread() || OnDecodeThread(),
"Should be on main thread or decode thread.");
if (mMainDecoder) { mMainDecoder->SetMediaSeekable(aMediaSeekable); }
}
void
DASHRepDecoder::Progress(bool aTimer)
{
if (mMainDecoder) { mMainDecoder->Progress(aTimer); }
}
void
DASHRepDecoder::NotifyDataArrived(const char* aBuffer,
uint32_t aLength,
int64_t aOffset)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
LOG("Data bytes [%lld - %lld] arrived via buffer [%p].",
aOffset, aOffset+aLength, aBuffer);
// Notify reader directly, since call to |MediaDecoderStateMachine|::
// |NotifyDataArrived| will go to |DASHReader|::|NotifyDataArrived|, which
// has no way to forward the notification to the correct sub-reader.
if (mReader) {
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
}
// Forward to main decoder which will notify state machine.
if (mMainDecoder) {
mMainDecoder->NotifyDataArrived(aBuffer, aLength, aOffset);
}
}
void
DASHRepDecoder::NotifyBytesDownloaded()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (mMainDecoder) { mMainDecoder->NotifyBytesDownloaded(); }
}
void
DASHRepDecoder::NotifySuspendedStatusChanged()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (mMainDecoder) { mMainDecoder->NotifySuspendedStatusChanged(); }
}
bool
DASHRepDecoder::OnStateMachineThread() const
{
return (mMainDecoder ? mMainDecoder->OnStateMachineThread() : false);
}
bool
DASHRepDecoder::OnDecodeThread() const
{
return (mMainDecoder ? mMainDecoder->OnDecodeThread() : false);
}
ReentrantMonitor&
DASHRepDecoder::GetReentrantMonitor()
{
NS_ASSERTION(mMainDecoder, "Can't get monitor if main decoder is null!");
if (mMainDecoder) {
return mMainDecoder->GetReentrantMonitor();
} else {
// XXX If mMainDecoder is gone, most likely we're past shutdown and
// a waiting function has been wakened. Just return this decoder's own
// monitor and let the function complete.
return MediaDecoder::GetReentrantMonitor();
}
}
mozilla::layers::ImageContainer*
DASHRepDecoder::GetImageContainer()
{
return (mMainDecoder ? mMainDecoder->GetImageContainer() : nullptr);
}
void
DASHRepDecoder::DecodeError()
{
if (NS_IsMainThread()) {
MediaDecoder::DecodeError();
} else {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &MediaDecoder::DecodeError);
nsresult rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
LOG("Error dispatching DecodeError event to main thread: rv[%x]", rv);
}
}
}
void
DASHRepDecoder::ReleaseStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
// Since state machine owns mReader, remove reference to it.
mReader = nullptr;
MediaDecoder::ReleaseStateMachine();
}
void DASHRepDecoder::StopProgressUpdates()
{
NS_ENSURE_TRUE_VOID(mMainDecoder);
MediaDecoder::StopProgressUpdates();
}
void DASHRepDecoder::StartProgressUpdates()
{
NS_ENSURE_TRUE_VOID(mMainDecoder);
MediaDecoder::StartProgressUpdates();
}
} // namespace mozilla

View File

@ -1,237 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for info on DASH interaction with the media engine.*/
#if !defined(DASHRepDecoder_h_)
#define DASHRepDecoder_h_
#include "Representation.h"
#include "DASHDecoder.h"
#include "WebMDecoder.h"
#include "WebMReader.h"
#include "MediaDecoder.h"
namespace mozilla {
namespace layers {
class ImageContainer;
}
class DASHDecoder;
class DASHRepReader;
class DASHRepDecoder : public MediaDecoder
{
public:
typedef mozilla::net::Representation Representation;
typedef mozilla::net::SegmentBase SegmentBase;
typedef mozilla::layers::ImageContainer ImageContainer;
// Constructor takes a ptr to the main decoder.
DASHRepDecoder(DASHDecoder* aMainDecoder) :
mMainDecoder(aMainDecoder),
mMPDRepresentation(nullptr),
mMetadataChunkCount(0),
mCurrentByteRange(),
mSubsegmentIdx(-1),
mReader(nullptr)
{
MOZ_COUNT_CTOR(DASHRepDecoder);
}
~DASHRepDecoder()
{
MOZ_COUNT_DTOR(DASHRepDecoder);
}
// Clone not supported; just return nullptr.
virtual MediaDecoder* Clone() { return nullptr; }
// Called by the main decoder at creation time; points to the main state
// machine managed by the main decoder. Called on the main thread only.
nsresult SetStateMachine(MediaDecoderStateMachine* aSM);
private:
// Overridden to return the ptr set by SetStateMachine. Called on the main
// thread only.
MediaDecoderStateMachine* CreateStateMachine();
public:
// Called by DASHDecoder at creation time; points to the media resource
// for this decoder's |Representation|. Called on the main thread only.
void SetResource(MediaResource* aResource);
// Sets the |Representation| object for this decoder. Called on the main
// thread.
void SetMPDRepresentation(Representation const * aRep);
// Called from DASHDecoder on main thread; Starts media stream download.
virtual nsresult Load(nsIStreamListener** aListener = nullptr,
MediaDecoder* aCloneDonor = nullptr) MOZ_OVERRIDE;
// Loads the next byte range (or first one on first call). Called on the main
// thread only.
void LoadNextByteRange();
// Returns true if the subsegment is already in the media cache.
bool IsSubsegmentCached(int32_t aSubsegmentIdx);
// Calls from DASHRepDecoder. Called on the main thread only.
void SetReader(WebMReader* aReader);
// Called if the media file encounters a network error. Call on the main
// thread only.
void NetworkError();
// Called from reader during ReadMetadata. This should be ignored here, and
// instead, duration should be set following MPD parsing.
void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE { };
// Set the duration of the media resource in units of seconds.
// This is called via a channel listener if it can pick up the duration
// from a content header. Must be called from the main thread only.
virtual void SetDuration(double aDuration);
// Set media stream as infinite. Called on the main thread only.
void SetInfinite(bool aInfinite);
// Sets media stream as seekable. Called on main thread only.
void SetMediaSeekable(bool aSeekable);
// Fire progress events if needed according to the time and byte
// constraints outlined in the specification. aTimer is true
// if the method is called as a result of the progress timer rather
// than the result of downloaded data.
void Progress(bool aTimer);
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
void NotifyDataArrived(const char* aBuffer,
uint32_t aLength,
int64_t aOffset);
// Called by MediaResource when some data has been received.
// Call on the main thread only.
void NotifyBytesDownloaded();
// Notify that a byte range request has been completed by the media resource.
// Called on the main thread only.
void NotifyDownloadEnded(nsresult aStatus);
// Called asynchronously by |LoadNextByteRange| if the data is already in the
// media cache. This will call NotifyDownloadEnded on the main thread with
// |aStatus| of NS_OK.
void DoNotifyDownloadEnded();
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
void NotifySuspendedStatusChanged();
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE {
if (mMainDecoder) {mMainDecoder->NotifyDecodedFrames(aParsed, aDecoded); }
}
// Gets a byte range containing the byte offset. Call on main thread only.
nsresult GetByteRangeForSeek(int64_t const aOffset,
MediaByteRange& aByteRange);
// Gets the number of data byte ranges (not inc. metadata).
uint32_t GetNumDataByteRanges() {
return mByteRanges.Length();
}
// Notify that a switch is about to happen. Called on the main thread.
void PrepareForSwitch();
// Returns true if the current thread is the state machine thread.
bool OnStateMachineThread() const MOZ_OVERRIDE;
// Returns true if the current thread is the decode thread.
bool OnDecodeThread() const MOZ_OVERRIDE;
// Returns main decoder's monitor for synchronised access.
ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
// Called on the decode thread from WebMReader.
ImageContainer* GetImageContainer() MOZ_OVERRIDE;
// Called when Metadata has been read; notifies that index data is read.
// Called on the decode thread only.
void OnReadMetadataCompleted() MOZ_OVERRIDE;
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Must be called with the decoder monitor held.
void StopProgressUpdates() MOZ_OVERRIDE;
// Allow updating the bytes downloaded for progress notifications. Must
// be called with the decoder monitor held.
void StartProgressUpdates() MOZ_OVERRIDE;
// Overridden to cleanup ref to |DASHDecoder|. Called on main thread only.
void Shutdown() {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Remove ref to state machine before |MediaDecoder|::|Shutdown|, since
// |DASHDecoder| is responsible for its shutdown.
mDecoderStateMachine = nullptr;
// Call parent class shutdown.
MediaDecoder::Shutdown();
NS_ENSURE_TRUE_VOID(mShuttingDown);
// Cleanup ref to main decoder.
mMainDecoder = nullptr;
}
// Drop reference to state machine and mReader (owned by state machine).
// Only called during shutdown dance.
void ReleaseStateMachine();
// Notifies the element that decoding has failed.
void DecodeError();
private:
// Populates |mByteRanges| by calling |GetIndexByteRanges| from |mReader|.
// Called on the main thread only.
nsresult PopulateByteRanges();
// The main decoder.
nsRefPtr<DASHDecoder> mMainDecoder;
// This decoder's MPD |Representation| object.
Representation const * mMPDRepresentation;
// Countdown var for loading metadata byte ranges.
uint16_t mMetadataChunkCount;
// All the byte ranges for this |Representation|.
nsTArray<MediaByteRange> mByteRanges;
// Byte range for the init and index bytes.
MediaByteRange mInitByteRange;
MediaByteRange mIndexByteRange;
// The current byte range being requested.
MediaByteRange mCurrentByteRange;
// Index of the current byte range. Initialized to -1.
int32_t mSubsegmentIdx;
// Ptr to the reader object for this |Representation|. Owned by state
// machine.
DASHRepReader* mReader;
};
} // namespace mozilla
#endif //DASHRepDecoder_h_

View File

@ -1,68 +0,0 @@
/* -*- 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/. */
/* DASH - Dynamic Adaptive Streaming over HTTP
*
* DASH is an adaptive bitrate streaming technology where a multimedia file is
* partitioned into one or more segments and delivered to a client using HTTP.
*
* see DASHDecoder.cpp for comments on DASH object interaction
*/
#if !defined(DASHRepReader_h_)
#define DASHRepReader_h_
#include "VideoUtils.h"
#include "MediaDecoderReader.h"
#include "DASHReader.h"
namespace mozilla {
class DASHReader;
class DASHRepReader : public MediaDecoderReader
{
public:
DASHRepReader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder) { }
virtual ~DASHRepReader() { }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DASHRepReader)
virtual void SetMainReader(DASHReader *aMainReader) = 0;
// Sets range for initialization bytes; used by DASH.
virtual void SetInitByteRange(MediaByteRange &aByteRange) = 0;
// Sets range for index frame bytes; used by DASH.
virtual void SetIndexByteRange(MediaByteRange &aByteRange) = 0;
// Returns the index of the subsegment which contains the seek time (usecs).
virtual int64_t GetSubsegmentForSeekTime(int64_t aSeekToTime) = 0;
// Returns list of ranges for index frame start/end offsets. Used by DASH.
virtual nsresult GetSubsegmentByteRanges(nsTArray<MediaByteRange>& aByteRanges) = 0;
// Returns true if the reader has reached a DASH switch access point.
virtual bool HasReachedSubsegment(uint32_t aSubsegmentIndex) = 0;
// Requests a seek to the start of a particular DASH subsegment.
virtual void RequestSeekToSubsegment(uint32_t aIdx) = 0;
// Reader should stop reading at the start of the specified subsegment, and
// should prepare for the next reader to add data to the video queue.
// Should be implemented by a sub-reader, e.g. |nsDASHWebMReader|.
virtual void RequestSwitchAtSubsegment(int32_t aCluster,
MediaDecoderReader* aNextReader) = 0;
// Returns true if data at the end of the final subsegment has been cached.
virtual bool IsDataCachedAtEndOfSubsegments() = 0;
};
}// namespace mozilla
#endif /*DASHRepReader*/

View File

@ -1,19 +0,0 @@
# -*- Mode: makefile; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- #
# vim: set ts=2 et sw=2 tw=80: #
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Contributor(s):
# Steve Workman <sworkman@mozilla.com>
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES := \
-I$(topsrcdir)/netwerk/dash/mpd \
-I$(srcdir)/../webm \
-I$(srcdir)/../../base/src \
-I$(srcdir)/../../html/content/src \
$(MOZ_LIBVPX_INCLUDES) \
$(NULL)

View File

@ -1,25 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
MODULE = 'content'
EXPORTS += [
'DASHDecoder.h',
'DASHReader.h',
'DASHRepDecoder.h',
'DASHRepReader.h',
]
SOURCES += [
'DASHDecoder.cpp',
'DASHReader.cpp',
'DASHRepDecoder.cpp',
]
LIBRARY_NAME = 'gkcondash_s'
LIBXUL_LIBRARY = True

View File

@ -26,9 +26,6 @@ if CONFIG['MOZ_WEBM']:
if CONFIG['MOZ_GSTREAMER']:
PARALLEL_DIRS += ['gstreamer']
if CONFIG['MOZ_DASH']:
PARALLEL_DIRS += ['dash']
if CONFIG['MOZ_DIRECTSHOW']:
PARALLEL_DIRS += ['directshow']

View File

@ -381,26 +381,6 @@ MOCHITEST_FILES += \
$(NULL)
endif
ifdef MOZ_DASH
MOCHITEST_FILES += \
test_can_play_type_dash.html \
dash/dash-manifest.mpd \
dash/dash-manifest-sjs.mpd \
test_dash_detect_stream_switch.html \
dash_detect_stream_switch.sjs \
dash/dash-webm-video-320x180.webm \
dash/dash-webm-video-428x240.webm \
dash/dash-webm-audio-128k.webm \
dash/dash-manifest-garbled.mpd \
dash/dash-manifest-garbled-webm.mpd \
dash/garbled.webm \
$(NULL)
else
MOCHITEST_FILES += \
test_can_play_type_no_dash.html \
$(NULL)
endif
ifdef MOZ_WAVE
MOCHITEST_FILES += \
test_can_play_type_wave.html \

View File

@ -1,29 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=792935
-->
<head>
<title>Test for Bug 792935: DASH: Add DASH-WebM cases to mochitests</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792935">Mozilla Bug 792935: DASH: Add DASH-WebM cases to mochitests</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<pre id="test">
<script src="can_play_type_dash.js"></script>
<script>
var enabledByPref = SpecialPowers.getBoolPref("media.dash.enabled");
check_dash(document.getElementById('v'), enabledByPref);
mediaTestCleanup();
</script>
</pre>
</body>
</html>

View File

@ -1,28 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=792935
-->
<head>
<title>Test for Bug 792935: DASH: Add DASH-WebM cases to mochitests</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792935">Mozilla Bug 792935: DASH: Add DASH-WebM cases to mochitests</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<pre id="test">
<script src="can_play_type_dash.js"></script>
<script>
check_dash(document.getElementById('v'), false);
mediaTestCleanup();
</script>
</pre>
</body>
</html>

View File

@ -1,81 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=792935
-->
<head>
<title>Test for Bug 792935 - DASH Stream Switching</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792935">Mozilla Bug 792935</a>
</div>
<pre id="test">
<script type="text/javascript">
var manager = new MediaTestManager;
function createTestArray() {
var tests = [];
var tmpVid = document.createElement("video");
for (var testNum=0; testNum<gStreamSwitchTests.length; testNum++) {
var test = gStreamSwitchTests[testNum];
if (!tmpVid.canPlayType(test.type)) {
continue;
}
tests.push(test);
}
return tests;
}
function ended(evt) {
var v = evt.target;
if (v.parentNode) {
v.parentNode.removeChild(v);
}
ok(true, "Fully played DASH video implies correct byte ranges downloaded.");
dump("STREAM-SWITCH-TEST: Finished " + v._name + "\n");
manager.finished(v.token);
}
function error(evt) {
var v = evt.target;
ok(false, "Error suggests wrong byte range requested for " + v._name);
}
function startTest(test, token) {
var v = document.createElement('video');
manager.started(token);
v.type = test.type;
v.src = test.name;
v._name = test.name + " stream switch test";
v.token = token;
v.autoplay = true;
v.addEventListener("error", error, false);
v.addEventListener("ended", ended, false);
dump("STREAM-SWITCH-TEST: Started " + name + "\n");
document.body.appendChild(v);
}
var testArray = createTestArray();
if (testArray && testArray.length > 0) {
manager.runTests(testArray, startTest);
} else {
var v = document.createElement('video');
var canPlay = v.canPlayType("application/dash+xml");
// If the test array is empty even though DASH is enabled, the test should
// fail, i.e. canPlay should be false when testArray is empty.
todo(canPlay, "No types supported - DASH " +
(canPlay ? "enabled" : "disabled"));
}
</script>
</pre>
</body>
</html>

View File

@ -8,8 +8,3 @@ LOCAL_INCLUDES = \
$(MOZ_LIBVPX_CFLAGS) \
$(NULL)
ifdef MOZ_DASH
LOCAL_INCLUDES += \
-I$(srcdir)/../dash \
$(NULL)
endif

View File

@ -48,9 +48,6 @@ PRLogModuleInfo* gNesteggLog;
static const unsigned NS_PER_USEC = 1000;
static const double NS_PER_S = 1e9;
#ifdef MOZ_DASH
static const double USEC_PER_S = 1e6;
#endif
// Functions for reading and seeking using MediaResource required for
// nestegg_io. The 'user data' passed to these functions is the
@ -140,11 +137,7 @@ static void webm_log(nestegg * context,
}
WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
#ifdef MOZ_DASH
: DASHRepReader(aDecoder),
#else
: MediaDecoderReader(aDecoder),
#endif
mContext(nullptr),
mPacketCount(0),
mChannels(0),
@ -154,16 +147,6 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
mAudioFrames(0),
mHasVideo(false),
mHasAudio(false)
#ifdef MOZ_DASH
, mMainReader(nullptr),
mSwitchingCluster(-1),
mNextReader(nullptr),
mSeekToCluster(-1),
mCurrentOffset(-1),
mNextCluster(1),
mPushVideoPacketToNextReader(false),
mReachedSwitchAccessPoint(false)
#endif
{
MOZ_COUNT_CTOR(WebMReader);
#ifdef PR_LOGGING
@ -234,16 +217,6 @@ nsresult WebMReader::ResetDecode()
mVideoPackets.Reset();
mAudioPackets.Reset();
#ifdef MOZ_DASH
LOG(PR_LOG_DEBUG, ("Resetting DASH seek vars"));
mSwitchingCluster = -1;
mNextReader = nullptr;
mSeekToCluster = -1;
mCurrentOffset = -1;
mPushVideoPacketToNextReader = false;
mReachedSwitchAccessPoint = false;
#endif
return res;
}
@ -260,23 +233,12 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
#ifdef MOZ_DASH
LOG(PR_LOG_DEBUG, ("Reader [%p] for Decoder [%p]: Reading WebM Metadata: "
"init bytes [%d - %d] cues bytes [%d - %d]",
this, mDecoder,
mInitByteRange.mStart, mInitByteRange.mEnd,
mCuesByteRange.mStart, mCuesByteRange.mEnd));
#endif
nestegg_io io;
io.read = webm_read;
io.seek = webm_seek;
io.tell = webm_tell;
io.userdata = mDecoder;
#ifdef MOZ_DASH
int64_t maxOffset = mInitByteRange.IsNull() ? -1 : mInitByteRange.mEnd;
#else
int64_t maxOffset = -1;
#endif
int r = nestegg_init(&mContext, io, &webm_log, maxOffset);
if (r == -1) {
return NS_ERROR_FAILURE;
@ -424,45 +386,6 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
}
}
#ifdef MOZ_DASH
// Byte range for cues has been specified; load them.
if (!mCuesByteRange.IsNull()) {
maxOffset = mCuesByteRange.mEnd;
// Iterate through cluster ranges until nestegg returns the last one
NS_ENSURE_TRUE(mClusterByteRanges.IsEmpty(),
NS_ERROR_ALREADY_INITIALIZED);
int clusterNum = 0;
bool done = false;
uint64_t timestamp;
do {
mClusterByteRanges.AppendElement();
r = nestegg_get_cue_point(mContext, clusterNum, maxOffset,
&(mClusterByteRanges[clusterNum].mStart),
&(mClusterByteRanges[clusterNum].mEnd),
&timestamp);
if (r != 0) {
Cleanup();
return NS_ERROR_FAILURE;
}
LOG(PR_LOG_DEBUG, ("Reader [%p] for Decoder [%p]: Cluster [%d]: "
"start [%lld] end [%lld], timestamp [%.2llfs]",
this, mDecoder, clusterNum,
mClusterByteRanges[clusterNum].mStart,
mClusterByteRanges[clusterNum].mEnd,
timestamp/NS_PER_S));
mClusterByteRanges[clusterNum].mStartTime = timestamp/NS_PER_USEC;
// Last cluster will have '-1' as end value
if (mClusterByteRanges[clusterNum].mEnd == -1) {
mClusterByteRanges[clusterNum].mEnd = (mCuesByteRange.mStart-1);
done = true;
} else {
clusterNum++;
}
} while (!done);
}
#endif
// We can't seek in buffered regions if we have no cues.
mDecoder->SetMediaSeekable(nestegg_has_cues(mContext) == 1);
@ -470,10 +393,6 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
*aTags = nullptr;
#ifdef MOZ_DASH
mDecoder->OnReadMetadataCompleted();
#endif
return NS_OK;
}
@ -611,93 +530,6 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
}
nsReturnRef<NesteggPacketHolder> WebMReader::NextPacket(TrackType aTrackType)
#ifdef MOZ_DASH
{
nsAutoRef<NesteggPacketHolder> holder;
// It is possible that following a seek, a requested switching offset could
// be reached before |DASHReader| calls |RequestSwitchAtSubsegment|. In this
// case |mNextReader| will be null, so check its value and at every possible
// switch access point, i.e. cluster boundary, ask |mMainReader| to
// |GetReaderForSubsegment|.
if (mMainReader && !mNextReader && aTrackType == VIDEO) {
WebMReader* nextReader = nullptr;
LOG(PR_LOG_DEBUG,
("WebMReader[%p] for decoder [%p] NextPacket mNextReader not set: "
"mCurrentOffset[%lld] nextCluster [%d] comparing with offset[%lld]",
this, mDecoder, mCurrentOffset, mNextCluster,
mClusterByteRanges[mNextCluster].mStart));
if (mNextCluster < mClusterByteRanges.Length() &&
mCurrentOffset == mClusterByteRanges[mNextCluster].mStart) {
DASHRepReader* nextDASHRepReader =
mMainReader->GetReaderForSubsegment(mNextCluster);
nextReader = static_cast<WebMReader*>(nextDASHRepReader);
LOG(PR_LOG_DEBUG,
("WebMReader[%p] for decoder [%p] reached SAP at cluster [%d]: next "
"reader is [%p]", this, mDecoder, mNextCluster, nextReader));
if (nextReader && nextReader != this) {
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// Ensure this reader is set to switch for the next packet.
RequestSwitchAtSubsegment(mNextCluster, nextReader);
NS_ASSERTION(mNextReader == nextReader, "mNextReader should be set");
// Ensure the next reader seeks to |mNextCluster|. |PrepareToDecode|
// must be called to ensure the reader's variables are set correctly.
nextReader->RequestSeekToSubsegment(mNextCluster);
nextReader->PrepareToDecode();
}
}
// Keep mNextCluster up-to-date with the |mCurrentOffset|.
if (mNextCluster+1 < mClusterByteRanges.Length()) {
// At least one more cluster to go.
mNextCluster++;
} else {
// Reached last cluster; prepare for being in cluster 0 again.
mNextCluster = 1;
}
LOG(PR_LOG_DEBUG,
("WebMReader [%p] for decoder [%p] updating mNextCluster to [%d] "
"at offset [%lld]", this, mDecoder, mNextCluster, mCurrentOffset));
}
}
// Get packet from next reader if we're at a switching point; most likely we
// did not download the next packet for this reader's stream, so we have to
// get it from the next one. Note: Switch to next reader only for video;
// audio switching is not supported in the DASH-WebM On Demand profile.
if (aTrackType == VIDEO &&
(uint32_t)mSwitchingCluster < mClusterByteRanges.Length() &&
mCurrentOffset == mClusterByteRanges[mSwitchingCluster].mStart) {
if (mVideoPackets.GetSize() > 0) {
holder = NextPacketInternal(VIDEO);
LOG(PR_LOG_DEBUG,
("WebMReader[%p] got packet from mVideoPackets @[%lld]",
this, holder->mOffset));
} else {
mReachedSwitchAccessPoint = true;
NS_ASSERTION(mNextReader,
"Stream switch has been requested but mNextReader is null");
holder = mNextReader->NextPacket(aTrackType);
mPushVideoPacketToNextReader = true;
// Reset for possible future switches.
mSwitchingCluster = -1;
LOG(PR_LOG_DEBUG,
("WebMReader[%p] got packet from mNextReader[%p] @[%lld]",
this, mNextReader.get(), (holder ? holder->mOffset : 0)));
}
} else {
holder = NextPacketInternal(aTrackType);
if (holder) {
mCurrentOffset = holder->mOffset;
}
}
return holder.out();
}
nsReturnRef<NesteggPacketHolder>
WebMReader::NextPacketInternal(TrackType aTrackType)
#endif
{
// The packet queue that packets will be pushed on if they
// are not the type we are interested in.
@ -928,18 +760,7 @@ bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
void
WebMReader::PushVideoPacket(NesteggPacketHolder* aItem)
{
#ifdef MOZ_DASH
if (mPushVideoPacketToNextReader) {
NS_ASSERTION(mNextReader,
"Stream switch has been requested but mNextReader is null");
mNextReader->mVideoPackets.PushFront(aItem);
mPushVideoPacketToNextReader = false;
} else {
#endif
mVideoPackets.PushFront(aItem);
#ifdef MOZ_DASH
}
#endif
}
nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
@ -957,56 +778,9 @@ nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
if (r != 0) {
return NS_ERROR_FAILURE;
}
#ifdef MOZ_DASH
// Find next cluster index;
MediaResource* resource = mDecoder->GetResource();
int64_t newOffset = resource->Tell();
for (uint32_t i = 1; i < mClusterByteRanges.Length(); i++) {
if (newOffset < mClusterByteRanges[i].mStart) {
mNextCluster = i;
LOG(PR_LOG_DEBUG,
("WebMReader [%p] for decoder [%p] updating mNextCluster to [%d] "
"after seek to offset [%lld]",
this, mDecoder, mNextCluster, resource->Tell()));
break;
}
}
#endif
return DecodeToTarget(aTarget);
}
#ifdef MOZ_DASH
bool WebMReader::IsDataCachedAtEndOfSubsegments()
{
MediaResource* resource = mDecoder->GetResource();
NS_ENSURE_TRUE(resource, false);
if (resource->IsDataCachedToEndOfResource(0)) {
return true;
}
if (mClusterByteRanges.IsEmpty()) {
return false;
}
nsTArray<MediaByteRange> ranges;
nsresult rv = resource->GetCachedRanges(ranges);
NS_ENSURE_SUCCESS(rv, false);
if (ranges.IsEmpty()) {
return false;
}
// Return true if data at the end of the final subsegment is cached.
uint32_t finalSubsegmentIndex = mClusterByteRanges.Length()-1;
uint64_t finalSubEndOffset = mClusterByteRanges[finalSubsegmentIndex].mEnd;
uint32_t finalRangeIndex = ranges.Length()-1;
uint64_t finalRangeStartOffset = ranges[finalRangeIndex].mStart;
uint64_t finalRangeEndOffset = ranges[finalRangeIndex].mEnd;
return (finalRangeStartOffset < finalSubEndOffset &&
finalSubEndOffset <= finalRangeEndOffset);
}
#endif
nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MediaResource* resource = mDecoder->GetResource();
@ -1044,29 +818,6 @@ nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
if (rv) {
double startTime = start * timecodeScale / NS_PER_S - aStartTime;
double endTime = end * timecodeScale / NS_PER_S - aStartTime;
#ifdef MOZ_DASH
// If this range extends to the end of a cluster, the true end time is
// the cluster's end timestamp. Since WebM frames do not have an end
// timestamp, a fully cached cluster must be reported with the correct
// end time of its final frame. Otherwise, buffered ranges could be
// reported with missing frames at cluster boundaries, specifically
// boundaries where stream switching has occurred.
if (!mClusterByteRanges.IsEmpty()) {
for (uint32_t clusterIndex = 0;
clusterIndex < (mClusterByteRanges.Length()-1);
clusterIndex++) {
if (ranges[index].mEnd >= mClusterByteRanges[clusterIndex].mEnd) {
double clusterEndTime =
mClusterByteRanges[clusterIndex+1].mStartTime / USEC_PER_S;
if (endTime < clusterEndTime) {
LOG(PR_LOG_DEBUG, ("End of cluster: endTime becoming %0.3fs",
clusterEndTime));
endTime = clusterEndTime;
}
}
}
}
#endif
// If this range extends to the end of the file, the true end time
// is the file's duration.
if (resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
@ -1089,136 +840,4 @@ void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_
mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
}
#ifdef MOZ_DASH
int64_t
WebMReader::GetSubsegmentForSeekTime(int64_t aSeekToTime)
{
NS_ENSURE_TRUE(0 <= aSeekToTime, -1);
// Check the first n-1 subsegments. End time is the start time of the next
// subsegment.
for (uint32_t i = 1; i < (mClusterByteRanges.Length()); i++) {
if (aSeekToTime < mClusterByteRanges[i].mStartTime) {
return i-1;
}
}
// Check the last subsegment. End time is the end time of the file.
NS_ASSERTION(mDecoder, "Decoder should not be null!");
if (aSeekToTime <= mDecoder->GetMediaDuration()) {
return mClusterByteRanges.Length()-1;
}
return (-1);
}
nsresult
WebMReader::GetSubsegmentByteRanges(nsTArray<MediaByteRange>& aByteRanges)
{
NS_ENSURE_TRUE(mContext, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aByteRanges.IsEmpty(), NS_ERROR_ALREADY_INITIALIZED);
NS_ENSURE_FALSE(mClusterByteRanges.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_FALSE(mCuesByteRange.IsNull(), NS_ERROR_NOT_INITIALIZED);
for (uint32_t i = 0; i < mClusterByteRanges.Length(); i++) {
aByteRanges.AppendElement();
aByteRanges[i] = mClusterByteRanges[i];
}
return NS_OK;
}
void
WebMReader::RequestSwitchAtSubsegment(int32_t aSubsegmentIdx,
MediaDecoderReader* aNextReader)
{
NS_ASSERTION(NS_IsMainThread() || mDecoder->OnDecodeThread(),
"Should be on main thread or decode thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
// Only allow one switch at a time; ignore if one is already requested.
if (mSwitchingCluster != -1) {
return;
}
NS_ENSURE_TRUE_VOID((uint32_t)aSubsegmentIdx < mClusterByteRanges.Length());
mSwitchingCluster = aSubsegmentIdx;
NS_ENSURE_TRUE_VOID(aNextReader);
NS_ENSURE_TRUE_VOID(aNextReader != this);
mNextReader = static_cast<WebMReader*>(aNextReader);
}
void
WebMReader::RequestSeekToSubsegment(uint32_t aIdx)
{
NS_ASSERTION(NS_IsMainThread() || mDecoder->OnDecodeThread(),
"Should be on main thread or decode thread.");
NS_ASSERTION(mDecoder, "decoder should not be null!");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
// Don't seek if we're about to switch to another reader.
if (mSwitchingCluster != -1) {
return;
}
// Only allow seeking if a request was not already made.
if (mSeekToCluster != -1) {
return;
}
NS_ENSURE_TRUE_VOID(aIdx < mClusterByteRanges.Length());
mSeekToCluster = aIdx;
// XXX Hack to get the resource to seek to the correct offset if the decode
// thread is in shutdown, e.g. if the video is not autoplay.
if (mDecoder->IsShutdown()) {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
mDecoder->GetResource()->Seek(PR_SEEK_SET,
mClusterByteRanges[mSeekToCluster].mStart);
}
}
void
WebMReader::PrepareToDecode()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
if (mSeekToCluster != -1) {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
SeekToCluster(mSeekToCluster);
}
}
void
WebMReader::SeekToCluster(uint32_t aIdx)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
NS_ENSURE_TRUE_VOID(aIdx < mClusterByteRanges.Length());
LOG(PR_LOG_DEBUG, ("Reader [%p] for Decoder [%p]: seeking to "
"subsegment [%lld] at offset [%lld]",
this, mDecoder, aIdx, mClusterByteRanges[aIdx].mStart));
int r = nestegg_offset_seek(mContext, mClusterByteRanges[aIdx].mStart);
NS_ENSURE_TRUE_VOID(r == 0);
if (aIdx + 1 < mClusterByteRanges.Length()) {
mNextCluster = aIdx + 1;
} else {
mNextCluster = 1;
}
mSeekToCluster = -1;
}
bool
WebMReader::HasReachedSubsegment(uint32_t aSubsegmentIndex)
{
NS_ASSERTION(mDecoder, "Decoder is null.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
NS_ENSURE_TRUE(aSubsegmentIndex < mClusterByteRanges.Length(), false);
NS_ASSERTION(mDecoder->GetResource(), "Decoder has no media resource.");
if (mReachedSwitchAccessPoint) {
LOG(PR_LOG_DEBUG,
("Reader [%p] for Decoder [%p]: reached switching offset [%lld] = "
"mClusterByteRanges[%d].mStart[%lld]",
this, mDecoder, mCurrentOffset, aSubsegmentIndex,
mClusterByteRanges[aSubsegmentIndex].mStart));
mReachedSwitchAccessPoint = false;
return true;
}
return false;
}
#endif /* MOZ_DASH */
} // namespace mozilla

View File

@ -22,10 +22,6 @@
#include "vorbis/codec.h"
#endif
#ifdef MOZ_DASH
#include "DASHRepReader.h"
#endif
namespace mozilla {
class WebMBufferedState;
@ -101,11 +97,7 @@ class WebMPacketQueue : private nsDeque {
}
};
#ifdef MOZ_DASH
class WebMReader : public DASHRepReader
#else
class WebMReader : public MediaDecoderReader
#endif
{
public:
WebMReader(AbstractMediaDecoder* aDecoder);
@ -139,80 +131,6 @@ public:
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
#ifdef MOZ_DASH
virtual void SetMainReader(DASHReader *aMainReader) MOZ_OVERRIDE {
NS_ASSERTION(aMainReader, "aMainReader is null.");
mMainReader = aMainReader;
}
// Called by |DASHReader| on the decode thread so that this reader will
// start reading at the appropriate subsegment/cluster. If this is not the
// current reader and a switch was previously requested, then it will seek to
// starting offset of the subsegment at which it is supposed to switch.
// Called on the decode thread, enters the decode monitor.
void PrepareToDecode() MOZ_OVERRIDE;
// Returns a reference to the audio/video queue of the main reader.
// Allows for a single audio/video queue to be shared among multiple
// |WebMReader|s.
MediaQueue<AudioData>& AudioQueue() MOZ_OVERRIDE {
if (mMainReader) {
return mMainReader->AudioQueue();
} else {
return MediaDecoderReader::AudioQueue();
}
}
MediaQueue<VideoData>& VideoQueue() MOZ_OVERRIDE {
if (mMainReader) {
return mMainReader->VideoQueue();
} else {
return MediaDecoderReader::VideoQueue();
}
}
// Sets byte range for initialization (EBML); used by DASH.
void SetInitByteRange(MediaByteRange &aByteRange) MOZ_OVERRIDE {
mInitByteRange = aByteRange;
}
// Sets byte range for cue points, i.e. cluster offsets; used by DASH.
void SetIndexByteRange(MediaByteRange &aByteRange) MOZ_OVERRIDE {
mCuesByteRange = aByteRange;
}
// Returns the index of the subsegment which contains the seek time.
int64_t GetSubsegmentForSeekTime(int64_t aSeekToTime) MOZ_OVERRIDE;
// Returns list of ranges for cluster start and end offsets.
nsresult GetSubsegmentByteRanges(nsTArray<MediaByteRange>& aByteRanges)
MOZ_OVERRIDE;
// Called by |DASHReader|::|PossiblySwitchVideoReaders| to check if this
// reader has reached a switch access point and it's ok to switch readers.
// Called on the decode thread.
bool HasReachedSubsegment(uint32_t aSubsegmentIndex) MOZ_OVERRIDE;
// Requests that this reader seek to the specified subsegment. Seek will
// happen when |PrepareDecodeVideoFrame| is called on the decode
// thread.
// Called on the main thread or decoder thread. Decode monitor must be held.
void RequestSeekToSubsegment(uint32_t aIdx) MOZ_OVERRIDE;
// Requests that this reader switch to |aNextReader| at the start of the
// specified subsegment. This is the reader to switch FROM.
// Called on the main thread or decoder thread. Decode monitor must be held.
void RequestSwitchAtSubsegment(int32_t aSubsegmentIdx,
MediaDecoderReader* aNextReader) MOZ_OVERRIDE;
// Seeks to the beginning of the specified cluster. Called on the decode
// thread.
void SeekToCluster(uint32_t aIdx);
// Returns true if data at the end of the final subsegment has been cached.
bool IsDataCachedAtEndOfSubsegments() MOZ_OVERRIDE;
#endif
protected:
// Value passed to NextPacket to determine if we are reading a video or an
// audio packet.
@ -224,14 +142,6 @@ protected:
// Read a packet from the nestegg file. Returns nullptr if all packets for
// the particular track have been read. Pass VIDEO or AUDIO to indicate the
// type of the packet we want to read.
#ifdef MOZ_DASH
nsReturnRef<NesteggPacketHolder> NextPacketInternal(TrackType aTrackType);
// Read a packet from the nestegg file. Returns nullptr if all packets for
// the particular track have been read. Pass VIDEO or AUDIO to indicate the
// type of the packet we want to read. If the reader reaches a switch access
// point, this function will get a packet from |mNextReader|.
#endif
nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType);
// Pushes a packet to the front of the video packet queue.
@ -301,54 +211,6 @@ private:
// Booleans to indicate if we have audio and/or video data
bool mHasVideo;
bool mHasAudio;
#ifdef MOZ_DASH
// Byte range for initialisation data; e.g. specified in DASH manifest.
MediaByteRange mInitByteRange;
// Byte range for cues; e.g. specified in DASH manifest.
MediaByteRange mCuesByteRange;
// Byte ranges for clusters; set internally, derived from cues.
nsTArray<TimestampedMediaByteRange> mClusterByteRanges;
// Pointer to the main |DASHReader|. Set in the constructor.
DASHReader* mMainReader;
// Index of the cluster to switch to. Monitor must be entered for write
// access on all threads, read access off the decode thread.
int32_t mSwitchingCluster;
// Pointer to the next reader. Used in |NextPacket| and |PushVideoPacket| at
// switch access points. Monitor must be entered for write access on all
// threads, read access off the decode thread.
nsRefPtr<WebMReader> mNextReader;
// Index of the cluster to seek to for a DASH stream request. Monitor must be
// entered for write access on all threads, read access off the decode
// thread.
int32_t mSeekToCluster;
// Current end offset of the last packet read in |NextPacket|. Used to check
// if the reader reached the switch access point. Accessed on the decode
// thread only.
int64_t mCurrentOffset;
// Index of next cluster to be read. Used to determine the starting offset of
// the next cluster. Accessed on the decode thread only.
uint32_t mNextCluster;
// Set in |NextPacket| if we read a packet from the next reader. If true in
// |PushVideoPacket|, we will push the packet onto the next reader's
// video packet queue (not video data queue!). Accessed on decode thread
// only.
bool mPushVideoPacketToNextReader;
// Indicates if the reader has reached a switch access point. Set in
// |NextPacket| and read in |HasReachedSubsegment|. Accessed on
// decode thread only.
bool mReachedSwitchAccessPoint;
#endif
};
} // namespace mozilla

View File

@ -14,6 +14,3 @@ EXPORT_RESOURCE_CONTENT = \
$(NULL)
libs::
$(INSTALL) $(EXPORT_RESOURCE_CONTENT) $(DIST)/bin/res/dtd
install::
$(SYSINSTALL) $(IFLAGS1) $(EXPORT_RESOURCE_CONTENT) $(DESTDIR)$(mozappdir)/res/dtd

View File

@ -3651,6 +3651,14 @@ NS_IMETHODIMP
nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
JSObject *obj)
{
// Since this call is virtual, the exact rooting hazard static analysis is
// not able to determine that it happens during finalization and should be
// ignored. Moreover, the analysis cannot discover and validate the
// potential targets of the virtual call to OnFinalize below because of the
// indirection through nsCOMMPtr. Thus, we annotate the analysis here so
// that it does not report OnFinalize as GCing with |obj| on stack.
JS::AutoAssertNoGC nogc;
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);

View File

@ -205,8 +205,10 @@ function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) {
'process-priority-with-background-LRU-set',
function(subject, topic, data) {
dump("browserElementTestHelpers got notify: topic "+ topic + ", data " + data +"\n");
[id, priority, cpuPriority, backgroundLRU] = data.split(":");
if (id != childID) {
dump("id(" + id + ") != childID(" + childID + ")\n");
return;
}

View File

@ -25,7 +25,12 @@ using namespace mozilla::dom;
using namespace mozilla::hal_sandbox;
using namespace mozilla::services;
#else
namespace mozilla {
namespace dom {
class PContentParent;
}
}
class nsIPrincipal;
#endif
@ -280,16 +285,16 @@ AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor,
}
bool
AssertAppPrincipal(PContentParent* aActor,
AssertAppPrincipal(mozilla::dom::PContentParent* aActor,
nsIPrincipal* aPrincipal)
{
return true;
}
uint32_t
CheckPermission(PContentParent*,
nsIPrincipal*,
const char*)
CheckPermission(mozilla::dom::PContentParent* aActor,
nsIPrincipal* aPrincipal,
const char* aPermission)
{
return nsIPermissionManager::ALLOW_ACTION;
}

View File

@ -72,6 +72,8 @@
#include "nsPermissionManager.h"
#endif
#include "PermissionMessageUtils.h"
#if defined(MOZ_WIDGET_ANDROID)
#include "APKOpen.h"
#endif
@ -1172,14 +1174,15 @@ ContentChild::RecvNotifyVisited(const URIParams& aURI)
bool
ContentChild::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal)
{
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, false, &cloneData, &cpows, nullptr);
aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
}
return true;
}

View File

@ -188,7 +188,8 @@ public:
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal);
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere);

View File

@ -1139,7 +1139,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
if (ppm) {
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
nullptr, nullptr, nullptr);
nullptr, nullptr, nullptr, nullptr);
}
nsCOMPtr<nsIThreadObserver>
kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
@ -2865,14 +2865,21 @@ bool
ContentParent::RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals)
{
nsIPrincipal* principal = aPrincipal;
if (principal && !AssertAppPrincipal(this, principal)) {
return false;
}
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, &cpows, aRetvals);
aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
}
return true;
}
@ -2881,14 +2888,20 @@ bool
ContentParent::AnswerRpcMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals)
{
nsIPrincipal* principal = aPrincipal;
if (principal && !AssertAppPrincipal(this, principal)) {
return false;
}
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, &cpows, aRetvals);
aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
}
return true;
}
@ -2896,14 +2909,20 @@ ContentParent::AnswerRpcMessage(const nsString& aMsg,
bool
ContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal)
{
nsIPrincipal* principal = aPrincipal;
if (principal && !AssertAppPrincipal(this, principal)) {
return false;
}
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, false, &cloneData, &cpows, nullptr);
aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
}
return true;
}
@ -3110,7 +3129,8 @@ bool
ContentParent::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
ClonedMessageData data;
if (!BuildClonedMessageDataForParent(this, aData, data)) {
@ -3120,7 +3140,7 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return SendAsyncMessage(nsString(aMessage), data, cpows);
return SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal);
}
bool

View File

@ -117,7 +117,8 @@ public:
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows) MOZ_OVERRIDE;
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;
@ -420,14 +421,17 @@ private:
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals);
virtual bool AnswerRpcMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal);
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName,

View File

@ -61,7 +61,8 @@ intr protocol PBrowser
manages PIndexedDB;
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows);
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows,
Principal aPrincipal);
parent:
/**
@ -74,10 +75,12 @@ parent:
intr CreateWindow() returns (PBrowser window);
sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
rpc RpcMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
/**

View File

@ -375,10 +375,12 @@ parent:
sync ReadFontList() returns (FontListEntry[] retValue);
sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
rpc RpcMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
ShowAlertNotification(nsString imageUrl,
@ -469,7 +471,8 @@ parent:
returns (OptionalInputStreamParams postData, OptionalURIParams uri);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows);
AsyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal);
};
}

View File

@ -43,7 +43,9 @@
//
// (Wow, our logging story is a huge mess.)
// #define ENABLE_LOGGING 1
#ifndef HAVE_64BIT_OS
#define ENABLE_LOGGING 1
#endif
#if defined(ANDROID) && defined(ENABLE_LOGGING)
# include <android/log.h>

View File

@ -62,6 +62,7 @@
#include "nsPrintfCString.h"
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "PermissionMessageUtils.h"
#include "PCOMContentPermissionRequestChild.h"
#include "PuppetWidget.h"
#include "StructuredCloneUtils.h"
@ -1506,7 +1507,7 @@ TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
aMessageName, false, &cloneData, nullptr, nullptr);
aMessageName, false, &cloneData, nullptr, nullptr, nullptr);
}
bool
@ -2071,7 +2072,8 @@ TabChild::RecvLoadRemoteScript(const nsString& aURL)
bool
TabChild::RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal)
{
if (mTabChildGlobal) {
nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
@ -2080,7 +2082,7 @@ TabChild::RecvAsyncMessage(const nsString& aMessage,
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
CpowIdHolder cpows(static_cast<ContentChild*>(Manager())->GetCPOWManager(), aCpows);
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
aMessage, false, &cloneData, &cpows, nullptr);
aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
}
return true;
}
@ -2404,6 +2406,7 @@ TabChild::DoSendBlockingMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync)
{
@ -2418,16 +2421,21 @@ TabChild::DoSendBlockingMessage(JSContext* aCx,
return false;
}
}
if (aIsSync)
return SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal);
return CallRpcMessage(nsString(aMessage), data, cpows, aJSONRetVal);
if (aIsSync) {
return SendSyncMessage(nsString(aMessage), data, cpows, aPrincipal,
aJSONRetVal);
}
return CallRpcMessage(nsString(aMessage), data, cpows, aPrincipal,
aJSONRetVal);
}
bool
TabChild::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
ContentChild* cc = Manager();
ClonedMessageData data;
@ -2440,7 +2448,8 @@ TabChild::DoSendAsyncMessage(JSContext* aCx,
return false;
}
}
return SendAsyncMessage(nsString(aMessage), data, cpows);
return SendAsyncMessage(nsString(aMessage), data, cpows,
aPrincipal);
}
TabChild*

View File

@ -63,23 +63,27 @@ public:
NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote,
aPrincipal, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD SendRpcMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
nsIPrincipal* aPrincipal,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
aPrincipal, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
@ -194,12 +198,14 @@ public:
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows) MOZ_OVERRIDE;
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual bool RecvLoadURL(const nsCString& uri);
virtual bool RecvCacheFileDescriptor(const nsString& aPath,
@ -237,7 +243,8 @@ public:
virtual bool RecvLoadRemoteScript(const nsString& aURL);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
virtual PDocumentRendererChild*
AllocPDocumentRendererChild(const nsRect& documentRect, const gfxMatrix& transform,

View File

@ -8,6 +8,7 @@
#include "TabParent.h"
#include "AppProcessChecker.h"
#include "IDBFactory.h"
#include "IndexedDBParent.h"
#include "mozIApplication.h"
@ -52,6 +53,7 @@
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "private/pprio.h"
#include "PermissionMessageUtils.h"
#include "StructuredCloneUtils.h"
#include "JavaScriptParent.h"
#include "TabChild.h"
@ -299,7 +301,8 @@ TabParent::ActorDestroy(ActorDestroyReason why)
if (frameLoader) {
fmm = frameLoader->GetFrameMessageManager();
nsCOMPtr<Element> frameElement(mFrameElement);
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr,
nullptr);
frameLoader->DestroyChild();
if (why == AbnormalShutdown && os) {
@ -765,32 +768,53 @@ bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsIPrincipal* principal = aPrincipal;
ContentParent* parent = static_cast<ContentParent*>(Manager());
if (principal && !AssertAppPrincipal(parent, principal)) {
return false;
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal);
CpowIdHolder cpows(parent->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
}
bool
TabParent::AnswerRpcMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsIPrincipal* principal = aPrincipal;
ContentParent* parent = static_cast<ContentParent*>(Manager());
if (principal && !AssertAppPrincipal(parent, principal)) {
return false;
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal);
CpowIdHolder cpows(parent->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
}
bool
TabParent::RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal)
{
nsIPrincipal* principal = aPrincipal;
ContentParent* parent = static_cast<ContentParent*>(Manager());
if (principal && !AssertAppPrincipal(parent, principal)) {
return false;
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, false, &cloneData, &cpows, nullptr);
CpowIdHolder cpows(parent->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
}
bool
@ -1214,6 +1238,7 @@ TabParent::ReceiveMessage(const nsString& aMessage,
bool aSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
@ -1226,6 +1251,7 @@ TabParent::ReceiveMessage(const nsString& aMessage,
aSync,
aCloneData,
aCpows,
aPrincipal,
aJSONRetVal);
}
return true;

View File

@ -23,6 +23,7 @@
struct gfxMatrix;
class nsFrameLoader;
class nsIContent;
class nsIPrincipal;
class nsIURI;
class nsIWidget;
class CpowHolder;
@ -121,14 +122,17 @@ public:
virtual bool RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool AnswerRpcMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal);
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
uint32_t* aSeqno);
@ -254,6 +258,7 @@ protected:
bool aSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal = nullptr);
virtual bool Recv__delete__() MOZ_OVERRIDE;

View File

@ -151,7 +151,7 @@ partial interface Document {
* True if this document is synthetic : stand alone image, video, audio file,
* etc.
*/
[ChromeOnly] readonly attribute boolean mozSyntheticDocument;
[Func="IsChromeOrXBL"] readonly attribute boolean mozSyntheticDocument;
/**
* Returns the script element whose script is currently being processed.
*

View File

@ -30,6 +30,3 @@ _FILES = \
libs::
$(INSTALL) $(_FILES) $(DIST)/bin/res
install::
$(SYSINSTALL) $(IFLAGS1) $(_FILES) $(DESTDIR)$(mozappdir)/res

View File

@ -1662,6 +1662,7 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner()
static void DrawThebesLayer(ThebesLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData)
{

View File

@ -11,7 +11,4 @@ DICTIONARY_FILES = $(strip $(wildcard $(LOCALE_SRCDIR)/hunspell/*.dic) $(wildcar
ifneq (,$(DICTIONARY_FILES))
libs::
$(INSTALL) $(DICTIONARY_FILES) $(FINAL_TARGET)/dictionaries
install::
$(SYSINSTALL) $(IFLAGS1) $(DICTIONARY_FILES) $(DESTDIR)$(mozappdir)/dictionaries
endif

View File

@ -214,7 +214,10 @@ void RecordingFontUserDataDestroyFunc(void *aUserData)
RecordingFontUserData *userData =
static_cast<RecordingFontUserData*>(aUserData);
// TODO support font in b2g recordings
#ifndef MOZ_WIDGET_GONK
userData->recorder->RecordEvent(RecordedScaledFontDestruction(userData->refPtr));
#endif
delete userData;
}
@ -227,7 +230,10 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont,
const GlyphRenderingOptions *aRenderingOptions)
{
if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
// TODO support font in b2g recordings
#ifndef MOZ_WIDGET_GONK
mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, aFont));
#endif
RecordingFontUserData *userData = new RecordingFontUserData;
userData->refPtr = aFont;
userData->recorder = mRecorder;
@ -235,7 +241,10 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont,
&RecordingFontUserDataDestroyFunc);
}
// TODO support font in b2g recordings
#ifndef MOZ_WIDGET_GONK
mRecorder->RecordEvent(RecordedFillGlyphs(this, aFont, aPattern, aOptions, aBuffer.mGlyphs, aBuffer.mNumGlyphs));
#endif
mFinalDT->FillGlyphs(aFont, aBuffer, aPattern, aOptions, aRenderingOptions);
}

View File

@ -265,6 +265,7 @@ public:
typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);

View File

@ -58,6 +58,12 @@ enum BufferMode {
BUFFER_BUFFERED
};
enum DrawRegionClip {
CLIP_DRAW,
CLIP_DRAW_SNAPPED,
CLIP_NONE,
};
// LayerRenderState for Composer2D
// We currently only support Composer2D using gralloc. If we want to be backed
// by other surfaces we will need a more generic LayerRenderState.

View File

@ -856,6 +856,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
nsIntPoint topLeft;
result.mContext = GetContextForQuadrantUpdate(drawBounds, BUFFER_BOTH, &topLeft);
result.mClip = CLIP_DRAW_SNAPPED;
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
if (IsAzureBuffer()) {
@ -873,7 +874,6 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
FillSurface(mBuffer, result.mRegionToDraw, topLeft, gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(mBufferOnWhite, result.mRegionToDraw, topLeft, gfxRGBA(1.0, 1.0, 1.0, 1.0));
}
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
} else if (contentType == GFX_CONTENT_COLOR_ALPHA && !isClear) {
if (IsAzureBuffer()) {
nsIntRegionRectIterator iter(result.mRegionToDraw);
@ -883,16 +883,14 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
}
// Clear will do something expensive with a complex clip pushed, so clip
// here.
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
} else {
MOZ_ASSERT(result.mContext->IsCairo());
result.mContext->Save();
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
result.mContext->Paint();
result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
result.mContext->Restore();
}
} else {
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
}
return result;

View File

@ -21,6 +21,7 @@
#include "nsRect.h" // for nsIntRect
#include "nsRegion.h" // for nsIntRegion
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "LayersTypes.h"
struct gfxMatrix;
struct nsIntSize;
@ -218,6 +219,7 @@ public:
nsIntRegion mRegionToDraw;
nsIntRegion mRegionToInvalidate;
bool mDidSelfCopy;
DrawRegionClip mClip;
};
enum {

View File

@ -115,10 +115,10 @@ protected:
{
EnsureSurface();
if (!mSurface) {
mSurface = mCompositor->GetDrawTarget()->CreateSourceSurfaceFromData(mThebesImage->Data(),
mSize,
mThebesImage->Stride(),
mFormat);
mSurface = Factory::CreateWrappingDataSourceSurface(mThebesImage->Data(),
mThebesImage->Stride(),
mSize,
mFormat);
}
return true;
}

View File

@ -131,7 +131,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
groupContext = aContext;
}
SetAntialiasingFlags(this, groupContext);
aCallback(this, groupContext, toDraw, nsIntRegion(), aCallbackData);
aCallback(this, groupContext, toDraw, CLIP_NONE, nsIntRegion(), aCallbackData);
if (needsGroup) {
BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext);
if (needsClipToVisibleRegion) {
@ -236,6 +236,7 @@ BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback,
PaintBuffer(state.mContext,
state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
state.mDidSelfCopy,
state.mClip,
aCallback, aCallbackData);
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();

View File

@ -103,6 +103,7 @@ protected:
const nsIntRegion& aExtendedRegionToDraw,
const nsIntRegion& aRegionToInvalidate,
bool aDidSelfCopy,
DrawRegionClip aClip,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
@ -110,8 +111,8 @@ protected:
BasicManager()->SetTransactionIncomplete();
return;
}
aCallback(this, aContext, aExtendedRegionToDraw, aRegionToInvalidate,
aCallbackData);
aCallback(this, aContext, aExtendedRegionToDraw, aClip,
aRegionToInvalidate, aCallbackData);
// Everything that's visible has been validated. Do this instead of just
// OR-ing with aRegionToDraw, since that can lead to a very complex region
// here (OR doesn't automatically simplify to the simplest possible

View File

@ -106,7 +106,7 @@ ClientThebesLayer::PaintThebes()
PaintBuffer(state.mContext,
state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
state.mDidSelfCopy);
state.mDidSelfCopy, state.mClip);
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();
} else {
@ -146,7 +146,7 @@ ClientThebesLayer::PaintBuffer(gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aExtendedRegionToDraw,
const nsIntRegion& aRegionToInvalidate,
bool aDidSelfCopy)
bool aDidSelfCopy, DrawRegionClip aClip)
{
ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
MOZ_ASSERT(contentClientRemote->GetIPDLActor());
@ -161,7 +161,8 @@ ClientThebesLayer::PaintBuffer(gfxContext* aContext,
}
ClientManager()->GetThebesLayerCallback()(this,
aContext,
aExtendedRegionToDraw,
aExtendedRegionToDraw,
aClip,
aRegionToInvalidate,
ClientManager()->GetThebesLayerCallbackData());

View File

@ -105,7 +105,8 @@ protected:
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aExtendedRegionToDraw,
const nsIntRegion& aRegionToInvalidate,
bool aDidSelfCopy);
bool aDidSelfCopy,
DrawRegionClip aClip);
void PaintThebes();

View File

@ -69,18 +69,6 @@ private:
return static_cast<ClientLayerManager*>(mManager);
}
// BasicImplData
virtual void
PaintBuffer(gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aExtendedRegionToDraw,
const nsIntRegion& aRegionToInvalidate,
bool aDidSelfCopy,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{ NS_RUNTIMEABORT("Not reached."); }
/**
* For the initial PaintThebes of a transaction, calculates all the data
* needed for that paint and any repeated transactions.

View File

@ -894,12 +894,14 @@ ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer,
// although they never cover it. This leads to two draw rects, the narow strip and the actually
// newly exposed area. It would be wise to fix this glitch in any way to have simpler
// clip and draw regions.
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
result.mClip = CLIP_DRAW;
if (mContentType == GFX_CONTENT_COLOR_ALPHA) {
result.mContext->Save();
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
result.mContext->Paint();
result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
result.mContext->Restore();
}
return result;

View File

@ -274,7 +274,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
#endif
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw");
mCallback(mThebesLayer, ctxt, aPaintRegion, nsIntRegion(), mCallbackData);
mCallback(mThebesLayer, ctxt, aPaintRegion, CLIP_NONE, nsIntRegion(), mCallbackData);
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
@ -383,6 +383,7 @@ BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
mCallback(mThebesLayer, ctxt,
nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(),
GetScaledTileLength()))),
CLIP_NONE,
nsIntRegion(), mCallbackData);
}

View File

@ -392,7 +392,6 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToGecko;
GetInputTransforms(apzc, transformToApzc, transformToGecko);
ApplyTransform(&(aOutEvent->refPoint), transformToApzc);
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
ApplyTransform(&(aOutEvent->refPoint), outTransform);
return nsEventStatus_eIgnore;

View File

@ -158,20 +158,6 @@ public:
void* GetThebesLayerCallbackData() const
{ return mThebesLayerCallbackData; }
/*
* Helper functions for our layers
*/
void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw)
{
NS_ASSERTION(mThebesLayerCallback,
"CallThebesLayerDrawCallback without callback!");
mThebesLayerCallback(aLayer, aContext,
aRegionToDraw, nsIntRegion(),
mThebesLayerCallbackData);
}
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() const MOZ_OVERRIDE { return ""; }
#endif // MOZ_LAYERS_HAVE_LOG

View File

@ -414,40 +414,22 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
destinationSurface = mD2DSurface;
}
nsRefPtr<gfxContext> context;
MOZ_ASSERT(mDrawTarget);
nsRefPtr<gfxContext> context = new gfxContext(mDrawTarget);
if (mDrawTarget) {
context = new gfxContext(mDrawTarget);
} else {
context = new gfxContext(destinationSurface);
}
nsIntRegionRectIterator iter(aRegion);
context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
context->NewPath();
const nsIntRect *iterRect;
while ((iterRect = iter.Next())) {
context->Rectangle(gfxRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
if (mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
if (aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
nsIntRegionRectIterator iter(aRegion);
const nsIntRect *iterRect;
while ((iterRect = iter.Next())) {
mDrawTarget->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
}
}
context->Clip();
if (!mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
context->SetOperator(gfxContext::OPERATOR_CLEAR);
context->Paint();
context->SetOperator(gfxContext::OPERATOR_OVER);
}
if (mD2DSurface) {
mD2DSurface->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
} else if (mDrawTarget) {
mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
}
mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
cbInfo.Callback(this, context, aRegion, CLIP_DRAW, nsIntRegion(), cbInfo.CallbackData);
}
void

View File

@ -493,7 +493,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
context->Translate(gfxPoint(-bounds.x, -bounds.y));
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
cbInfo.Callback(this, context, aRegion, CLIP_NONE, nsIntRegion(), cbInfo.CallbackData);
for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
NS_ASSERTION(aMode == SURFACE_OPAQUE,

View File

@ -383,7 +383,7 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
PostDelayedTask(mTouchListenerTimeoutTask, gTouchListenerTimeout);
}
}
return nsEventStatus_eConsumeNoDefault;
return nsEventStatus_eIgnore;
}
return HandleInputEvent(aEvent);

View File

@ -200,21 +200,6 @@ public:
void* GetThebesLayerCallbackData() const
{ return mThebesLayerCallbackData; }
/*
* Helper functions for our layers
*/
void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw)
{
NS_ASSERTION(mThebesLayerCallback,
"CallThebesLayerDrawCallback without callback!");
mThebesLayerCallback(aLayer, aContext,
aRegionToDraw, nsIntRegion(),
mThebesLayerCallbackData);
}
GLenum FBOTextureTarget() { return mFBOTextureTarget; }
/**

View File

@ -828,12 +828,14 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
// although they never cover it. This leads to two draw rects, the narow strip and the actually
// newly exposed area. It would be wise to fix this glitch in any way to have simpler
// clip and draw regions.
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
result.mClip = CLIP_DRAW;
if (mTexImage->GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
result.mContext->Save();
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
result.mContext->Paint();
result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
result.mContext->Restore();
}
return result;
@ -931,7 +933,7 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
} else {
void* callbackData = mOGLManager->GetThebesLayerCallbackData();
SetAntialiasingFlags(this, state.mContext);
callback(this, state.mContext, state.mRegionToDraw,
callback(this, state.mContext, state.mRegionToDraw, state.mClip,
state.mRegionToInvalidate, callbackData);
// Everything that's visible has been validated. Do this instead of just
// OR-ing with aRegionToDraw, since that can lead to a very complex region

View File

@ -15,7 +15,14 @@
#include "gfxPlatform.h"
#ifdef XP_WIN
#include <process.h>
#define getpid _getpid
#endif
#include "nsXULAppAPI.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#if defined(XP_WIN)
#include "gfxWindowsPlatform.h"
@ -319,10 +326,23 @@ int RecordingPrefChanged(const char *aPrefName, void *aClosure)
if (prefFileName) {
fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
} else {
fileName.AssignLiteral("browserrecording.aer");
nsCOMPtr<nsIFile> tmpFile;
if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
return 0;
}
fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
nsresult rv = tmpFile->AppendNative(fileName);
if (NS_FAILED(rv))
return 0;
rv = tmpFile->GetNativePath(fileName);
if (NS_FAILED(rv))
return 0;
}
gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
printf_stderr("Recording to %s\n", fileName.get());
Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
} else {
Factory::SetGlobalEventRecorder(nullptr);

View File

@ -30,6 +30,3 @@ GARBAGE += \
libs::
$(INSTALL) $(EXPORT_RESOURCE) $(DIST)/bin/res
install::
$(SYSINSTALL) $(IFLAGS1) $(EXPORT_RESOURCE) $(DESTDIR)$(mozappdir)/res

View File

@ -11,7 +11,4 @@ PATTERN_FILES = $(strip $(wildcard $(srcdir)/*/hyphenation/*.dic))
ifneq (,$(PATTERN_FILES))
libs::
$(INSTALL) $(PATTERN_FILES) $(FINAL_TARGET)/hyphenation
install::
$(SYSINSTALL) $(IFLAGS1) $(PATTERN_FILES) $(DESTDIR)$(mozappdir)/hyphenation
endif

Some files were not shown because too many files have changed in this diff Show More