--- a/accessible/src/atk/AccessibleWrap.cpp
+++ b/accessible/src/atk/AccessibleWrap.cpp
@@ -22,16 +22,17 @@
#include "nsStateMap.h"
#include "Relation.h"
#include "RootAccessible.h"
#include "States.h"
#include "mozilla/Util.h"
#include "nsXPCOMStrings.h"
#include "nsComponentManagerUtils.h"
+#include "nsIPersistentProperties2.h"
using namespace mozilla;
using namespace mozilla::a11y;
AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals =
eUnknown;
//defined in ApplicationAccessibleWrap.cpp
--- a/accessible/src/atk/nsMaiInterfaceImage.cpp
+++ b/accessible/src/atk/nsMaiInterfaceImage.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InterfaceInitFuncs.h"
#include "AccessibleWrap.h"
#include "ImageAccessible.h"
#include "mozilla/Likely.h"
#include "nsMai.h"
+#include "nsIAccessibleTypes.h"
#include "nsIURI.h"
using namespace mozilla;
using namespace mozilla::a11y;
extern "C" {
const gchar* getDescriptionCB(AtkObject* aAtkObj);
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InterfaceInitFuncs.h"
#include "Accessible-inl.h"
#include "HyperTextAccessible.h"
#include "nsMai.h"
+#include "nsIAccessibleTypes.h"
#include "nsIPersistentProperties2.h"
#include "mozilla/Likely.h"
using namespace mozilla::a11y;
AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
--- a/accessible/src/base/ARIAMap.cpp
+++ b/accessible/src/base/ARIAMap.cpp
@@ -2,17 +2,16 @@
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ARIAMap.h"
-#include "Accessible.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "Role.h"
#include "States.h"
#include "nsAttrName.h"
#include "nsWhitespaceTokenizer.h"
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -1,29 +1,22 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#include "AccEvent.h"
-#include "ApplicationAccessibleWrap.h"
-#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "DocAccessible.h"
-#include "nsIAccessibleText.h"
#include "xpcAccEvents.h"
#include "States.h"
#include "nsEventStateManager.h"
-#include "nsIServiceManager.h"
-#ifdef MOZ_XUL
-#include "nsIDOMXULMultSelectCntrlEl.h"
-#endif
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// AccEvent
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/AccGroupInfo.cpp
+++ b/accessible/src/base/AccGroupInfo.cpp
@@ -1,13 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AccGroupInfo.h"
+#include "nsAccUtils.h"
#include "Role.h"
#include "States.h"
using namespace mozilla::a11y;
AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) :
mPosInSet(0), mSetSize(0), mParent(nullptr)
--- a/accessible/src/base/AccGroupInfo.h
+++ b/accessible/src/base/AccGroupInfo.h
@@ -1,17 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AccGroupInfo_h_
#define AccGroupInfo_h_
#include "Accessible-inl.h"
-#include "nsAccUtils.h"
namespace mozilla {
namespace a11y {
/**
* Calculate and store group information.
*/
class AccGroupInfo
--- a/accessible/src/base/AccIterator.cpp
+++ b/accessible/src/base/AccIterator.cpp
@@ -1,23 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AccIterator.h"
-#include "nsAccessibilityService.h"
#include "AccGroupInfo.h"
-#include "Accessible-inl.h"
#ifdef MOZ_XUL
#include "XULTreeAccessible.h"
#endif
#include "mozilla/dom/Element.h"
-#include "nsBindingManager.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// AccIterator
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/AccIterator.h
+++ b/accessible/src/base/AccIterator.h
@@ -4,17 +4,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_AccIterator_h__
#define mozilla_a11y_AccIterator_h__
#include "DocAccessible.h"
#include "Filters.h"
-#include "nsAccessibilityService.h"
+
+class nsITreeView;
namespace mozilla {
namespace a11y {
/**
* AccIterable is a basic interface for iterators over accessibles.
*/
class AccIterable
--- a/accessible/src/base/AccTypes.h
+++ b/accessible/src/base/AccTypes.h
@@ -24,17 +24,16 @@ enum AccType {
eHTMLCanvasType,
eHTMLCaptionType,
eHTMLCheckboxType,
eHTMLComboboxType,
eHTMLFileInputType,
eHTMLGroupboxType,
eHTMLHRType,
eHTMLImageMapType,
- eHTMLLabelType,
eHTMLLiType,
eHTMLSelectListType,
eHTMLMediaType,
eHTMLRadioButtonType,
eHTMLRangeType,
eHTMLTableType,
eHTMLTableCellType,
eHTMLTableRowType,
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -1,39 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DocManager.h"
-#include "Accessible-inl.h"
#include "ApplicationAccessible.h"
#include "ARIAMap.h"
#include "DocAccessible-inl.h"
#include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
#include "RootAccessibleWrap.h"
-#include "States.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
#include "nsCURILoader.h"
#include "nsDocShellLoadTypes.h"
#include "nsDOMEvent.h"
#include "nsIChannel.h"
-#include "nsIContentViewer.h"
#include "nsIDOMDocument.h"
#include "nsEventListenerManager.h"
#include "nsIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIWebNavigation.h"
#include "nsServiceManagerUtils.h"
+#include "nsIWebProgress.h"
+#include "nsCoreUtils.h"
using namespace mozilla;
using namespace mozilla::a11y;
using namespace mozilla::dom;
////////////////////////////////////////////////////////////////////////////////
// DocManager
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/DocManager.h
+++ b/accessible/src/base/DocManager.h
@@ -3,17 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11_DocManager_h_
#define mozilla_a11_DocManager_h_
#include "nsIDocument.h"
#include "nsIDOMEventListener.h"
#include "nsRefPtrHashtable.h"
-#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
#include "nsIPresShell.h"
namespace mozilla {
namespace a11y {
class Accessible;
--- a/accessible/src/base/EventQueue.cpp
+++ b/accessible/src/base/EventQueue.cpp
@@ -1,18 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EventQueue.h"
#include "Accessible-inl.h"
-#include "DocAccessible-inl.h"
#include "nsEventShell.h"
+#include "DocAccessible.h"
+#include "nsAccessibilityService.h"
+#ifdef A11Y_LOG
+#include "Logging.h"
+#endif
using namespace mozilla;
using namespace mozilla::a11y;
// Defines the number of selection add/remove events in the queue when they
// aren't packed into single selection within event.
const unsigned int kSelChangeCountToPack = 5;
--- a/accessible/src/base/EventQueue.h
+++ b/accessible/src/base/EventQueue.h
@@ -3,18 +3,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_EventQueue_h_
#define mozilla_a11y_EventQueue_h_
#include "AccEvent.h"
-class nsIContent;
-
namespace mozilla {
namespace a11y {
class DocAccessible;
/**
* Used to organize and coalesce pending events.
*/
--- a/accessible/src/base/FocusManager.cpp
+++ b/accessible/src/base/FocusManager.cpp
@@ -5,20 +5,20 @@
#include "FocusManager.h"
#include "Accessible-inl.h"
#include "DocAccessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsEventShell.h"
#include "Role.h"
-#include "RootAccessible.h"
#include "nsEventStateManager.h"
#include "nsFocusManager.h"
+#include "mozilla/dom/Element.h"
namespace dom = mozilla::dom;
using namespace mozilla::a11y;
FocusManager::FocusManager()
{
}
--- a/accessible/src/base/FocusManager.h
+++ b/accessible/src/base/FocusManager.h
@@ -1,17 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_FocusManager_h_
#define mozilla_a11y_FocusManager_h_
#include "nsAutoPtr.h"
-#include "mozilla/dom/Element.h"
+
+class nsINode;
+class nsIDocument;
+class nsISupports;
namespace mozilla {
namespace a11y {
class AccEvent;
class Accessible;
class DocAccessible;
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -17,16 +17,17 @@
#include "nsIChannel.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISelectionPrivate.h"
#include "nsTraceRefcntImpl.h"
#include "nsIWebProgress.h"
#include "prenv.h"
#include "nsIDocShellTreeItem.h"
#include "nsIURI.h"
+#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// Logging helpers
static uint32_t sModules = 0;
--- a/accessible/src/base/Logging.h
+++ b/accessible/src/base/Logging.h
@@ -3,22 +3,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_logs_h__
#define mozilla_a11y_logs_h__
#include "nscore.h"
-#include "nsAString.h"
+#include "nsStringFwd.h"
class nsIDocument;
class nsINode;
class nsIRequest;
class nsISelection;
+class nsISupports;
class nsIWebProgress;
namespace mozilla {
namespace a11y {
class AccEvent;
class Accessible;
class DocAccessible;
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -1,16 +1,15 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NotificationController.h"
-#include "Accessible-inl.h"
#include "DocAccessible-inl.h"
#include "TextLeafAccessible.h"
#include "TextUpdater.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -10,22 +10,19 @@
#include "nsCycleCollectionParticipant.h"
#include "nsRefreshDriver.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
-class nsIContent;
-
namespace mozilla {
namespace a11y {
-class Accessible;
class DocAccessible;
/**
* Notification interface.
*/
class Notification
{
public:
--- a/accessible/src/base/RoleAsserts.cpp
+++ b/accessible/src/base/RoleAsserts.cpp
@@ -2,18 +2,16 @@
/* 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/. */
#include "nsIAccessibleRole.h"
#include "Role.h"
-#include "mozilla/Assertions.h"
-
using namespace mozilla::a11y;
#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
static_assert(static_cast<uint32_t>(roles::geckoRole) \
== static_cast<uint32_t>(nsIAccessibleRole::ROLE_ ## geckoRole), \
"internal and xpcom roles differ!");
#include "RoleMap.h"
#undef ROLE
--- a/accessible/src/base/SelectionManager.cpp
+++ b/accessible/src/base/SelectionManager.cpp
@@ -5,27 +5,25 @@
#include "mozilla/a11y/SelectionManager.h"
#include "DocAccessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsIAccessibleEvent.h"
-#include "RootAccessible.h"
#include "nsCaret.h"
+#include "nsIAccessibleTypes.h"
#include "nsIDOMDocument.h"
-#include "nsIDOMHTMLAnchorElement.h"
-#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsISelectionPrivate.h"
-#include "nsServiceManagerUtils.h"
#include "mozilla/Selection.h"
+#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::a11y;
void
SelectionManager::Shutdown()
{
ClearControlSelectionListener();
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -1,25 +1,24 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TextAttrs.h"
#include "Accessible-inl.h"
-#include "HyperTextAccessibleWrap.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "StyleInfo.h"
#include "gfxFont.h"
-#include "gfxUserFontSet.h"
#include "nsFontMetrics.h"
#include "nsLayoutUtils.h"
+#include "HyperTextAccessible.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// TextAttrsMgr
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/TreeWalker.h
+++ b/accessible/src/base/TreeWalker.h
@@ -1,17 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_TreeWalker_h_
#define mozilla_a11y_TreeWalker_h_
-#include "nsAutoPtr.h"
+#include <stdint.h>
class nsIContent;
namespace mozilla {
namespace a11y {
class Accessible;
class DocAccessible;
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -10,23 +10,20 @@
#include "nsAccessibilityService.h"
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "HyperTextAccessible.h"
#include "nsIAccessibleTypes.h"
#include "Role.h"
#include "States.h"
#include "TextLeafAccessible.h"
-#include "nsIMutableArray.h"
#include "nsIDOMXULContainerElement.h"
-#include "nsIDOMXULSelectCntrlEl.h"
-#include "nsIDOMXULSelectCntrlItemEl.h"
-#include "nsWhitespaceTokenizer.h"
-#include "nsComponentManagerUtils.h"
+#include "nsIPersistentProperties2.h"
+#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::a11y;
void
nsAccUtils::GetAccAttr(nsIPersistentProperties *aAttributes,
nsIAtom *aAttrName, nsAString& aAttrValue)
{
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -2,33 +2,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsAccUtils_h_
#define nsAccUtils_h_
#include "mozilla/a11y/Accessible.h"
-#include "nsIAccessibleText.h"
#include "nsAccessibilityService.h"
#include "nsCoreUtils.h"
-#include "mozilla/dom/Element.h"
#include "nsIDocShell.h"
-#include "nsIPersistentProperties2.h"
-#include "nsIPresShell.h"
#include "nsPoint.h"
-struct nsRoleMapEntry;
+namespace mozilla {
-namespace mozilla {
+namespace dom {
+class Element;
+}
+
namespace a11y {
-class Accessible;
class HyperTextAccessible;
class DocAccessible;
class nsAccUtils
{
public:
/**
* Returns value of attribute from the given attributes container.
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -1,29 +1,20 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAccessNode.h"
-#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "RootAccessible.h"
#include "nsIDocShell.h"
-#include "nsIDOMWindow.h"
-#include "nsIFrame.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIPresShell.h"
-#include "nsIServiceManager.h"
-#include "nsFocusManager.h"
-#include "nsPresContext.h"
-#include "mozilla/Services.h"
using namespace mozilla::a11y;
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
*/
/*
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -5,24 +5,20 @@
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
*/
#ifndef _nsAccessNode_H_
#define _nsAccessNode_H_
-#include "nsIAccessibleTypes.h"
#include "nsINode.h"
class nsIContent;
-class nsIDocShellTreeItem;
class nsIFrame;
-class nsIPresShell;
-class nsPresContext;
namespace mozilla {
namespace a11y {
class DocAccessible;
class RootAccessible;
class nsAccessNode : public nsISupports
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1,93 +1,95 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAccessibilityService.h"
// NOTE: alphabetically ordered
-#include "Accessible-inl.h"
#include "ApplicationAccessibleWrap.h"
#include "ARIAGridAccessibleWrap.h"
#include "ARIAMap.h"
#include "DocAccessible-inl.h"
#include "FocusManager.h"
#include "HTMLCanvasAccessible.h"
#include "HTMLElementAccessibles.h"
#include "HTMLImageMapAccessible.h"
#include "HTMLLinkAccessible.h"
#include "HTMLListAccessible.h"
#include "HTMLSelectAccessible.h"
#include "HTMLTableAccessibleWrap.h"
#include "HyperTextAccessibleWrap.h"
+#include "RootAccessible.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
+#include "nsAttrName.h"
#include "nsEventShell.h"
+#include "nsIURI.h"
#include "OuterDocAccessible.h"
#include "Platform.h"
#include "Role.h"
+#ifdef MOZ_ACCESSIBILITY_ATK
#include "RootAccessibleWrap.h"
+#endif
#include "States.h"
#include "Statistics.h"
#include "TextLeafAccessibleWrap.h"
#ifdef MOZ_ACCESSIBILITY_ATK
#include "AtkSocketAccessible.h"
#endif
#ifdef XP_WIN
#include "mozilla/a11y/Compatibility.h"
#include "HTMLWin32ObjectAccessible.h"
+#include "mozilla/StaticPtr.h"
#endif
#ifdef A11Y_LOG
#include "Logging.h"
#endif
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
-#include "nsIDOMDocument.h"
-#include "nsIDOMHTMLObjectElement.h"
-#include "nsIDOMXULElement.h"
#include "nsImageFrame.h"
#include "nsIObserverService.h"
#include "nsLayoutUtils.h"
-#include "nsNPAPIPluginInstance.h"
#include "nsObjectFrame.h"
#include "nsSVGPathGeometryFrame.h"
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
#include "nsTreeUtils.h"
-#include "nsBindingManager.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLBinding.h"
-#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
#include "mozilla/Util.h"
#include "nsDeckFrame.h"
#ifdef MOZ_XUL
#include "XULAlertAccessible.h"
#include "XULColorPickerAccessible.h"
#include "XULComboboxAccessible.h"
#include "XULElementAccessibles.h"
#include "XULFormControlAccessible.h"
#include "XULListboxAccessibleWrap.h"
#include "XULMenuAccessibleWrap.h"
#include "XULSliderAccessible.h"
#include "XULTabAccessible.h"
#include "XULTreeGridAccessibleWrap.h"
#endif
+#if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
+#include "nsNPAPIPluginInstance.h"
+#endif
+
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// Statics
////////////////////////////////////////////////////////////////////////////////
/**
@@ -1428,16 +1430,22 @@ nsAccessibilityService::CreateHTMLAccess
tag == nsGkAtoms::h5 ||
tag == nsGkAtoms::h6 ||
tag == nsGkAtoms::q) {
nsRefPtr<Accessible> accessible =
new HyperTextAccessibleWrap(aContent, document);
return accessible.forget();
}
+ if (tag == nsGkAtoms::label) {
+ nsRefPtr<Accessible> accessible =
+ new HTMLLabelAccessible(aContent, document);
+ return accessible.forget();
+ }
+
if (tag == nsGkAtoms::output) {
nsRefPtr<Accessible> accessible =
new HTMLOutputAccessible(aContent, document);
return accessible.forget();
}
if (tag == nsGkAtoms::progress) {
nsRefPtr<Accessible> accessible =
@@ -1487,19 +1495,16 @@ nsAccessibilityService::CreateAccessible
newAcc = new HTMLGroupboxAccessible(aContent, document);
break;
case eHTMLHRType:
newAcc = new HTMLHRAccessible(aContent, document);
break;
case eHTMLImageMapType:
newAcc = new HTMLImageMapAccessible(aContent, document);
break;
- case eHTMLLabelType:
- newAcc = new HTMLLabelAccessible(aContent, document);
- break;
case eHTMLLiType:
if (aContext->IsList() &&
aContext->GetContent() == aContent->GetParent()) {
newAcc = new HTMLLIAccessible(aContent, document);
}
break;
case eHTMLSelectListType:
newAcc = new HTMLSelectListAccessible(aContent, document);
--- a/accessible/src/base/nsAccessiblePivot.cpp
+++ b/accessible/src/base/nsAccessiblePivot.cpp
@@ -1,25 +1,20 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#include "nsAccessiblePivot.h"
-#include "DocAccessible.h"
#include "HyperTextAccessible.h"
#include "nsAccUtils.h"
#include "States.h"
-#include "nsArrayUtils.h"
-#include "nsComponentManagerUtils.h"
-#include "nsISupportsPrimitives.h"
-
using namespace mozilla::a11y;
/**
* An object that stores a given traversal rule during
*/
class RuleCache
{
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -10,17 +10,16 @@
#include "nsIAccessiblePivot.h"
#include "Accessible-inl.h"
#include "nsAutoPtr.h"
#include "nsTObserverArray.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
-class nsIAccessibleTraversalRule;
class RuleCache;
/**
* Class represents an accessible pivot.
*/
class nsAccessiblePivot MOZ_FINAL : public nsIAccessiblePivot
{
public:
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -2,46 +2,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCoreUtils.h"
#include "nsIAccessibleTypes.h"
-#include "nsAccessNode.h"
-
#include "nsIBaseWindow.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsRange.h"
-#include "nsIDOMWindow.h"
+#include "nsIBoxObject.h"
#include "nsIDOMXULElement.h"
#include "nsIDocShell.h"
-#include "nsIContentViewer.h"
#include "nsEventListenerManager.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsIScrollableFrame.h"
#include "nsEventStateManager.h"
#include "nsISelectionPrivate.h"
#include "nsISelectionController.h"
-#include "nsPIDOMWindow.h"
#include "nsGUIEvent.h"
#include "nsView.h"
-#include "nsLayoutUtils.h"
#include "nsGkAtoms.h"
#include "nsDOMTouchEvent.h"
#include "nsComponentManagerUtils.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "mozilla/dom/Element.h"
#include "nsITreeBoxObject.h"
#include "nsITreeColumns.h"
using namespace mozilla;
////////////////////////////////////////////////////////////////////////////////
// nsCoreUtils
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -2,24 +2,24 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsCoreUtils_h_
#define nsCoreUtils_h_
#include "nsIContent.h"
-#include "nsIBoxObject.h"
#include "nsIPresShell.h"
#include "nsIDOMDOMStringList.h"
#include "nsPoint.h"
#include "nsTArray.h"
class nsRange;
+class nsIBoxObject;
class nsIFrame;
class nsIDocShell;
class nsITreeColumn;
class nsITreeBoxObject;
class nsIWidget;
/**
* Core utils.
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -4,24 +4,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsTextEquivUtils.h"
#include "Accessible-inl.h"
#include "AccIterator.h"
-#include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
-#include "nsStyleStructInlines.h"
-
+#include "nsCoreUtils.h"
#include "nsIDOMXULLabeledControlEl.h"
-#include "nsArrayUtils.h"
-
using namespace mozilla::a11y;
/**
* The accessible for which we are computing a text equivalent. It is useful
* for bailing out during recursive text computation, or for special cases
* like step f. of the ARIA implementation guide.
*/
static Accessible* sInitiatorAcc = nullptr;
--- a/accessible/src/base/nsTextEquivUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -4,17 +4,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsTextEquivUtils_H_
#define _nsTextEquivUtils_H_
#include "Accessible.h"
-#include "nsIStringBundle.h"
#include "Role.h"
class nsIContent;
/**
* Text equivalent computation rules (see nsTextEquivUtils::gRoleToNameRulesMap)
*/
enum ETextEquivRule
--- a/accessible/src/generic/ARIAGridAccessible.cpp
+++ b/accessible/src/generic/ARIAGridAccessible.cpp
@@ -7,16 +7,17 @@
#include "Accessible-inl.h"
#include "AccIterator.h"
#include "nsAccUtils.h"
#include "Role.h"
#include "States.h"
#include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
#include "nsComponentManagerUtils.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// ARIAGridAccessible
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/generic/DocAccessible-inl.h
+++ b/accessible/src/generic/DocAccessible-inl.h
@@ -6,16 +6,17 @@
#ifndef mozilla_a11y_DocAccessible_inl_h_
#define mozilla_a11y_DocAccessible_inl_h_
#include "DocAccessible.h"
#include "nsAccessibilityService.h"
#include "NotificationController.h"
#include "States.h"
+#include "nsIScrollableFrame.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
namespace mozilla {
namespace a11y {
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -27,16 +27,17 @@
#include "nsIDOMMutationEvent.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMXULPopupElement.h"
#include "nsIEditingSession.h"
#include "nsEventStateManager.h"
#include "nsIFrame.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsINameSpaceManager.h"
+#include "nsIPersistentProperties2.h"
#include "nsIPresShell.h"
#include "nsIServiceManager.h"
#include "nsViewManager.h"
#include "nsIScrollableFrame.h"
#include "nsUnicharUtils.h"
#include "nsIURI.h"
#include "nsIWebNavigation.h"
#include "nsFocusManager.h"
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -20,16 +20,17 @@
#include "nsFocusManager.h"
#include "nsIDOMRange.h"
#include "nsIEditingSession.h"
#include "nsIEditor.h"
#include "nsIFrame.h"
#include "nsFrameSelection.h"
#include "nsILineIterator.h"
#include "nsIInterfaceRequestorUtils.h"
+#include "nsIPersistentProperties2.h"
#include "nsIPlaintextEditor.h"
#include "nsIScrollableFrame.h"
#include "nsIServiceManager.h"
#include "nsTextFragment.h"
#include "mozilla/Selection.h"
#include "gfxSkipChars.h"
#include <algorithm>
--- a/accessible/src/generic/ImageAccessible.cpp
+++ b/accessible/src/generic/ImageAccessible.cpp
@@ -13,16 +13,17 @@
#include "imgIContainer.h"
#include "imgIRequest.h"
#include "nsGenericHTMLElement.h"
#include "nsIDocument.h"
#include "nsIImageLoadingContent.h"
#include "nsIPresShell.h"
#include "nsIServiceManager.h"
#include "nsIDOMHTMLImageElement.h"
+#include "nsIPersistentProperties2.h"
#include "nsPIDOMWindow.h"
#include "nsIURI.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// ImageAccessible
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/html/HTMLElementAccessibles.cpp
+++ b/accessible/src/html/HTMLElementAccessibles.cpp
@@ -3,16 +3,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HTMLElementAccessibles.h"
#include "DocAccessible.h"
#include "nsAccUtils.h"
#include "nsIAccessibleRelation.h"
+#include "nsIPersistentProperties2.h"
#include "nsTextEquivUtils.h"
#include "Relation.h"
#include "Role.h"
#include "States.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -18,16 +18,17 @@
#include "nsCxPusher.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "nsIAccessibleRelation.h"
#include "nsIDOMNSEditableElement.h"
#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIEditor.h"
#include "nsIFormControl.h"
#include "nsINameSpaceManager.h"
+#include "nsIPersistentProperties2.h"
#include "nsISelectionController.h"
#include "jsapi.h"
#include "nsIServiceManager.h"
#include "nsITextControlFrame.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -23,16 +23,17 @@
#include "nsIDOMDocument.h"
#include "nsIDOMRange.h"
#include "nsISelectionPrivate.h"
#include "nsINameSpaceManager.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMHTMLCollection.h"
#include "nsIDocument.h"
#include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
#include "nsIPresShell.h"
#include "nsITableCellLayout.h"
#include "nsFrameSelection.h"
#include "nsError.h"
#include "nsArrayUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsTableCellFrame.h"
#include "nsTableOuterFrame.h"
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -8,16 +8,17 @@
#import "MacUtils.h"
#import "mozView.h"
#include "Accessible-inl.h"
#include "nsAccUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleEditableText.h"
+#include "nsIPersistentProperties2.h"
#include "Relation.h"
#include "Role.h"
#include "RootAccessible.h"
#include "mozilla/Services.h"
#include "nsRect.h"
#include "nsCocoaUtils.h"
#include "nsCoord.h"
--- a/accessible/src/mac/mozTextAccessible.mm
+++ b/accessible/src/mac/mozTextAccessible.mm
@@ -1,16 +1,17 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Accessible-inl.h"
#include "AccessibleWrap.h"
#include "TextLeafAccessible.h"
+#include "nsIAccessibleTypes.h"
#include "nsCocoaUtils.h"
#include "nsObjCExceptions.h"
#import "mozTextAccessible.h"
using namespace mozilla::a11y;
--- a/accessible/src/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleText.cpp
@@ -8,16 +8,17 @@
#include "ia2AccessibleText.h"
#include "Accessible2.h"
#include "AccessibleText_i.c"
#include "HyperTextAccessibleWrap.h"
#include "nsIPersistentProperties2.h"
+#include "nsIAccessibleTypes.h"
using namespace mozilla::a11y;
// IAccessibleText
STDMETHODIMP
ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset)
{
--- a/accessible/src/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/AccessibleWrap.cpp
@@ -37,16 +37,18 @@
#include "nsEventMap.h"
#include "nsArrayUtils.h"
#include "mozilla/Preferences.h"
#include "Accessible2_i.c"
#include "AccessibleRole.h"
#include "AccessibleStates.h"
#include "oleacc.h"
+#include "nsIAccessibleTypes.h"
+#include "nsIPersistentProperties2.h"
using namespace mozilla;
using namespace mozilla::a11y;
const uint32_t USE_ROLE_STRING = 0;
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
--- a/accessible/src/windows/sdn/sdnAccessible.cpp
+++ b/accessible/src/windows/sdn/sdnAccessible.cpp
@@ -6,16 +6,17 @@
#include "sdnAccessible-inl.h"
#include "ISimpleDOMNode_i.c"
#include "DocAccessibleWrap.h"
#include "nsAttrName.h"
#include "nsCoreUtils.h"
+#include "nsIAccessibleTypes.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsServiceManagerUtils.h"
#include "nsWinUtils.h"
#include "nsAutoPtr.h"
#include "mozilla/dom/Element.h"
--- a/accessible/src/windows/sdn/sdnTextAccessible.cpp
+++ b/accessible/src/windows/sdn/sdnTextAccessible.cpp
@@ -11,16 +11,17 @@
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "nsIFrame.h"
#include "nsFontMetrics.h"
#include "nsPresContext.h"
#include "nsLayoutUtils.h"
#include "gfxFont.h"
+#include "nsIAccessibleTypes.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// sdnTextAccessible
////////////////////////////////////////////////////////////////////////////////
IMPL_IUNKNOWN_QUERY_HEAD(sdnTextAccessible)
--- a/accessible/src/xul/XULFormControlAccessible.cpp
+++ b/accessible/src/xul/XULFormControlAccessible.cpp
@@ -23,16 +23,17 @@
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDOMXULTextboxElement.h"
#include "nsIEditor.h"
#include "nsIFrame.h"
#include "nsINameSpaceManager.h"
#include "nsITextControlFrame.h"
#include "nsMenuPopupFrame.h"
+#include "mozilla/dom/Element.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// XULButtonAccessible
////////////////////////////////////////////////////////////////////////////////
XULButtonAccessible::
--- a/accessible/src/xul/XULListboxAccessible.cpp
+++ b/accessible/src/xul/XULListboxAccessible.cpp
@@ -16,16 +16,17 @@
#include "nsIAutoCompleteInput.h"
#include "nsIAutoCompletePopup.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMXULPopupElement.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// XULColumAccessible
////////////////////////////////////////////////////////////////////////////////
XULColumAccessible::
--- a/accessible/src/xul/XULSliderAccessible.cpp
+++ b/accessible/src/xul/XULSliderAccessible.cpp
@@ -5,16 +5,17 @@
#include "XULSliderAccessible.h"
#include "nsAccessibilityService.h"
#include "Role.h"
#include "States.h"
#include "nsIFrame.h"
+#include "mozilla/dom/Element.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// XULSliderAccessible
////////////////////////////////////////////////////////////////////////////////
XULSliderAccessible::
--- a/accessible/src/xul/XULTreeAccessible.cpp
+++ b/accessible/src/xul/XULTreeAccessible.cpp
@@ -16,16 +16,17 @@
#include "Relation.h"
#include "Role.h"
#include "States.h"
#include "nsComponentManagerUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsIAutoCompleteInput.h"
#include "nsIAutoCompletePopup.h"
+#include "nsIBoxObject.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIDOMXULTreeElement.h"
#include "nsITreeSelection.h"
#include "nsIMutableArray.h"
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
--- a/accessible/src/xul/XULTreeGridAccessible.cpp
+++ b/accessible/src/xul/XULTreeGridAccessible.cpp
@@ -9,17 +9,19 @@
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "DocAccessible.h"
#include "nsEventShell.h"
#include "Relation.h"
#include "Role.h"
#include "States.h"
+#include "nsIBoxObject.h"
#include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
#include "nsITreeSelection.h"
#include "nsComponentManagerUtils.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// XULTreeGridAccessible: nsISupports implementation
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -68,17 +68,17 @@ pref("browser.sessionstore.resume_from_c
pref("browser.sessionstore.interval", 10000); // milliseconds
pref("browser.sessionstore.max_tabs_undo", 1);
/* these should help performance */
pref("mozilla.widget.force-24bpp", true);
pref("mozilla.widget.use-buffer-pixmap", true);
pref("mozilla.widget.disable-native-theme", true);
pref("layout.reflow.synthMouseMove", false);
-pref("layers.force-tiles", false);
+pref("layers.force-tiles", true);
/* download manager (don't show the window or alert) */
pref("browser.download.useDownloadDir", true);
pref("browser.download.folderList", 1); // Default to ~/Downloads
pref("browser.download.manager.showAlertOnComplete", false);
pref("browser.download.manager.showAlertInterval", 2000);
pref("browser.download.manager.retention", 2);
pref("browser.download.manager.showWhenStarting", false);
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
{
- "revision": "9e3d2b3f6706916168b9ad9bb96084c01df8771f",
+ "revision": "af6b88994605d8833693cde83e43fe3d9e93d181",
"repo_path": "/integration/gaia-central"
}
--- a/browser/base/content/test/browser_tabopen_reflows.js
+++ b/browser/base/content/test/browser_tabopen_reflows.js
@@ -33,18 +33,17 @@ const EXPECTED_REFLOWS = [
"GroupItem_getContentBounds@chrome://browser/content/tabview.js|" +
"GroupItem_shouldStack@chrome://browser/content/tabview.js|" +
"GroupItem_arrange@chrome://browser/content/tabview.js|" +
"GroupItem_add@chrome://browser/content/tabview.js|" +
"GroupItems_newTab@chrome://browser/content/tabview.js|" +
"TabItem__reconnect@chrome://browser/content/tabview.js|" +
"TabItem@chrome://browser/content/tabview.js|" +
"TabItems_link@chrome://browser/content/tabview.js|" +
- "@chrome://browser/content/tabview.js|" +
- "addTab@chrome://browser/content/tabbrowser.xml|",
+ "@chrome://browser/content/tabview.js|",
// SessionStore.getWindowDimensions()
"ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" +
"@resource:///modules/sessionstore/SessionStore.jsm|" +
"ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
"ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|",
// tabPreviews.capture()
@@ -83,31 +82,32 @@ function test() {
}
let observer = {
reflow: function (start, end) {
// Gather information about the current code path.
let path = (new Error().stack).split("\n").slice(1).map(line => {
return line.replace(/:\d+$/, "");
}).join("|");
+ let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
// Stack trace is empty. Reflow was triggered by native code.
if (path === "") {
return;
}
// Check if this is an expected reflow.
for (let stack of EXPECTED_REFLOWS) {
if (path.startsWith(stack)) {
ok(true, "expected uninterruptible reflow '" + stack + "'");
return;
}
}
- ok(false, "unexpected uninterruptible reflow '" + path + "'");
+ ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
},
reflowInterruptible: function (start, end) {
// We're not interested in interruptible reflows.
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
Ci.nsISupportsWeakReference])
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -364,16 +364,23 @@ WebContentConverterRegistrar.prototype =
/**
* See nsIWebContentHandlerRegistrar
*/
registerProtocolHandler:
function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
+ var uri = this._checkAndGetURI(aURIString, aContentWindow);
+
+ // If the protocol handler is already registered, just return early.
+ if (this._protocolHandlerRegistered(aProtocol, uri.spec)) {
+ return;
+ }
+
var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
if (PrivateBrowsingUtils.isWindowPrivate(browserWindow)) {
// Inside the private browsing mode, we don't want to alert the user to save
// a protocol handler. We log it to the error console so that web developers
// would have some way to tell what's going wrong.
Cc["@mozilla.org/consoleservice;1"].
getService(Ci.nsIConsoleService).
logStringMessage("Web page denied access to register a protocol handler inside private browsing mode");
@@ -401,35 +408,28 @@ WebContentConverterRegistrar.prototype =
catch (e) {
allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
}
if (!allowed) {
// XXX this should be a "security exception" according to spec
throw("Not allowed to register a protocol handler for " + aProtocol);
}
- var uri = this._checkAndGetURI(aURIString, aContentWindow);
+ // Now Ask the user and provide the proper callback
+ var message = this._getFormattedString("addProtocolHandler",
+ [aTitle, uri.host, aProtocol]);
- var buttons, message;
- if (this._protocolHandlerRegistered(aProtocol, uri.spec))
- message = this._getFormattedString("protocolHandlerRegistered",
- [aTitle, aProtocol]);
- else {
- // Now Ask the user and provide the proper callback
- message = this._getFormattedString("addProtocolHandler",
- [aTitle, uri.host, aProtocol]);
+ var notificationIcon = uri.prePath + "/favicon.ico";
+ var notificationValue = "Protocol Registration: " + aProtocol;
+ var addButton = {
+ label: this._getString("addProtocolHandlerAddButton"),
+ accessKey: this._getString("addHandlerAddButtonAccesskey"),
+ protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
- var notificationIcon = uri.prePath + "/favicon.ico";
- var notificationValue = "Protocol Registration: " + aProtocol;
- var addButton = {
- label: this._getString("addProtocolHandlerAddButton"),
- accessKey: this._getString("addHandlerAddButtonAccesskey"),
- protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
-
- callback:
+ callback:
function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
var protocol = aButtonInfo.protocolInfo.protocol;
var uri = aButtonInfo.protocolInfo.uri;
var name = aButtonInfo.protocolInfo.name;
var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
createInstance(Ci.nsIWebHandlerApp);
handler.name = name;
@@ -445,21 +445,18 @@ WebContentConverterRegistrar.prototype =
// to want to use it. Reset the handlerInfo to ask before the next
// use.
handlerInfo.alwaysAskBeforeHandling = true;
var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
hs.store(handlerInfo);
}
- };
- buttons = [addButton];
- }
-
-
+ };
+ var buttons;
var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
notificationBox.appendNotification(message,
notificationValue,
notificationIcon,
notificationBox.PRIORITY_INFO_LOW,
buttons);
},
--- a/browser/components/sessionstore/test/browser_483330.js
+++ b/browser/components/sessionstore/test/browser_483330.js
@@ -23,15 +23,18 @@ function test() {
let newBrowser = newTab.linkedBrowser;
// check that the scroll position was restored
is(newBrowser.contentWindow.scrollX, 1100, "still scrolled horizontally");
is(newBrowser.contentWindow.scrollY, 1200, "still scrolled vertically");
gBrowser.removeTab(newTab);
+ // Call stopPropagation on the event so we won't fire the
+ // tabbrowser's SSTabRestored listeners.
+ e.stopPropagation();
finish();
}, true);
}, true);
browser.loadURI("data:text/html;charset=utf-8,<body style='width: 100000px; height: 100000px;'><p>top</p></body>");
}
--- a/browser/components/sessionstore/test/browser_491168.js
+++ b/browser/components/sessionstore/test/browser_491168.js
@@ -19,27 +19,34 @@ function test() {
let tabState = JSON.parse(ss.getTabState(tab));
is(tabState.entries[0].referrer, REFERRER1,
"Referrer retrieved via getTabState matches referrer set via loadURI.");
tabState.entries[0].referrer = REFERRER2;
ss.setTabState(tab, JSON.stringify(tabState));
- tab.addEventListener("SSTabRestored", function() {
+ tab.addEventListener("SSTabRestored", function(e) {
tab.removeEventListener("SSTabRestored", arguments.callee, true);
is(window.content.document.referrer, REFERRER2, "document.referrer matches referrer set via setTabState.");
gBrowser.removeTab(tab);
+ // Call stopPropagation on the event so we won't fire the
+ // tabbrowser's SSTabRestored listeners.
+ e.stopPropagation();
+
let newTab = ss.undoCloseTab(window, 0);
- newTab.addEventListener("SSTabRestored", function() {
+ newTab.addEventListener("SSTabRestored", function(e) {
newTab.removeEventListener("SSTabRestored", arguments.callee, true);
is(window.content.document.referrer, REFERRER2, "document.referrer is still correct after closing and reopening the tab.");
gBrowser.removeTab(newTab);
+ // Call stopPropagation on the event so we won't fire the
+ // tabbrowser's SSTabRestored listeners.
+ e.stopPropagation();
finish();
}, true);
}, true);
},true);
let referrerURI = Services.io.newURI(REFERRER1, null, null);
browser.loadURI("http://example.org", referrerURI, null);
--- a/browser/components/sessionstore/test/browser_662743.js
+++ b/browser/components/sessionstore/test/browser_662743.js
@@ -93,16 +93,19 @@ function testTabRestoreData(aFormData, a
let value = select.options[select.selectedIndex].value;
// test select options values
is(value, aExpectedValues[0],
"Select Option by selectedIndex &/or value has been restored correctly");
// clean up
gBrowser.removeTab(tab);
+ // Call stopPropagation on the event so we won't fire the
+ // tabbrowser's SSTabRestored listeners.
+ aEvent.stopPropagation();
aCallback();
});
tab.addEventListener("TabClose", function(aEvent) {
tab.removeEventListener("TabClose", arguments.callee);
let restoredTabState = JSON.parse(ss.getTabState(tab));
let restoredFormData = restoredTabState.entries[0].formdata;
let selectIdFormData = restoredFormData.id.select_id;
--- a/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
+++ b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
@@ -44,10 +44,8 @@ feedSubscriptionVideoPodcast1=This is a
feedSubscriptionFeed2=You can subscribe to this feed to receive updates when this content changes.
feedSubscriptionAudioPodcast2=You can subscribe to this podcast to receive updates when this content changes.
feedSubscriptionVideoPodcast2=You can subscribe to this video podcast to receive updates when this content changes.
# Protocol Handling
# "Add %appName (%appDomain) as an application for %protocolType links?"
addProtocolHandler=Add %S (%S) as an application for %S links?
addProtocolHandlerAddButton=Add Application
-# "%appName has already been added as an application for %protocolType links."
-protocolHandlerRegistered=%S has already been added as an application for %S links.
--- a/build/pymake/pymake/parser.py
+++ b/build/pymake/pymake/parser.py
@@ -367,16 +367,19 @@ def parsefile(pathname):
"""
Parse a filename into a parserdata.StatementList. A cache is used to avoid re-parsing
makefiles that have already been parsed and have not changed.
"""
pathname = os.path.realpath(pathname)
return _parsecache.get(pathname)
+# colon followed by anything except a slash (Windows path detection)
+_depfilesplitter = re.compile(r':(?![\\/])')
+
def parsedepfile(pathname):
"""
Parse a filename listing only depencencies into a parserdata.StatementList.
"""
def continuation_iter(lines):
current_line = []
for line in lines:
line = line.rstrip()
@@ -389,17 +392,17 @@ def parsedepfile(pathname):
yield ''.join(current_line)
current_line = []
if current_line:
yield ''.join(current_line)
pathname = os.path.realpath(pathname)
stmts = parserdata.StatementList()
for line in continuation_iter(open(pathname).readlines()):
- target, deps = line.split(":", 1)
+ target, deps = _depfilesplitter.split(line, 1)
stmts.append(parserdata.Rule(data.StringExpansion(target, None),
data.StringExpansion(deps, None), False))
return stmts
def parsestring(s, filename):
"""
Parse a string containing makefile data into a parserdata.StatementList.
"""
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -49,21 +49,21 @@ INCLUDED_RULES_MK = 1
XPIDL_FLAGS \
$(NULL)
ifndef EXTERNALLY_MANAGED_MAKE_FILE
# Using $(firstword) may not be perfect. But it should be good enough for most
# scenarios.
_current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
-$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
$(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
))
-$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
$(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
))
ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
$(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
endif
# Import the automatically generated backend file. If this file doesn't exist,
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -41,16 +41,17 @@ class nsIFrame;
class nsIMutationObserver;
class nsINodeList;
class nsIPresShell;
class nsIPrincipal;
class nsIURI;
class nsNodeSupportsWeakRefTearoff;
class nsNodeWeakReference;
class nsXPCClassInfo;
+class nsDOMMutationObserver;
namespace mozilla {
namespace dom {
/**
* @return true if aChar is what the DOM spec defines as 'space character'.
* http://dom.spec.whatwg.org/#space-character
*/
inline bool IsSpaceCharacter(PRUnichar aChar) {
@@ -1469,16 +1470,18 @@ protected:
public:
// Makes nsINode object to keep aObject alive.
void BindObject(nsISupports* aObject);
// After calling UnbindObject nsINode object doesn't keep
// aObject alive anymore.
void UnbindObject(nsISupports* aObject);
+ void GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult);
+
/**
* Returns the length of this node, as specified at
* <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
*/
uint32_t Length() const;
void GetNodeName(nsAString& aNodeName) const
{
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -61,17 +61,16 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(
// Observer
NS_IMPL_ADDREF(nsMutationReceiver)
NS_IMPL_RELEASE(nsMutationReceiver)
NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
- NS_INTERFACE_MAP_ENTRY(nsMutationReceiver)
NS_INTERFACE_MAP_END
nsMutationReceiver::nsMutationReceiver(nsINode* aTarget,
nsDOMMutationObserver* aObserver)
: nsMutationReceiverBase(aTarget, aObserver)
{
mTarget->BindObject(aObserver);
}
@@ -316,16 +315,17 @@ void nsMutationReceiver::NodeWillBeDestr
Disconnect(true);
}
// Observer
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsDOMMutationObserver)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationObserver)
@@ -520,16 +520,42 @@ nsDOMMutationObserver::Disconnect()
void
nsDOMMutationObserver::TakeRecords(
nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal)
{
aRetVal.Clear();
mPendingMutations.SwapElements(aRetVal);
}
+void
+nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfoInitializer> >& aResult)
+{
+ aResult.SetCapacity(mReceivers.Count());
+ for (int32_t i = 0; i < mReceivers.Count(); ++i) {
+ MutationObservingInfoInitializer& info = aResult.AppendElement()->SetValue();
+ nsMutationReceiver* mr = mReceivers[i];
+ info.mChildList = mr->ChildList();
+ info.mAttributes = mr->Attributes();
+ info.mCharacterData = mr->CharacterData();
+ info.mSubtree = mr->Subtree();
+ info.mAttributeOldValue = mr->AttributeOldValue();
+ info.mCharacterDataOldValue = mr->CharacterDataOldValue();
+ nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
+ if (filters.Count()) {
+ info.mAttributeFilter.Construct();
+ mozilla::dom::Sequence<nsString>& filtersAsStrings =
+ info.mAttributeFilter.Value();
+ for (int32_t j = 0; j < filters.Count(); ++j) {
+ filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]));
+ }
+ }
+ info.mObservedNode = mr->Target();
+ }
+}
+
// static
already_AddRefed<nsDOMMutationObserver>
nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
mozilla::dom::MutationCallback& aCb,
mozilla::ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
--- a/content/base/src/nsDOMMutationObserver.h
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -20,16 +20,17 @@
#include "mozilla/dom/Element.h"
#include "nsClassHashtable.h"
#include "nsNodeUtils.h"
#include "nsIDOMMutationEvent.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/MutationObserverBinding.h"
class nsDOMMutationObserver;
+using mozilla::dom::MutationObservingInfoInitializer;
class nsDOMMutationRecord : public nsISupports,
public nsWrapperCache
{
public:
nsDOMMutationRecord(const nsAString& aType, nsISupports* aOwner)
: mType(aType), mOwner(aOwner)
{
@@ -262,20 +263,16 @@ private:
bool mCharacterDataOldValue;
bool mAttributes;
bool mAllAttributes;
bool mAttributeOldValue;
nsCOMArray<nsIAtom> mAttributeFilter;
};
-#define NS_MUTATION_OBSERVER_IID \
-{ 0xe628f313, 0x8129, 0x4f90, \
- { 0x8e, 0xc3, 0x85, 0xe8, 0x28, 0x22, 0xe7, 0xab } }
-
class nsMutationReceiver : public nsMutationReceiverBase
{
public:
nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
: nsMutationReceiverBase(aRegisterTarget, aParent)
{
@@ -310,17 +307,16 @@ public:
mParent = nullptr;
NS_ASSERTION(!mTarget, "Should not have mTarget");
NS_ASSERTION(!mObserver, "Should not have mObserver");
}
void Disconnect(bool aRemoveFromObserver);
- NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_IID)
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
@@ -332,31 +328,34 @@ public:
nsIAtom* aAttribute) MOZ_OVERRIDE
{
// We can reuse AttributeWillChange implementation.
AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
nsIDOMMutationEvent::MODIFICATION);
}
};
-NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)
+#define NS_DOM_MUTATION_OBSERVER_IID \
+{ 0x0c3b91f8, 0xcc3b, 0x4b08, \
+ { 0x9e, 0xab, 0x07, 0x47, 0xa9, 0xe4, 0x65, 0xb4 } }
class nsDOMMutationObserver : public nsISupports,
public nsWrapperCache
{
public:
nsDOMMutationObserver(already_AddRefed<nsPIDOMWindow> aOwner,
mozilla::dom::MutationCallback& aCb)
: mOwner(aOwner), mCallback(&aCb), mWaitingForRun(false), mId(++sCount)
{
SetIsDOMBinding();
}
virtual ~nsDOMMutationObserver();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationObserver)
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_MUTATION_OBSERVER_IID)
static already_AddRefed<nsDOMMutationObserver>
Constructor(const mozilla::dom::GlobalObject& aGlobal,
mozilla::dom::MutationCallback& aCb,
mozilla::ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
@@ -374,16 +373,20 @@ public:
mozilla::ErrorResult& aRv);
void Disconnect();
void TakeRecords(nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal);
void HandleMutation();
+ void GetObservingInfo(nsTArray<Nullable<MutationObservingInfoInitializer> >& aResult);
+
+ mozilla::dom::MutationCallback* MutationCallback() { return mCallback; }
+
// static methods
static void HandleMutations()
{
if (sScheduledMutationObservers) {
HandleMutationsInternal();
}
}
@@ -440,16 +443,18 @@ protected:
static nsTArray<nsRefPtr<nsDOMMutationObserver> >* sScheduledMutationObservers;
static nsDOMMutationObserver* sCurrentObserver;
static uint32_t sMutationLevel;
static nsAutoTArray<nsTArray<nsRefPtr<nsDOMMutationObserver> >, 4>*
sCurrentlyHandlingObservers;
};
+NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMMutationObserver, NS_DOM_MUTATION_OBSERVER_IID)
+
class nsAutoMutationBatch
{
public:
nsAutoMutationBatch()
: mPreviousBatch(nullptr), mBatchTarget(nullptr), mRemovalDone(false),
mFromFirstToLast(false), mAllowNestedBatches(false)
{
}
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -98,16 +98,17 @@
#include "nsCSSParser.h"
#include "HTMLLegendElement.h"
#include "nsWrapperCacheInlines.h"
#include "WrapperFactory.h"
#include "DocumentType.h"
#include <algorithm>
#include "nsDOMEvent.h"
#include "nsGlobalWindow.h"
+#include "nsDOMMutationObserver.h"
using namespace mozilla;
using namespace mozilla::dom;
nsINode::nsSlots::~nsSlots()
{
if (mChildNodes) {
mChildNodes->DropReference();
@@ -2139,16 +2140,32 @@ nsINode::UnbindObject(nsISupports* aObje
{
nsCOMArray<nsISupports>* objects =
static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
if (objects) {
objects->RemoveObject(aObject);
}
}
+void
+nsINode::GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult)
+{
+ nsCOMArray<nsISupports>* objects =
+ static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
+ if (objects) {
+ for (int32_t i = 0; i < objects->Count(); ++i) {
+ nsCOMPtr<nsDOMMutationObserver> mo = do_QueryInterface(objects->ObjectAt(i));
+ if (mo) {
+ MOZ_ASSERT(!aResult.Contains(mo));
+ aResult.AppendElement(mo.forget());
+ }
+ }
+ }
+}
+
size_t
nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
nsEventListenerManager* elm =
const_cast<nsINode*>(this)->GetListenerManager(false);
if (elm) {
n += elm->SizeOfIncludingThis(aMallocSizeOf);
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -12,16 +12,17 @@
#include "jsfriendapi.h"
#include "nsScriptLoader.h"
#include "nsICharsetConverterManager.h"
#include "nsIUnicodeDecoder.h"
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
#include "nsGkAtoms.h"
#include "nsNetUtil.h"
+#include "nsIJSRuntimeService.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsContentPolicyUtils.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
@@ -93,16 +94,17 @@ public:
nsCOMPtr<nsIScriptElement> mElement;
bool mLoading; // Are we still waiting for a load to complete?
bool mIsInline; // Is the script inline or loaded?
nsString mScriptText; // Holds script for loaded scripts
uint32_t mJSVersion;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
+ nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
int32_t mLineNo;
const CORSMode mCORSMode;
};
// The nsScriptLoadRequest is passed as the context to necko, and thus
// it needs to be threadsafe. Necko won't do anything with this
// context, but it will AddRef and Release it on other threads.
NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
@@ -686,22 +688,132 @@ nsScriptLoader::ProcessScriptElement(nsI
// there's no document.write currently on the call stack. However,
// this way matches IE more closely than checking if document.write
// is on the call stack.
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Not safe to run a parser-inserted script?");
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
+namespace {
+
+class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable
+{
+ nsRefPtr<nsScriptLoader> mLoader;
+ void *mToken;
+
+public:
+ NotifyOffThreadScriptLoadCompletedRunnable(already_AddRefed<nsScriptLoader> aLoader,
+ void *aToken)
+ : mLoader(aLoader), mToken(aToken)
+ {}
+
+ NS_DECL_NSIRUNNABLE
+};
+
+} /* anonymous namespace */
+
nsresult
-nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
+nsScriptLoader::ProcessOffThreadRequest(void **aOffThreadToken)
+{
+ nsCOMPtr<nsScriptLoadRequest> request = mOffThreadScriptRequest;
+ mOffThreadScriptRequest = nullptr;
+ mDocument->UnblockOnload(false);
+
+ return ProcessRequest(request, aOffThreadToken);
+}
+
+NS_IMETHODIMP
+NotifyOffThreadScriptLoadCompletedRunnable::Run()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsresult rv = mLoader->ProcessOffThreadRequest(&mToken);
+
+ if (mToken) {
+ // The result of the off thread parse was not actually needed to process
+ // the request (disappearing window, some other error, ...). Finish the
+ // request to avoid leaks in the JS engine.
+ nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+ NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
+ JSRuntime *rt;
+ svc->GetRuntime(&rt);
+ NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
+ JS::FinishOffThreadScript(nullptr, rt, mToken);
+ }
+
+ return rv;
+}
+
+static void
+OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
+{
+ // Be careful not to adjust the refcount on the loader, as this callback
+ // may be invoked off the main thread.
+ nsScriptLoader* aLoader = static_cast<nsScriptLoader*>(aCallbackData);
+ nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> notify =
+ new NotifyOffThreadScriptLoadCompletedRunnable(
+ already_AddRefed<nsScriptLoader>(aLoader), aToken);
+ NS_DispatchToMainThread(notify);
+}
+
+nsresult
+nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
+{
+ if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (mOffThreadScriptRequest) {
+ return NS_ERROR_FAILURE;
+ }
+
+ JSObject *unrootedGlobal;
+ nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal);
+ if (!context) {
+ return NS_ERROR_FAILURE;
+ }
+ AutoPushJSContext cx(context->GetNativeContext());
+ JS::Rooted<JSObject*> global(cx, unrootedGlobal);
+
+ JS::CompileOptions options(cx);
+ FillCompileOptionsForRequest(aRequest, &options);
+
+ if (!JS::CanCompileOffThread(cx, options)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mOffThreadScriptRequest = aRequest;
+ if (!JS::CompileOffThread(cx, global, options,
+ aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
+ OffThreadScriptLoaderCallback,
+ static_cast<void*>(this))) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // This reference will be consumed by the NotifyOffThreadScriptLoadCompletedRunnable.
+ NS_ADDREF(this);
+
+ mDocument->BlockOnload();
+
+ return NS_OK;
+}
+
+nsresult
+nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken)
{
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Processing requests when running scripts is unsafe.");
+ if (!aOffThreadToken) {
+ nsresult rv = AttemptAsyncScriptParse(aRequest);
+ if (rv != NS_ERROR_FAILURE)
+ return rv;
+ }
+
NS_ENSURE_ARG(aRequest);
nsAFlatString* script;
nsAutoString textData;
nsCOMPtr<nsIDocument> doc;
nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->mElement);
@@ -746,17 +858,17 @@ nsScriptLoader::ProcessRequest(nsScriptL
}
nsresult rv = NS_OK;
if (runScript) {
if (doc) {
doc->BeginEvaluatingExternalScript();
}
aRequest->mElement->BeginEvaluating();
- rv = EvaluateScript(aRequest, *script);
+ rv = EvaluateScript(aRequest, *script, aOffThreadToken);
aRequest->mElement->EndEvaluating();
if (doc) {
doc->EndEvaluatingExternalScript();
}
nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
scriptElem,
NS_LITERAL_STRING("afterscriptexecute"),
@@ -794,80 +906,97 @@ nsScriptLoader::FireScriptEvaluated(nsre
nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
obs->ScriptEvaluated(aResult, aRequest->mElement,
aRequest->mIsInline);
}
aRequest->FireScriptEvaluated(aResult);
}
+nsIScriptContext *
+nsScriptLoader::GetScriptContext(JSObject **aGlobal)
+{
+ nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
+ NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
+
+ nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
+ NS_ASSERTION(globalObject, "windows must be global objects");
+
+ // and make sure we are setup for this type of script.
+ nsresult rv = globalObject->EnsureScriptEnvironment();
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+
+ *aGlobal = globalObject->GetGlobalJSObject();
+ return globalObject->GetScriptContext();
+}
+
+void
+nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
+ JS::CompileOptions *aOptions)
+{
+ // It's very important to use aRequest->mURI, not the final URI of the channel
+ // aRequest ended up getting script data from, as the script filename.
+ nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, aRequest->mURL);
+
+ aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
+ aOptions->setVersion(JSVersion(aRequest->mJSVersion));
+ if (aRequest->mOriginPrincipal) {
+ aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
+ }
+}
+
nsresult
nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
- const nsAFlatString& aScript)
+ const nsAFlatString& aScript,
+ void** aOffThreadToken)
{
nsresult rv = NS_OK;
// We need a document to evaluate scripts.
if (!mDocument) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
nsIDocument* ownerDoc = scriptContent->OwnerDoc();
if (ownerDoc != mDocument) {
// Willful violation of HTML5 as of 2010-12-01
return NS_ERROR_FAILURE;
}
- nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
- NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
-
- nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
- NS_ASSERTION(globalObject, "windows must be global objects");
-
// Get the script-type to be used by this element.
NS_ASSERTION(scriptContent, "no content - what is default script-type?");
- // and make sure we are setup for this type of script.
- rv = globalObject->EnsureScriptEnvironment();
- if (NS_FAILED(rv))
- return rv;
-
// Make sure context is a strong reference since we access it after
// we've executed a script, which may cause all other references to
// the context to go away.
- nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext();
+ JSObject *unrootedGlobal;
+ nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal);
if (!context) {
return NS_ERROR_FAILURE;
}
AutoPushJSContext cx(context->GetNativeContext());
+ JS::Rooted<JSObject*> global(cx, unrootedGlobal);
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
context->SetProcessingScriptTag(true);
// Update our current script.
nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
mCurrentScript = aRequest->mElement;
- // It's very important to use aRequest->mURI, not the final URI of the channel
- // aRequest ended up getting script data from, as the script filename.
- nsAutoCString url;
- nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, url);
-
JSVersion version = JSVersion(aRequest->mJSVersion);
if (version != JSVERSION_UNKNOWN) {
JS::CompileOptions options(cx);
- options.setFileAndLine(url.get(), aRequest->mLineNo)
- .setVersion(JSVersion(aRequest->mJSVersion));
- if (aRequest->mOriginPrincipal) {
- options.setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
- }
- JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
+ FillCompileOptionsForRequest(aRequest, &options);
rv = context->EvaluateString(aScript, global,
- options, /* aCoerceToString = */ false, nullptr);
+ options, /* aCoerceToString = */ false, nullptr,
+ aOffThreadToken);
}
// Put the old script back in case it wants to do anything else.
mCurrentScript = oldCurrent;
context->SetProcessingScriptTag(oldProcessingScriptTag);
return rv;
}
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -202,16 +202,22 @@ public:
* Void if not present.
* @param aScriptFromHead Whether or not the script was a child of head
*/
virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
const nsAString &aType,
const nsAString &aCrossOrigin,
bool aScriptFromHead);
+ /**
+ * Process a request that was deferred so that the script could be compiled
+ * off thread.
+ */
+ nsresult ProcessOffThreadRequest(void **aOffThreadToken);
+
private:
/**
* Unblocks the creator parser of the parser-blocking scripts.
*/
void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
/**
* Asynchronously resumes the creator parser of the parser-blocking scripts.
@@ -256,24 +262,31 @@ private:
bool SelfReadyToExecuteScripts()
{
return mEnabled && !mBlockerCount;
}
bool AddPendingChildLoader(nsScriptLoader* aChild) {
return mPendingChildLoaders.AppendElement(aChild) != nullptr;
}
-
- nsresult ProcessRequest(nsScriptLoadRequest* aRequest);
+
+ nsresult AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest);
+ nsresult ProcessRequest(nsScriptLoadRequest* aRequest,
+ void **aOffThreadToken = nullptr);
void FireScriptAvailable(nsresult aResult,
nsScriptLoadRequest* aRequest);
void FireScriptEvaluated(nsresult aResult,
nsScriptLoadRequest* aRequest);
nsresult EvaluateScript(nsScriptLoadRequest* aRequest,
- const nsAFlatString& aScript);
+ const nsAFlatString& aScript,
+ void **aOffThreadToken);
+
+ nsIScriptContext *GetScriptContext(JSObject **aGlobal);
+ void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
+ JS::CompileOptions *aOptions);
nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
nsIStreamLoader* aLoader,
nsresult aStatus,
uint32_t aStringLen,
const uint8_t* aString);
nsIDocument* mDocument; // [WEAK]
@@ -297,16 +310,17 @@ private:
return aRequest == aPi.mRequest;
}
};
struct PreloadURIComparator {
bool Equals(const PreloadInfo &aPi, nsIURI * const &aURI) const;
};
nsTArray<PreloadInfo> mPreloads;
+ nsCOMPtr<nsScriptLoadRequest> mOffThreadScriptRequest;
nsCOMPtr<nsIScriptElement> mCurrentScript;
nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
// XXXbz do we want to cycle-collect these or something? Not sure.
nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
uint32_t mBlockerCount;
bool mEnabled;
bool mDeferEnabled;
bool mDocumentParsingDone;
--- a/content/base/test/test_mutationobservers.html
+++ b/content/base/test/test_mutationobservers.html
@@ -148,17 +148,20 @@ function runTest() {
is(records.length, 1, "Should have one record.");
is(records[0].type, "attributes", "Should have got attributes record");
is(records[0].target, div, "Should have got div as target");
is(records[0].attributeName, "foo", "Should have got record about foo attribute");
observer.disconnect();
then(testThisBind);
m = null;
});
- m.observe(div, { attributes: true});
+ m.observe(div, { attributes: true, attributeFilter: ["foo"] });
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true);
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter.length, 1)
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter[0], "foo")
div.setAttribute("foo", "bar");
}
// 'this' handling when fn.bind() is used.
function testThisBind() {
var child = div.appendChild(document.createElement("div"));
var gchild = child.appendChild(document.createElement("div"));
m = new M((function(records, observer) {
@@ -177,16 +180,19 @@ function testThisBind() {
is(records[2].target, gchild, "Should have got div as target");
is(records[2].attributeName, "foo", "Should have got record about foo attribute");
is(records[2].oldValue, null, "oldValue should be bar2");
observer.disconnect();
then(testCharacterData);
m = null;
}).bind(window));
m.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true)
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeOldValue, true)
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
div.setAttribute("foo", "bar2");
div.removeAttribute("foo");
div.removeChild(child);
child.removeChild(gchild);
div.appendChild(gchild);
div.removeChild(gchild);
gchild.setAttribute("foo", "bar");
}
@@ -220,16 +226,21 @@ function testCharacterData() {
div.appendChild(document.createTextNode("foo"));
m.observe(div, { characterData: true, subtree: true });
m2.observe(div, { characterData: true, characterDataOldValue: true, subtree: true});
// If observing the same node twice, only the latter option should apply.
m3.observe(div, { characterData: true, subtree: true });
m3.observe(div, { characterData: true, subtree: false });
m4.observe(div.firstChild, { characterData: true, subtree: false });
+
+ is(SpecialPowers.wrap(div).getBoundMutationObservers().length, 3)
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].characterData, true)
+ is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].subtree, false)
+
div.firstChild.data = "bar";
}
function testChildList() {
var fc = div.firstChild;
m = new M(function(records, observer) {
is(records[0].type, "childList", "Should have got childList");
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
@@ -273,35 +284,42 @@ function testChildList3() {
function testChildList4() {
div.textContent = null;
var df = document.createDocumentFragment();
var t1 = df.appendChild(document.createTextNode("Hello "));
var t2 = df.appendChild(document.createTextNode("world!"));
var s1 = div.appendChild(document.createElement("span"));
s1.textContent = "foo";
var s2 = div.appendChild(document.createElement("span"));
- m = new M(function(records, observer) {
+ function callback(records, observer) {
is(records.length, 3, "Should have got one record for removing nodes from document fragment and one record for adding them to div");
is(records[0].removedNodes.length, 2, "Should have got removedNodes");
is(records[0].removedNodes[0], t1, "Should be the 1st textnode");
is(records[0].removedNodes[1], t2, "Should be the 2nd textnode");
is(records[1].addedNodes.length, 2, "Should have got addedNodes");
is(records[1].addedNodes[0], t1, "Should be the 1st textnode");
is(records[1].addedNodes[1], t2, "Should be the 2nd textnode");
is(records[1].previousSibling, s1, "Should have previousSibling");
is(records[1].nextSibling, s2, "Should have nextSibling");
is(records[2].type, "characterData", "3rd record should be characterData");
is(records[2].target, t1, "target should be the textnode");
is(records[2].oldValue, "Hello ", "oldValue was 'Hello '");
observer.disconnect();
then(testChildList5);
m = null;
- });
+ };
+ m = new M(callback);
m.observe(df, { childList: true, characterData: true, characterDataOldValue: true, subtree: true });
+ is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].childList, true)
+ is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterData, true)
+ is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterDataOldValue, true)
+ is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
+ ok(SpecialPowers.compare(SpecialPowers.wrap(df).getBoundMutationObservers()[0].mutationCallback, callback))
m.observe(div, { childList: true });
+ is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo().length, 2)
// Make sure transient observers aren't leaked.
var leakTest = new M(function(){});
leakTest.observe(div, { characterData: true, subtree: true });
div.insertBefore(df, s2);
s1.firstChild.data = "bar"; // This should *not* create a record.
t1.data = "Hello the whole "; // This should create a record.
@@ -549,16 +567,18 @@ function testTakeRecords() {
is(records[1].attributeName, "foo", "");
is(records[1].oldValue, "bar", "");
observer.disconnect();
div.removeEventListener("DOMAttrModified", mutationListener);
then(testExpandos);
m = null;
});
m.observe(div, { attributes: true, attributeOldValue: true });
+ // Note, [0] points to a mutation observer which is there for a leak test!
+ ok(SpecialPowers.compare(SpecialPowers.wrap(div).getBoundMutationObservers()[1], m));
var mutationEventCount = 0;
div.addEventListener("DOMAttrModified", mutationListener);
div.setAttribute("foo", "bar");
div.setAttribute("foo", "bar");
is(mutationEventCount, 1, "Should have got only one mutation event!");
}
function testExpandos() {
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -26,17 +26,19 @@ namespace mozilla {
namespace layers {
class CanvasLayer;
class LayerManager;
}
namespace dom {
+class FileCallback;
class HTMLCanvasPrintState;
+class PrintCallback;
class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
public nsICanvasElementExternal,
public nsIDOMHTMLCanvasElement
{
enum {
DEFAULT_CANVAS_WIDTH = 300,
DEFAULT_CANVAS_HEIGHT = 150
@@ -87,26 +89,20 @@ public:
nsAString& aDataURL, ErrorResult& aRv)
{
JS::Value params = aParams.WasPassed()
? aParams.Value()
: JS::UndefinedValue();
aRv = ToDataURL(aType, params, aCx, aDataURL);
}
void ToBlob(JSContext* aCx,
- nsIFileCallback* aCallback,
+ FileCallback& aCallback,
const nsAString& aType,
const Optional<JS::Handle<JS::Value> >& aParams,
- ErrorResult& aRv)
- {
- JS::Value params = aParams.WasPassed()
- ? aParams.Value()
- : JS::UndefinedValue();
- aRv = ToBlob(aCallback, aType, params, aCx);
- }
+ ErrorResult& aRv);
bool MozOpaque() const
{
return GetBoolAttr(nsGkAtoms::moz_opaque);
}
void SetMozOpaque(bool aValue, ErrorResult& aRv)
{
SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
@@ -121,18 +117,18 @@ public:
aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
return context.forget();
}
void MozFetchAsStream(nsIInputStreamCallback* aCallback,
const nsAString& aType, ErrorResult& aRv)
{
aRv = MozFetchAsStream(aCallback, aType);
}
- nsIPrintCallback* GetMozPrintCallback() const;
- // Using XPCOM SetMozPrintCallback.
+ PrintCallback* GetMozPrintCallback() const;
+ void SetMozPrintCallback(PrintCallback* aCallback);
/**
* Get the size in pixels of this canvas element
*/
nsIntSize GetSize();
/**
* Determine whether the canvas is write-only.
@@ -239,19 +235,19 @@ protected:
const nsAString& aType,
nsIDOMFile** aResult);
nsresult GetContextHelper(const nsAString& aContextId,
nsICanvasRenderingContextInternal **aContext);
void CallPrintCallback();
nsString mCurrentContextId;
nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
- nsCOMPtr<nsIPrintCallback> mPrintCallback;
+ nsRefPtr<PrintCallback> mPrintCallback;
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
- nsCOMPtr<HTMLCanvasPrintState> mPrintState;
+ nsRefPtr<HTMLCanvasPrintState> mPrintState;
public:
// Record whether this canvas should be write-only or not.
// We set this when script paints an image from a different origin.
// We also transitively set it when script paints a canvas which
// is itself write-only.
bool mWriteOnly;
@@ -261,12 +257,47 @@ public:
nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
void ResetPrintCallback();
HTMLCanvasElement* GetOriginalCanvas();
};
+class HTMLCanvasPrintState MOZ_FINAL : public nsWrapperCache
+{
+public:
+ HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
+ nsICanvasRenderingContextInternal* aContext,
+ nsITimerCallback* aCallback);
+
+ nsISupports* Context() const;
+
+ void Done();
+
+ void NotifyDone();
+
+ bool mIsDone;
+
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState)
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(HTMLCanvasPrintState)
+
+ virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
+
+ HTMLCanvasElement* GetParentObject()
+ {
+ return mCanvas;
+ }
+
+private:
+ ~HTMLCanvasPrintState();
+ bool mPendingNotify;
+
+protected:
+ nsRefPtr<HTMLCanvasElement> mCanvas;
+ nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
+ nsCOMPtr<nsITimerCallback> mCallback;
+};
+
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_HTMLCanvasElement_h */
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -43,110 +43,98 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
namespace {
typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
HTMLImageOrCanvasOrVideoElement;
class ToBlobRunnable : public nsRunnable
{
public:
- ToBlobRunnable(nsIFileCallback* aCallback,
+ ToBlobRunnable(mozilla::dom::FileCallback& aCallback,
nsIDOMBlob* aBlob)
- : mCallback(aCallback),
+ : mCallback(&aCallback),
mBlob(aBlob)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
}
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
- mCallback->Receive(mBlob);
- return NS_OK;
+ mozilla::ErrorResult rv;
+ mCallback->Call(mBlob, rv);
+ return rv.ErrorCode();
}
private:
- nsCOMPtr<nsIFileCallback> mCallback;
+ nsRefPtr<mozilla::dom::FileCallback> mCallback;
nsCOMPtr<nsIDOMBlob> mBlob;
};
} // anonymous namespace
namespace mozilla {
namespace dom {
-class HTMLCanvasPrintState : public nsIDOMMozCanvasPrintState
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(HTMLCanvasPrintState, mCanvas,
+ mContext, mCallback)
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
+
+HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
+ nsICanvasRenderingContextInternal* aContext,
+ nsITimerCallback* aCallback)
+ : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
+ mContext(aContext), mCallback(aCallback)
{
-public:
- HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
- nsICanvasRenderingContextInternal* aContext,
- nsITimerCallback* aCallback)
- : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
- mContext(aContext), mCallback(aCallback)
- {
- }
+ SetIsDOMBinding();
+}
- NS_IMETHOD GetContext(nsISupports** aContext)
- {
- NS_ADDREF(*aContext = mContext);
- return NS_OK;
- }
+HTMLCanvasPrintState::~HTMLCanvasPrintState()
+{
+}
- NS_IMETHOD Done()
- {
- if (!mPendingNotify && !mIsDone) {
- // The canvas needs to be invalidated for printing reftests on linux to
- // work.
- if (mCanvas) {
- mCanvas->InvalidateCanvas();
- }
- nsRefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
- NS_NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
- if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
- mPendingNotify = true;
- }
+/* virtual */ JSObject*
+HTMLCanvasPrintState::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+ return MozCanvasPrintStateBinding::Wrap(aCx, aScope, this);
+}
+
+nsISupports*
+HTMLCanvasPrintState::Context() const
+{
+ return mContext;
+}
+
+void
+HTMLCanvasPrintState::Done()
+{
+ if (!mPendingNotify && !mIsDone) {
+ // The canvas needs to be invalidated for printing reftests on linux to
+ // work.
+ if (mCanvas) {
+ mCanvas->InvalidateCanvas();
}
- return NS_OK;
- }
-
- void NotifyDone()
- {
- mIsDone = true;
- mPendingNotify = false;
- if (mCallback) {
- mCallback->Notify(nullptr);
+ nsRefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
+ NS_NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
+ if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
+ mPendingNotify = true;
}
}
-
- bool mIsDone;
-
- // CC
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS(HTMLCanvasPrintState)
-private:
- virtual ~HTMLCanvasPrintState()
- {
- }
- bool mPendingNotify;
+}
-protected:
- nsRefPtr<HTMLCanvasElement> mCanvas;
- nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
- nsCOMPtr<nsITimerCallback> mCallback;
-};
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLCanvasPrintState)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLCanvasPrintState)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLCanvasPrintState)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_ENTRY(nsIDOMMozCanvasPrintState)
- NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozCanvasPrintState)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_3(HTMLCanvasPrintState, mCanvas, mContext, mCallback)
+void
+HTMLCanvasPrintState::NotifyDone()
+{
+ mIsDone = true;
+ mPendingNotify = false;
+ if (mCallback) {
+ mCallback->Notify(nullptr);
+ }
+}
// ---------------------------------------------------------------------------
HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
mWriteOnly(false)
{
}
@@ -221,21 +209,19 @@ HTMLCanvasElement::SetAttr(int32_t aName
void
HTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
{
// Only call the print callback here if 1) we're in a print testing mode or
// print preview mode, 2) the canvas has a print callback and 3) the callback
// hasn't already been called. For real printing the callback is handled in
// nsSimplePageSequenceFrame::PrePrintNextPage.
- nsCOMPtr<nsIPrintCallback> printCallback;
if ((aType == nsPresContext::eContext_PageLayout ||
aType == nsPresContext::eContext_PrintPreview) &&
- !mPrintState &&
- NS_SUCCEEDED(GetMozPrintCallback(getter_AddRefs(printCallback))) && printCallback) {
+ !mPrintState && GetMozPrintCallback()) {
DispatchPrintCallback(nullptr);
}
}
nsresult
HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
{
// For print reftests the context may not be initialized yet, so get a context
@@ -251,19 +237,18 @@ HTMLCanvasElement::DispatchPrintCallback
nsRefPtr<nsRunnableMethod<HTMLCanvasElement> > renderEvent =
NS_NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback);
return NS_DispatchToCurrentThread(renderEvent);
}
void
HTMLCanvasElement::CallPrintCallback()
{
- nsCOMPtr<nsIPrintCallback> printCallback;
- GetMozPrintCallback(getter_AddRefs(printCallback));
- printCallback->Render(mPrintState);
+ ErrorResult rv;
+ GetMozPrintCallback()->Call(*mPrintState, rv);
}
void
HTMLCanvasElement::ResetPrintCallback()
{
if (mPrintState) {
mPrintState = nullptr;
}
@@ -381,39 +366,31 @@ HTMLCanvasElement::MozFetchAsStream(nsII
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStreamCallback> asyncCallback =
NS_NewInputStreamReadyEvent(aCallback, mainThread);
return asyncCallback->OnInputStreamReady(asyncData);
}
-NS_IMETHODIMP
-HTMLCanvasElement::SetMozPrintCallback(nsIPrintCallback *aCallback)
+void
+HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
{
mPrintCallback = aCallback;
- return NS_OK;
}
-nsIPrintCallback*
+PrintCallback*
HTMLCanvasElement::GetMozPrintCallback() const
{
if (mOriginalCanvas) {
return mOriginalCanvas->GetMozPrintCallback();
}
return mPrintCallback;
}
-NS_IMETHODIMP
-HTMLCanvasElement::GetMozPrintCallback(nsIPrintCallback** aCallback)
-{
- NS_IF_ADDREF(*aCallback = GetMozPrintCallback());
- return NS_OK;
-}
-
nsresult
HTMLCanvasElement::ExtractData(const nsAString& aType,
const nsAString& aOptions,
nsIInputStream** aStream,
bool& aFellBackToPNG)
{
// note that if we don't have a current context, the spec says we're
// supposed to just return transparent black pixels of the canvas
@@ -566,81 +543,92 @@ HTMLCanvasElement::ToDataURLImpl(JSConte
rv = stream->Available(&count);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(count <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
}
// XXXkhuey the encoding should be off the main thread, but we're lazy.
-NS_IMETHODIMP
-HTMLCanvasElement::ToBlob(nsIFileCallback* aCallback,
+void
+HTMLCanvasElement::ToBlob(JSContext* aCx,
+ FileCallback& aCallback,
const nsAString& aType,
- const JS::Value& aEncoderOptions,
- JSContext* aCx)
+ const Optional<JS::Handle<JS::Value> >& aParams,
+ ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
-
- if (!aCallback) {
- return NS_ERROR_UNEXPECTED;
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
}
nsAutoString type;
- nsresult rv = nsContentUtils::ASCIIToLower(aType, type);
- if (NS_FAILED(rv)) {
- return rv;
+ aRv = nsContentUtils::ASCIIToLower(aType, type);
+ if (aRv.Failed()) {
+ return;
}
+ JS::Value encoderOptions = aParams.WasPassed()
+ ? aParams.Value()
+ : JS::UndefinedValue();
+
nsAutoString params;
bool usingCustomParseOptions;
- rv = ParseParams(aCx, type, aEncoderOptions, params, &usingCustomParseOptions);
- if (NS_FAILED(rv)) {
- return rv;
+ aRv = ParseParams(aCx, type, encoderOptions, params, &usingCustomParseOptions);
+ if (aRv.Failed()) {
+ return;
}
bool fallbackToPNG = false;
nsCOMPtr<nsIInputStream> stream;
- rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
+ aRv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
// If there are unrecognized custom parse options, we should fall back to
// the default values for the encoder without any options at all.
- if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
+ if (aRv.ErrorCode() == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
fallbackToPNG = false;
- rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
+ aRv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
}
- NS_ENSURE_SUCCESS(rv, rv);
+ if (aRv.Failed()) {
+ return;
+ }
if (fallbackToPNG) {
type.AssignLiteral("image/png");
}
uint64_t imgSize;
- rv = stream->Available(&imgSize);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
+ aRv = stream->Available(&imgSize);
+ if (aRv.Failed()) {
+ return;
+ }
+ if (imgSize > UINT32_MAX) {
+ aRv.Throw(NS_ERROR_FILE_TOO_BIG);
+ return;
+ }
void* imgData = nullptr;
- rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
- NS_ENSURE_SUCCESS(rv, rv);
+ aRv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
+ if (aRv.Failed()) {
+ return;
+ }
// The DOMFile takes ownership of the buffer
nsRefPtr<nsDOMMemoryFile> blob =
new nsDOMMemoryFile(imgData, imgSize, type);
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
JS_updateMallocCounter(cx, imgSize);
}
nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
- return NS_DispatchToCurrentThread(runnable);
+ aRv = NS_DispatchToCurrentThread(runnable);
}
already_AddRefed<nsIDOMFile>
HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
const nsAString& aType,
ErrorResult& aRv)
{
nsCOMPtr<nsIDOMFile> file;
@@ -1047,10 +1035,8 @@ HTMLCanvasElement::RenderContextsExterna
if (!mCurrentContext)
return NS_OK;
return mCurrentContext->Render(aContext, aFilter, aFlags);
}
} // namespace dom
} // namespace mozilla
-
-DOMCI_DATA(MozCanvasPrintState, mozilla::dom::HTMLCanvasPrintState)
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2347,19 +2347,22 @@ MediaStreamGraph::CreateNonRealtimeInsta
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(false);
return graph;
}
void
MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph)
{
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
- MOZ_ASSERT(aGraph != gGraph, "Should not destroy the global graph here");
+ MOZ_ASSERT(aGraph->IsNonRealtime(), "Should not destroy the global graph here");
MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(aGraph);
+ if (graph->mForceShutDown)
+ return; // already done
+
if (!graph->mNonRealtimeProcessing) {
// Start the graph, but don't produce anything
graph->StartNonRealtimeProcessing(0);
}
graph->ForceShutDown();
}
SourceMediaStream*
@@ -2416,16 +2419,22 @@ MediaStreamGraph::CreateAudioNodeStream(
stream->SetChannelMixingParametersImpl(aEngine->NodeMainThread()->ChannelCount(),
aEngine->NodeMainThread()->ChannelCountModeValue(),
aEngine->NodeMainThread()->ChannelInterpretationValue());
}
graph->AppendMessage(new CreateMessage(stream));
return stream;
}
+bool
+MediaStreamGraph::IsNonRealtime() const
+{
+ return this != gGraph;
+}
+
void
MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess)
{
NS_ASSERTION(NS_IsMainThread(), "main thread only");
MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
NS_ASSERTION(!graph->mRealtime, "non-realtime only");
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -970,16 +970,17 @@ public:
// We ensure that the graph current time advances in multiples of
// IdealAudioBlockSize()/IdealAudioRate(). A stream that never blocks
// and has a track with the ideal audio rate will produce audio in
// multiples of the block size.
// Main thread only
static MediaStreamGraph* GetInstance();
static MediaStreamGraph* CreateNonRealtimeInstance();
+ // Idempotent
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
// Control API.
/**
* Create a stream that a media decoder (or some other source of
* media data, such as a camera) can write to.
*/
SourceMediaStream* CreateSourceStream(DOMMediaStream* aWrapper);
@@ -1017,16 +1018,18 @@ public:
TrackRate aSampleRate = 0);
/**
* Returns the number of graph updates sent. This can be used to track
* whether a given update has been processed by the graph thread and reflected
* in main-thread stream state.
*/
int64_t GetCurrentGraphUpdateIndex() { return mGraphUpdatesSent; }
+
+ bool IsNonRealtime() const;
/**
* Start processing non-realtime for a specific number of ticks.
*/
void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
/**
* Media graph thread only.
* Dispatches a runnable that will run on the main thread after all
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -84,17 +84,16 @@ MOCHITEST_FILES = \
test_metadata.html \
test_no_load_event.html \
test_networkState.html \
test_new_audio.html \
test_paused.html \
test_paused_after_ended.html \
test_play_events.html \
test_play_events_2.html \
- $(filter disabled-temporarily--bug-751539, test_played.html) \
test_playback_errors.html \
test_seekable1.html \
test_preload_actions.html \
test_preload_attribute.html \
test_progress.html \
test_reactivate.html \
test_readyState.html \
test_replay_metadata.html \
@@ -160,26 +159,38 @@ endif
# test_videoDocumentTitle.html
# Bug 493692:
# test_preload_suspend.html
# Bug 567954 and Bug 574586:
# test_mixed_principals.html
# Disabled since we don't play Wave files standalone, for now
# test_audioDocumentTitle.html
-# The below tests are disabled due to frequent timeouts.
+# The below tests are disabled on Windows due to frequent timeouts.
# Bug 832768 and Bug 864682:
# test_buffered.html
# test_bug465498.html
# Bug 707777:
# test_bug493187.html
# Bug 832678, bug 795271, and bug 857424
# test_seek.html
# Bug 832768, bug 814533, bug 840742
# test_playback_rate.html
+# Bug 751539
+# test_played.html
+ifneq ($(OS_ARCH), WINNT)
+MOCHITEST_FILES += \
+ test_buffered.html \
+ test_bug465498.html \
+ test_bug493187.html \
+ test_seek.html \
+ test_playback_rate.html \
+ test_played.html \
+ $(NULL)
+endif
# sample files
MOCHITEST_FILES += \
320x240.ogv \
448636.ogv \
audio-overhang.ogg \
audio-gaps.ogg \
badtags.ogg \
--- a/content/media/test/test_playback_rate.html
+++ b/content/media/test/test_playback_rate.html
@@ -5,16 +5,18 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type='application/javascript;version=1.8'>
+SimpleTest.expectAssertions(0, 2);
+
if (navigator.platform.startsWith("Win")) {
SimpleTest.expectAssertions(0, 1);
} else if (navigator.platform.startsWith("Mac")) {
SimpleTest.expectAssertions(0, 2);
}
let manager = new MediaTestManager;
--- a/content/media/test/test_played.html
+++ b/content/media/test/test_played.html
@@ -8,16 +8,18 @@
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id='test'>
<script class="testbody" type='application/javascript;version=1.8'>
let manager = new MediaTestManager;
+SimpleTest.expectAssertions(0, 2);
+
function finish_test(element) {
if (element.parentNode)
element.parentNode.removeChild(element);
element.src="";
manager.finished(element.token);
}
// Check that a file has been played in its entirety.
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -408,17 +408,17 @@ public:
FillWithZeroes(aOutput, channels, &written, ¤tPosition, TRACK_TICKS_MAX);
}
}
}
// We've finished if we've gone past mStop, or if we're past mDuration when
// looping is disabled.
if (currentPosition >= mStop ||
- (!mLoop && currentPosition - mStart + mOffset > mDuration)) {
+ (!mLoop && currentPosition - mStart + mOffset >= mDuration)) {
*aFinished = true;
}
}
TrackTicks mStart;
TrackTicks mStop;
nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
SpeexResamplerState* mResampler;
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -58,21 +58,26 @@ AudioContext::AudioContext(nsPIDOMWindow
aIsOffline, aNumberOfChannels,
aLength, aSampleRate))
, mNumberOfChannels(aNumberOfChannels)
, mIsOffline(aIsOffline)
{
// Actually play audio
mDestination->Stream()->AddAudioOutput(&gWebAudioOutputKey);
nsDOMEventTargetHelper::BindToOwner(aWindow);
+ aWindow->AddAudioContext(this);
SetIsDOMBinding();
}
AudioContext::~AudioContext()
{
+ nsPIDOMWindow* window = GetOwner();
+ if (window) {
+ window->RemoveAudioContext(this);
+ }
}
JSObject*
AudioContext::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
if (mIsOffline) {
return OfflineAudioContextBinding::Wrap(aCx, aScope, this);
} else {
@@ -86,17 +91,16 @@ AudioContext::Constructor(const GlobalOb
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<AudioContext> object = new AudioContext(window, false);
- window->AddAudioContext(object);
return object.forget();
}
/* static */ already_AddRefed<AudioContext>
AudioContext::Constructor(const GlobalObject& aGlobal,
uint32_t aNumberOfChannels,
uint32_t aLength,
float aSampleRate,
@@ -118,17 +122,16 @@ AudioContext::Constructor(const GlobalOb
return nullptr;
}
nsRefPtr<AudioContext> object = new AudioContext(window,
true,
aNumberOfChannels,
aLength,
aSampleRate);
- window->AddAudioContext(object);
return object.forget();
}
already_AddRefed<AudioBufferSourceNode>
AudioContext::CreateBufferSource()
{
nsRefPtr<AudioBufferSourceNode> bufferNode =
new AudioBufferSourceNode(this);
@@ -513,35 +516,20 @@ GetHashtableEntry(nsPtrHashKey<T>* aEntr
template <class T>
static void
GetHashtableElements(nsTHashtable<nsPtrHashKey<T> >& aHashtable, nsTArray<T*>& aArray)
{
aHashtable.EnumerateEntries(&GetHashtableEntry<T>, &aArray);
}
void
-AudioContext::ShutdownDecoder()
-{
- mDecoder.Shutdown();
-}
-
-void
AudioContext::Shutdown()
{
Suspend();
- // We need to hold the AudioContext object alive here to make sure that
- // it doesn't get destroyed before our decoder shutdown runnable has had
- // a chance to run.
- nsCOMPtr<nsIRunnable> threadShutdownEvent =
- NS_NewRunnableMethod(this, &AudioContext::ShutdownDecoder);
- if (threadShutdownEvent) {
- NS_DispatchToCurrentThread(threadShutdownEvent);
- }
-
// Stop all audio buffer source nodes, to make sure that they release
// their self-references.
// We first gather an array of the nodes and then call Stop on each one,
// since Stop may delete the object and therefore trigger a re-entrant
// hashtable call to remove the pointer from the hashtable, which is
// not safe.
nsTArray<AudioBufferSourceNode*> sourceNodes;
GetHashtableElements(mAudioBufferSourceNodes, sourceNodes);
@@ -562,17 +550,17 @@ AudioContext::Shutdown()
nsTArray<ScriptProcessorNode*> spNodes;
GetHashtableElements(mScriptProcessorNodes, spNodes);
for (uint32_t i = 0; i < spNodes.Length(); ++i) {
spNodes[i]->Stop();
}
// For offline contexts, we can destroy the MediaStreamGraph at this point.
if (mIsOffline) {
- mDestination->DestroyGraph();
+ mDestination->OfflineShutdown();
}
}
void
AudioContext::Suspend()
{
MediaStream* ds = DestinationStream();
if (ds) {
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -74,17 +74,17 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioContext,
nsDOMEventTargetHelper)
nsPIDOMWindow* GetParentObject() const
{
return GetOwner();
}
- void Shutdown();
+ void Shutdown(); // idempotent
void Suspend();
void Resume();
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
using nsDOMEventTargetHelper::DispatchTrustedEvent;
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -120,21 +120,23 @@ public:
}
nsRefPtr<AudioContext> context;
{
MutexAutoLock lock(mStream->Engine()->NodeMutex());
AudioNode* node = mStream->Engine()->Node();
if (node) {
context = node->Context();
+ MOZ_ASSERT(context, "node hasn't kept context alive");
}
}
if (!context) {
return NS_OK;
}
+ context->Shutdown(); // drops self reference
AutoPushJSContext cx(context->GetJSContext());
if (cx) {
JSAutoRequest ar(cx);
// Create the input buffer
nsRefPtr<AudioBuffer> renderedBuffer = new AudioBuffer(context,
mLength,
@@ -230,16 +232,29 @@ AudioDestinationNode::AudioDestinationNo
AudioNodeEngine* engine = aIsOffline ?
new OfflineDestinationNodeEngine(this, aNumberOfChannels,
aLength, aSampleRate) :
static_cast<AudioNodeEngine*>(new DestinationNodeEngine(this));
mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
}
+void
+AudioDestinationNode::DestroyMediaStream()
+{
+ if (!mStream)
+ return;
+
+ MediaStreamGraph* graph = mStream->Graph();
+ if (graph->IsNonRealtime()) {
+ MediaStreamGraph::DestroyNonRealtimeInstance(graph);
+ }
+ AudioNode::DestroyMediaStream();
+}
+
uint32_t
AudioDestinationNode::MaxChannelCount() const
{
return Context()->MaxChannelCount();
}
void
AudioDestinationNode::SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
@@ -262,29 +277,32 @@ AudioDestinationNode::Mute()
void
AudioDestinationNode::Unmute()
{
MOZ_ASSERT(Context() && !Context()->IsOffline());
SendDoubleParameterToStream(DestinationNodeEngine::VOLUME, 1.0f);
}
void
-AudioDestinationNode::DestroyGraph()
+AudioDestinationNode::OfflineShutdown()
{
MOZ_ASSERT(Context() && Context()->IsOffline(),
"Should only be called on a valid OfflineAudioContext");
+
MediaStreamGraph::DestroyNonRealtimeInstance(mStream->Graph());
+ mOfflineRenderingRef.Drop(this);
}
JSObject*
AudioDestinationNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return AudioDestinationNodeBinding::Wrap(aCx, aScope, this);
}
void
AudioDestinationNode::StartRendering()
{
+ mOfflineRenderingRef.Take(this);
mStream->Graph()->StartNonRealtimeProcessing(mFramesToProduce);
}
}
}
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -20,16 +20,18 @@ public:
// This node type knows what MediaStreamGraph to use based on
// whether it's in offline mode.
AudioDestinationNode(AudioContext* aContext,
bool aIsOffline,
uint32_t aNumberOfChannels = 0,
uint32_t aLength = 0,
float aSampleRate = 0.0f);
+ virtual void DestroyMediaStream() MOZ_OVERRIDE;
+
NS_DECL_ISUPPORTS_INHERITED
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
virtual uint16_t NumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
{
return 0;
@@ -39,19 +41,20 @@ public:
virtual void SetChannelCount(uint32_t aChannelCount,
ErrorResult& aRv) MOZ_OVERRIDE;
void Mute();
void Unmute();
void StartRendering();
- void DestroyGraph();
+ void OfflineShutdown();
private:
+ SelfReference<AudioDestinationNode> mOfflineRenderingRef;
uint32_t mFramesToProduce;
};
}
}
#endif
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -97,21 +97,19 @@ private:
/**
* The DOM object representing a Web Audio AudioNode.
*
* Each AudioNode has a MediaStream representing the actual
* real-time processing and output of this AudioNode.
*
* We track the incoming and outgoing connections to other AudioNodes.
- * All connections are strong and thus rely on cycle collection to break them.
- * However, we also track whether an AudioNode is capable of producing output
- * in the future. If it isn't, then we break its connections to its inputs
- * and outputs, allowing nodes to be immediately disconnected. This
- * disconnection is done internally, invisible to DOM users.
+ * Outgoing connections have strong ownership. Also, AudioNodes add self
+ * references if they produce sound on their output even when they have silent
+ * or no input.
*/
class AudioNode : public nsDOMEventTargetHelper,
public EnableWebAudioCheck
{
protected:
// You can only use refcounting to delete this object
virtual ~AudioNode();
--- a/content/media/webaudio/MediaBufferDecoder.cpp
+++ b/content/media/webaudio/MediaBufferDecoder.cpp
@@ -567,25 +567,16 @@ MediaBufferDecoder::EnsureThreadPoolInit
if (!mThreadPool) {
return false;
}
mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
}
return true;
}
-void
-MediaBufferDecoder::Shutdown() {
- if (mThreadPool) {
- mThreadPool->Shutdown();
- mThreadPool = nullptr;
- }
- MOZ_ASSERT(!mThreadPool);
-}
-
WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
AudioContext* aContext,
const ArrayBuffer& aBuffer,
DecodeSuccessCallback* aSuccessCallback,
DecodeErrorCallback* aFailureCallback)
: mContentType(aContentType)
, mWriteIndex(0)
, mContext(aContext)
--- a/content/media/webaudio/MediaBufferDecoder.h
+++ b/content/media/webaudio/MediaBufferDecoder.h
@@ -75,18 +75,16 @@ class MediaBufferDecoder
{
public:
void AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
bool SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
- void Shutdown();
-
private:
bool EnsureThreadPoolInitialized();
private:
nsCOMPtr<nsIThreadPool> mThreadPool;
};
}
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -44,20 +44,22 @@ MOCHITEST_FILES := \
test_audioBufferSourceNodeNullBuffer.html \
test_badConnect.html \
test_biquadFilterNode.html \
test_channelMergerNode.html \
test_channelMergerNodeWithVolume.html \
test_channelSplitterNode.html \
test_channelSplitterNodeWithVolume.html \
test_convolverNode.html \
+ test_convolverNodeChannelCount.html \
test_convolverNodeWithGain.html \
test_convolverNode_mono_mono.html \
test_currentTime.html \
test_delayNode.html \
+ test_delayNodeAtMax.html \
test_delayNodeSmallMaxDelay.html \
test_delayNodeWithGain.html \
test_dynamicsCompressorNode.html \
test_gainNode.html \
test_gainNodeInLoop.html \
test_maxChannelCount.html \
test_mediaDecoding.html \
test_decodeMultichannel.html \
@@ -100,20 +102,13 @@ MOCHITEST_FILES := \
noaudio.webm \
audio.ogv \
audio-expected.wav \
audio-mono-expected.wav \
audio-mono-expected-2.wav \
audio-quad.wav \
$(NULL)
-ifneq ($(MOZ_DEBUG)+$(MOZ_WIDGET_TOOLKIT),+gtk2) # bug 911777
-MOCHITEST_FILES += \
- test_convolverNodeChannelCount.html \
- test_delayNodeAtMax.html \
- $(NULL)
-endif # bug 911777
-
ifneq ($(OS_TARGET),Android) # bug 912474
MOCHITEST_FILES += \
test_pannerNodeChannelCount.html \
$(NULL)
endif
--- a/content/media/webaudio/test/test_maxChannelCount.html
+++ b/content/media/webaudio/test/test_maxChannelCount.html
@@ -5,16 +5,20 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
+// Work around bug 911777
+SpecialPowers.forceGC();
+SpecialPowers.forceCC();
+
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var ac = new AudioContext();
ok(ac.destination.maxChannelCount > 0, "We can query the maximum number of channels");
var oac = new OfflineAudioContext(2, 1024, 48000);
ok(oac.destination.maxChannelCount, 2, "This OfflineAudioContext should have 2 max channels.");
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -44,18 +44,17 @@ static RedirEntry kRedirMap[] = {
{ "buildconfig", "chrome://global/content/buildconfig.html",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
{ "license", "chrome://global/content/license.html",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
{ "neterror", "chrome://global/content/netError.xhtml",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
- // aboutMemory.xhtml implements about:compartments
- { "compartments", "chrome://global/content/aboutMemory.xhtml",
+ { "compartments", "chrome://global/content/aboutCompartments.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "memory", "chrome://global/content/aboutMemory.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "addons", "chrome://mozapps/content/extensions/extensions.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -20,17 +20,17 @@
#include "nsICookiePermission.h"
#include "nsIScriptSecurityManager.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsContentUtils.h"
#include "nsUnicharUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "BatteryManager.h"
-#include "PowerManager.h"
+#include "mozilla/dom/PowerManager.h"
#include "nsIDOMWakeLock.h"
#include "nsIPowerManagerService.h"
#include "mozilla/dom/MobileMessageManager.h"
#include "mozilla/Hal.h"
#include "nsISiteSpecificUserAgent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "Connection.h"
@@ -71,18 +71,16 @@
#include "nsIDOMGlobalPropertyInitializer.h"
#include "nsJSUtils.h"
#include "nsScriptNameSpaceManager.h"
#include "mozilla/dom/NavigatorBinding.h"
-using namespace mozilla::dom::power;
-
// This should not be in the namespace.
DOMCI_DATA(Navigator, mozilla::dom::Navigator)
namespace mozilla {
namespace dom {
static bool sDoNotTrackEnabled = false;
static bool sVibratorEnabled = false;
@@ -1095,17 +1093,17 @@ Navigator::GetBattery(ErrorResult& aRv)
mBatteryManager = new battery::BatteryManager();
mBatteryManager->Init(mWindow);
}
return mBatteryManager;
}
-power::PowerManager*
+PowerManager*
Navigator::GetMozPower(ErrorResult& aRv)
{
if (!mPowerManager) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
mPowerManager = PowerManager::CreateInstance(mWindow);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -87,19 +87,17 @@ class BluetoothManager;
#endif // MOZ_B2G_BT
#ifdef MOZ_B2G_RIL
class CellBroadcast;
class Telephony;
class Voicemail;
#endif
-namespace power {
class PowerManager;
-} // namespace power
namespace time {
class TimeManager;
} // namespace time
namespace system {
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
class AudioChannelManager;
@@ -189,17 +187,17 @@ public:
// The XPCOM GetVendor is OK
// The XPCOM GetVendorSub is OK
// The XPCOM GetProductSub is OK
bool CookieEnabled();
void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
{
aRv = GetBuildID(aBuildID);
}
- power::PowerManager* GetMozPower(ErrorResult& aRv);
+ PowerManager* GetMozPower(ErrorResult& aRv);
bool JavaEnabled(ErrorResult& aRv);
bool TaintEnabled()
{
return false;
}
void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
already_AddRefed<nsIDOMMozWakeLock> RequestWakeLock(const nsAString &aTopic,
@@ -317,17 +315,17 @@ private:
nsRefPtr<nsMimeTypeArray> mMimeTypes;
nsRefPtr<nsPluginArray> mPlugins;
nsRefPtr<Geolocation> mGeolocation;
nsRefPtr<DesktopNotificationCenter> mNotification;
nsRefPtr<battery::BatteryManager> mBatteryManager;
#ifdef MOZ_B2G_FM
nsRefPtr<FMRadio> mFMRadio;
#endif
- nsRefPtr<power::PowerManager> mPowerManager;
+ nsRefPtr<PowerManager> mPowerManager;
nsRefPtr<MobileMessageManager> mMobileMessageManager;
#ifdef MOZ_B2G_RIL
nsRefPtr<Telephony> mTelephony;
nsRefPtr<Voicemail> mVoicemail;
#endif
nsRefPtr<network::Connection> mConnection;
#ifdef MOZ_B2G_RIL
nsRefPtr<network::MobileConnection> mMobileConnection;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -33,17 +33,16 @@
#include "nsIComponentRegistrar.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsIXPConnect.h"
#include "nsIXPCSecurityManager.h"
#include "xptcall.h"
#include "nsTArray.h"
#include "nsDOMEventTargetHelper.h"
-#include "nsIDOMHTMLCanvasElement.h"
#include "nsContentList.h"
#include "nsHTMLDocument.h"
#include "nsDOMBlobBuilder.h"
// General helper includes
#include "nsGlobalWindow.h"
#include "nsIContent.h"
#include "nsIDocument.h"
@@ -418,19 +417,16 @@ static nsDOMClassInfoData sClassInfoData
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// other SVG classes
NS_DEFINE_CLASSINFO_DATA(SVGLength, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
- NS_DEFINE_CLASSINFO_DATA(MozCanvasPrintState, nsDOMGenericSH,
- DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
NS_DEFINE_CLASSINFO_DATA(WindowUtils, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1228,20 +1224,16 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(SVGLength, nsIDOMSVGLength)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLength)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGNumber, nsIDOMSVGNumber)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGNumber)
DOM_CLASSINFO_MAP_END
- DOM_CLASSINFO_MAP_BEGIN(MozCanvasPrintState, nsIDOMMozCanvasPrintState)
- DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCanvasPrintState)
- DOM_CLASSINFO_MAP_END
-
DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -60,19 +60,16 @@ DOMCI_CLASS(TreeColumn)
DOMCI_CLASS(CSSMozDocumentRule)
DOMCI_CLASS(CSSSupportsRule)
// other SVG classes
DOMCI_CLASS(SVGLength)
DOMCI_CLASS(SVGNumber)
-// Canvas
-DOMCI_CLASS(MozCanvasPrintState)
-
// WindowUtils
DOMCI_CLASS(WindowUtils)
// XSLTProcessor
DOMCI_CLASS(XSLTProcessor)
// DOM Level 3 XPath objects
DOMCI_CLASS(XPathExpression)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1382,16 +1382,21 @@ nsGlobalWindow::CleanUp()
}
mInnerWindowHolder = nullptr;
mArguments = nullptr;
mDialogArguments = nullptr;
CleanupCachedXBLHandlers(this);
+ for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
+ mAudioContexts[i]->Shutdown();
+ }
+ mAudioContexts.Clear();
+
if (mIdleTimer) {
mIdleTimer->Cancel();
mIdleTimer = nullptr;
}
DisableTimeChangeNotifications();
}
@@ -1646,17 +1651,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
#endif
// Traverse stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
@@ -1701,17 +1705,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
#endif
// Unlink stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
@@ -3254,16 +3257,22 @@ nsPIDOMWindow::AddAudioContext(AudioCont
nsIDocShell* docShell = GetDocShell();
if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) {
aAudioContext->Mute();
}
}
void
+nsPIDOMWindow::RemoveAudioContext(AudioContext* aAudioContext)
+{
+ mAudioContexts.RemoveElement(aAudioContext);
+}
+
+void
nsPIDOMWindow::MuteAudioContexts()
{
for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
if (!mAudioContexts[i]->IsOffline()) {
mAudioContexts[i]->Mute();
}
}
}
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -53,22 +53,25 @@ public:
* @param aOptions an options object. You probably want to at least set
* filename and line number. The principal is computed
* internally, though 'originPrincipals' may be passed.
* @param aCoerceToString if the return value is not JSVAL_VOID, convert it
* to a string before returning.
* @param aRetValue the result of executing the script. Pass null if you
* don't care about the result. Note that asking for a
* result will deoptimize your script somewhat in many cases.
+ * @param aOffThreadToken if specified, the result of compiling the script
+ * on another thread.
*/
virtual nsresult EvaluateString(const nsAString& aScript,
JS::Handle<JSObject*> aScopeObject,
JS::CompileOptions& aOptions,
bool aCoerceToString,
- JS::Value* aRetValue) = 0;
+ JS::Value* aRetValue,
+ void **aOffThreadToken = nullptr) = 0;
/**
* Bind an already-compiled event handler function to the given
* target. Scripting languages with static scoping must re-bind the
* scope chain for aHandler to begin (after the activation scope for
* aHandler itself, typically) with aTarget's scope.
*
* The result of the bind operation is a new handler object, with
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -975,28 +975,30 @@ nsJSContext::GetCCRefcnt()
return refcnt;
}
nsresult
nsJSContext::EvaluateString(const nsAString& aScript,
JS::Handle<JSObject*> aScopeObject,
JS::CompileOptions& aCompileOptions,
bool aCoerceToString,
- JS::Value* aRetValue)
+ JS::Value* aRetValue,
+ void **aOffThreadToken)
{
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
if (!mScriptsEnabled) {
return NS_OK;
}
AutoCxPusher pusher(mContext);
nsJSUtils::EvaluateOptions evalOptions;
evalOptions.setCoerceToString(aCoerceToString);
return nsJSUtils::EvaluateString(mContext, aScript, aScopeObject,
- aCompileOptions, evalOptions, aRetValue);
+ aCompileOptions, evalOptions, aRetValue,
+ aOffThreadToken);
}
#ifdef DEBUG
bool
AtomIsEventHandlerName(nsIAtom *aName)
{
const PRUnichar *name = aName->GetUTF16String();
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -39,17 +39,18 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
nsIScriptContext)
virtual nsresult EvaluateString(const nsAString& aScript,
JS::Handle<JSObject*> aScopeObject,
JS::CompileOptions &aOptions,
bool aCoerceToString,
- JS::Value* aRetValue) MOZ_OVERRIDE;
+ JS::Value* aRetValue,
+ void **aOffThreadToken = nullptr) MOZ_OVERRIDE;
virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
JS::Handle<JSObject*> aScope,
JS::Handle<JSObject*> aHandler,
JS::MutableHandle<JSObject*> aBoundHandler) MOZ_OVERRIDE;
virtual nsIScriptGlobalObject *GetGlobalObject() MOZ_OVERRIDE;
inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; }
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -218,17 +218,18 @@ public:
};
nsresult
nsJSUtils::EvaluateString(JSContext* aCx,
const nsAString& aScript,
JS::Handle<JSObject*> aScopeObject,
JS::CompileOptions& aCompileOptions,
EvaluateOptions& aEvaluateOptions,
- JS::Value* aRetValue)
+ JS::Value* aRetValue,
+ void **aOffThreadToken)
{
PROFILER_LABEL("JS", "EvaluateString");
MOZ_ASSERT_IF(aCompileOptions.versionSet,
aCompileOptions.version != JSVERSION_UNKNOWN);
MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, aRetValue);
MOZ_ASSERT_IF(!aEvaluateOptions.reportUncaught, aRetValue);
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
@@ -260,19 +261,30 @@ nsJSUtils::EvaluateString(JSContext* aCx
}
// Scope the JSAutoCompartment so that we can later wrap the return value
// into the caller's cx.
{
JSAutoCompartment ac(aCx, aScopeObject);
JS::RootedObject rootedScope(aCx, aScopeObject);
- ok = JS::Evaluate(aCx, rootedScope, aCompileOptions,
- PromiseFlatString(aScript).get(),
- aScript.Length(), aRetValue);
+ if (aOffThreadToken) {
+ JSScript *script = JS::FinishOffThreadScript(aCx, JS_GetRuntime(aCx), *aOffThreadToken);
+ *aOffThreadToken = nullptr; // Mark the token as having been finished.
+ if (script) {
+ ok = JS_ExecuteScript(aCx, rootedScope, script, aRetValue);
+ } else {
+ ok = false;
+ }
+ } else {
+ ok = JS::Evaluate(aCx, rootedScope, aCompileOptions,
+ PromiseFlatString(aScript).get(),
+ aScript.Length(), aRetValue);
+ }
+
if (ok && aEvaluateOptions.coerceToString && !aRetValue->isUndefined()) {
JSString* str = JS_ValueToString(aCx, *aRetValue);
ok = !!str;
*aRetValue = ok ? JS::StringValue(str) : JS::UndefinedValue();
}
}
if (!ok) {
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -80,17 +80,18 @@ public:
}
};
static nsresult EvaluateString(JSContext* aCx,
const nsAString& aScript,
JS::Handle<JSObject*> aScopeObject,
JS::CompileOptions &aCompileOptions,
EvaluateOptions& aEvaluateOptions,
- JS::Value* aRetValue);
+ JS::Value* aRetValue,
+ void **aOffThreadToken = nullptr);
};
class nsDependentJSString : public nsDependentString
{
public:
/**
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -607,16 +607,17 @@ public:
/**
* Like nsIDOMWindow::Open, except that we don't navigate to the given URL.
*/
virtual nsresult
OpenNoNavigate(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, nsIDOMWindow **_retval) = 0;
void AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
+ void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext);
void MuteAudioContexts();
void UnmuteAudioContexts();
// Given an inner window, return its outer if the inner is the current inner.
// Otherwise (argument null or not an inner or not current) return null.
static nsPIDOMWindow* GetOuterFromCurrentInner(nsPIDOMWindow* aInner)
{
if (!aInner) {
@@ -703,17 +704,17 @@ protected:
nsPIDOMWindow *mInnerWindow;
nsCOMPtr<nsPIDOMWindow> mOuterWindow;
// the element within the document that is currently focused when this
// window is active
nsCOMPtr<nsIContent> mFocusedNode;
// The AudioContexts created for the current document, if any.
- nsTArray<nsRefPtr<mozilla::dom::AudioContext> > mAudioContexts;
+ nsTArray<mozilla::dom::AudioContext*> mAudioContexts; // Weak
// A unique (as long as our 64-bit counter doesn't roll over) id for
// this window.
uint64_t mWindowID;
// This is only used by the inner window. Set to true once we've sent
// the (chrome|content)-document-global-created notification.
bool mHasNotifiedGlobalCreated;
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -711,17 +711,17 @@ ReportGhostWindowsEnumerator(nsUint64Has
AppendWindowURI(window, path);
nsresult rv = data->callback->Callback(
/* process = */ EmptyCString(),
path,
nsIMemoryReporter::KIND_OTHER,
nsIMemoryReporter::UNITS_COUNT,
/* amount = */ 1,
- /* desc = */ EmptyCString(),
+ /* description = */ NS_LITERAL_CSTRING("A ghost window."),
data->closure);
if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
data->rv = rv;
}
return PL_DHASH_NEXT;
}
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -747,16 +747,20 @@ DOMInterfaces = {
'MouseEvent': {
'nativeType': 'nsDOMMouseEvent',
},
'MouseScrollEvent': {
'nativeType': 'nsDOMMouseScrollEvent',
},
+'MozCanvasPrintState': {
+ 'headerFile': 'mozilla/dom/HTMLCanvasElement.h',
+ 'nativeType': 'mozilla::dom::HTMLCanvasPrintState',
+},
'MozChannel': [
{
'nativeType': 'nsIChannel',
'notflattened': True
},
{
'workers': True,
@@ -766,17 +770,17 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::CellBroadcast',
},
'MozNamedAttrMap': {
'nativeType': 'nsDOMAttributeMap',
},
'MozPowerManager': {
- 'nativeType': 'mozilla::dom::power::PowerManager',
+ 'nativeType': 'mozilla::dom::PowerManager',
},
'MozStkCommandEvent' : {
'nativeType': 'mozilla::dom::icc::StkCommandEvent',
'headerFile': 'StkCommandEvent.h',
},
'MozTimeManager': {
@@ -1765,18 +1769,16 @@ addExternalIface('Counter')
addExternalIface('CSSRule')
addExternalIface('DeviceAcceleration', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
addExternalIface('DeviceRotationRate', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
addExternalIface('CSSRuleList')
addExternalIface('DOMStringList')
addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
addExternalIface('File')
-addExternalIface('FileCallback', nativeType='nsIFileCallback',
- headerFile='nsIDOMHTMLCanvasElement.h')
addExternalIface('HitRegionOptions', nativeType='nsISupports')
addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
addExternalIface('LockedFile')
addExternalIface('MediaList')
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
@@ -1806,18 +1808,16 @@ addExternalIface('nsIInputStreamCallback
addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
addExternalIface('nsISupports', nativeType='nsISupports')
addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
addExternalIface('OutputStream', nativeType='nsIOutputStream',
notflattened=True)
addExternalIface('Principal', nativeType='nsIPrincipal',
headerFile='nsIPrincipal.h', notflattened=True)
-addExternalIface('PrintCallback', nativeType='nsIPrintCallback',
- headerFile='nsIDOMHTMLCanvasElement.h')
addExternalIface('Selection', nativeType='nsISelection')
addExternalIface('StackFrame', nativeType='nsIStackFrame',
headerFile='nsIException.h', notflattened=True)
addExternalIface('StyleSheetList')
addExternalIface('SVGLength')
addExternalIface('SVGNumber')
addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
notflattened=True)
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -99,16 +99,19 @@ private:
{
MOZ_ASSERT(aCallback && !mCallback);
// Set mCallback before we hold, on the off chance that a GC could somehow
// happen in there... (which would be pretty odd, granted).
mCallback = aCallback;
mozilla::HoldJSObjects(this);
}
+ CallbackObject(const CallbackObject&) MOZ_DELETE;
+ CallbackObject& operator =(const CallbackObject&) MOZ_DELETE;
+
protected:
void DropCallback()
{
if (mCallback) {
mCallback = nullptr;
mozilla::DropJSObjects(this);
}
}
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10536,16 +10536,17 @@ struct PrototypeTraits;
(includes, implincludes,
declarations, unions) = UnionTypes(config.getDescriptors(),
config.getDictionaries(),
config.getCallbacks(),
config)
includes.add("mozilla/dom/OwningNonNull.h")
includes.add("mozilla/dom/UnionMember.h")
+ includes.add("mozilla/dom/BindingDeclarations.h")
implincludes.add("mozilla/dom/PrimitiveConversions.h")
# Wrap all of that in our namespaces.
curr = CGNamespace.build(['mozilla', 'dom'], unions)
curr = CGWrapper(curr, post='\n')
namespaces = []
@@ -10738,22 +10739,25 @@ class CGEventMethod(CGNativeMember):
self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
self.args.append(Argument('ErrorResult&', 'aRv'))
return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
def define(self, cgClass):
self.args = list(self.originalArgs)
members = ""
holdJS = ""
- for m in self.descriptorProvider.interface.members:
- if m.isAttr():
- name = CGDictionary.makeMemberName(m.identifier.name)
- members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
- if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
- holdJS = "mozilla::HoldJSObjects(e.get());\n"
+ iface = self.descriptorProvider.interface
+ while iface.identifier.name != "Event":
+ for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members:
+ if m.isAttr():
+ name = CGDictionary.makeMemberName(m.identifier.name)
+ members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
+ if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
+ holdJS = "mozilla::HoldJSObjects(e.get());\n"
+ iface = iface.parent
self.body = (
"nsRefPtr<${nativeType}> e = new ${nativeType}(aOwner);\n"
"bool trusted = e->Init(aOwner);\n"
"e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);\n"
"${members}"
"e->SetTrusted(trusted);\n"
"${holdJS}"
@@ -10819,31 +10823,34 @@ class CGEventClass(CGBindingImplClass):
nativeType = "JS::Heap<JS::Value>"
elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
nativeType = "JS::Heap<JSObject*>"
members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
nativeType,
visibility="private",
body="body"))
+ parent = self.descriptor.interface.parent
+ self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1]
baseDeclarations=(
"public:\n"
" NS_DECL_ISUPPORTS_INHERITED\n"
- " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, nsDOMEvent)\n"
+ " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})\n"
" virtual ~${nativeType}();\n"
"protected:\n"
" ${nativeType}(mozilla::dom::EventTarget* aOwner);\n\n")
baseDeclarations = string.Template(baseDeclarations).substitute(
{
- "nativeType": self.descriptor.nativeType.split('::')[-1]
+ "nativeType": self.descriptor.nativeType.split('::')[-1],
+ "parentType": self.parentType
})
CGClass.__init__(self, descriptor.nativeType.split('::')[-1],
- bases=[ClassBase("nsDOMEvent")],
+ bases=[ClassBase(self.parentType)],
methods=self.methodDecls,
members=members,
extradeclarations=baseDeclarations)
def getWrapObjectBody(self):
return "return %sBinding::Wrap(aCx, aScope, this);" % self.descriptor.name
def implTraverse(self):
@@ -10886,47 +10893,52 @@ class CGEventClass(CGBindingImplClass):
member = CGDictionary.makeMemberName(m.identifier.name);
if m.type.isAny():
dropJS += " " + member + " = JS::UndefinedValue();\n"
elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
dropJS += " " + member + " = nullptr;\n"
if dropJS != "":
dropJS += " mozilla::DropJSObjects(this);\n"
# Just override CGClass and do our own thing
+ nativeType = self.descriptor.nativeType.split('::')[-1]
+ ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "nsDOMEvent"
+ else "aOwner")
classImpl = """
NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
-NS_IMPL_ADDREF_INHERITED(${nativeType}, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(${nativeType}, nsDOMEvent)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
+NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
${traverse}NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
${trace}NS_IMPL_CYCLE_COLLECTION_TRACE_END
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
${unlink}NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType})
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+NS_INTERFACE_MAP_END_INHERITING(${parentType})
${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
- : nsDOMEvent(aOwner, nullptr, nullptr)
+ : ${parentType}(${ctorParams})
{
}
${nativeType}::~${nativeType}()
{
${dropJS}}
"""
return string.Template(classImpl).substitute(
{ "ifaceName": self.descriptor.name,
- "nativeType": self.descriptor.nativeType.split('::')[-1],
+ "nativeType": nativeType,
+ "ctorParams": ctorParams,
+ "parentType": self.parentType,
"traverse": self.implTraverse(),
"unlink": self.implUnlink(),
"trace": self.implTrace(),
"dropJS": dropJS}
) + CGBindingImplClass.define(self)
class CGEventRoot(CGThing):
@@ -10937,19 +10949,21 @@ class CGEventRoot(CGThing):
self.root = CGWrapper(CGEventClass(descriptor),
pre="\n", post="\n")
self.root = CGNamespace.build(["mozilla", "dom"], self.root)
self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
self.root], "\n")
+ parent = descriptor.interface.parent.identifier.name
+
# Throw in our #includes
self.root = CGHeaders([descriptor], [], [], [],
- [ "nsDOMEvent.h",
+ [ config.getDescriptor(parent, False).headerFile,
"mozilla/Attributes.h",
"mozilla/ErrorResult.h" ,
"mozilla/dom/%sBinding.h" % interfaceName,
'mozilla/dom/BindingUtils.h',
],
[ "%s.h" % interfaceName,
"js/GCAPI.h",
'mozilla/dom/Nullable.h',
--- a/dom/camera/test/Makefile.in
+++ b/dom/camera/test/Makefile.in
@@ -1,21 +1,8 @@
#
# 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/.
-DEPTH = @DEPTH@
-topsrcdir = @top_srcdir@
-srcdir = @srcdir@
-VPATH = @srcdir@
-relativesrcdir = @relativesrcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-DIRS = \
- $(NULL)
-
MOCHITEST_FILES = \
test_camera.html \
$(NULL)
-
-include $(topsrcdir)/config/rules.mk
--- a/dom/gamepad/GamepadService.cpp
+++ b/dom/gamepad/GamepadService.cpp
@@ -7,28 +7,29 @@
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "GamepadService.h"
#include "Gamepad.h"
#include "nsAutoPtr.h"
#include "nsIDOMEvent.h"
#include "nsIDOMDocument.h"
-#include "nsIDOMGamepadButtonEvent.h"
-#include "nsIDOMGamepadAxisMoveEvent.h"
-#include "nsIDOMGamepadEvent.h"
#include "GeneratedEvents.h"
#include "nsIDOMWindow.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsITimer.h"
#include "nsThreadUtils.h"
#include "mozilla/Services.h"
+#include "mozilla/dom/GamepadAxisMoveEvent.h"
+#include "mozilla/dom/GamepadButtonEvent.h"
+#include "mozilla/dom/GamepadEvent.h"
+
#include <cstddef>
namespace mozilla {
namespace dom {
namespace {
const char* kGamepadEnabledPref = "dom.gamepad.enabled";
const char* kGamepadEventsEnabledPref =
@@ -236,28 +237,29 @@ GamepadService::NewButtonEvent(uint32_t
}
void
GamepadService::FireButtonEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t aButton,
double aValue)
{
- nsCOMPtr<nsIDOMEvent> event;
- bool defaultActionEnabled = true;
- NS_NewDOMGamepadButtonEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
- nsCOMPtr<nsIDOMGamepadButtonEvent> je = do_QueryInterface(event);
- MOZ_ASSERT(je, "QI should not fail");
-
-
nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
NS_LITERAL_STRING("gamepadbuttonup");
- je->InitGamepadButtonEvent(name, false, false, aGamepad, aButton);
- je->SetTrusted(true);
+ GamepadButtonEventInitInitializer init;
+ init.mBubbles = false;
+ init.mCancelable = false;
+ init.mGamepad = aGamepad;
+ init.mButton = aButton;
+ nsRefPtr<GamepadButtonEvent> event =
+ GamepadButtonEvent::Constructor(aTarget, name, init);
+ event->SetTrusted(true);
+
+ bool defaultActionEnabled = true;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue)
{
if (mShuttingDown || aIndex >= mGamepads.Length()) {
return;
@@ -300,27 +302,30 @@ GamepadService::NewAxisMoveEvent(uint32_
}
void
GamepadService::FireAxisMoveEvent(EventTarget* aTarget,
Gamepad* aGamepad,
uint32_t aAxis,
double aValue)
{
- nsCOMPtr<nsIDOMEvent> event;
+ GamepadAxisMoveEventInitInitializer init;
+ init.mBubbles = false;
+ init.mCancelable = false;
+ init.mGamepad = aGamepad;
+ init.mAxis = aAxis;
+ init.mValue = aValue;
+ nsRefPtr<GamepadAxisMoveEvent> event =
+ GamepadAxisMoveEvent::Constructor(aTarget,
+ NS_LITERAL_STRING("gamepadaxismove"),
+ init);
+
+ event->SetTrusted(true);
+
bool defaultActionEnabled = true;
- NS_NewDOMGamepadAxisMoveEvent(getter_AddRefs(event), aTarget, nullptr,
- nullptr);
- nsCOMPtr<nsIDOMGamepadAxisMoveEvent> je = do_QueryInterface(event);
- MOZ_ASSERT(je, "QI should not fail");
-
- je->InitGamepadAxisMoveEvent(NS_LITERAL_STRING("gamepadaxismove"),
- false, false, aGamepad, aAxis, aValue);
- je->SetTrusted(true);
-
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
{
if (mShuttingDown || aIndex >= mGamepads.Length()) {
return;
@@ -376,27 +381,28 @@ GamepadService::NewConnectionEvent(uint3
}
}
void
GamepadService::FireConnectionEvent(EventTarget* aTarget,
Gamepad* aGamepad,
bool aConnected)
{
- nsCOMPtr<nsIDOMEvent> event;
- bool defaultActionEnabled = true;
- NS_NewDOMGamepadEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
- nsCOMPtr<nsIDOMGamepadEvent> je = do_QueryInterface(event);
- MOZ_ASSERT(je, "QI should not fail");
-
nsString name = aConnected ? NS_LITERAL_STRING("gamepadconnected") :
NS_LITERAL_STRING("gamepaddisconnected");
- je->InitGamepadEvent(name, false, false, aGamepad);
- je->SetTrusted(true);
+ GamepadEventInitInitializer init;
+ init.mBubbles = false;
+ init.mCancelable = false;
+ init.mGamepad = aGamepad;
+ nsRefPtr<GamepadEvent> event =
+ GamepadEvent::Constructor(aTarget, name, init);
+ event->SetTrusted(true);
+
+ bool defaultActionEnabled = true;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad)
{
if (mShuttingDown || !mEnabled || aIndex > mGamepads.Length()) {
return;
--- a/dom/interfaces/events/moz.build
+++ b/dom/interfaces/events/moz.build
@@ -13,26 +13,22 @@ XPIDL_SOURCES += [
'nsIDOMCompositionEvent.idl',
'nsIDOMCustomEvent.idl',
'nsIDOMDOMTransactionEvent.idl',
'nsIDOMDataContainerEvent.idl',
'nsIDOMDataTransfer.idl',
'nsIDOMDeviceLightEvent.idl',
'nsIDOMDeviceMotionEvent.idl',
'nsIDOMDeviceOrientationEvent.idl',
- 'nsIDOMDeviceProximityEvent.idl',
'nsIDOMDragEvent.idl',
'nsIDOMElementReplaceEvent.idl',
'nsIDOMEvent.idl',
'nsIDOMEventListener.idl',
'nsIDOMEventTarget.idl',
'nsIDOMFocusEvent.idl',
- 'nsIDOMGamepadAxisMoveEvent.idl',
- 'nsIDOMGamepadButtonEvent.idl',
- 'nsIDOMGamepadEvent.idl',
'nsIDOMHashChangeEvent.idl',
'nsIDOMKeyEvent.idl',
'nsIDOMMessageEvent.idl',
'nsIDOMMouseEvent.idl',
'nsIDOMMouseScrollEvent.idl',
'nsIDOMMutationEvent.idl',
'nsIDOMNSEvent.idl',
'nsIDOMNotifyAudioAvailableEvent.idl',
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMDeviceProximityEvent.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(86c7c396-9c2b-4d45-9c7c-b0dcda024105)]
-interface nsIDOMDeviceProximityEvent : nsIDOMEvent
-{
- [noscript] void initDeviceProximityEvent(in DOMString eventTypeArg,
- in boolean canBubbleArg,
- in boolean cancelableArg,
- in double value,
- in double min,
- in double max);
- readonly attribute double value;
- readonly attribute double min;
- readonly attribute double max;
-};
-
-
-dictionary DeviceProximityEventInit : EventInit
-{
- double value = Infinity;
- double min = -Infinity;
- double max = Infinity;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadAxisMoveEvent.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMGamepadEvent.idl"
-
-[builtinclass, scriptable, uuid(bd09eef8-8e07-4baf-8d39-4f92003dbca8)]
-interface nsIDOMGamepadAxisMoveEvent : nsIDOMGamepadEvent
-{
- /**
- * Index in gamepad.axes of the axis that was moved.
- */
- readonly attribute unsigned long axis;
-
- /**
- * Position of the axis in the range -1.0...1.0.
- */
- readonly attribute double value;
-
- [noscript]
- void initGamepadAxisMoveEvent(in DOMString typeArg,
- in boolean canBubbleArg,
- in boolean cancelableArg,
- in nsIDOMGamepad gamepad,
- in unsigned long axis,
- in double value);
-};
-
-dictionary GamepadAxisMoveEventInit : GamepadEventInit
-{
- unsigned long axis;
- double value;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadButtonEvent.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMGamepadEvent.idl"
-
-[builtinclass, scriptable, uuid(d75d4d2b-e7b4-4b93-ac35-2e70b57d9b28)]
-interface nsIDOMGamepadButtonEvent : nsIDOMGamepadEvent
-{
- /**
- * Index in gamepad.buttons of the button that was pressed or released.
- */
- readonly attribute unsigned long button;
-
- [noscript]
- void initGamepadButtonEvent(in DOMString typeArg,
- in boolean canBubbleArg,
- in boolean cancelableArg,
- in nsIDOMGamepad gamepad,
- in unsigned long button);
-};
-
-dictionary GamepadButtonEventInit : GamepadEventInit
-{
- unsigned long button;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadEvent.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEvent.idl"
-
-interface nsIDOMGamepad;
-
-[builtinclass, scriptable, uuid(93b048d6-2aef-46a9-b0f4-06d7f00d8ef2)]
-interface nsIDOMGamepadEvent : nsIDOMEvent
-{
- /**
- * The device that generated this event.
- */
- readonly attribute nsIDOMGamepad gamepad;
-
- [noscript]
- void initGamepadEvent(in DOMString typeArg,
- in boolean canBubbleArg,
- in boolean cancelableArg,
- in nsIDOMGamepad gamepad);
-};
-
-dictionary GamepadEventInit : EventInit
-{
- nsIDOMGamepad gamepad;
-};
--- a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
@@ -15,37 +15,16 @@
* @status UNDER_DEVELOPMENT
*/
interface nsIDOMBlob;
interface nsIDOMFile;
interface nsIVariant;
interface nsIInputStreamCallback;
-[scriptable, builtinclass, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a67)]
-interface nsIDOMMozCanvasPrintState : nsISupports
-{
- // A canvas rendering context.
- readonly attribute nsISupports context;
-
- // To be called when rendering to the context is done.
- void done();
-};
-
-[scriptable, function, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a66)]
-interface nsIPrintCallback : nsISupports
-{
- void render(in nsIDOMMozCanvasPrintState ctx);
-};
-
-[scriptable, function, uuid(6e9ffb59-2067-4aef-a51c-65e65a3e0d81)]
-interface nsIFileCallback : nsISupports {
- void receive(in nsIDOMBlob file);
-};
-
[scriptable, uuid(8978d1c5-2981-4678-a1c3-b0b7bae04fbc)]
interface nsIDOMHTMLCanvasElement : nsISupports
{
attribute unsigned long width;
attribute unsigned long height;
attribute boolean mozOpaque;
// Valid calls are:
@@ -56,30 +35,18 @@ interface nsIDOMHTMLCanvasElement : nsIS
DOMString toDataURL([optional] in DOMString type,
[optional] in jsval params);
// Valid calls are
// mozGetAsFile(name); -- defaults to image/png
// mozGetAsFile(name, type); -- uses given type
nsIDOMFile mozGetAsFile(in DOMString name, [optional] in DOMString type);
- // Valid calls are:
- // toBlob(); -- defaults to image/png
- // toBlob(type); -- uses given type
- // toBlob(type, params); -- uses given type, and any valid parameters
- [implicit_jscontext]
- void toBlob(in nsIFileCallback callback,
- [optional] in DOMString type,
- [optional] in jsval params);
-
// A Mozilla-only extension to get a canvas context backed by double-buffered
// shared memory. Only privileged callers can call this.
nsISupports MozGetIPCContext(in DOMString contextId);
// A Mozilla-only extension that returns the canvas' image data as a data
// stream in the desired image format.
void mozFetchAsStream(in nsIInputStreamCallback callback,
[optional] in DOMString type);
-
- // A Mozilla-only callback that is called during the printing process.
- attribute nsIPrintCallback mozPrintCallback;
};
--- a/dom/network/tests/marionette/manifest.ini
+++ b/dom/network/tests/marionette/manifest.ini
@@ -5,15 +5,16 @@ qemu = true
[test_mobile_networks.js]
disabled = Bug 808783
[test_mobile_voice_state.js]
[test_mobile_iccinfo.js]
[test_mobile_operator_names.js]
[test_mobile_preferred_network_type.js]
disabled = Bug 808783
+[test_mobile_data_connection.js]
[test_mobile_data_location.js]
[test_mobile_data_state.js]
[test_mobile_mmi.js]
[test_mobile_roaming_preference.js]
[test_call_barring_get_option.js]
[test_call_barring_set_error.js]
[test_call_barring_change_password.js]
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/marionette/test_mobile_data_connection.js
@@ -0,0 +1,308 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+
+const DATA_KEY = "ril.data.enabled";
+const DATA_ROAMING_KEY = "ril.data.roaming_enabled";
+const APN_KEY = "ril.data.apnSettings";
+
+SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
+SpecialPowers.addPermission("mobileconnection", true, document);
+SpecialPowers.addPermission("settings-read", true, document);
+SpecialPowers.addPermission("settings-write", true, document);
+
+let settings = window.navigator.mozSettings;
+let connection = window.navigator.mozMobileConnection;
+ok(connection instanceof MozMobileConnection,
+ "connection is instanceof " + connection.constructor);
+
+
+let pendingEmulatorCmdCount = 0;
+function sendCmdToEmulator(cmd, callback) {
+ ++pendingEmulatorCmdCount;
+
+ runEmulatorCmd(cmd, function (result) {
+ --pendingEmulatorCmdCount;
+
+ is(result[0], "OK", "Emulator response");
+
+ if (callback) {
+ callback();
+ }
+ });
+}
+
+let tasks = {
+ // List of test fuctions. Each of them should call |tasks.next()| when
+ // completed or |tasks.finish()| to jump to the last one.
+ _tasks: [],
+ _nextTaskIndex: 0,
+
+ push: function push(func) {
+ this._tasks.push(func);
+ },
+
+ next: function next() {
+ let index = this._nextTaskIndex++;
+ let task = this._tasks[index];
+ try {
+ task();
+ } catch (ex) {
+ ok(false, "test task[" + index + "] throws: " + ex);
+ // Run last task as clean up if possible.
+ if (index != this._tasks.length - 1) {
+ this.finish();
+ }
+ }
+ },
+
+ finish: function finish() {
+ this._tasks[this._tasks.length - 1]();
+ },
+
+ run: function run() {
+ this.next();
+ }
+};
+
+function setSetting(key, value, callback) {
+ let setLock = settings.createLock();
+ let obj = {};
+ obj[key] = value;
+
+ let setReq = setLock.set(obj);
+ setReq.addEventListener("success", function onSetSuccess() {
+ ok(true, "set '" + key + "' to " + obj[key]);
+ if (callback) {
+ callback();
+ }
+ });
+ setReq.addEventListener("error", function onSetError() {
+ ok(false, "cannot set '" + key + "'");
+ tasks.finish();
+ });
+}
+
+function getSetting(key, callback) {
+ let getLock = settings.createLock();
+
+ let getReq = getLock.get(key);
+ getReq.addEventListener("success", function onGetSuccess() {
+ ok(true, "get " + key + " setting okay");
+ let value = getReq.result[key];
+ callback(value);
+ });
+ getReq.addEventListener("error", function onGetError() {
+ ok(false, "cannot get '" + key + "'");
+ tasks.finish();
+ });
+}
+
+function setEmulatorAPN(callback) {
+ let apn =
+ [
+ [
+ {"carrier":"T-Mobile US",
+ "apn":"epc.tmobile.com",
+ "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc",
+ "types":["default","supl","mms"]}
+ ]
+ ];
+ setSetting(APN_KEY, apn, callback);
+}
+
+function setEmulatorRoaming(roaming, callback) {
+ log("Setting emulator roaming state: " + roaming + ".");
+
+ // Set voice registration state first and then data registration state.
+ let cmd = "gsm voice " + (roaming ? "roaming" : "home");
+ sendCmdToEmulator(cmd, function() {
+
+ connection.addEventListener("voicechange", function onvoicechange() {
+ connection.removeEventListener("voicechange", onvoicechange);
+ log("mobileConnection.voice.roaming is now '"
+ + connection.voice.roaming + "'.");
+ is(connection.voice.roaming, roaming, "voice.roaming");
+
+ let cmd = "gsm data " + (roaming ? "roaming" : "home");
+ sendCmdToEmulator(cmd, function () {
+
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.roaming is now '"
+ + connection.data.roaming + "'.");
+ is(connection.data.roaming, roaming, "data.roaming");
+ if (callback) {
+ callback();
+ }
+ });
+ });
+ });
+ });
+}
+
+function setEmulatorHome(callback) {
+ let voiceRegistration = false;
+ let dataRegistration = false;
+
+ if (connection.voice.state != "registered") {
+ sendCmdToEmulator("gsm voice home", function() {
+ connection.addEventListener("voicechange", function onvoicechange() {
+ connection.removeEventListener("voicechange", onvoicechange);
+ log("mobileConnection.voice.state is now '"
+ + connection.voice.state + "'.");
+ is(connection.voice.state, "registered", "voice.state");
+ voiceRegistration = true;
+ });
+ });
+ } else {
+ voiceRegistration = true;
+ }
+
+ if (connection.data.state != "registered") {
+ sendCmdToEmulator("gsm data home", function() {
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.state is now '"
+ + connection.data.state + "'.");
+ is(connection.data.state, "registered", "data.state");
+ dataRegistration = true;
+ });
+ });
+ } else {
+ dataRegistration = true;
+ }
+
+ waitFor(callback, function() {
+ return (voiceRegistration && dataRegistration);
+ });
+}
+
+
+tasks.push(function verifyInitialState() {
+ log("Verifying initial state.");
+
+ // Want to start test with mobileConnection.data.state 'registered',
+ // This is the default state; if it is not currently this value then set it.
+ setEmulatorHome(function() {
+ // Want to start test with data off,
+ // This is the default state; if it is not currently this value then set it.
+ getSetting(DATA_KEY, function(result) {
+ let value = result;
+ log("Starting data enabled: " + value);
+ if (value) {
+ setSetting(DATA_KEY, false);
+
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.connected is now '"
+ + connection.data.connected + "'.");
+ is(connection.data.connected, false, "data.connected");
+ setEmulatorAPN(function() {
+ tasks.next();
+ });
+ });
+ } else {
+ setEmulatorAPN(function() {
+ tasks.next();
+ });
+ }
+ });
+ });
+});
+
+tasks.push(function testEnableData() {
+ log("Turn data on.");
+
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.connected is now '"
+ + connection.data.connected + "'.");
+ is(connection.data.connected, true, "data.connected");
+ tasks.next();
+ });
+
+ setSetting(DATA_KEY, true);
+});
+
+tasks.push(function testDisableDataRoamingWhileRoaming() {
+ log("Disable data roaming while roaming.");
+
+ setSetting(DATA_ROAMING_KEY, false);
+
+ // Wait for roaming state to change, then data connection should
+ // be disconnected due to data roaming set to off.
+ setEmulatorRoaming(true, function() {
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.connected is now '"
+ + connection.data.connected + "'.");
+ is(connection.data.connected, false, "data.connected");
+ tasks.next();
+ });
+ });
+});
+
+tasks.push(function testEnableDataRoamingWhileRoaming() {
+ log("Enable data roaming while roaming.");
+
+ // Data should be re-connected as we enabled data roaming.
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.connected is now '"
+ + connection.data.connected + "'.");
+ is(connection.data.connected, true, "data.connected");
+ tasks.next();
+ });
+
+ setSetting(DATA_ROAMING_KEY, true);
+});
+
+tasks.push(function testDisableDataRoamingWhileNotRoaming() {
+ log("Disable data roaming while not roaming.");
+
+ // Wait for roaming state to change then set data roaming back
+ // to off.
+ setEmulatorRoaming(false, function() {
+ setSetting(DATA_ROAMING_KEY, false);
+
+ // No change event will be received cause data connection state
+ // remains the same.
+ window.setTimeout(function() {
+ is(connection.data.connected, true, "data.connected");
+ tasks.next();
+ }, 1000);
+ });
+});
+
+tasks.push(function testDisableData() {
+ log("Turn data off.");
+
+ connection.addEventListener("datachange", function ondatachange() {
+ connection.removeEventListener("datachange", ondatachange);
+ log("mobileConnection.data.connected is now '"
+ + connection.data.connected + "'.");
+ is(connection.data.connected, false, "data.connected");
+ tasks.next();
+ });
+
+ setSetting(DATA_KEY, false);
+});
+
+// WARNING: All tasks should be pushed before this!!!
+tasks.push(function cleanUp() {
+ if (pendingEmulatorCmdCount) {
+ window.setTimeout(cleanUp, 100);
+ return;
+ }
+
+ SpecialPowers.removePermission("mobileconnection", document);
+ SpecialPowers.removePermission("settings-write", document);
+ SpecialPowers.removePermission("settings-read", document);
+ SpecialPowers.clearUserPref("dom.mozSettings.enabled");
+ finish();
+});
+
+tasks.run();
+
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,30 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "mozilla/dom/PowerManager.h"
+
#include "mozilla/Hal.h"
-#include "PowerManager.h"
#include "WakeLock.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIDocument.h"
#include "nsIPermissionManager.h"
#include "nsIPowerManagerService.h"
#include "nsIPrincipal.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
#include "nsError.h"
#include "mozilla/dom/MozPowerManagerBinding.h"
namespace mozilla {
namespace dom {
-namespace power {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PowerManager)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozWakeLockListener)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(PowerManager, mListeners, mWindow)
@@ -200,11 +200,10 @@ PowerManager::CreateInstance(nsPIDOMWind
nsRefPtr<PowerManager> powerManager = new PowerManager();
if (NS_FAILED(powerManager->Init(aWindow))) {
powerManager = nullptr;
}
return powerManager.forget();
}
-} // power
} // dom
} // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -14,17 +14,16 @@
#include "nsWrapperCache.h"
class nsPIDOMWindow;
namespace mozilla {
class ErrorResult;
namespace dom {
-namespace power {
class PowerManager MOZ_FINAL : public nsIDOMMozWakeLockListener
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PowerManager)
NS_DECL_NSIDOMMOZWAKELOCKLISTENER
@@ -61,13 +60,12 @@ public:
bool CpuSleepAllowed();
void SetCpuSleepAllowed(bool aAllowed);
private:
nsCOMPtr<nsIDOMWindow> mWindow;
nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
};
-} // namespace power
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_power_PowerManager_h
--- a/dom/power/WakeLock.cpp
+++ b/dom/power/WakeLock.cpp
@@ -9,17 +9,16 @@
#include "mozilla/HalWakeLock.h"
#include "nsDOMClassInfoID.h"
#include "nsDOMEvent.h"
#include "nsError.h"
#include "nsIDocument.h"
#include "nsIDOMWindow.h"
#include "nsIDOMEvent.h"
#include "nsPIDOMWindow.h"
-#include "PowerManager.h"
DOMCI_DATA(MozWakeLock, mozilla::dom::power::WakeLock)
using namespace mozilla::hal;
namespace mozilla {
namespace dom {
namespace power {
--- a/dom/power/moz.build
+++ b/dom/power/moz.build
@@ -10,18 +10,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
XPIDL_SOURCES += [
'nsIDOMWakeLock.idl',
'nsIDOMWakeLockListener.idl',
'nsIPowerManagerService.idl',
]
XPIDL_MODULE = 'dom_power'
+EXPORTS.mozilla.dom += [
+ 'PowerManager.h',
+]
+
EXPORTS.mozilla.dom.power += [
- 'PowerManager.h',
'PowerManagerService.h',
'Types.h',
]
CPP_SOURCES += [
'PowerManager.cpp',
'PowerManagerService.cpp',
'WakeLock.cpp',
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1353,20 +1353,17 @@ let RIL = {
* String containing the number to dial.
* @param clirMode
* Integer for showing/hidding the caller Id to the called party.
* @param uusInfo
* Integer doing something XXX TODO
*/
dial: function dial(options) {
let onerror = (function onerror(errorMsg) {
- options.callIndex = -1;
- options.rilMessageType = "callError";
- options.errorMsg = errorMsg;
- this.sendChromeMessage(options);
+ this._sendCallError(-1, errorMsg);
}).bind(this);
if (this._isEmergencyNumber(options.number)) {
this.dialEmergencyNumber(options, onerror);
} else {
if (!this._isCdma) {
// TODO: Both dial() and sendMMI() functions should be unified at some
// point in the future. In the mean time we handle temporary CLIR MMI
@@ -3647,17 +3644,25 @@ let RIL = {
},
_handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
let message = {rilMessageType: "callDisconnected",
call: disconnectedCall};
this.sendChromeMessage(message);
},
+ _sendCallError: function _sendCallError(callIndex, errorMsg) {
+ this.sendChromeMessage({rilMessageType: "callError",
+ callIndex: callIndex,
+ errorMsg: errorMsg});
+ },
+
_sendDataCallError: function _sendDataCallError(message, errorCode) {
+ // Should not include token for unsolicited response.
+ delete message.rilMessageToken;
message.rilMessageType = "datacallerror";
if (errorCode == ERROR_GENERIC_FAILURE) {
message.errorMsg = RIL_ERROR_TO_GECKO_ERROR[errorCode];
} else {
message.errorMsg = RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[errorCode];
}
this.sendChromeMessage(message);
},
@@ -4974,19 +4979,18 @@ RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = func
}
let failCause = Buf.readUint32();
switch (failCause) {
case CALL_FAIL_NORMAL:
this._handleDisconnectedCall(options);
break;
default:
- options.rilMessageType = "callError";
- options.errorMsg = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause];
- this.sendChromeMessage(options);
+ this._sendCallError(options.callIndex,
+ RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause]);
break;
}
};
RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) {
this._receivedNetworkInfo(NETWORK_INFO_SIGNAL);
if (options.rilRequestError) {
return;
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -13,16 +13,17 @@
#include "nsPIDOMWindow.h"
#include "nsIDOMDocument.h"
#include "nsIServiceManager.h"
#include "nsIServiceManager.h"
#include "GeneratedEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/Attributes.h"
#include "nsIPermissionManager.h"
+#include "mozilla/dom/DeviceProximityEvent.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace hal;
#undef near
// also see sDefaultSensorHint in mobile/android/base/GeckoAppShell.java
@@ -252,27 +253,26 @@ nsDeviceSensors::FireDOMLightEvent(mozil
}
void
nsDeviceSensors::FireDOMProximityEvent(mozilla::dom::EventTarget* aTarget,
double aValue,
double aMin,
double aMax)
{
- nsCOMPtr<nsIDOMEvent> event;
- NS_NewDOMDeviceProximityEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
- nsCOMPtr<nsIDOMDeviceProximityEvent> oe = do_QueryInterface(event);
-
- oe->InitDeviceProximityEvent(NS_LITERAL_STRING("deviceproximity"),
- true,
- false,
- aValue,
- aMin,
- aMax);
-
+ DeviceProximityEventInitInitializer init;
+ init.mBubbles = true;
+ init.mCancelable = false;
+ init.mValue = aValue;
+ init.mMin = aMin;
+ init.mMax = aMax;
+ nsRefPtr<DeviceProximityEvent> event =
+ DeviceProximityEvent::Constructor(aTarget,
+ NS_LITERAL_STRING("deviceproximity"),
+ init);
event->SetTrusted(true);
bool defaultActionEnabled;
aTarget->DispatchEvent(event, &defaultActionEnabled);
// Some proximity sensors only support a binary near or
// far measurement. In this case, the sensor should report
// its maximum range value in the far state and a lesser
--- a/dom/system/nsDeviceSensors.h
+++ b/dom/system/nsDeviceSensors.h
@@ -8,17 +8,16 @@
#include "nsIDeviceSensors.h"
#include "nsIDOMDeviceMotionEvent.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
#include "nsITimer.h"
#include "nsIDOMDeviceLightEvent.h"
#include "nsIDOMDeviceOrientationEvent.h"
-#include "nsIDOMDeviceProximityEvent.h"
#include "nsIDOMUserProximityEvent.h"
#include "nsIDOMDeviceMotionEvent.h"
#include "nsDOMDeviceMotionEvent.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/HalSensor.h"
#include "nsDataHashtable.h"
#define NS_DEVICE_SENSORS_CID \
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -6,16 +6,17 @@ qemu = true
[test_crash_emulator.js]
[test_incoming_answer_hangup.js]
[test_incoming_reject.js]
[test_outgoing_answer_hangup.js]
[test_incoming_answer_hangup_oncallschanged.js]
[test_outgoing_answer_hangup_oncallschanged.js]
[test_outgoing_hangup_alerting.js]
[test_outgoing_hangup_held.js]
+[test_outgoing_radio_off.js]
[test_outgoing_badNumber.js]
[test_outgoing_busy.js]
[test_outgoing_reject.js]
[test_incoming_hold_resume.js]
[test_outgoing_hold_resume.js]
[test_incoming_already_connected.js]
[test_incoming_answer_remote_hangup.js]
[test_incoming_connecting_hangup.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js
@@ -0,0 +1,126 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+
+permissions = [
+ "mobileconnection",
+ "settings-write",
+ "telephony"
+];
+
+for (let per of permissions) {
+ SpecialPowers.addPermission(per, true, document);
+}
+
+let gSettingsEnabled = SpecialPowers.getBoolPref("dom.mozSettings.enabled");
+if (!gSettingsEnabled) {
+ SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
+}
+
+let icc = navigator.mozIccManager;
+ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor);
+
+let connection = navigator.mozMobileConnection;
+ok(connection instanceof MozMobileConnection,
+ "connection is instanceof " + connection.constructor);
+
+let telephony = navigator.mozTelephony;
+ok(telephony instanceof Telephony,
+ "telephony is instanceof " + telephony.constructor);
+
+let outgoing;
+let pendingEmulatorCmdCount = 0;
+
+function sendToEmulator(cmd, callback) {
+ pendingEmulatorCmdCount++;
+ runEmulatorCmd(cmd, function (result) {
+ pendingEmulatorCmdCount--;
+ if (callback && typeof callback === 'function') {
+ callback(result);
+ }
+ });
+}
+
+function changeSetting(key, value, callback) {
+ let obj = {};
+ obj[key] = value;
+
+ let setReq = navigator.mozSettings.createLock().set(obj);
+ setReq.addEventListener("success", function onSetSuccess() {
+ ok(true, "set '" + key + "' to " + obj[key]);
+ setReq.removeEventListener("success", onSetSuccess);
+ callback();
+ });
+ setReq.addEventListener("error", function onSetError() {
+ ok(false, "cannot set '" + key + "'");
+ cleanUp();
+ });
+}
+
+function setRadioEnabled(enabled, callback) {
+ changeSetting("ril.radio.disabled", !enabled, function() {
+ icc.addEventListener("cardstatechange", function handler() {
+ // Wait until card state changes to "ready" after turning on radio.
+ // Wait until card state changes to "not-ready" after turning off radio.
+ if ((enabled && icc.cardState == "ready") ||
+ (!enabled && icc.cardState != "ready")) {
+ icc.removeEventListener("cardstatechange", handler);
+ callback();
+ }
+ });
+ });
+}
+
+function dial(number) {
+ // Verify initial state before dial.
+ ok(telephony);
+ is(telephony.active, null);
+ ok(telephony.calls);
+ is(telephony.calls.length, 0);
+
+ log("Make an outgoing call.");
+ outgoing = telephony.dial(number);
+
+ ok(outgoing);
+ is(outgoing.number, number);
+ is(outgoing.state, "dialing");
+
+ is(telephony.active, outgoing);
+ is(telephony.calls.length, 1);
+ is(telephony.calls[0], outgoing);
+
+ outgoing.onerror = function onerror(event) {
+ log("Received 'error' event.");
+ is(event.call, outgoing);
+ ok(event.call.error);
+ is(event.call.error.name, "RadioNotAvailable");
+
+ sendToEmulator("gsm list", function(result) {
+ log("Initial call list: " + result);
+ is(result[0], "OK");
+
+ setRadioEnabled(true, cleanUp);
+ });
+ };
+}
+
+function cleanUp() {
+ if (pendingEmulatorCmdCount) {
+ window.setTimeout(cleanUp, 100);
+ return;
+ }
+
+ for (let per of permissions) {
+ SpecialPowers.removePermission(per, document);
+ }
+ SpecialPowers.clearUserPref("dom.mozSettings.enabled");
+ finish();
+}
+
+setRadioEnabled(false, function() {
+ sendToEmulator("gsm clear", function(result) {
+ is(result[0], "OK");
+ dial("0912345678");
+ });
+});
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -310,17 +310,16 @@ var interfaceNamesInGlobalScope =
"MessageEvent",
"MimeType",
"MimeTypeArray",
"ModalContentWindow",
"MouseEvent",
"MouseScrollEvent",
{name: "MozActivity", b2g: true},
"MozApplicationEvent",
- "MozCanvasPrintState",
{name: "MozCellBroadcast", b2g: true},
{name: "MozCellBroadcastEvent", b2g: true},
"MozConnection",
"mozContact",
"MozContactChangeEvent",
"MozCSSKeyframeRule",
"MozCSSKeyframesRule",
{name: "MozEmergencyCbModeEvent", b2g: true},
--- a/dom/webidl/DeviceProximityEvent.webidl
+++ b/dom/webidl/DeviceProximityEvent.webidl
@@ -1,15 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-[Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
+[Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict)]
interface DeviceProximityEvent : Event
{
readonly attribute double value;
readonly attribute double min;
readonly attribute double max;
};
dictionary DeviceProximityEventInit : EventInit
--- a/dom/webidl/GamepadAxisMoveEvent.webidl
+++ b/dom/webidl/GamepadAxisMoveEvent.webidl
@@ -1,17 +1,16 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Pref="dom.gamepad.non_standard_events.enabled",
- Constructor(DOMString type, optional GamepadAxisMoveEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadAxisMoveEventInit eventInitDict)]
interface GamepadAxisMoveEvent : GamepadEvent
{
readonly attribute unsigned long axis;
readonly attribute double value;
};
dictionary GamepadAxisMoveEventInit : GamepadEventInit
{
--- a/dom/webidl/GamepadButtonEvent.webidl
+++ b/dom/webidl/GamepadButtonEvent.webidl
@@ -1,17 +1,16 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Pref="dom.gamepad.non_standard_events.enabled",
- Constructor(DOMString type, optional GamepadButtonEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadButtonEventInit eventInitDict)]
interface GamepadButtonEvent : GamepadEvent
{
readonly attribute unsigned long button;
};
dictionary GamepadButtonEventInit : GamepadEventInit
{
unsigned long button = 0;
--- a/dom/webidl/GamepadEvent.webidl
+++ b/dom/webidl/GamepadEvent.webidl
@@ -1,17 +1,16 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Pref="dom.gamepad.enabled",
- Constructor(DOMString type, optional GamepadEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadEventInit eventInitDict)]
interface GamepadEvent : Event
{
readonly attribute Gamepad? gamepad;
};
dictionary GamepadEventInit : EventInit
{
Gamepad? gamepad = null;
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -6,20 +6,18 @@
* The origin of this IDL file is
* http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
interface Blob;
-interface FileCallback;
interface nsIInputStreamCallback;
interface nsISupports;
-interface PrintCallback;
interface Variant;
interface HTMLCanvasElement : HTMLElement {
[Pure, SetterThrows]
attribute unsigned long width;
[Pure, SetterThrows]
attribute unsigned long height;
@@ -42,8 +40,22 @@ partial interface HTMLCanvasElement {
[Throws]
File mozGetAsFile(DOMString name, optional DOMString? type = null);
[ChromeOnly, Throws]
nsISupports? MozGetIPCContext(DOMString contextId);
[ChromeOnly]
void mozFetchAsStream(nsIInputStreamCallback callback, optional DOMString? type = null);
attribute PrintCallback? mozPrintCallback;
};
+
+[ChromeOnly]
+interface MozCanvasPrintState
+{
+ // A canvas rendering context.
+ readonly attribute nsISupports context;
+
+ // To be called when rendering to the context is done.
+ void done();
+};
+
+callback PrintCallback = void(MozCanvasPrintState ctx);
+
+callback FileCallback = void(Blob file);
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -22,21 +22,31 @@ interface MutationRecord {
};
[Constructor(MutationCallback mutationCallback)]
interface MutationObserver {
[Throws]
void observe(Node target, optional MutationObserverInit options);
void disconnect();
sequence<MutationRecord> takeRecords();
+
+ [ChromeOnly]
+ sequence<MutationObservingInfo?> getObservingInfo();
+ [ChromeOnly]
+ readonly attribute MutationCallback mutationCallback;
};
callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
dictionary MutationObserverInit {
boolean childList = false;
boolean attributes = false;
boolean characterData = false;
boolean subtree = false;
boolean attributeOldValue = false;
boolean characterDataOldValue = false;
sequence<DOMString> attributeFilter;
};
+
+dictionary MutationObservingInfo : MutationObserverInit
+{
+ Node? observedNode = null;
+};
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -99,9 +99,11 @@ interface Node : EventTarget {
[Throws, Func="IsChromeOrXBL"]
any setUserData(DOMString key, any data, UserDataHandler? handler);
[Throws, Func="IsChromeOrXBL"]
any getUserData(DOMString key);
[ChromeOnly]
readonly attribute Principal nodePrincipal;
[ChromeOnly]
readonly attribute URI? baseURIObject;
+ [ChromeOnly]
+ sequence<MutationObserver> getBoundMutationObservers();
};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -455,17 +455,16 @@ if CONFIG['MOZ_B2G_RIL']:
'MozVoicemail.webidl',
]
WEBIDL_FILES += [
'CloseEvent.webidl',
'CustomEvent.webidl',
'DeviceLightEvent.webidl',
'DeviceOrientationEvent.webidl',
- 'DeviceProximityEvent.webidl',
'DeviceStorageChangeEvent.webidl',
'DOMTransactionEvent.webidl',
'ElementReplaceEvent.webidl',
'HashChangeEvent.webidl',
'MozApplicationEvent.webidl',
'MozContactChangeEvent.webidl',
'MozMmsEvent.webidl',
'MozSettingsEvent.webidl',
@@ -502,23 +501,16 @@ if CONFIG['MOZ_B2G_RIL']:
'MozEmergencyCbModeEvent.webidl',
'MozOtaStatusEvent.webidl',
'MozVoicemailEvent.webidl',
'MozWifiConnectionInfoEvent.webidl',
'MozWifiStatusChangeEvent.webidl',
'USSDReceivedEvent.webidl',
]
-if CONFIG['MOZ_GAMEPAD']:
- WEBIDL_FILES += [
- 'GamepadAxisMoveEvent.webidl',
- 'GamepadButtonEvent.webidl',
- 'GamepadEvent.webidl',
- ]
-
if CONFIG['MOZ_WEBSPEECH']:
WEBIDL_FILES += [
'SpeechRecognitionError.webidl',
'SpeechRecognitionEvent.webidl',
]
if CONFIG['MOZ_B2G_FM']:
WEBIDL_FILES += [
@@ -537,9 +529,19 @@ if CONFIG['ENABLE_TESTS']:
if CONFIG['MOZ_B2G']:
WEBIDL_FILES += [
'InputMethod.webidl',
]
GENERATED_EVENTS_WEBIDL_FILES = [
'BlobEvent.webidl',
+ 'DeviceProximityEvent.webidl',
]
+
+if CONFIG['MOZ_GAMEPAD']:
+ GENERATED_EVENTS_WEBIDL_FILES += [
+ 'GamepadAxisMoveEvent.webidl',
+ 'GamepadButtonEvent.webidl',
+ 'GamepadEvent.webidl',
+ ]
+
+
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -22,16 +22,20 @@
#include "cairo-quartz.h"
#include <ApplicationServices/ApplicationServices.h>
#endif
#ifdef CAIRO_HAS_XLIB_SURFACE
#include "cairo-xlib.h"
#endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#include "cairo-win32.h"
+#endif
+
#include <algorithm>
namespace mozilla {
namespace gfx {
namespace {
// An RAII class to prepare to draw a context and optional path. Saves and
@@ -101,16 +105,25 @@ GetCairoSurfaceSize(cairo_surface_t* sur
// It's valid to call these CGBitmapContext functions on non-bitmap
// contexts; they'll just return 0 in that case.
size.width = CGBitmapContextGetWidth(cgc);
size.height = CGBitmapContextGetWidth(cgc);
return true;
}
#endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+ case CAIRO_SURFACE_TYPE_WIN32:
+ case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ {
+ size.width = cairo_win32_surface_get_width(surface);
+ size.height = cairo_win32_surface_get_height(surface);
+ return true;
+ }
+#endif
default:
return false;
}
}
static bool
PatternIsCompatible(const Pattern& aPattern)
@@ -437,30 +450,38 @@ DrawTargetCairo::DrawSurface(SourceSurfa
cairo_surface_destroy(surf);
cairo_pattern_set_matrix(pat, &src_mat);
cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter));
cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
+ double clipX1, clipY1, clipX2, clipY2;
+ cairo_clip_extents(mContext, &clipX1, &clipY1, &clipX2, &clipY2);
+ Rect clip(clipX1, clipY1, clipX2 - clipX1, clipY2 - clipY1); // Narrowing of doubles to floats
+ // If the destination rect covers the entire clipped area, then unbounded and bounded
+ // operations are identical, and we don't need to push a group.
+ bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) &&
+ !aDest.Contains(clip);
+
cairo_translate(mContext, aDest.X(), aDest.Y());
- if (IsOperatorBoundByMask(aOptions.mCompositionOp)) {
- cairo_new_path(mContext);
- cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
- cairo_clip(mContext);
- cairo_set_source(mContext, pat);
- } else {
+ if (needsGroup) {
cairo_push_group(mContext);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
cairo_set_source(mContext, pat);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext);
+ } else {
+ cairo_new_path(mContext);
+ cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
+ cairo_clip(mContext);
+ cairo_set_source(mContext, pat);
}
cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
cairo_paint_with_alpha(mContext, aOptions.mAlpha);
cairo_pattern_destroy(pat);
}
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -38,17 +38,17 @@ typedef void *EGLNativeWindowType;
// We only need to explicitly dlopen egltrace
// on android as we can use LD_PRELOAD or other tricks
// on other platforms. We look for it in /data/local
// as that's writeable by all users
//
// This should really go in GLLibraryEGL.cpp but we currently reference
// APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring
// will come in subsequent patches on Bug 732865
-#define APITRACE_LIB "/data/local/egltrace.so"
+#define APITRACE_LIB "/data/local/tmp/egltrace.so"
#ifdef MOZ_WIDGET_ANDROID
#endif // MOZ_WIDGET_ANDROID
#endif // ANDROID
#endif
#if defined(MOZ_X11)
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -415,14 +415,22 @@ public:
* This can only be used from the compositor thread!
*/
static LayersBackend GetBackend();
protected:
uint32_t mCompositorID;
static LayersBackend sBackend;
DiagnosticTypes mDiagnosticTypes;
+
+ /**
+ * We keep track of the total number of pixels filled as we composite the
+ * current frame. This value is an approximation and is not accurate,
+ * especially in the presence of transforms.
+ */
+ size_t mPixelsPerFrame;
+ size_t mPixelsFilled;
};
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_COMPOSITOR_H */
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -156,16 +156,17 @@ RotatedBuffer::DrawBufferQuadrant(gfxCon
* the bottom side of the buffer (which is drawn on the top side of
* mBufferRect).
*/
void
RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
+ gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const
{
// The rectangle that we're going to fill. Basically we're going to
// render the buffer at mBufferRect + quadrantTranslation to get the
// pixels in the right place, but we're only going to paint within
// mBufferRect
nsIntRect quadrantRect = GetQuadrantRectangle(aXSide, aYSide);
@@ -188,24 +189,36 @@ RotatedBuffer::DrawBufferQuadrant(gfx::D
transform.Translate(quadrantTranslation.x, quadrantTranslation.y);
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
SurfacePattern source(snapshot, EXTEND_CLAMP, transform, FILTER_POINT);
#else
SurfacePattern source(snapshot, EXTEND_CLAMP, transform);
#endif
+ if (aOperator == OP_SOURCE) {
+ // OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
+ // We also can't do a ClearRect+FillRect since we need the drawing to happen
+ // as an atomic operation (to prevent flickering).
+ aTarget->PushClipRect(gfx::Rect(fillRect.x, fillRect.y,
+ fillRect.width, fillRect.height));
+ }
+
if (aMask) {
SurfacePattern mask(aMask, EXTEND_CLAMP, *aMaskTransform);
- aTarget->Mask(source, mask, DrawOptions(aOpacity));
+ aTarget->Mask(source, mask, DrawOptions(aOpacity, aOperator));
} else {
aTarget->FillRect(gfx::Rect(fillRect.x, fillRect.y,
fillRect.width, fillRect.height),
- source, DrawOptions(aOpacity));
+ source, DrawOptions(aOpacity, aOperator));
+ }
+
+ if (aOperator == OP_SOURCE) {
+ aTarget->PopClip();
}
aTarget->Flush();
}
void
RotatedBuffer::DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
float aOpacity,
@@ -219,27 +232,28 @@ RotatedBuffer::DrawBufferWithRotation(gf
DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
}
void
RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aSource,
float aOpacity,
+ gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const
{
PROFILER_LABEL("RotatedBuffer", "DrawBufferWithRotation");
// See above, in Azure Repeat should always be a safe, even faster choice
// though! Particularly on D2D Repeat should be a lot faster, need to look
// into that. TODO[Bas]
- DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aMask, aMaskTransform);
- DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
- DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
- DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
+ DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+ DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+ DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+ DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
}
/* static */ bool
ThebesLayerBuffer::IsClippingCheap(gfxContext* aTarget, const nsIntRegion& aRegion)
{
// Assume clipping is cheap if the context just has an integer
// translation, and the visible region is simple.
return !aTarget->CurrentMatrix().HasNonIntegerTranslation() &&
@@ -301,17 +315,18 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* a
mask = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aMask);
}
Matrix maskTransform;
if (aMaskTransform) {
maskTransform = ToMatrix(*aMaskTransform);
}
- DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, mask, &maskTransform);
+ CompositionOp op = CompositionOpForOp(aTarget->CurrentOperator());
+ DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, op, mask, &maskTransform);
if (clipped) {
dt->PopClip();
}
}
}
static void
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
@@ -419,16 +434,20 @@ ThebesLayerBuffer::IsAzureBuffer()
{
MOZ_ASSERT(!(mDTBuffer && mBuffer), "Trying to use Azure and Thebes in the same buffer?");
if (mDTBuffer) {
return true;
}
if (mBuffer) {
return false;
}
+ if (mBufferProvider) {
+ return gfxPlatform::GetPlatform()->SupportsAzureContentForType(
+ mBufferProvider->BackendType());
+ }
return SupportsAzureContent();
}
void
ThebesLayerBuffer::EnsureBuffer()
{
if ((!mBuffer && !mDTBuffer) && mBufferProvider) {
if (IsAzureBuffer()) {
@@ -646,46 +665,38 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
result.mDidSelfCopy = true;
// Don't set destBuffer; we special-case self-copies, and
// just did the necessary work above.
mBufferRect = destBufferRect;
} else {
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
- if (IsAzureBuffer()) {
- MOZ_ASSERT(!mBuffer);
- destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags, &destDTBufferOnWhite);
- } else {
- MOZ_ASSERT(!mDTBuffer);
- destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
- }
+ CreateBuffer(contentType, destBufferRect, bufferFlags,
+ getter_AddRefs(destBuffer), getter_AddRefs(destBufferOnWhite),
+ &destDTBuffer, &destDTBufferOnWhite);
if (!destBuffer && !destDTBuffer)
return result;
}
} else {
mBufferRect = destBufferRect;
mBufferRotation = newRotation;
}
} else {
// No pixels are going to be kept. The whole visible region
// will be redrawn, so we don't need to copy anything, so we don't
// set destBuffer.
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
- if (IsAzureBuffer()) {
- MOZ_ASSERT(!mBuffer);
- destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags, &destDTBufferOnWhite);
- } else {
- MOZ_ASSERT(!mDTBuffer);
- destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
- }
+ CreateBuffer(contentType, destBufferRect, bufferFlags,
+ getter_AddRefs(destBuffer), getter_AddRefs(destBufferOnWhite),
+ &destDTBuffer, &destDTBufferOnWhite);
if (!destBuffer && !destDTBuffer)
return result;
}
NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
// If we have no buffered data already, then destBuffer will be a fresh buffer
@@ -722,25 +733,25 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
if (!isClear && (mode != Layer::SURFACE_COMPONENT_ALPHA || HaveBufferOnWhite())) {
// Copy the bits
nsIntPoint offset = -destBufferRect.TopLeft();
Matrix mat;
mat.Translate(offset.x, offset.y);
destDTBuffer->SetTransform(mat);
EnsureBuffer();
MOZ_ASSERT(mDTBuffer, "Have we got a Thebes buffer for some reason?");
- DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK);
+ DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK, 1.0, OP_SOURCE);
destDTBuffer->SetTransform(Matrix());
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
NS_ASSERTION(destDTBufferOnWhite, "Must have a white buffer!");
destDTBufferOnWhite->SetTransform(mat);
EnsureBufferOnWhite();
MOZ_ASSERT(destDTBufferOnWhite, "Have we got a Thebes buffer for some reason?");
- DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE);
+ DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE, 1.0, OP_SOURCE);
destDTBufferOnWhite->SetTransform(Matrix());
}
}
mDTBuffer = destDTBuffer.forget();
mBuffer = nullptr;
mDTBufferOnWhite = destDTBufferOnWhite.forget();
mBufferOnWhite = nullptr;
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -82,16 +82,17 @@ public:
};
void DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
float aOpacity = 1.0,
gfxASurface* aMask = nullptr,
const gfxMatrix* aMaskTransform = nullptr) const;
void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
float aOpacity = 1.0,
+ gfx::CompositionOp aOperator = gfx::OP_OVER,
gfx::SourceSurface* aMask = nullptr,
const gfx::Matrix* aMaskTransform = nullptr) const;
/**
* |BufferRect()| is the rect of device pixels that this
* ThebesLayerBuffer covers. That is what DrawBufferWithRotation()
* will paint when it's called.
*/
@@ -119,16 +120,17 @@ protected:
void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfxASurface* aMask,
const gfxMatrix* aMaskTransform) const;
void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
+ gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
nsRefPtr<gfxASurface> mBuffer;
nsRefPtr<gfxASurface> mBufferOnWhite;
RefPtr<gfx::DrawTarget> mDTBuffer;
RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
/** The area of the ThebesLayer that is covered by the buffer as a whole */
@@ -240,22 +242,24 @@ public:
ALLOW_REPEAT = 0x01,
BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
// component alpha.
};
/**
* Return a new surface of |aSize| and |aType|.
* @param aFlags if ALLOW_REPEAT is set, then the buffer should be configured
* to allow repeat-mode, otherwise it should be in pad (clamp) mode
+ * If the created buffer supports azure content, then the result(s) will
+ * be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
+ * will be used.
*/
- virtual already_AddRefed<gfxASurface>
- CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface** aWhiteSurface) = 0;
- virtual TemporaryRef<gfx::DrawTarget>
- CreateDTBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, RefPtr<gfx::DrawTarget>* aWhiteDT)
- { NS_RUNTIMEABORT("CreateDTBuffer not implemented on this platform!"); return nullptr; }
+ virtual void
+ CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+ gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
virtual bool SupportsAzureContent() const
{ return false; }
/**
* Get the underlying buffer, if any. This is useful because we can pass
* in the buffer as the default "reference surface" if there is one.
* Don't use it for anything else!
*/
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -72,52 +72,51 @@ ContentClient::CreateContentClient(Compo
}
ContentClientBasic::ContentClientBasic(CompositableForwarder* aForwarder,
BasicLayerManager* aManager)
: ContentClient(aForwarder), ThebesLayerBuffer(ContainsVisibleBounds), mManager(aManager)
{}
-already_AddRefed<gfxASurface>
+void
ContentClientBasic::CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags,
- gfxASurface**)
+ gfxASurface** aBlackSurface,
+ gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT,
+ RefPtr<gfx::DrawTarget>* aWhiteDT)
{
MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
+ if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+ gfxASurface::gfxImageFormat format =
+ gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
+
+ *aBlackDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
+ IntSize(aRect.width, aRect.height),
+ ImageFormatToSurfaceFormat(format));
+ return;
+ }
+
nsRefPtr<gfxASurface> referenceSurface = GetBuffer();
if (!referenceSurface) {
gfxContext* defaultTarget = mManager->GetDefaultTarget();
if (defaultTarget) {
referenceSurface = defaultTarget->CurrentSurface();
} else {
nsIWidget* widget = mManager->GetRetainerWidget();
if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
referenceSurface = mManager->GetTarget()->CurrentSurface();
}
}
}
- return referenceSurface->CreateSimilarSurface(
+ nsRefPtr<gfxASurface> ret = referenceSurface->CreateSimilarSurface(
aType, gfxIntSize(aRect.width, aRect.height));
-}
-
-TemporaryRef<DrawTarget>
-ContentClientBasic::CreateDTBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- RefPtr<DrawTarget>* aWhiteDT)
-{
- MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
- gfxASurface::gfxImageFormat format =
- gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
-
- return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
- IntSize(aRect.width, aRect.height),
- ImageFormatToSurfaceFormat(format));
+ *aBlackSurface = ret.forget().get();
}
void
ContentClientRemoteBuffer::DestroyBuffers()
{
if (!mDeprecatedTextureClient) {
return;
}
@@ -220,56 +219,47 @@ bool
ContentClientBasic::SupportsAzureContent() const
{
return gfxPlatform::GetPlatform()->SupportsAzureContent();
}
bool
ContentClientRemoteBuffer::SupportsAzureContent() const
{
- if (!mDeprecatedTextureClient) {
- // Hopefully we don't call this method before we have a texture client. But if
- // we do, then we have no idea if we can support Azure for whatever surface the
- // texture client might come up with.
- return false;
- }
+ MOZ_ASSERT(mDeprecatedTextureClient);
return gfxPlatform::GetPlatform()->SupportsAzureContentForType(
mDeprecatedTextureClient->BackendType());
}
-TemporaryRef<DrawTarget>
-ContentClientRemoteBuffer::CreateDTBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aWhiteDT)
+void
+ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
+ const nsIntRect& aRect,
+ uint32_t aFlags,
+ gfxASurface** aBlackSurface,
+ gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT,
+ RefPtr<gfx::DrawTarget>* aWhiteDT)
{
BuildDeprecatedTextureClients(aType, aRect, aFlags);
- RefPtr<DrawTarget> ret = mDeprecatedTextureClient->LockDrawTarget();
- if (aFlags & BUFFER_COMPONENT_ALPHA) {
- *aWhiteDT = mDeprecatedTextureClientOnWhite->LockDrawTarget();
+ if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(
+ mDeprecatedTextureClient->BackendType())) {
+ *aBlackDT = mDeprecatedTextureClient->LockDrawTarget();
+ if (aFlags & BUFFER_COMPONENT_ALPHA) {
+ *aWhiteDT = mDeprecatedTextureClientOnWhite->LockDrawTarget();
+ }
+ } else {
+ nsRefPtr<gfxASurface> ret = mDeprecatedTextureClient->LockSurface();
+ *aBlackSurface = ret.forget().get();
+ if (aFlags & BUFFER_COMPONENT_ALPHA) {
+ nsRefPtr<gfxASurface> retWhite = mDeprecatedTextureClientOnWhite->LockSurface();
+ *aWhiteSurface = retWhite.forget().get();
+ }
}
- return ret.forget();
-}
-
-already_AddRefed<gfxASurface>
-ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- gfxASurface** aWhiteSurface)
-{
- BuildDeprecatedTextureClients(aType, aRect, aFlags);
-
- nsRefPtr<gfxASurface> ret = mDeprecatedTextureClient->LockSurface();
- if (aFlags & BUFFER_COMPONENT_ALPHA) {
- nsRefPtr<gfxASurface> retWhite = mDeprecatedTextureClientOnWhite->LockSurface();
- *aWhiteSurface = retWhite.forget().get();
- }
- return ret.forget();
}
nsIntRegion
ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy)
{
nsIntRegion updatedRegion;
@@ -532,21 +522,17 @@ ContentClientDoubleBuffered::UpdateDesti
bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
}
if (SupportsAzureContent()) {
MOZ_ASSERT(!destCtx->IsCairo());
-
- if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
- destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
- }
- aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK);
+ aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK, 1.0, OP_SOURCE);
} else {
aSource.DrawBufferWithRotation(destCtx, BUFFER_BLACK);
}
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
nsRefPtr<gfxContext> destCtx =
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
@@ -554,21 +540,17 @@ ContentClientDoubleBuffered::UpdateDesti
bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
}
if (SupportsAzureContent()) {
MOZ_ASSERT(!destCtx->IsCairo());
-
- if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
- destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
- }
- aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE);
+ aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE, 1.0, OP_SOURCE);
} else {
aSource.DrawBufferWithRotation(destCtx, BUFFER_WHITE);
}
}
}
ContentClientSingleBuffered::~ContentClientSingleBuffered()
{
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -147,24 +147,19 @@ public:
}
void DrawTo(ThebesLayer* aLayer, gfxContext* aTarget, float aOpacity,
gfxASurface* aMask, const gfxMatrix* aMaskTransform)
{
ThebesLayerBuffer::DrawTo(aLayer, aTarget, aOpacity, aMask, aMaskTransform);
}
- virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- gfxASurface**) MOZ_OVERRIDE;
- virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aWhiteDT);
+ virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+ gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
virtual bool SupportsAzureContent() const;
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
{
MOZ_CRASH("Should not be called on non-remote ContentClient");
}
private:
@@ -233,24 +228,19 @@ public:
{
return ThebesLayerBuffer::BufferRect();
}
virtual const nsIntPoint& BufferRotation() const
{
return ThebesLayerBuffer::BufferRotation();
}
- virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- gfxASurface** aWhiteSurface) MOZ_OVERRIDE;
- virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
- const nsIntRect& aRect,
- uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
+ virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+ gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
virtual bool SupportsAzureContent() const MOZ_OVERRIDE;
void DestroyBuffers();
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
{
return mTextureInfo;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -101,25 +101,21 @@ DrawWithVertexBuffer2(GLContext *aGLCont
aGLContext->fDisableVertexAttribArray(aAttr1);
aGLContext->fDisableVertexAttribArray(aAttr2);
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
void
-FPSState::DrawFPS(TimeStamp aNow,
- GLContext* context, ShaderProgramOGL* copyprog)
+FPSState::DrawCounter(float offset,
+ unsigned value,
+ GLContext* context,
+ ShaderProgramOGL* copyprog)
{
- int fps = int(mCompositionFps.AddFrameAndGetFps(aNow));
- int txnFps = int(mTransactionFps.GetFpsAt(aNow));
-
- GLint viewport[4];
- context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
-
if (!mTexture) {
// Bind the number of textures we need, in this case one.
context->fGenTextures(1, &mTexture);
context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
const char *text =
@@ -139,67 +135,45 @@ FPSState::DrawFPS(TimeStamp aNow,
uint32_t white = 0xffffffff;
buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
}
}
context->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
free(buf);
}
- mVBOs.Reset();
+ GLint viewport[4];
+ context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
struct Vertex2D {
float x,y;
};
float oneOverVP2 = 1.0 / viewport[2];
float oneOverVP3 = 1.0 / viewport[3];
const Vertex2D vertices[] = {
- { -1.0f, 1.0f - 42.f * oneOverVP3 },
- { -1.0f, 1.0f},
- { -1.0f + 22.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 22.f * oneOverVP2, 1.0f },
+ { -1.0f + (offset + 0.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 0.f) * oneOverVP2, 1.0f},
+ { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
- { -1.0f + 22.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 22.f * oneOverVP2, 1.0f },
- { -1.0f + 44.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 44.f * oneOverVP2, 1.0f },
+ { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
+ { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
- { -1.0f + 44.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 44.f * oneOverVP2, 1.0f },
- { -1.0f + 66.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 66.f * oneOverVP2, 1.0f }
+ { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
+ { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+ { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f }
};
- const Vertex2D vertices2[] = {
- { -1.0f + 80.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 80.f * oneOverVP2, 1.0f },
- { -1.0f + 102.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 102.f * oneOverVP2, 1.0f },
-
- { -1.0f + 102.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 102.f * oneOverVP2, 1.0f },
- { -1.0f + 124.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 124.f * oneOverVP2, 1.0f },
+ unsigned v1 = value % 10;
+ unsigned v10 = (value % 100) / 10;
+ unsigned v100 = (value % 1000) / 100;
- { -1.0f + 124.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 124.f * oneOverVP2, 1.0f },
- { -1.0f + 146.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
- { -1.0f + 146.f * oneOverVP2, 1.0f },
- };
-
- int v1 = fps % 10;
- int v10 = (fps % 100) / 10;
- int v100 = (fps % 1000) / 100;
-
- int txn1 = txnFps % 10;
- int txn10 = (txnFps % 100) / 10;
- int txn100 = (txnFps % 1000) / 100;
-
- // Feel free to comment these texture coordinates out and use one
- // of the ones below instead, or play around with your own values.
const GLfloat texCoords[] = {
(v100 * 4.f) / 64, 7.f / 8,
(v100 * 4.f) / 64, 0.0f,
(v100 * 4.f + 4) / 64, 7.f / 8,
(v100 * 4.f + 4) / 64, 0.0f,
(v10 * 4.f) / 64, 7.f / 8,
(v10 * 4.f) / 64, 0.0f,
@@ -207,33 +181,16 @@ FPSState::DrawFPS(TimeStamp aNow,
(v10 * 4.f + 4) / 64, 0.0f,
(v1 * 4.f) / 64, 7.f / 8,
(v1 * 4.f) / 64, 0.0f,
(v1 * 4.f + 4) / 64, 7.f / 8,
(v1 * 4.f + 4) / 64, 0.0f,
};
- const GLfloat texCoords2[] = {
- (txn100 * 4.f) / 64, 7.f / 8,
- (txn100 * 4.f) / 64, 0.0f,
- (txn100 * 4.f + 4) / 64, 7.f / 8,
- (txn100 * 4.f + 4) / 64, 0.0f,
-
- (txn10 * 4.f) / 64, 7.f / 8,
- (txn10 * 4.f) / 64, 0.0f,
- (txn10 * 4.f + 4) / 64, 7.f / 8,
- (txn10 * 4.f + 4) / 64, 0.0f,
-
- (txn1 * 4.f) / 64, 7.f / 8,
- (txn1 * 4.f) / 64, 0.0f,
- (txn1 * 4.f + 4) / 64, 7.f / 8,
- (txn1 * 4.f + 4) / 64, 0.0f,
- };
-
// Turn necessary features on
context->fEnable(LOCAL_GL_BLEND);
context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
context->fActiveTexture(LOCAL_GL_TEXTURE0);
context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
copyprog->Activate();
@@ -245,20 +202,31 @@ FPSState::DrawFPS(TimeStamp aNow,
GLint vcattr = copyprog->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
GLint tcattr = copyprog->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
DrawWithVertexBuffer2(context, mVBOs,
LOCAL_GL_TRIANGLE_STRIP, 12,
vcattr, (GLfloat *) vertices,
tcattr, (GLfloat *) texCoords);
- DrawWithVertexBuffer2(context, mVBOs,
- LOCAL_GL_TRIANGLE_STRIP, 12,
- vcattr, (GLfloat *) vertices2,
- tcattr, (GLfloat *) texCoords2);
+}
+
+void
+FPSState::DrawFPS(TimeStamp aNow,
+ unsigned aFillRatio,
+ GLContext* context, ShaderProgramOGL* copyprog)
+{
+ mVBOs.Reset();
+
+ unsigned fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
+ unsigned txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
+
+ DrawCounter(0, fps, context, copyprog);
+ DrawCounter(80, txnFps, context, copyprog);
+ DrawCounter(160, aFillRatio, context, copyprog);
}
#ifdef CHECK_CURRENT_PROGRAM
int ShaderProgramOGL::sCurrentProgramKey = 0;
#endif
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
int aSurfaceHeight, bool aUseExternalSurfaceSize)
@@ -824,16 +792,19 @@ CompositorOGL::BeginFrame(const Rect *aC
MakeCurrent(ForceMakeCurrent);
mWidgetSize.width = width;
mWidgetSize.height = height;
} else {
MakeCurrent();
}
+ mPixelsPerFrame = width * height;
+ mPixelsFilled = 0;
+
#if MOZ_ANDROID_OMTC
TexturePoolOGL::Fill(gl());
#endif
mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
IntSize(width, height),
aTransform);
mCurrentRenderTarget->BindRenderTarget();
@@ -1048,16 +1019,18 @@ CompositorOGL::DrawQuad(const Rect& aRec
maskType = effectMask->mIs3D
? Mask3d
: Mask2d;
} else {
maskType = MaskNone;
}
+ mPixelsFilled += aRect.width * aRect.height;
+
ShaderProgramType programType = GetProgramTypeForEffect(aEffectChain.mPrimaryEffect);
ShaderProgramOGL *program = GetProgram(programType, maskType);
program->Activate();
if (programType == RGBARectLayerProgramType ||
programType == RGBXRectLayerProgramType) {
TexturedEffect* texturedEffect =
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
@@ -1309,17 +1282,23 @@ CompositorOGL::EndFrame()
if (sDrawFPS && !mFPS) {
mFPS = new FPSState();
} else if (!sDrawFPS && mFPS) {
mFPS = nullptr;
}
if (mFPS) {
- mFPS->DrawFPS(TimeStamp::Now(), mGLContext, GetProgram(Copy2DProgramType));
+ float fillRatio = 0;
+ if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
+ fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
+ if (fillRatio > 999.0f)
+ fillRatio = 999.0f;
+ }
+ mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(Copy2DProgramType));
}
mGLContext->SwapBuffers();
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
void
CompositorOGL::EndFrameForExternalComposition(const gfxMatrix& aTransform)
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/opengl/FPSCounter.h
@@ -70,17 +70,18 @@ private:
struct FPSState {
GLuint mTexture;
FPSCounter mCompositionFps;
FPSCounter mTransactionFps;
gl::VBOArena mVBOs;
FPSState() : mTexture(0) { }
- void DrawFPS(TimeStamp, gl::GLContext*, ShaderProgramOGL*);
+ void DrawCounter(float, unsigned, gl::GLContext*, ShaderProgramOGL*);
+ void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
void NotifyShadowTreeTransaction() {
mTransactionFps.AddFrame(TimeStamp::Now());
}
};
}
}
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -891,17 +891,17 @@ LayerManagerOGL::Render()
if (sDrawFPS && !mFPS) {
mFPS = new FPSState();
} else if (!sDrawFPS && mFPS) {
mFPS = nullptr;
}
if (mFPS) {
- mFPS->DrawFPS(TimeStamp::Now(), mGLContext, GetProgram(Copy2DProgramType));
+ mFPS->DrawFPS(TimeStamp::Now(), 0, mGLContext, GetProgram(Copy2DProgramType));
}
if (mGLContext->IsDoubleBuffered()) {
mGLContext->SwapBuffers();
LayerManager::PostPresent();
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
return;
}
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -350,23 +350,26 @@ public:
{
// Let ThebesLayerBuffer do all the hard work for us! :D
return ThebesLayerBuffer::BeginPaint(mLayer,
aContentType,
aFlags);
}
// ThebesLayerBuffer interface
- virtual already_AddRefed<gfxASurface>
- CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface**)
+ void
+ CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+ gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE
{
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
mTexImage = CreateClampOrRepeatTextureImage(gl(), aRect.Size(), aType, aFlags);
- return mTexImage ? mTexImage->GetBackingSurface() : nullptr;
+ nsRefPtr<gfxASurface> ret = mTexImage ? mTexImage->GetBackingSurface() : nullptr;
+ *aBlackSurface = ret.forget().get();
}
virtual nsIntPoint GetOriginOffset() {
return BufferRect().TopLeft() - BufferRotation();
}
};
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -5,19 +5,25 @@
#include "nsMimeTypes.h"
#include "Image.h"
namespace mozilla {
namespace image {
+#ifdef DEBUG_imagelib
+static const bool allowOMTURIAccess = true;
+#else
+static const bool allowOMTURIAccess = false;
+#endif
+
// Constructor
ImageResource::ImageResource(imgStatusTracker* aStatusTracker, nsIURI* aURI) :
- mURI(aURI),
+ mURI(new nsMainThreadPtrHolder<nsIURI>(aURI, allowOMTURIAccess)),
mInnerWindowId(0),
mAnimationConsumers(0),
mAnimationMode(kNormalAnimMode),
mInitialized(false),
mAnimating(false),
mError(false)
{
if (aStatusTracker) {
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -5,16 +5,17 @@
#ifndef MOZILLA_IMAGELIB_IMAGE_H_
#define MOZILLA_IMAGELIB_IMAGE_H_
#include "mozilla/MemoryReporting.h"
#include "imgIContainer.h"
#include "imgStatusTracker.h"
#include "nsIURI.h"
+#include "nsProxyRelease.h" // for nsMainThreadPtrHolder and nsMainThreadPtrHandle
class nsIRequest;
class nsIInputStream;
namespace mozilla {
namespace image {
class Image : public imgIContainer
@@ -151,18 +152,19 @@ public:
}
virtual uint64_t InnerWindowID() const MOZ_OVERRIDE { return mInnerWindowId; }
virtual bool HasError() MOZ_OVERRIDE { return mError; }
virtual void SetHasError() MOZ_OVERRIDE { mError = true; }
/*
* Returns a non-AddRefed pointer to the URI associated with this image.
+ * Illegal to use off-main-thread.
*/
- virtual nsIURI* GetURI() MOZ_OVERRIDE { return mURI; }
+ virtual nsIURI* GetURI() MOZ_OVERRIDE { return mURI.get(); }
protected:
ImageResource(imgStatusTracker* aStatusTracker, nsIURI* aURI);
// Shared functionality for implementors of imgIContainer. Every
// implementation of attribute animationMode should forward here.
nsresult GetAnimationModeInternal(uint16_t *aAnimationMode);
nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
@@ -180,22 +182,22 @@ protected:
virtual bool ShouldAnimate() {
return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
}
virtual nsresult StartAnimation() = 0;
virtual nsresult StopAnimation() = 0;
// Member data shared by all implementations of this abstract class
- nsRefPtr<imgStatusTracker> mStatusTracker;
- nsCOMPtr<nsIURI> mURI;
- uint64_t mInnerWindowId;
- uint32_t mAnimationConsumers;
- uint16_t mAnimationMode; // Enum values in imgIContainer
- bool mInitialized:1; // Have we been initalized?
- bool mAnimating:1; // Are we currently animating?
- bool mError:1; // Error handling
+ nsRefPtr<imgStatusTracker> mStatusTracker;
+ nsMainThreadPtrHandle<nsIURI> mURI;
+ uint64_t mInnerWindowId;
+ uint32_t mAnimationConsumers;
+ uint16_t mAnimationMode; // Enum values in imgIContainer
+ bool mInitialized:1; // Have we been initalized?
+ bool mAnimating:1; // Are we currently animating?
+ bool mError:1; // Error handling
};
} // namespace image
} // namespace mozilla
#endif // MOZILLA_IMAGELIB_IMAGE_H_
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -908,16 +908,13 @@ void
AsyncChannel::ProcessGoodbyeMessage()
{
AssertLinkThread();
mMonitor->AssertCurrentThreadOwns();
// TODO sort out Close() on this side racing with Close() on the
// other side
mChannelState = ChannelClosing;
-
- printf("NOTE: %s process received `Goodbye', closing down\n",
- mChild ? "child" : "parent");
}
} // namespace ipc
} // namespace mozilla
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -17,16 +17,17 @@
// entry points expecting a jsid and do not need to handle JSID_VOID in hooks
// receiving a jsid except when explicitly noted in the API contract.
//
// A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
// JS_IdToValue must be used instead.
#include "jstypes.h"
+#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
#ifdef JS_USE_JSID_STRUCT_TYPES
struct jsid
{
size_t asBits;
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
@@ -155,9 +156,35 @@ extern JS_PUBLIC_DATA(const jsid) JSID_E
#else
# define JSID_VOID ((jsid)JSID_TYPE_VOID)
# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
#endif
extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_VOIDHANDLE;
extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_EMPTYHANDLE;
+namespace js {
+
+inline bool
+IsPoisonedId(jsid iden)
+{
+ if (JSID_IS_STRING(iden))
+ return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
+ if (JSID_IS_OBJECT(iden))
+ return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
+ return false;
+}
+
+template <> struct GCMethods<jsid>
+{
+ static jsid initial() { return JSID_VOID; }
+ static ThingRootKind kind() { return THING_ROOT_ID; }
+ static bool poisoned(jsid id) { return IsPoisonedId(id); }
+ static bool needsPostBarrier(jsid id) { return false; }
+#ifdef JSGC_GENERATIONAL
+ static void postBarrier(jsid *idp) {}
+ static void relocate(jsid *idp) {}
+#endif
+};
+
+}
+
#endif /* js_Id_h */
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -49,21 +49,21 @@ INCLUDED_RULES_MK = 1
XPIDL_FLAGS \
$(NULL)
ifndef EXTERNALLY_MANAGED_MAKE_FILE
# Using $(firstword) may not be perfect. But it should be good enough for most
# scenarios.
_current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
-$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
$(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
))
-$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
$(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
))
ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
$(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
endif
# Import the automatically generated backend file. If this file doesn't exist,
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -13,144 +13,16 @@
#include "gc/Marking.h"
#include "gc/StoreBuffer.h"
#include "vm/String-inl.h"
namespace js {
-/*
- * This is a post barrier for HashTables whose key is a GC pointer. Any
- * insertion into a HashTable not marked as part of the runtime, with a GC
- * pointer as a key, must call this immediately after each insertion.
- */
-template <class Map, class Key>
-inline void
-HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
-{
-#ifdef JSGC_GENERATIONAL
- if (key && IsInsideNursery(rt, key))
- rt->gcStoreBuffer.putGeneric(gc::HashKeyRef<Map, Key>(map, key));
-#endif
-}
-
-inline
-EncapsulatedId::~EncapsulatedId()
-{
- pre();
-}
-
-inline EncapsulatedId &
-EncapsulatedId::operator=(const EncapsulatedId &v)
-{
- if (v.value != value)
- pre();
- JS_ASSERT(!IsPoisonedId(v.value));
- value = v.value;
- return *this;
-}
-
-inline void
-EncapsulatedId::pre()
-{
-#ifdef JSGC_INCREMENTAL
- if (JSID_IS_OBJECT(value)) {
- JSObject *obj = JSID_TO_OBJECT(value);
- Zone *zone = obj->zone();
- if (zone->needsBarrier()) {
- js::gc::MarkObjectUnbarriered(zone->barrierTracer(), &obj, "write barrier");
- JS_ASSERT(obj == JSID_TO_OBJECT(value));
- }
- } else if (JSID_IS_STRING(value)) {
- JSString *str = JSID_TO_STRING(value);
- Zone *zone = str->zone();
- if (zone->needsBarrier()) {
- js::gc::MarkStringUnbarriered(zone->barrierTracer(), &str, "write barrier");
- JS_ASSERT(str == JSID_TO_STRING(value));
- }
- }
-#endif
-}
-
-inline
-RelocatableId::~RelocatableId()
-{
- pre();
-}
-
-inline RelocatableId &
-RelocatableId::operator=(jsid id)
-{
- if (id != value)
- pre();
- JS_ASSERT(!IsPoisonedId(id));
- value = id;
- return *this;
-}
-
-inline RelocatableId &
-RelocatableId::operator=(const RelocatableId &v)
-{
- if (v.value != value)
- pre();
- JS_ASSERT(!IsPoisonedId(v.value));
- value = v.value;
- return *this;
-}
-
-inline
-HeapId::HeapId(jsid id)
- : EncapsulatedId(id)
-{
- JS_ASSERT(!IsPoisonedId(id));
- post();
-}
-
-inline
-HeapId::~HeapId()
-{
- pre();
-}
-
-inline void
-HeapId::init(jsid id)
-{
- JS_ASSERT(!IsPoisonedId(id));
- value = id;
- post();
-}
-
-inline void
-HeapId::post()
-{
-}
-
-inline HeapId &
-HeapId::operator=(jsid id)
-{
- if (id != value)
- pre();
- JS_ASSERT(!IsPoisonedId(id));
- value = id;
- post();
- return *this;
-}
-
-inline HeapId &
-HeapId::operator=(const HeapId &v)
-{
- if (v.value != value)
- pre();
- JS_ASSERT(!IsPoisonedId(v.value));
- value = v.value;
- post();
- return *this;
-}
-
inline const Value &
ReadBarrieredValue::get() const
{
if (value.isObject())
JSObject::readBarrier(&value.toObject());
else if (value.isString())
JSString::readBarrier(value.toString());
else
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -119,30 +119,69 @@
namespace js {
class PropertyName;
namespace gc {
// Direct value access used by the write barriers and the jits.
void
MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+
+// These two declarations are also present in gc/Marking.h, via the DeclMarker
+// macro. Not great, but hard to avoid.
+void
+MarkObjectUnbarriered(JSTracer *trc, JSObject **obj, const char *name);
+void
+MarkStringUnbarriered(JSTracer *trc, JSString **str, const char *name);
}
+// Note: these functions must be equivalent to the zone() functions implemented
+// by all the subclasses of Cell.
+
JS::Zone *
ZoneOfObject(const JSObject &obj);
+static inline JS::shadow::Zone *
+ShadowZoneOfObject(JSObject *obj)
+{
+ return JS::shadow::Zone::asShadowZone(ZoneOfObject(*obj));
+}
+
+static inline JS::shadow::Zone *
+ShadowZoneOfString(JSString *str)
+{
+ return JS::shadow::Zone::asShadowZone(reinterpret_cast<const js::gc::Cell *>(str)->tenuredZone());
+}
+
JS_ALWAYS_INLINE JS::Zone *
ZoneOfValue(const JS::Value &value)
{
JS_ASSERT(value.isMarkable());
if (value.isObject())
return ZoneOfObject(value.toObject());
return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
}
+/*
+ * This is a post barrier for HashTables whose key is a GC pointer. Any
+ * insertion into a HashTable not marked as part of the runtime, with a GC
+ * pointer as a key, must call this immediately after each insertion.
+ */
+template <class Map, class Key>
+inline void
+HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
+{
+#ifdef JSGC_GENERATIONAL
+ if (key && IsInsideNursery(rt, key)) {
+ JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+ shadowRuntime->gcStoreBufferPtr()->putGeneric(gc::HashKeyRef<Map, Key>(map, key));
+ }
+#endif
+}
+
template<class T, typename Unioned = uintptr_t>
class EncapsulatedPtr
{
protected:
union {
T *value;
Unioned other;
};
@@ -818,57 +857,120 @@ class EncapsulatedId
jsid value;
private:
EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
public:
explicit EncapsulatedId() : value(JSID_VOID) {}
explicit EncapsulatedId(jsid id) : value(id) {}
- ~EncapsulatedId();
+ ~EncapsulatedId() { pre(); }
- inline EncapsulatedId &operator=(const EncapsulatedId &v);
+ EncapsulatedId &operator=(const EncapsulatedId &v) {
+ if (v.value != value)
+ pre();
+ JS_ASSERT(!IsPoisonedId(v.value));
+ value = v.value;
+ return *this;
+ }
bool operator==(jsid id) const { return value == id; }
bool operator!=(jsid id) const { return value != id; }
jsid get() const { return value; }
jsid *unsafeGet() { return &value; }
void unsafeSet(jsid newId) { value = newId; }
operator jsid() const { return value; }
protected:
- inline void pre();
+ void pre() {
+#ifdef JSGC_INCREMENTAL
+ if (JSID_IS_OBJECT(value)) {
+ JSObject *obj = JSID_TO_OBJECT(value);
+ JS::shadow::Zone *shadowZone = ShadowZoneOfObject(obj);
+ if (shadowZone->needsBarrier()) {
+ js::gc::MarkObjectUnbarriered(shadowZone->barrierTracer(), &obj, "write barrier");
+ JS_ASSERT(obj == JSID_TO_OBJECT(value));
+ }
+ } else if (JSID_IS_STRING(value)) {
+ JSString *str = JSID_TO_STRING(value);
+ JS::shadow::Zone *shadowZone = ShadowZoneOfString(str);
+ if (shadowZone->needsBarrier()) {
+ js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
+ JS_ASSERT(str == JSID_TO_STRING(value));
+ }
+ }
+#endif
+ }
};
class RelocatableId : public EncapsulatedId
{
public:
explicit RelocatableId() : EncapsulatedId() {}
explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
- inline ~RelocatableId();
+ ~RelocatableId() { pre(); }
- inline RelocatableId &operator=(jsid id);
- inline RelocatableId &operator=(const RelocatableId &v);
+ RelocatableId &operator=(jsid id) {
+ if (id != value)
+ pre();
+ JS_ASSERT(!IsPoisonedId(id));
+ value = id;
+ return *this;
+ }
+
+ RelocatableId &operator=(const RelocatableId &v) {
+ if (v.value != value)
+ pre();
+ JS_ASSERT(!IsPoisonedId(v.value));
+ value = v.value;
+ return *this;
+ }
};
class HeapId : public EncapsulatedId
{
public:
explicit HeapId() : EncapsulatedId() {}
- explicit inline HeapId(jsid id);
- inline ~HeapId();
+
+ explicit HeapId(jsid id)
+ : EncapsulatedId(id)
+ {
+ JS_ASSERT(!IsPoisonedId(id));
+ post();
+ }
+
+ ~HeapId() { pre(); }
+
+ void init(jsid id) {
+ JS_ASSERT(!IsPoisonedId(id));
+ value = id;
+ post();
+ }
- inline void init(jsid id);
+ HeapId &operator=(jsid id) {
+ if (id != value)
+ pre();
+ JS_ASSERT(!IsPoisonedId(id));
+ value = id;
+ post();
+ return *this;
+ }
- inline HeapId &operator=(jsid id);
- inline HeapId &operator=(const HeapId &v);
+ HeapId &operator=(const HeapId &v) {
+ if (v.value != value)
+ pre();
+ JS_ASSERT(!IsPoisonedId(v.value));
+ value = v.value;
+ post();
+ return *this;
+ }
private:
- inline void post();
+ void post() {};
HeapId(const HeapId &v) MOZ_DELETE;
};
/*
* Incremental GC requires that weak pointers have read barriers. This is mostly
* an issue for empty shapes stored in JSCompartment. The problem happens when,
* during an incremental GC, some JS code stores one of the compartment's empty
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -161,30 +161,41 @@ CodeGenerator::visitValueToInt32(LValueT
MDefinition *input;
if (lir->mode() == LValueToInt32::NORMAL)
input = lir->mirNormal()->input();
else
input = lir->mirTruncate()->input();
Label fails;
if (lir->mode() == LValueToInt32::TRUNCATE) {
+ OutOfLineCode *oolDouble = oolTruncateDouble(temp, output);
+ if (!oolDouble)
+ return false;
+
// We can only handle strings in truncation contexts, like bitwise
// operations.
+ Label *stringEntry, *stringRejoin;
+ Register stringReg;
if (input->mightBeType(MIRType_String)) {
- Register stringReg = ToRegister(lir->temp());
- OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
- StoreFloatRegisterTo(temp));
- if (!ool)
+ stringReg = ToRegister(lir->temp());
+ OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
+ StoreFloatRegisterTo(temp));
+ if (!oolString)
return false;
-
- masm.truncateValueToInt32(operand, input, ool->entry(), ool->rejoin(), stringReg,
- temp, output, &fails);
+ stringEntry = oolString->entry();
+ stringRejoin = oolString->rejoin();
} else {
- masm.truncateValueToInt32(operand, input, temp, output, &fails);
+ stringReg = InvalidReg;
+ stringEntry = NULL;
+ stringRejoin = NULL;
}
+
+ masm.truncateValueToInt32(operand, input, stringEntry, stringRejoin, oolDouble->entry(),
+ stringReg, temp, output, &fails);
+ masm.bind(oolDouble->rejoin());
} else {
masm.convertValueToInt32(operand, input, temp, output, &fails,
lir->mirNormal()->canBeNegativeZero());
}
return bailoutFrom(&fails, lir->snapshot());
}
@@ -6774,26 +6785,38 @@ CodeGenerator::visitClampDToUint8(LClamp
bool
CodeGenerator::visitClampVToUint8(LClampVToUint8 *lir)
{
ValueOperand operand = ToValue(lir, LClampVToUint8::Input);
FloatRegister tempFloat = ToFloatRegister(lir->tempFloat());
Register output = ToRegister(lir->output());
MDefinition *input = lir->mir()->input();
- Label fails;
+ OutOfLineCode *oolDouble = oolTruncateDouble(tempFloat, output);
+ if (!oolDouble)
+ return false;
+
+ Label *stringEntry, *stringRejoin;
if (input->mightBeType(MIRType_String)) {
- OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
- StoreFloatRegisterTo(tempFloat));
- masm.clampValueToUint8(operand, input, ool->entry(), ool->rejoin(), output,
- tempFloat, output, &fails);
-
+ OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
+ StoreFloatRegisterTo(tempFloat));
+ if (!oolString)
+ return false;
+ stringEntry = oolString->entry();
+ stringRejoin = oolString->rejoin();
} else {
- masm.clampValueToUint8(operand, input, tempFloat, output, &fails);
- }
+ stringEntry = NULL;
+ stringRejoin = NULL;
+ }
+
+ Label fails;
+ masm.clampValueToUint8(operand, input,
+ stringEntry, stringRejoin, oolDouble->entry(),
+ output, tempFloat, output, &fails);
+
if (!bailoutFrom(&fails, lir->snapshot()))
return false;
return true;
}
typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, bool *);
static const VMFunction OperatorInInfo = FunctionInfo<OperatorInFn>(OperatorIn);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1530,36 +1530,37 @@ MacroAssembler::convertTypedOrValueToDou
loadStaticDouble(&js_NaN, output);
break;
default:
MOZ_ASSUME_UNREACHABLE("Bad MIRType");
}
}
void
-MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *fail,
- IntConversionBehavior behavior)
+MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail,
+ Label *fail, IntConversionBehavior behavior)
{
switch (behavior) {
case IntConversion_Normal:
case IntConversion_NegativeZeroCheck:
convertDoubleToInt32(src, output, fail, behavior == IntConversion_NegativeZeroCheck);
break;
case IntConversion_Truncate:
- branchTruncateDouble(src, output, fail);
+ branchTruncateDouble(src, output, truncateFail ? truncateFail : fail);
break;
case IntConversion_ClampToUint8:
clampDoubleToUint8(src, output);
break;
}
}
void
MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
Label *handleStringEntry, Label *handleStringRejoin,
+ Label *truncateDoubleSlow,
Register stringReg, FloatRegister temp, Register output,
Label *fail, IntConversionBehavior behavior)
{
Register tag = splitTagForTest(value);
bool handleStrings = (behavior == IntConversion_Truncate ||
behavior == IntConversion_ClampToUint8) &&
handleStringEntry &&
handleStringRejoin;
@@ -1608,17 +1609,17 @@ MacroAssembler::convertValueToInt(ValueO
if (isDouble.used()) {
bind(&isDouble);
unboxDouble(value, temp);
}
if (handleStrings)
bind(handleStringRejoin);
- convertDoubleToInt(temp, output, fail, behavior);
+ convertDoubleToInt(temp, output, truncateDoubleSlow, fail, behavior);
jump(&done);
}
// Just unbox a bool, the result is 0 or 1.
if (isBool.used()) {
bind(&isBool);
unboxBoolean(value, output);
jump(&done);
@@ -1719,17 +1720,17 @@ MacroAssembler::convertTypedOrValueToInt
move32(Imm32(0), output);
break;
case MIRType_Boolean:
case MIRType_Int32:
if (src.typedReg().gpr() != output)
move32(src.typedReg().gpr(), output);
break;
case MIRType_Double:
- convertDoubleToInt(src.typedReg().fpu(), output, fail, behavior);
+ convertDoubleToInt(src.typedReg().fpu(), output, NULL, fail, behavior);
break;
case MIRType_String:
case MIRType_Object:
jump(fail);
break;
default:
MOZ_ASSUME_UNREACHABLE("Bad MIRType");
}
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1008,31 +1008,32 @@ class MacroAssembler : public MacroAssem
IntConversion_NegativeZeroCheck,
IntConversion_Truncate,
IntConversion_ClampToUint8,
};
//
// Functions for converting values to int.
//
- void convertDoubleToInt(FloatRegister src, Register output, Label *fail,
+ void convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail, Label *fail,
IntConversionBehavior behavior);
// Strings may be handled by providing labels to jump to when the behavior
// is truncation or clamping. The subroutine, usually an OOL call, is
// passed the unboxed string in |stringReg| and should convert it to a
// double store into |temp|.
void convertValueToInt(ValueOperand value, MDefinition *input,
Label *handleStringEntry, Label *handleStringRejoin,
+ Label *truncateDoubleSlow,
Register stringReg, FloatRegister temp, Register output,
Label *fail, IntConversionBehavior behavior);
void convertValueToInt(ValueOperand value, FloatRegister temp, Register output, Label *fail,
IntConversionBehavior behavior)
{
- convertValueToInt(value, NULL, NULL, NULL, InvalidReg, temp, output, fail, behavior);
+ convertValueToInt(value, NULL, NULL, NULL, NULL, InvalidReg, temp, output, fail, behavior);
}
bool convertValueToInt(JSContext *cx, const Value &v, Register output, Label *fail,
IntConversionBehavior behavior);
bool convertConstantOrRegisterToInt(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
Register output, Label *fail, IntConversionBehavior behavior);
void convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, Register output,
Label *fail, IntConversionBehavior behavior);
@@ -1045,17 +1046,17 @@ class MacroAssembler : public MacroAssem
convertValueToInt(value, temp, output, fail, negativeZeroCheck
? IntConversion_NegativeZeroCheck
: IntConversion_Normal);
}
void convertValueToInt32(ValueOperand value, MDefinition *input,
FloatRegister temp, Register output, Label *fail,
bool negativeZeroCheck)
{
- convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+ convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
negativeZeroCheck
? IntConversion_NegativeZeroCheck
: IntConversion_Normal);
}
bool convertValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail,
bool negativeZeroCheck)
{
return convertValueToInt(cx, v, output, fail, negativeZeroCheck
@@ -1080,26 +1081,26 @@ class MacroAssembler : public MacroAssem
//
// Convenience functions for truncating values to int32.
//
void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail) {
convertValueToInt(value, temp, output, fail, IntConversion_Truncate);
}
void truncateValueToInt32(ValueOperand value, MDefinition *input,
Label *handleStringEntry, Label *handleStringRejoin,
- Register stringReg, FloatRegister temp, Register output,
- Label *fail)
+ Label *truncateDoubleSlow,
+ Register stringReg, FloatRegister temp, Register output, Label *fail)
{
- convertValueToInt(value, input, handleStringEntry, handleStringRejoin,
+ convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
stringReg, temp, output, fail, IntConversion_Truncate);
}
void truncateValueToInt32(ValueOperand value, MDefinition *input,
FloatRegister temp, Register output, Label *fail)
{
- convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+ convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
IntConversion_Truncate);
}
bool truncateValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail) {
return convertValueToInt(cx, v, output, fail, IntConversion_Truncate);
}
bool truncateConstantOrRegisterToInt32(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
Register output, Label *fail)
{
@@ -1112,26 +1113,26 @@ class MacroAssembler : public MacroAssem
}
// Convenience functions for clamping values to uint8.
void clampValueToUint8(ValueOperand value, FloatRegister temp, Register output, Label *fail) {
convertValueToInt(value, temp, output, fail, IntConversion_ClampToUint8);
}
void clampValueToUint8(ValueOperand value, MDefinition *input,
Label *handleStringEntry, Label *handleStringRejoin,
- Register stringReg, FloatRegister temp, Register output,
- Label *fail)
+ Label *truncateDoubleSlow,
+ Register stringReg, FloatRegister temp, Register output, Label *fail)
{
- convertValueToInt(value, input, handleStringEntry, handleStringRejoin,
+ convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
stringReg, temp, output, fail, IntConversion_ClampToUint8);
}
void clampValueToUint8(ValueOperand value, MDefinition *input,
FloatRegister temp, Register output, Label *fail)
{
- convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+ convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
IntConversion_ClampToUint8);
}
bool clampValueToUint8(JSContext *cx, const Value &v, Register output, Label *fail) {
return convertValueToInt(cx, v, output, fail, IntConversion_ClampToUint8);
}
bool clampConstantOrRegisterToUint8(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
Register output, Label *fail)
{
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2589,17 +2589,19 @@ class MReturnFromCtor
}
};
// Passes an MDefinition to an MCall. Must occur between an MPrepareCall and
// MCall. Boxes the input and stores it to the correct location on stack.
//
// Arguments are *not* simply pushed onto a call stack: they are evaluated
// left-to-right, but stored in the arg vector in C-style, right-to-left.
-class MPassArg : public MUnaryInstruction
+class MPassArg
+ : public MUnaryInstruction,
+ public NoFloatPolicy<0>
{
int32_t argnum_;
private:
MPassArg(MDefinition *def)
: MUnaryInstruction(def), argnum_(-1)
{
setResultType(def->type());
@@ -2624,16 +2626,20 @@ class MPassArg : public MUnaryInstructio
uint32_t getArgnum() const {
JS_ASSERT(argnum_ >= 0);
return (uint32_t)argnum_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
void printOpcode(FILE *fp) const;
+
+ TypePolicy *typePolicy() {
+ return this;
+ }
};
// Converts a primitive (either typed or untyped) to a double. If the input is
// not primitive at runtime, a bailout occurs.
class MToDouble
: public MUnaryInstruction,
public ToDoublePolicy
{
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -551,28 +551,16 @@ template bool ObjectPolicy<1>::staticAdj
template bool ObjectPolicy<2>::staticAdjustInputs(MInstruction *ins);
template bool ObjectPolicy<3>::staticAdjustInputs(MInstruction *ins);
bool
CallPolicy::adjustInputs(MInstruction *ins)
{
MCall *call = ins->toCall();
- // External calls shouldn't have Float32 parameters
- for (uint32_t i = 0, numArgs = call->numActualArgs(); i < numArgs; i++) {
- MDefinition *arg = call->getArg(i+1); // arg 0 is |this|
- if (arg->type() == MIRType_Float32) {
- JS_ASSERT(arg->isPassArg()); // can't be a type barrier, as Float32 doesn't rely on type inference
- MPassArg *passArg = arg->toPassArg();
- MInstruction *replace = MToDouble::New(passArg->getArgument());
- passArg->replaceOperand(0, replace);
- call->block()->insertBefore(passArg, replace);
- }
- }
-
MDefinition *func = call->getFunction();
if (func->type() == MIRType_Object)
return true;
// If the function is impossible to call,
// bail out by causing a subsequent unbox to fail.
if (func->type() != MIRType_Value)
func = boxAt(call, func);
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -170,17 +170,17 @@ class RuntimePolicy : public TypePolicy
return Float32Policy<Op>::staticAdjustInputs(def);
}
void setPolicyType(MIRType type) {
policyType_ = type;
}
};
template <unsigned Op>
-class NoFloatPolicy
+class NoFloatPolicy : public TypePolicy
{
public:
static bool staticAdjustInputs(MInstruction *def);
bool adjustInputs(MInstruction *def) {
return staticAdjustInputs(def);
}
};
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -670,21 +670,30 @@ class OutOfLineTruncateSlow : public Out
FloatRegister src() const {
return src_;
}
Register dest() const {
return dest_;
}
};
+OutOfLineCode *
+CodeGeneratorShared::oolTruncateDouble(const FloatRegister &src, const Register &dest)
+{
+ OutOfLineTruncateSlow *ool = new OutOfLineTruncateSlow(src, dest);
+ if (!addOutOfLineCode(ool))
+ return NULL;
+ return ool;
+}
+
bool
CodeGeneratorShared::emitTruncateDouble(const FloatRegister &src, const Register &dest)
{
- OutOfLineTruncateSlow *ool = new OutOfLineTruncateSlow(src, dest);
- if (!addOutOfLineCode(ool))
+ OutOfLineCode *ool = oolTruncateDouble(src, dest);
+ if (!ool)
return false;
masm.branchTruncateDouble(src, dest, ool->entry());
masm.bind(ool->rejoin());
return true;
}
bool
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -278,16 +278,17 @@ class CodeGeneratorShared : public LInst
// Ensure that there is enough room between the last OSI point and the
// current instruction, such that:
// (1) Invalidation will not overwrite the current instruction, and
// (2) Overwriting the current instruction will not overwrite
// an invalidation marker.
void ensureOsiSpace();
+ OutOfLineCode *oolTruncateDouble(const FloatRegister &src, const Register &dest);
bool emitTruncateDouble(const FloatRegister &src, const Register &dest);
void emitPreBarrier(Register base, const LAllocation *index, MIRType type);
void emitPreBarrier(Address address, MIRType type);
inline bool isNextBlock(LBlock *block) {
return (current->mir()->id() + 1 == block->mir()->id());
}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6332,8 +6332,19 @@ JS_PreventExtensions(JSContext *cx, JS::
{
bool extensible;
if (!JSObject::isExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return true;
return JSObject::preventExtensions(cx, obj);
}
+
+char *
+JSAutoByteString::encodeLatin1(ExclusiveContext *cx, JSString *str)
+{
+ JSLinearString *linear = str->ensureLinear(cx);
+ if (!linear)
+ return NULL;
+
+ mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
+ return mBytes;
+}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1354,38 +1354,16 @@ JS_BeginRequest(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_EndRequest(JSContext *cx);
extern JS_PUBLIC_API(bool)
JS_IsInRequest(JSRuntime *rt);
namespace js {
-inline bool
-IsPoisonedId(jsid iden)
-{
- if (JSID_IS_STRING(iden))
- return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
- if (JSID_IS_OBJECT(iden))
- return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
- return false;
-}
-
-template <> struct GCMethods<jsid>
-{
- static jsid initial() { return JSID_VOID; }
- static ThingRootKind kind() { return THING_ROOT_ID; }
- static bool poisoned(jsid id) { return IsPoisonedId(id); }
- static bool needsPostBarrier(jsid id) { return false; }
-#ifdef JSGC_GENERATIONAL
- static void postBarrier(jsid *idp) {}
- static void relocate(jsid *idp) {}
-#endif
-};
-
void
AssertHeapIsIdle(JSRuntime *rt);
void
AssertHeapIsIdle(JSContext *cx);
} /* namespace js */
@@ -3844,17 +3822,17 @@ class JSAutoByteString
char *encodeLatin1(JSContext *cx, JSString *str) {
JS_ASSERT(!mBytes);
JS_ASSERT(cx);
mBytes = JS_EncodeString(cx, str);
return mBytes;
}
- char *encodeLatin1(js::ContextFriendFields *cx, JSString *str);
+ char *encodeLatin1(js::ExclusiveContext *cx, JSString *str);
char *encodeUtf8(JSContext *cx, JSString *str) {
JS_ASSERT(!mBytes);
JS_ASSERT(cx);
mBytes = JS_EncodeStringToUTF8(cx, str);
return mBytes;
}
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -33,21 +33,20 @@ using namespace js::gc;
using mozilla::ArrayEnd;
using mozilla::ArrayLength;
using mozilla::RangedPtr;
const char *
js::AtomToPrintableString(ExclusiveContext *cx, JSAtom *atom, JSAutoByteString *bytes)
{
- // The only uses for this method when running off the main thread are for
- // parse errors/warnings, which will not actually be reported in such cases.
- if (!cx->isJSContext())
- return "";
- return js_ValueToPrintable(cx->asJSContext(), StringValue(atom), bytes);
+ JSString *str = js_QuoteString(cx, atom, 0);
+ if (!str)
+ return NULL;
+ return bytes->encodeLatin1(cx, str);
}
const char * const js::TypeStrings[] = {
js_undefined_str,
js_object_str,
js_function_str,
js_string_str,
js_number_str,
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -289,23 +289,23 @@ class ExclusiveContext : public ThreadSa
friend class gc::ArenaLists;
friend class AutoCompartment;
friend class AutoLockForExclusiveAccess;
friend struct StackBaseShape;
friend void JSScript::initCompartment(ExclusiveContext *cx);
friend class jit::IonContext;
// The worker on which this context is running, if this is not a JSContext.
- WorkerThread *workerThread;
+ WorkerThread *workerThread_;
public:
ExclusiveContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
: ThreadSafeContext(rt, pt, kind),
- workerThread(NULL),
+ workerThread_(NULL),
enterCompartmentDepth_(0)
{}
/*
* "Entering" a compartment changes cx->compartment (which changes
* cx->global). Note that this does not push any StackFrame which means
* that it is possible for cx->fp()->compartment() != cx->compartment.
* This is not a problem since, in general, most places in the VM cannot
@@ -331,16 +331,17 @@ class ExclusiveContext : public ThreadSa
return enterCompartmentDepth_;
}
#endif
inline void enterCompartment(JSCompartment *c);
inline void leaveCompartment(JSCompartment *oldCompartment);
void setWorkerThread(WorkerThread *workerThread);
+ WorkerThread *workerThread() const { return workerThread_; }
// If required, pause this thread until notified to continue by the main thread.
inline void maybePause() const;
// Threads with an ExclusiveContext may freely access any data in their
// compartment and zone.
JSCompartment *compartment() const {
JS_ASSERT_IF(runtime_->isAtomsCompartment(compartment_),
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -347,18 +347,18 @@ GetNativeStackLimit(ThreadSafeContext *c
}
return cx->perThreadData->nativeStackLimit[kind];
}
inline void
ExclusiveContext::maybePause() const
{
#ifdef JS_WORKER_THREADS
- if (workerThread)
- workerThread->maybePause();
+ if (workerThread())
+ workerThread()->maybePause();
#endif
}
class AutoLockForExclusiveAccess
{
#ifdef JS_WORKER_THREADS
JSRuntime *runtime;
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -727,17 +727,17 @@ Sprinter::realloc_(size_t newSize)
return false;
}
base = newBuf;
size = newSize;
base[size - 1] = 0;
return true;
}
-Sprinter::Sprinter(JSContext *cx)
+Sprinter::Sprinter(ExclusiveContext *cx)
: context(cx),
#ifdef DEBUG
initialized(false),
#endif
base(NULL), size(0), offset(0), reportedOOM(false)
{ }
Sprinter::~Sprinter()
@@ -862,17 +862,17 @@ Sprinter::putString(JSString *s)
size_t size = length;
if (size == (size_t) -1)
return -1;
ptrdiff_t oldOffset = offset;
char *buffer = reserve(size);
if (!buffer)
return -1;
- DeflateStringToBuffer(context, chars, length, buffer, &size);
+ DeflateStringToBuffer(NULL, chars, length, buffer, &size);
buffer[size] = 0;
return oldOffset;
}
int
Sprinter::printf(const char *fmt, ...)
{
@@ -1018,24 +1018,25 @@ QuoteString(Sprinter *sp, JSString *str,
*/
if (offset == sp->getOffset() && Sprint(sp, "") < 0)
return NULL;
return sp->stringAt(offset);
}
JSString *
-js_QuoteString(JSContext *cx, JSString *str, jschar quote)
+js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
{
Sprinter sprinter(cx);
if (!sprinter.init())
return NULL;
char *bytes = QuoteString(&sprinter, str, quote);
- JSString *escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
- return escstr;
+ if (!bytes)
+ return NULL;
+ return js_NewStringCopyZ<CanGC>(cx, bytes);
}
/************************************************************************/
static int ReconstructPCStack(JSContext*, JSScript*, jsbytecode*, jsbytecode**);
static unsigned
StackDepth(JSScript *script)
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -228,17 +228,17 @@ extern const char js_EscapeMap[];
#endif
/*
* Return a GC'ed string containing the chars in str, with any non-printing
* chars or quotes (' or " as specified by the quote argument) escaped, and
* with the quote character at the beginning and end of the result string.
*/
extern JSString *
-js_QuoteString(JSContext *cx, JSString *str, jschar quote);
+js_QuoteString(js::ExclusiveContext *cx, JSString *str, jschar quote);
namespace js {
static inline bool
IsJumpOpcode(JSOp op)
{
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
@@ -417,32 +417,32 @@ class Sprinter
parent->checkInvariants();
}
~InvariantChecker() {
parent->checkInvariants();
}
};
- JSContext *context; /* context executing the decompiler */
+ ExclusiveContext *context; /* context executing the decompiler */
private:
static const size_t DefaultSize;
#ifdef DEBUG
bool initialized; /* true if this is initialized, use for debug builds */
#endif
char *base; /* malloc'd buffer address */
size_t size; /* size of buffer allocated at base */
ptrdiff_t offset; /* offset of next free char in buffer */
bool reportedOOM; /* this sprinter has reported OOM in string ops */
bool realloc_(size_t newSize);
public:
- explicit Sprinter(JSContext *cx);
+ explicit Sprinter(ExclusiveContext *cx);
~Sprinter();
/* Initialize this sprinter, returns false on error */
bool init();
void checkInvariants() const;
const char *string() const;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -261,17 +261,17 @@ InflateStringToBuffer(JSContext *maybecx
/*
* Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
* 'length chars. The buffer is NOT null-terminated. The destination length
* must to be initialized with the buffer size and will contain on return the
* number of copied bytes.
*/
extern bool
-DeflateStringToBuffer(JSContext *cx, const jschar *chars,
+DeflateStringToBuffer(JSContext *maybecx, const jschar *chars,
size_t charsLength, char *bytes, size_t *length);
/*
* The String.prototype.replace fast-native entry point is exported for joined
* function optimization in js{interp,tracer}.cpp.
*/
extern bool
str_replace(JSContext *cx, unsigned argc, js::Value *vp);
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -716,27 +716,27 @@ WorkerThread::handleIonWorkload(WorkerTh
// this incorporation can be delayed indefinitely without affecting
// performance as long as the main thread is actually executing Ion code.
runtime->triggerOperationCallback(JSRuntime::TriggerCallbackAnyThreadDontStopIon);
}
void
ExclusiveContext::setWorkerThread(WorkerThread *workerThread)
{
- this->workerThread = workerThread;
- this->perThreadData = workerThread->threadData.addr();
+ workerThread_ = workerThread;
+ perThreadData = workerThread->threadData.addr();
}
frontend::CompileError &
ExclusiveContext::addPendingCompileError()
{
frontend::CompileError *error = js_new<frontend::CompileError>();
if (!error)
MOZ_CRASH();
- if (!workerThread->parseTask->errors.append(error))
+ if (!workerThread()->parseTask->errors.append(error))
MOZ_CRASH();
return *error;
}
void
WorkerThread::handleParseWorkload(WorkerThreadState &state)
{
JS_ASSERT(state.isLocked());
@@ -824,19 +824,35 @@ WorkerThreadState::compressionInProgress
bool
SourceCompressionTask::complete()
{
JS_ASSERT_IF(!ss, !chars);
if (active()) {
WorkerThreadState &state = *cx->workerThreadState();
AutoLockWorkerThreadState lock(state);
+ // If this compression task is itself being completed on a worker
+ // thread, treat the thread as paused while waiting for the completion.
+ // Otherwise we will not wake up and mark this as paused due to the
+ // loop in AutoPauseWorkersForGC.
+ if (cx->workerThread()) {
+ state.numPaused++;
+ if (state.numPaused == state.numThreads)
+ state.notify(WorkerThreadState::MAIN);
+ }
+
while (state.compressionInProgress(this))
state.wait(WorkerThreadState::MAIN);
+ if (cx->workerThread()) {
+ state.numPaused--;
+ if (state.shouldPause)
+ cx->workerThread()->pause();
+ }
+
ss->ready_ = true;
// Update memory accounting.
if (!oom)
cx->updateMallocCounter(ss->computedSizeOfData());
ss = NULL;
chars = NULL;
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -439,19 +439,17 @@ class GlobalObject : public JSObject
bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) {
RootedObject holder(cx, intrinsicsHolder());
RootedId id(cx, NameToId(name));
if (HasDataProperty(cx, holder, id, value.address()))
return true;
if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
return false;
- mozilla::DebugOnly<bool> ok = JS_DefinePropertyById(cx, holder, id, value, NULL, NULL, 0);
- JS_ASSERT(ok);
- return true;
+ return JS_DefinePropertyById(cx, holder, id, value, NULL, NULL, 0);
}
bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) {
#ifdef DEBUG
RootedObject self(cx, this);
JS_ASSERT(cx->runtime()->isSelfHostingGlobal(self));
#endif
RootedObject holder(cx, intrinsicsHolder());
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1558,65 +1558,65 @@ GetCompartmentName(JSCompartment *c, nsC
name.ReplaceChar('/', '\\');
} else {
name.AssignLiteral("null-principal");
}
}
// Telemetry relies on this being a uni-reporter (rather than part of the "js"
// reporter).
-class JSGCHeapReporter MOZ_FINAL : public MemoryUniReporter
+class JSMainRuntimeGCHeapReporter MOZ_FINAL : public MemoryUniReporter
{
public:
- JSGCHeapReporter()
- : MemoryUniReporter("js-gc-heap", KIND_OTHER, UNITS_BYTES,
-"Memory used by the garbage-collected JavaScript heap.")
+ JSMainRuntimeGCHeapReporter()
+ : MemoryUniReporter("js-main-runtime-gc-heap", KIND_OTHER, UNITS_BYTES,
+"Memory used by the garbage-collected heap in the main JSRuntime.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
js::gc::ChunkSize;
}
};
-// Nb: js-compartments/system + js-compartments/user could be different to the
-// number of compartments reported by JSReporter if a garbage collection
-// occurred between them being consulted. We could move these reporters into
-// JSReporter to avoid that problem, but then we couldn't easily report them
-// via telemetry, so we live with the small risk of inconsistencies.
-
-class JSCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
+// Nb: js-main-runtime-compartments/system + js-main-runtime-compartments/user
+// could be different to the number of compartments reported by JSReporter if a
+// garbage collection occurred between them being consulted. We could move
+// these reporters into JSReporter to avoid that problem, but then we couldn't
+// easily report them via telemetry, so we live with the small risk of
+// inconsistencies.
+
+class RedundantJSMainRuntimeCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
{
public:
- JSCompartmentsSystemReporter()
- : MemoryUniReporter("js-compartments/system", KIND_OTHER, UNITS_COUNT,
-"The number of JavaScript compartments for system code. The sum of this and "
-"'js-compartments/user' might not match the number of compartments listed "
-"in the 'explicit' tree if a garbage collection occurs at an inopportune "
-"time, but such cases should be rare.")
+ // An empty description is ok because this is a "redundant/"-prefixed
+ // reporter and so is ignored by about:memory.
+ RedundantJSMainRuntimeCompartmentsSystemReporter()
+ : MemoryUniReporter("redundant/js-main-runtime-compartments/system",
+ KIND_OTHER, UNITS_COUNT, "")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::SystemCompartmentCount(rt);
}
};
-class JSCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
+class RedundantJSMainRuntimeCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
{
public:
- JSCompartmentsUserReporter()
- : MemoryUniReporter("js-compartments/user", KIND_OTHER, UNITS_COUNT,
-"The number of JavaScript compartments for user code. The sum of this and "
-"'js-compartments/system' might not match the number of compartments listed "
-"under 'js' if a garbage collection occurs at an inopportune time, but such "
-"cases should be rare.")
+ // An empty description is ok because this is a "redundant/"-prefixed
+ // reporter and so is ignored by about:memory.
+ RedundantJSMainRuntimeCompartmentsUserReporter()
+ : MemoryUniReporter("redundant/js-main-runtime-compartments/user",
+ KIND_OTHER, UNITS_COUNT,
+"The number of JavaScript compartments for user code in the main JSRuntime.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
return JS::UserCompartmentCount(rt);
}
};
@@ -2355,36 +2355,36 @@ ReportJSRuntimeExplicitTreeStats(const J
do_GetService("@mozilla.org/addons/integration;1");
return ReportJSRuntimeExplicitTreeStats(rtStats, rtPath, am.get(), cb,
closure, rtTotalOut);
}
} // namespace xpc
-class JSCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
+class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD GetName(nsACString &name) {
- name.AssignLiteral("compartments");
+ name.AssignLiteral("js-main-runtime-compartments");
return NS_OK;
}
typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths;
static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c) {
// silently ignore OOM errors
Paths *paths = static_cast<Paths *>(data);
nsCString path;
GetCompartmentName(c, path, true);
path.Insert(js::IsSystemCompartment(c)
- ? NS_LITERAL_CSTRING("compartments/system/")
- : NS_LITERAL_CSTRING("compartments/user/"),
+ ? NS_LITERAL_CSTRING("js-main-runtime-compartments/system/")
+ : NS_LITERAL_CSTRING("js-main-runtime-compartments/user/"),
0);
paths->append(path);
}
NS_IMETHOD CollectReports(nsIMemoryReporterCallback *cb,
nsISupports *closure)
{
// First we collect the compartment paths. Then we report them. Doing
@@ -2395,23 +2395,24 @@ class JSCompartmentsReporter MOZ_FINAL :
Paths paths;
JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->Runtime(),
&paths, CompartmentCallback);
// Report.
for (size_t i = 0; i < paths.length(); i++)
// These ones don't need a description, hence the "".
- REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1, "");
+ REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1,
+ "A live compartment in the main JSRuntime.");
return NS_OK;
}
};
-NS_IMPL_ISUPPORTS1(JSCompartmentsReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS1(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(OrphanMallocSizeOf)
namespace xpc {
static size_t
SizeOfTreeIncludingThis(nsINode *tree)
{
@@ -3039,21 +3040,21 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect*
JS_SetSourceHook(runtime, SourceHook);
// Set up locale information and callbacks for the newly-created runtime so
// that the various toLocaleString() methods, localeCompare(), and other
// internationalization APIs work as desired.
if (!xpc_LocalizeRuntime(runtime))
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
- NS_RegisterMemoryReporter(new JSGCHeapReporter());
- NS_RegisterMemoryReporter(new JSCompartmentsSystemReporter());
- NS_RegisterMemoryReporter(new JSCompartmentsUserReporter());
+ NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
+ NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsSystemReporter());
+ NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsUserReporter());
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
- NS_RegisterMemoryReporter(new JSCompartmentsReporter);
+ NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
// Install a JavaScript 'debugger' keyword handler in debug builds only
#ifdef DEBUG
if (!JS_GetGlobalDebugHooks(runtime)->debuggerHandler)
xpc_InstallJSDebuggerKeywordHandler(runtime);
#endif
}
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -5,17 +5,16 @@
The name of the event which real interface should have nsIDOM-prefix,
and should be in nsIDOM<name>.idl file and which should have
<name>Init dictionary for the event constructor. """
simple_events = [
'ProgressEvent',
'StorageEvent',
- 'DeviceProximityEvent',
'MozSettingsEvent',
'UserProximityEvent',
'CustomEvent',
'PageTransitionEvent',
'DOMTransactionEvent',
'PopStateEvent',
'HashChangeEvent',
'CloseEvent',
@@ -47,21 +46,16 @@ simple_events = [
'MozSmsEvent',
'MozMmsEvent',
#ifdef MOZ_WEBSPEECH
'SpeechSynthesisEvent',
#endif
'DeviceStorageChangeEvent',
'PopupBlockedEvent',
'RecordErrorEvent',
-#ifdef MOZ_GAMEPAD
- 'GamepadEvent',
- 'GamepadButtonEvent',
- 'GamepadAxisMoveEvent',
-#endif
#ifdef MOZ_WEBSPEECH
'SpeechRecognitionEvent',
#endif
]
""" include file names """
special_includes = [
'nsContentUtils.h',
@@ -77,11 +71,10 @@ exclude_automatic_type_include = [
]
""" Map xpidl interface names to implementation classes. The third column is the canonical interface. """
xpidl_to_native = [
['nsIDOMBluetoothDevice', 'bluetooth::BluetoothDevice', 'nsIDOMBluetoothDevice'],
['nsIDOMDocument', 'nsIDocument', 'nsIDocument'],
['nsIDOMElement', 'mozilla::dom::Element', 'mozilla::dom::Element'],
['nsIDOMCSSStyleSheet', 'nsCSSStyleSheet', 'nsIStyleSheet'],
- ['nsIDOMGamepad', 'Gamepad', 'nsIDOMGamepad']
]
--- a/js/xpconnect/tests/chrome/test_bug732665.xul
+++ b/js/xpconnect/tests/chrome/test_bug732665.xul
@@ -54,16 +54,23 @@ https://bugzilla.mozilla.org/show_bug.cg
chromeSb.ok = contentSb.ok = ok;
Cu.evalInSandbox(nearNativeStackLimit.toSource(), chromeSb);
Cu.evalInSandbox(nearNativeStackLimit.toSource(), contentSb);
var chromeLimit = Cu.evalInSandbox("nearNativeStackLimit(0);", chromeSb);
var contentLimit = Cu.evalInSandbox("nearNativeStackLimit(0)", contentSb);
ok(chromeLimit >= contentLimit + 10,
"Chrome should be able to have at least 10 heavy frames more stack than content: " + chromeLimit + ", " + contentLimit);
- // Exhaust the stack space in content, and then make sure we can still get 10 heavy frames in chrome.
+ // Exhaust the stack space in content, and then make sure we can still get 10
+ // heavy frames in chrome.
+ //
+ // Note that sometimes, if we pass |0| to nearNativeStackLimit, we can end up
+ // so close to the border in content that we can't even get ourselves together
+ // enough to make the cross-compartment call. So rather than exhausting the
+ // stack entirely and then checking for 10 chrome frames, we leave ourselves
+ // one frame's worth, and check for 11.
contentSb.nnslChrome = chromeSb.nearNativeStackLimit;
- var nestedLimit = Cu.evalInSandbox("nearNativeStackLimit(0, function() { nestedLimit = nnslChrome(0);}); nestedLimit;", contentSb);
- ok(nestedLimit >= 10, "Chrome should be invokable from content script with an exhausted stack: " + nestedLimit);
+ var nestedLimit = Cu.evalInSandbox("nearNativeStackLimit(1, function() { nestedLimit = nnslChrome(0);}); nestedLimit;", contentSb);
+ ok(nestedLimit >= 11, "Chrome should be invokable from content script with an exhausted stack: " + nestedLimit);
]]>
</script>
</window>
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -36,23 +36,27 @@ StickyScrollContainer::StickyScrollConta
StickyScrollContainer::~StickyScrollContainer()
{
mScrollFrame->RemoveScrollPositionListener(this);
}
// static
StickyScrollContainer*
-StickyScrollContainer::StickyScrollContainerForFrame(nsIFrame* aFrame)
+StickyScrollContainer::GetStickyScrollContainerForFrame(nsIFrame* aFrame)
{
nsIScrollableFrame* scrollFrame =
nsLayoutUtils::GetNearestScrollableFrame(aFrame->GetParent(),
nsLayoutUtils::SCROLLABLE_SAME_DOC |
nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
- NS_ASSERTION(scrollFrame, "Need a scrolling container");
+ if (!scrollFrame) {
+ // We might not find any, for instance in the case of
+ // <html style="position: fixed">
+ return nullptr;
+ }
FrameProperties props = static_cast<nsIFrame*>(do_QueryFrame(scrollFrame))->
Properties();
StickyScrollContainer* s = static_cast<StickyScrollContainer*>
(props.Get(StickyScrollContainerProperty()));
if (!s) {
s = new StickyScrollContainer(scrollFrame);
props.Set(StickyScrollContainerProperty(), s);
}
@@ -85,18 +89,17 @@ void
StickyScrollContainer::ComputeStickyOffsets(nsIFrame* aFrame)
{
nsIScrollableFrame* scrollableFrame =
nsLayoutUtils::GetNearestScrollableFrame(aFrame->GetParent(),
nsLayoutUtils::SCROLLABLE_SAME_DOC |
nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
if (!scrollableFrame) {
- // Not sure how this would happen, but bail if it does.
- NS_ERROR("Couldn't find a scrollable frame");
+ // Bail.
return;
}
nsSize scrollContainerSize = scrollableFrame->GetScrolledFrame()->
GetContentRectRelativeToSelf().Size();
nsMargin computedOffsets;
const nsStylePosition* position = aFrame->StylePosition();
@@ -108,34 +111,34 @@ StickyScrollContainer::ComputeStickyOffs
computedOffsets.top = ComputeStickySideOffset(eSideTop, position->mOffset,
scrollContainerSize.height);
computedOffsets.bottom = ComputeStickySideOffset(eSideBottom, position->mOffset,
scrollContainerSize.height);
// Store the offset
FrameProperties props = aFrame->Properties();
nsMargin* offsets = static_cast<nsMargin*>
- (props.Get(nsIFrame::ComputedStickyOffsetProperty()));
+ (props.Get(nsIFrame::ComputedOffsetProperty()));
if (offsets) {
*offsets = computedOffsets;
} else {
- props.Set(nsIFrame::ComputedStickyOffsetProperty(),
+ props.Set(nsIFrame::ComputedOffsetProperty(),
new nsMargin(computedOffsets));
}
}
void
StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick,
nsRect* aContain) const
{
aStick->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
aContain->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
const nsMargin* computedOffsets = static_cast<nsMargin*>(
- aFrame->Properties().Get(nsIFrame::ComputedStickyOffsetProperty()));
+ aFrame->Properties().Get(nsIFrame::ComputedOffsetProperty()));
if (!computedOffsets) {
// We haven't reflowed the scroll frame yet, so offsets haven't been
// computed. Bail.
return;
}
nsIFrame* scrolledFrame = mScrollFrame->GetScrolledFrame();
nsIFrame* cbFrame = aFrame->GetContainingBlock();
--- a/layout/generic/StickyScrollContainer.h
+++ b/layout/generic/StickyScrollContainer.h
@@ -21,20 +21,20 @@ class nsIFrame;
class nsIScrollableFrame;
namespace mozilla {
class StickyScrollContainer MOZ_FINAL : public nsIScrollPositionListener
{
public:
/**
- * Find the StickyScrollContainer associated with the scroll container of
- * the given frame, creating it if necessary.
+ * Find (and create if necessary) the StickyScrollContainer associated with
+ * the scroll container of the given frame, if a scroll container exists.
*/
- static StickyScrollContainer* StickyScrollContainerForFrame(nsIFrame* aFrame);
+ static StickyScrollContainer* GetStickyScrollContainerForFrame(nsIFrame* aFrame);
/**
* Find the StickyScrollContainer associated with the given scroll frame,
* if it exists.
*/
static StickyScrollContainer* GetStickyScrollContainerForScrollFrame(nsIFrame* aScrollFrame);
void AddFrame(nsIFrame* aFrame) {
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/914891.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html style="position: fixed;">
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+<div style="position: sticky;"></div>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -495,8 +495,9 @@ load 849603.html
test-pref(layout.css.flexbox.enabled,true) load 851396-1.html
test-pref(layout.css.flexbox.enabled,true) load 854263-1.html
test-pref(layout.css.flexbox.enabled,true) load 862947-1.html
needs-focus pref(accessibility.browsewithcaret,true) load 868906.html
test-pref(layout.css.flexbox.enabled,true) load 866547-1.html
asserts(1-4) test-pref(layout.css.flexbox.enabled,true) load 876074-1.html # bug 876749
load 885009-1.html
load 893523.html
+test-pref(layout.css.sticky.enabled,true) load 914891.html
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2577,35 +2577,31 @@ nsBlockFrame::SlideLine(nsBlockReflowSta
// Adjust the frames in the line
nsIFrame* kid = aLine->mFirstChild;
if (!kid) {
return;
}
if (aLine->IsBlock()) {
if (aDY) {
- nsPoint p = kid->GetPosition();
- p.y += aDY;
- kid->SetPosition(p);
+ kid->MovePositionBy(nsPoint(0, aDY));
}
// Make sure the frame's view and any child views are updated
::PlaceFrameView(kid);
}
else {
// Adjust the Y coordinate of the frames in the line.
// Note: we need to re-position views even if aDY is 0, because
// one of our parent frames may have moved and so the view's position
// relative to its parent may have changed
int32_t n = aLine->GetChildCount();
while (--n >= 0) {
if (aDY) {
- nsPoint p = kid->GetPosition();
- p.y += aDY;
- kid->SetPosition(p);
+ kid->MovePositionBy(nsPoint(0, aDY));
}
// Make sure the frame's view and any child views are updated
::PlaceFrameView(kid);
kid = kid->GetNextSibling();
}
}
}
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -381,18 +381,17 @@ nsBlockReflowState::RecoverFloats(nsLine
{
if (aLine->HasFloats()) {
// Place the floats into the space-manager again. Also slide
// them, just like the regular frames on the line.
nsFloatCache* fc = aLine->GetFirstFloat();
while (fc) {
nsIFrame* floatFrame = fc->mFloat;
if (aDeltaY != 0) {
- nsPoint p = floatFrame->GetPosition();
- floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
+ floatFrame->MovePositionBy(nsPoint(0, aDeltaY));
nsContainerFrame::PositionFrameView(floatFrame);
nsContainerFrame::PositionChildViews(floatFrame);
}
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
nscoord tx, ty;
mFloatManager->GetTranslation(tx, ty);
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -1092,36 +1092,16 @@ nsFlexContainerFrame::SortChildrenIfNeed
/* virtual */
nsIAtom*
nsFlexContainerFrame::GetType() const
{
return nsGkAtoms::flexContainerFrame;
}
-/* virtual */
-int
-nsFlexContainerFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
-{
- // (same as nsBlockFrame's GetSkipSides impl)
- if (IS_TRUE_OVERFLOW_CONTAINER(this)) {
- return (1 << NS_SIDE_TOP) | (1 << NS_SIDE_BOTTOM);
- }
-
- int skip = 0;
- if (GetPrevInFlow()) {
- skip |= 1 << NS_SIDE_TOP;
- }
- nsIFrame* nif = GetNextInFlow();
- if (nif && !IS_TRUE_OVERFLOW_CONTAINER(nif)) {
- skip |= 1 << NS_SIDE_BOTTOM;
- }
- return skip;
-}
-
#ifdef DEBUG
NS_IMETHODIMP
nsFlexContainerFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("FlexContainer"), aResult);
}
#endif // DEBUG
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -44,17 +44,16 @@ public:
nsReflowStatus& aStatus) MOZ_OVERRIDE;
virtual nscoord
GetMinWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
virtual nscoord
GetPrefWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
- virtual int GetSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif // DEBUG
// Flexbox-specific public methods
bool IsHorizontal();
protected:
// Protected constructor & destructor
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -507,17 +507,21 @@ nsFrame::Init(nsIContent* aContent,
}
const nsStyleDisplay *disp = StyleDisplay();
if (disp->HasTransform(this)) {
// The frame gets reconstructed if we toggle the -moz-transform
// property, so we can set this bit here and then ignore it.
mState |= NS_FRAME_MAY_BE_TRANSFORMED;
}
if (disp->mPosition == NS_STYLE_POSITION_STICKY) {
- StickyScrollContainer::StickyScrollContainerForFrame(this)->AddFrame(this);
+ StickyScrollContainer* ssc =
+ StickyScrollContainer::GetStickyScrollContainerForFrame(this);
+ if (ssc) {
+ ssc->AddFrame(this);
+ }
}
if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
#ifdef DEBUG
// We have assertions that check inflation invariants even when
// font size inflation is not enabled.
|| true
#endif
@@ -588,18 +592,21 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
"Frames should be removed before destruction.");
NS_ASSERTION(aDestructRoot, "Must specify destruct root");
MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
nsSVGEffects::InvalidateDirectRenderingObservers(this);
if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
- StickyScrollContainer::StickyScrollContainerForFrame(this)->
- RemoveFrame(this);
+ StickyScrollContainer* ssc =
+ StickyScrollContainer::GetStickyScrollContainerForFrame(this);
+ if (ssc) {
+ ssc->RemoveFrame(this);
+ }
}
// Get the view pointer now before the frame properties disappear
// when we call NotifyDestroyingFrame()
nsView* view = GetView();
nsPresContext* presContext = PresContext();
nsIPresShell *shell = presContext->GetPresShell();
@@ -5058,16 +5065,32 @@ ComputeOutlineAndEffectsRect(nsIFrame* a
Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
}
r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
}
return r;
}
+void
+nsIFrame::MovePositionBy(const nsPoint& aTranslation)
+{
+ nsPoint position = GetNormalPosition() + aTranslation;
+
+ const nsMargin* computedOffsets = nullptr;
+ if (IsRelativelyPositioned()) {
+ computedOffsets = static_cast<nsMargin*>
+ (Properties().Get(nsIFrame::ComputedOffsetProperty()));
+ }
+ nsHTMLReflowState::ApplyRelativePositioning(this, computedOffsets ?
+ *computedOffsets : nsMargin(),
+ &position);
+ SetPosition(position);
+}
+
nsPoint
nsIFrame::GetNormalPosition() const
{
// It might be faster to first check
// StyleDisplay()->IsRelativelyPositionedStyle().
nsPoint* normalPosition = static_cast<nsPoint*>
(Properties().Get(NormalPositionProperty()));
if (normalPosition) {
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -826,16 +826,27 @@ nsHTMLReflowState::ComputeRelativeOffset
// 'Top' isn't 'auto' so compute its value
aComputedOffsets.top = nsLayoutUtils::
ComputeHeightDependentValue(aContainingBlockHeight,
position->mOffset.GetTop());
// Computed value for 'bottom' is minus the value of 'top'
aComputedOffsets.bottom = -aComputedOffsets.top;
}
+
+ // Store the offset
+ FrameProperties props = aFrame->Properties();
+ nsMargin* offsets = static_cast<nsMargin*>
+ (props.Get(nsIFrame::ComputedOffsetProperty()));
+ if (offsets) {
+ *offsets = aComputedOffsets;
+ } else {
+ props.Set(nsIFrame::ComputedOffsetProperty(),
+ new nsMargin(aComputedOffsets));
+ }
}
/* static */ void
nsHTMLReflowState::ApplyRelativePositioning(nsIFrame* aFrame,
const nsMargin& aComputedOffsets,
nsPoint* aPosition)
{
// Store the normal position
@@ -847,18 +858,21 @@ nsHTMLReflowState::ApplyRelativePosition
} else {
props.Set(nsIFrame::NormalPositionProperty(), new nsPoint(*aPosition));
}
const nsStyleDisplay* display = aFrame->StyleDisplay();
if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
*aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
} else if (NS_STYLE_POSITION_STICKY == display->mPosition) {
- *aPosition = StickyScrollContainer::StickyScrollContainerForFrame(aFrame)->
- ComputePosition(aFrame);
+ StickyScrollContainer* ssc =
+ StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame);
+ if (ssc) {
+ *aPosition = ssc->ComputePosition(aFrame);
+ }
}
}
nsIFrame*
nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
nscoord& aCBLeftEdge,
nscoord& aCBWidth)
{
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -862,16 +862,23 @@ public:
}
}
void SetSize(const nsSize& aSize) {
SetRect(nsRect(mRect.TopLeft(), aSize));
}
void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); }
/**
+ * Move the frame, accounting for relative positioning. Use this when
+ * adjusting the frame's position by a known amount, to properly update its
+ * saved normal position (see GetNormalPosition below).
+ */
+ void MovePositionBy(const nsPoint& aTranslation);
+
+ /**
* Return frame's position without relative positioning
*/
nsPoint GetNormalPosition() const;
virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
{ return aChild->GetPosition(); }
nsPoint GetPositionIgnoringScrolling() {
@@ -922,17 +929,17 @@ public:
static NS_PROPERTY_DESCRIPTOR_CONST FramePropertyDescriptor descriptor = { nullptr, dtor }; \
return &descriptor; \
}
NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialSibling, nullptr)
NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialPrevSibling, nullptr)
NS_DECLARE_FRAME_PROPERTY(NormalPositionProperty, DestroyPoint)
- NS_DECLARE_FRAME_PROPERTY(ComputedStickyOffsetProperty, DestroyMargin)
+ NS_DECLARE_FRAME_PROPERTY(ComputedOffsetProperty, DestroyMargin)
NS_DECLARE_FRAME_PROPERTY(OutlineInnerRectProperty, DestroyRect)
NS_DECLARE_FRAME_PROPERTY(PreEffectsBBoxProperty, DestroyRect)
NS_DECLARE_FRAME_PROPERTY(PreTransformOverflowAreasProperty,
DestroyOverflowAreas)
// The initial overflow area passed to FinishAndStoreOverflow. This is only set
// on frames that Preserve3D(), and when at least one of the overflow areas
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -911,18 +911,16 @@ nsInlineFrame::AccessibleType()
{
// Broken image accessibles are created here, because layout
// replaces the image or image control frame with an inline frame
nsIAtom *tagAtom = mContent->Tag();
if (tagAtom == nsGkAtoms::input) // Broken <input type=image ... />
return a11y::eHTMLButtonType;
if (tagAtom == nsGkAtoms::img) // Create accessible for broken <img>
return a11y::eHyperTextType;
- if (tagAtom == nsGkAtoms::label) // Creat accessible for <label>
- return a11y::eHTMLLabelType;
return a11y::eNoType;
}
#endif
//////////////////////////////////////////////////////////////////////
// nsLineFrame implementation
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2191,19 +2191,17 @@ nsLineLayout::VerticalAlignFrames(PerSpa
}
if (maxBottomBoxHeight > mMaxBottomBoxHeight) {
mMaxBottomBoxHeight = maxBottomBoxHeight;
}
}
static void SlideSpanFrameRect(nsIFrame* aFrame, nscoord aDeltaWidth)
{
- nsRect r = aFrame->GetRect();
- r.x -= aDeltaWidth;
- aFrame->SetRect(r);
+ aFrame->MovePositionBy(nsPoint(-aDeltaWidth, 0));
}
bool
nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
nscoord* aDeltaWidth)
{
#ifndef IBMBIDI
// XXX what about NS_STYLE_DIRECTION_RTL?
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -460,20 +460,17 @@ GetPrintCanvasElementsInFrame(nsIFrame*
// Check if child is a nsHTMLCanvasFrame.
nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child);
// If there is a canvasFrame, try to get actual canvas element.
if (canvasFrame) {
HTMLCanvasElement* canvas =
HTMLCanvasElement::FromContentOrNull(canvasFrame->GetContent());
- nsCOMPtr<nsIPrintCallback> printCallback;
- if (canvas &&
- NS_SUCCEEDED(canvas->GetMozPrintCallback(getter_AddRefs(printCallback))) &&
- printCallback) {
+ if (canvas && canvas->GetMozPrintCallback()) {
aArr->AppendElement(canvas);
continue;
}
}
if (!child->GetFirstPrincipalChild()) {
nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(child);
if (subdocumentFrame) {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2635,20 +2635,18 @@ DocHasPrintCallbackCanvas(nsIDocument* a
if (!root) {
return true;
}
nsRefPtr<nsContentList> canvases = NS_GetContentList(root,
kNameSpaceID_XHTML,
NS_LITERAL_STRING("canvas"));
uint32_t canvasCount = canvases->Length(true);
for (uint32_t i = 0; i < canvasCount; ++i) {
- nsCOMPtr<nsIDOMHTMLCanvasElement> canvas = do_QueryInterface(canvases->Item(i, false));
- nsCOMPtr<nsIPrintCallback> printCallback;
- if (canvas && NS_SUCCEEDED(canvas->GetMozPrintCallback(getter_AddRefs(printCallback))) &&
- printCallback) {
+ HTMLCanvasElement* canvas = HTMLCanvasElement::FromContentOrNull(canvases->Item(i, false));
+ if (canvas && canvas->GetMozPrintCallback()) {
// This subdocument has a print callback. Set result and return false to
// stop iteration.
*static_cast<bool*>(aData) = true;
return false;
}
}
return true;
}
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -14,18 +14,18 @@ default-preferences pref(dom.experimenta
!= different-fraction-of-range-unthemed-1.html different-fraction-of-range-unthemed-1-notref.html
== same-fraction-of-range-unthemed-1.html same-fraction-of-range-unthemed-1-ref.html
# dynamic value changes:
== value-prop-unthemed.html 75pct-unthemed-common-ref.html
== value-prop.html 75pct-common-ref.html
== valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
== valueAsNumber-prop.html 75pct-common-ref.html
-fails-if(B2G) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
-fails-if(B2G) == stepDown.html 75pct-common-ref.html
+== stepDown-unthemed.html 75pct-unthemed-common-ref.html
+== stepDown.html 75pct-common-ref.html
== stepUp-unthemed.html 75pct-unthemed-common-ref.html
== stepUp.html 75pct-common-ref.html
# 'direction' property:
== direction-unthemed-1.html direction-unthemed-1-ref.html
# ::-moz-range-progress pseudo-element:
fails-if(B2G) == moz-range-progress-1.html moz-range-progress-1-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -165,20 +165,20 @@ skip-if(B2G) == foreignObject-move-repai
== foreignObject-overflow-01.svg pass.svg
skip-if(B2G) == foreignObject-start-hidden-01.svg pass.svg # followup from Bug 596765
skip-if(B2G) == foreignObject-start-hidden-02.svg pass.svg
skip-if(B2G) == foreignObject-style-change-01.svg pass.svg
== foreignObject-dynamic-abspos-01.html foreignObject-dynamic-abspos-01-ref.html
fuzzy-if(Android,18,600) == foreignObject-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
== foreignObject-dynamic-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
== getElementById-a-element-01.svg pass.svg
-fuzzy-if(Android,9,980) == gradient-live-01a.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01b.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01c.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01a.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01b.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01c.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
== import-svg-01.html pass.svg
== invalid-text-01.svg pass.svg
== lang-attribute-01.svg pass.svg
== lang-attribute-02.svg pass.svg
== lang-attribute-03.svg pass.svg
== linearGradient-basic-01.svg pass.svg
== linearGradient-basic-02.svg pass.svg
== markers-and-group-opacity-01.svg markers-and-group-opacity-01-ref.svg
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -976,17 +976,18 @@ nsAnimationManager::GetAnimationRule(moz
if (ea->mStyleRule) {
ea->PostRestyleForAnimation(mPresContext);
}
return nullptr;
}
- NS_WARN_IF_FALSE(ea->mStyleRuleRefreshTime ==
+ NS_WARN_IF_FALSE(!ea->mNeedsRefreshes ||
+ ea->mStyleRuleRefreshTime ==
mPresContext->RefreshDriver()->MostRecentRefresh(),
"should already have refreshed style rule");
return ea->mStyleRule;
}
/* virtual */ void
nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3369,17 +3369,17 @@ CSS_PROP_SVGRESET(
filter,
filter,
Filter,
CSS_PROPERTY_PARSE_FUNCTION,
"",
0,
nullptr,
CSS_PROP_NO_OFFSET,
- eStyleAnimType_None)
+ eStyleAnimType_Custom)
CSS_PROP_SVGRESET(
flood-color,
flood_color,
FloodColor,
CSS_PROPERTY_PARSE_VALUE,
"",
VARIANT_HC,
nullptr,
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -243,16 +243,44 @@ ToPrimitive(nsCSSValue::Array* aArray)
inline void
nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue)
{
aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord),
eCSSUnit_Pixel);
}
+static void
+AppendCSSShadowValue(const nsCSSShadowItem *aShadow,
+ nsCSSValueList **&aResultTail)
+{
+ NS_ABORT_IF_FALSE(aShadow, "shadow expected");
+
+ // X, Y, Radius, Spread, Color, Inset
+ nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
+ nscoordToCSSValue(aShadow->mXOffset, arr->Item(0));
+ nscoordToCSSValue(aShadow->mYOffset, arr->Item(1));
+ nscoordToCSSValue(aShadow->mRadius, arr->Item(2));
+ // NOTE: This code sometimes stores mSpread: 0 even when
+ // the parser would be required to leave it null.
+ nscoordToCSSValue(aShadow->mSpread, arr->Item(3));
+ if (aShadow->mHasColor) {
+ arr->Item(4).SetColorValue(aShadow->mColor);
+ }
+ if (aShadow->mInset) {
+ arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
+ eCSSUnit_Enumerated);
+ }
+
+ nsCSSValueList *resultItem = new nsCSSValueList;
+ resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
+ *aResultTail = resultItem;
+ aResultTail = &resultItem->mNext;
+}
+
// Like nsStyleCoord::Calc, but with length in float pixels instead of nscoord.
struct CalcValue {
float mLength, mPercent;
bool mHasPercent;
};
// Requires a canonical calc() value that we generated.
static CalcValue
@@ -748,16 +776,18 @@ nsStyleAnimation::ComputeDistance(nsCSSP
shadow1 = shadow1->mNext;
shadow2 = shadow2->mNext;
NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length");
}
aDistance = sqrt(squareDistance);
return true;
}
+ case eUnit_Filter:
+ // FIXME: Support paced animations for filter function interpolation.
case eUnit_Transform: {
return false;
}
case eUnit_BackgroundPosition: {
const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
double squareDistance = 0.0;
@@ -1027,16 +1057,48 @@ AddCSSValuePixelPercentCalc(const uint32
break;
default:
return false;
}
return true;
}
+static inline float
+GetNumberOrPercent(const nsCSSValue &aValue)
+{
+ nsCSSUnit unit = aValue.GetUnit();
+ NS_ABORT_IF_FALSE(unit == eCSSUnit_Number || unit == eCSSUnit_Percent,
+ "unexpected unit");
+ return (unit == eCSSUnit_Number) ?
+ aValue.GetFloatValue() : aValue.GetPercentValue();
+}
+
+static inline void
+AddCSSValuePercentNumber(const uint32_t aValueRestrictions,
+ double aCoeff1, const nsCSSValue &aValue1,
+ double aCoeff2, const nsCSSValue &aValue2,
+ nsCSSValue &aResult, float aInitialVal)
+{
+ float n1 = GetNumberOrPercent(aValue1);
+ float n2 = GetNumberOrPercent(aValue2);
+
+ // Rather than interpolating aValue1 and aValue2 directly, we
+ // interpolate their *distances from aInitialVal* (the initial value,
+ // which is either 1 or 0 for "filter" functions). This matters in
+ // cases where aInitialVal is nonzero and the coefficients don't add
+ // up to 1. For example, if initialVal is 1, aCoeff1 is 0.5, and
+ // aCoeff2 is 0, then we'll return the value halfway between 1 and
+ // aValue1, rather than the value halfway between 0 and aValue1.
+ // Note that we do something similar in AddTransformScale().
+ float result = (n1 - aInitialVal) * aCoeff1 + (n2 - aInitialVal) * aCoeff2;
+ aResult.SetFloatValue(RestrictValue(aValueRestrictions, result + aInitialVal),
+ eCSSUnit_Number);
+}
+
static bool
AddShadowItems(double aCoeff1, const nsCSSValue &aValue1,
double aCoeff2, const nsCSSValue &aValue2,
nsCSSValueList **&aResultTail)
{
// X, Y, Radius, Spread, Color, Inset
NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array,
"wrong unit");
@@ -1542,16 +1604,131 @@ AddDifferentTransformLists(double aCoeff
}
static bool
TransformFunctionsMatch(nsCSSKeyword func1, nsCSSKeyword func2)
{
return ToPrimitive(func1) == ToPrimitive(func2);
}
+static bool
+AddFilterFunctionImpl(double aCoeff1, const nsCSSValueList* aList1,
+ double aCoeff2, const nsCSSValueList* aList2,
+ nsCSSValueList**& aResultTail)
+{
+ // AddFilterFunction should be our only caller, and it should ensure that both
+ // args are non-null.
+ NS_ABORT_IF_FALSE(aList1, "expected filter list");
+ NS_ABORT_IF_FALSE(aList2, "expected filter list");
+ NS_ABORT_IF_FALSE(aList1->mValue.GetUnit() == eCSSUnit_Function,
+ "expected function");
+ NS_ABORT_IF_FALSE(aList2->mValue.GetUnit() == eCSSUnit_Function,
+ "expected function");
+ nsRefPtr<nsCSSValue::Array> a1 = aList1->mValue.GetArrayValue(),
+ a2 = aList2->mValue.GetArrayValue();
+ nsCSSKeyword filterFunction = a1->Item(0).GetKeywordValue();
+ if (filterFunction != a2->Item(0).GetKeywordValue())
+ return false; // Can't add two filters of different types.
+
+ nsAutoPtr<nsCSSValueList> resultListEntry(new nsCSSValueList);
+ nsCSSValue::Array* result =
+ resultListEntry->mValue.InitFunction(filterFunction, 1);
+
+ // "hue-rotate" is the only filter-function that accepts negative values, and
+ // we don't use this "restrictions" variable in its clause below.
+ const uint32_t restrictions = CSS_PROPERTY_VALUE_NONNEGATIVE;
+ const nsCSSValue& funcArg1 = a1->Item(1);
+ const nsCSSValue& funcArg2 = a2->Item(1);
+ nsCSSValue& resultArg = result->Item(1);
+ float initialVal = 1.0f;
+ switch (filterFunction) {
+ case eCSSKeyword_blur: {
+ nsCSSUnit unit;
+ if (funcArg1.GetUnit() == funcArg2.GetUnit()) {
+ unit = funcArg1.GetUnit();
+ } else {
+ // If units differ, we'll just combine them with calc().
+ unit = eCSSUnit_Calc;
+ }
+ if (!AddCSSValuePixelPercentCalc(restrictions,
+ unit,
+ aCoeff1, funcArg1,
+ aCoeff2, funcArg2,
+ resultArg)) {
+ return false;
+ }
+ break;
+ }
+ case eCSSKeyword_grayscale:
+ case eCSSKeyword_invert:
+ case eCSSKeyword_sepia:
+ initialVal = 0.0f;
+ case eCSSKeyword_brightness:
+ case eCSSKeyword_contrast:
+ case eCSSKeyword_opacity:
+ case eCSSKeyword_saturate:
+ AddCSSValuePercentNumber(restrictions,
+ aCoeff1, funcArg1,
+ aCoeff2, funcArg2,
+ resultArg,
+ initialVal);
+ break;
+ case eCSSKeyword_hue_rotate:
+ AddCSSValueAngle(aCoeff1, funcArg1,
+ aCoeff2, funcArg2,
+ resultArg);
+ break;
+ case eCSSKeyword_drop_shadow: {
+ nsCSSValueList* resultShadow = resultArg.SetListValue();
+ nsAutoPtr<nsCSSValueList> shadowValue;
+ nsCSSValueList **shadowTail = getter_Transfers(shadowValue);
+ NS_ABORT_IF_FALSE(!funcArg1.GetListValue()->mNext &&
+ !funcArg2.GetListValue()->mNext,
+ "drop-shadow filter func doesn't support lists");
+ if (!AddShadowItems(aCoeff1, funcArg1.GetListValue()->mValue,
+ aCoeff2, funcArg2.GetListValue()->mValue,
+ shadowTail)) {
+ return false;
+ }
+ *resultShadow = *shadowValue;
+ break;
+ }
+ default:
+ NS_ABORT_IF_FALSE(false, "unknown filter function");
+ return false;
+ }
+
+ *aResultTail = resultListEntry.forget();
+ aResultTail = &(*aResultTail)->mNext;
+
+ return true;
+}
+
+static bool
+AddFilterFunction(double aCoeff1, const nsCSSValueList* aList1,
+ double aCoeff2, const nsCSSValueList* aList2,
+ nsCSSValueList**& aResultTail)
+{
+ NS_ABORT_IF_FALSE(aList1 || aList2,
+ "one function list item must not be null");
+ // Note that one of our arguments could be null, indicating that
+ // it's the initial value. Rather than adding special null-handling
+ // logic, we just check for null values and replace them with
+ // 0 * the other value. That way, AddFilterFunctionImpl can assume
+ // its args are non-null.
+ if (!aList1) {
+ return AddFilterFunctionImpl(aCoeff2, aList2, 0, aList2, aResultTail);
+ }
+ if (!aList2) {
+ return AddFilterFunctionImpl(aCoeff1, aList1, 0, aList1, aResultTail);
+ }
+
+ return AddFilterFunctionImpl(aCoeff1, aList1, aCoeff2, aList2, aResultTail);
+}
+
static nsCSSValueList*
AddTransformLists(double aCoeff1, const nsCSSValueList* aList1,
double aCoeff2, const nsCSSValueList* aList2)
{
nsAutoPtr<nsCSSValueList> result;
nsCSSValueList **resultTail = getter_Transfers(result);
do {
@@ -2055,16 +2232,54 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
}
longShadow = longShadow->mNext;
}
}
aResultValue.SetAndAdoptCSSValueListValue(result.forget(), eUnit_Shadow);
return true;
}
+
+ case eUnit_Filter: {
+ const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
+ const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
+
+ nsAutoPtr<nsCSSValueList> result;
+ nsCSSValueList **resultTail = getter_Transfers(result);
+ while (list1 || list2) {
+ NS_ABORT_IF_FALSE(!*resultTail,
+ "resultTail isn't pointing to the tail (may leak)");
+ if ((list1 && list1->mValue.GetUnit() != eCSSUnit_Function) ||
+ (list2 && list2->mValue.GetUnit() != eCSSUnit_Function)) {
+ // If we don't have filter-functions, we must have filter-URLs, which
+ // we can't add or interpolate.
+ return false;
+ }
+
+ if (!AddFilterFunction(aCoeff1, list1, aCoeff2, list2, resultTail)) {
+ // filter function mismatch
+ return false;
+ }
+
+ // move to next list items
+ if (list1) {
+ list1 = list1->mNext;
+ }
+ if (list2) {
+ list2 = list2->mNext;
+ }
+ };
+ NS_ABORT_IF_FALSE(!*resultTail,
+ "resultTail isn't pointing to the tail (may leak)");
+
+ aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
+ eUnit_Filter);
+ return true;
+ }
+
case eUnit_Transform: {
const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
// We want to avoid the matrix decomposition when we can, since
// avoiding it can produce better results both for compound
// transforms and for skew and skewY (see below). We can do this
// in two cases:
@@ -2427,16 +2642,17 @@ nsStyleAnimation::UncomputeValue(nsCSSPr
}
} break;
case eUnit_CSSRect: {
nsCSSRect& rect = aSpecifiedValue.SetRectValue();
rect = *aComputedValue.GetCSSRectValue();
} break;
case eUnit_Dasharray:
case eUnit_Shadow:
+ case eUnit_Filter:
case eUnit_Transform:
case eUnit_BackgroundPosition:
aSpecifiedValue.
SetDependentListValue(aComputedValue.GetCSSValueListValue());
break;
case eUnit_CSSValuePairList:
aSpecifiedValue.
SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
@@ -2539,22 +2755,37 @@ StyleCoordToValue(const nsStyleCoord& aC
static bool
StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Coord:
nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue);
break;
+ case eStyleUnit_Factor:
+ aCSSValue.SetFloatValue(aCoord.GetFactorValue(), eCSSUnit_Number);
+ break;
case eStyleUnit_Percent:
aCSSValue.SetPercentValue(aCoord.GetPercentValue());
break;
case eStyleUnit_Calc:
SetCalcValue(aCoord.GetCalcValue(), aCSSValue);
break;
+ case eStyleUnit_Degree:
+ aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Degree);
+ break;
+ case eStyleUnit_Grad:
+ aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Grad);
+ break;
+ case eStyleUnit_Radian:
+ aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Radian);
+ break;
+ case eStyleUnit_Turn:
+ aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Turn);
+ break;
default:
NS_ABORT_IF_FALSE(false, "unexpected unit");
return false;
}
return true;
}
/*
@@ -3007,16 +3238,73 @@ nsStyleAnimation::ExtractComputedValue(n
break;
}
}
aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget());
break;
}
+ case eCSSProperty_filter: {
+ const nsStyleSVGReset *svgReset =
+ static_cast<const nsStyleSVGReset*>(styleStruct);
+ const nsTArray<nsStyleFilter>& filters = svgReset->mFilters;
+ nsAutoPtr<nsCSSValueList> result;
+ nsCSSValueList **resultTail = getter_Transfers(result);
+ for (uint32_t i = 0; i < filters.Length(); ++i) {
+ nsCSSValueList *item = new nsCSSValueList;
+ *resultTail = item;
+ resultTail = &item->mNext;
+ const nsStyleFilter& filter = filters[i];
+ int32_t type = filter.GetType();
+ if (type == NS_STYLE_FILTER_URL) {
+ nsIDocument* doc = aStyleContext->PresContext()->Document();
+ nsRefPtr<nsStringBuffer> uriAsStringBuffer =
+ GetURIAsUtf16StringBuffer(filter.GetURL());
+ nsRefPtr<mozilla::css::URLValue> url =
+ new mozilla::css::URLValue(filter.GetURL(),
+ uriAsStringBuffer,
+ doc->GetDocumentURI(),
+ doc->NodePrincipal());
+ item->mValue.SetURLValue(url);
+ } else {
+ nsCSSKeyword functionName =
+ nsCSSProps::ValueToKeywordEnum(type,
+ nsCSSProps::kFilterFunctionKTable);
+ nsCSSValue::Array* filterArray =
+ item->mValue.InitFunction(functionName, 1);
+ if (type >= NS_STYLE_FILTER_BLUR && type <= NS_STYLE_FILTER_HUE_ROTATE) {
+ if (!StyleCoordToCSSValue(
+ filter.GetFilterParameter(),
+ filterArray->Item(1))) {
+ return false;
+ }
+ } else if (type == NS_STYLE_FILTER_DROP_SHADOW) {
+ nsCSSValueList* shadowResult = filterArray->Item(1).SetListValue();
+ nsAutoPtr<nsCSSValueList> tmpShadowValue;
+ nsCSSValueList **tmpShadowResultTail = getter_Transfers(tmpShadowValue);
+ nsCSSShadowArray* shadowArray = filter.GetDropShadow();
+ NS_ABORT_IF_FALSE(shadowArray->Length() == 1,
+ "expected exactly one shadow");
+ AppendCSSShadowValue(shadowArray->ShadowAt(0), tmpShadowResultTail);
+ *shadowResult = *tmpShadowValue;
+ } else {
+ // We checked all possible nsStyleFilter types but
+ // NS_STYLE_FILTER_NULL before. We should never enter this path.
+ NS_NOTREACHED("no other filter functions defined");
+ return false;
+ }
+ }
+ }
+
+ aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
+ eUnit_Filter);
+ break;
+ }
+
case eCSSProperty_transform: {
const nsStyleDisplay *display =
static_cast<const nsStyleDisplay*>(styleStruct);
nsAutoPtr<nsCSSValueList> result;
if (display->mSpecifiedTransform) {
// Clone, and convert all lengths (not percents) to pixels.
nsCSSValueList **resultTail = getter_Transfers(result);
for (const nsCSSValueList *l = display->mSpecifiedTransform;
@@ -3167,40 +3455,17 @@ nsStyleAnimation::ExtractComputedValue(n
StyleDataAtOffset(styleStruct, ssOffset));
if (!shadowArray) {
aComputedValue.SetAndAdoptCSSValueListValue(nullptr, eUnit_Shadow);
return true;
}
nsAutoPtr<nsCSSValueList> result;
nsCSSValueList **resultTail = getter_Transfers(result);
for (uint32_t i = 0, i_end = shadowArray->Length(); i < i_end; ++i) {
- const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i);
- // X, Y, Radius, Spread, Color, Inset
- nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
- nscoordToCSSValue(shadow->mXOffset, arr->Item(0));
- nscoordToCSSValue(shadow->mYOffset, arr->Item(1));
- nscoordToCSSValue(shadow->mRadius, arr->Item(2));
- // NOTE: This code sometimes stores mSpread: 0 even when
- // the parser would be required to leave it null.
- nscoordToCSSValue(shadow->mSpread, arr->Item(3));
- if (shadow->mHasColor) {
- arr->Item(4).SetColorValue(shadow->mColor);
- }
- if (shadow->mInset) {
- arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
- eCSSUnit_Enumerated);
- }
-
- nsCSSValueList *resultItem = new nsCSSValueList;
- if (!resultItem) {
- return false;
- }
- resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
- *resultTail = resultItem;
- resultTail = &resultItem->mNext;
+ AppendCSSShadowValue(shadowArray->ShadowAt(i), resultTail);
}
aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
eUnit_Shadow);
return true;
}
case eStyleAnimType_None:
NS_NOTREACHED("shouldn't use on non-animatable properties");
}
@@ -3294,22 +3559,24 @@ nsStyleAnimation::Value::operator=(const
break;
case eUnit_CSSRect:
NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null");
mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
if (!mValue.mCSSRect) {
mUnit = eUnit_Null;
}
break;
+ case eUnit_Filter:
case eUnit_Dasharray:
case eUnit_Shadow:
case eUnit_Transform:
case eUnit_BackgroundPosition:
- NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || aOther.mValue.mCSSValueList,
- "value lists other than shadows may not be null");
+ NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || mUnit == eUnit_Filter ||
+ aOther.mValue.mCSSValueList,
+ "value lists other than shadows and filters may not be null");
if (aOther.mValue.mCSSValueList) {
mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone();
if (!mValue.mCSSValueList) {
mUnit = eUnit_Null;
}
} else {
mValue.mCSSValueList = nullptr;
}
@@ -3448,18 +3715,19 @@ nsStyleAnimation::Value::SetAndAdoptCSSR
}
void
nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
nsCSSValueList *aValueList, Unit aUnit)
{
FreeValue();
NS_ABORT_IF_FALSE(IsCSSValueListUnit(aUnit), "bad unit");
- NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aValueList != nullptr,
- "dasharrays may not be null");
+ NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aUnit != eUnit_Filter ||
+ aValueList != nullptr,
+ "dasharrays and filters may not be null");
mUnit = aUnit;
mValue.mCSSValueList = aValueList; // take ownership
}
void
nsStyleAnimation::Value::SetAndAdoptCSSValuePairListValue(
nsCSSValuePairList *aValuePairList)
{
@@ -3518,16 +3786,17 @@ nsStyleAnimation::Value::operator==(cons
return *mValue.mCSSValue == *aOther.mValue.mCSSValue;
case eUnit_CSSValuePair:
return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
case eUnit_CSSValueTriplet:
return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet;
case eUnit_CSSRect:
return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
case eUnit_Dasharray:
+ case eUnit_Filter:
case eUnit_Shadow:
case eUnit_Transform:
case eUnit_BackgroundPosition:
return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList;
case eUnit_CSSValuePairList:
return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList;
case eUnit_UnparsedString:
return (NS_strcmp(GetStringBufferValue(),
--- a/layout/style/nsStyleAnimation.h
+++ b/layout/style/nsStyleAnimation.h
@@ -216,16 +216,17 @@ public:
eUnit_Float,
eUnit_Color,
eUnit_Calc, // nsCSSValue* (never null), always with a single
// calc() expression that's either length or length+percent
eUnit_CSSValuePair, // nsCSSValuePair* (never null)
eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
eUnit_CSSRect, // nsCSSRect* (never null)
eUnit_Dasharray, // nsCSSValueList* (never null)
+ eUnit_Filter, // nsCSSValueList* (may be null)
eUnit_Shadow, // nsCSSValueList* (may be null)
eUnit_Transform, // nsCSSValueList* (never null)
eUnit_BackgroundPosition, // nsCSSValueList* (never null)
eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
eUnit_UnparsedString // nsStringBuffer* (never null)
};
class Value {
@@ -375,18 +376,19 @@ public:
}
static bool IsCSSValueTripletUnit(Unit aUnit) {
return aUnit == eUnit_CSSValueTriplet;
}
static bool IsCSSRectUnit(Unit aUnit) {
return aUnit == eUnit_CSSRect;
}
static bool IsCSSValueListUnit(Unit aUnit) {
- return aUnit == eUnit_Dasharray || aUnit == eUnit_Shadow ||
- aUnit == eUnit_Transform || aUnit == eUnit_BackgroundPosition;
+ return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter ||
+ aUnit == eUnit_Shadow || aUnit == eUnit_Transform ||
+ aUnit == eUnit_BackgroundPosition;
}
static bool IsCSSValuePairListUnit(Unit aUnit) {
return aUnit == eUnit_CSSValuePairList;
}
static bool IsStringUnit(Unit aUnit) {
return aUnit == eUnit_UnparsedString;
}
};
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -117,16 +117,17 @@ var supported_properties = {
test_length_unclamped, test_percent_unclamped ],
"clip": [ test_rect_transition ],
"color": [ test_color_transition ],
"fill": [ test_color_transition ],
"fill-opacity" : [ test_float_zeroToOne_transition,
// opacity is clamped in computed style
// (not parsing/interpolation)
test_float_zeroToOne_clamped ],
+ "filter" : [ test_filter_transition ],
"flood-color": [ test_color_transition ],
"flood-opacity" : [ test_float_zeroToOne_transition,
// opacity is clamped in computed style
// (not parsing/interpolation)
test_float_zeroToOne_clamped ],
"font-size": [ test_length_transition, test_percent_transition,
test_length_percent_calc_transition,
test_length_clamped, test_percent_clamped ],
@@ -571,16 +572,166 @@ var transformTests = [
end: 'skewX(-45deg) rotate(90deg)',
expected_uncomputed: 'skewX(22.5deg) rotate(90deg)' },
{ start: 'skewX(-60deg) rotate(90deg) translate(0)',
end: 'skewX(60deg) rotate(90deg)',
expected: computeMatrix('rotate(120deg) skewX(' + Math.atan(Math.tan(Math.PI * 60/180) / 2) + 'rad) scale(2, 0.5)'),
round_error_ok: true },
];
+var filterTests = [
+ { start: "none", end: "none",
+ expected: ["none"] },
+ // function from none (number/length)
+ { start: "none", end: "brightness(0.5)",
+ expected: ["brightness", 0.875] },
+ { start: "none", end: "contrast(0.5)",
+ expected: ["contrast", 0.875] },
+ { start: "none", end: "grayscale(0.5)",
+ expected: ["grayscale", 0.125] },
+ { start: "none", end: "invert(0.5)",
+ expected: ["invert", 0.125] },
+ { start: "none", end: "opacity(0.5)",
+ expected: ["opacity", 0.875] },
+ { start: "none", end: "saturate(0.5)",
+ expected: ["saturate", 0.875] },
+ { start: "none", end: "sepia(0.5)",
+ expected: ["sepia", 0.125] },
+ { start: "none", end: "blur(50px)",
+ expected: ["blur", 12.5] },
+ // function to none (number/length)
+ { start: "brightness(0.5)", end: "none",
+ expected: ["brightness", 0.625] },
+ { start: "contrast(0.5)", end: "none",
+ expected: ["contrast", 0.625] },
+ { start: "grayscale(0.5)", end: "none",
+ expected: ["grayscale", 0.375] },
+ { start: "invert(0.5)", end: "none",
+ expected: ["invert", 0.375] },
+ { start: "opacity(0.5)", end: "none",
+ expected: ["opacity", 0.625] },
+ { start: "saturate(0.5)", end: "none",
+ expected: ["saturate", 0.625] },
+ { start: "sepia(0.5)", end: "none",
+ expected: ["sepia", 0.375] },
+ { start: "blur(50px)", end: "none",
+ expected: ["blur", 37.5] },
+ // function to same function (number/length)
+ { start: "brightness(0.25)", end: "brightness(0.75)",
+ expected: ["brightness", 0.375] },
+ { start: "contrast(0.25)", end: "contrast(0.75)",
+ expected: ["contrast", 0.375] },
+ { start: "grayscale(0.25)", end: "grayscale(0.75)",
+ expected: ["grayscale", 0.375] },
+ { start: "invert(0.25)", end: "invert(0.75)",
+ expected: ["invert", 0.375] },
+ { start: "opacity(0.25)", end: "opacity(0.75)",
+ expected: ["opacity", 0.375] },
+ { start: "saturate(0.25)", end: "saturate(0.75)",
+ expected: ["saturate", 0.375] },
+ { start: "sepia(0.25)", end: "sepia(0.75)",
+ expected: ["sepia", 0.375] },
+ { start: "blur(25px)", end: "blur(75px)",
+ expected: ["blur", 37.5] },
+ // function to same function (percent)
+ { start: "brightness(25%)", end: "brightness(75%)",
+ expected: ["brightness", 0.375] },
+ { start: "contrast(25%)", end: "contrast(75%)",
+ expected: ["contrast", 0.375] },
+ { start: "grayscale(25%)", end: "grayscale(75%)",
+ expected: ["grayscale", 0.375] },
+ { start: "invert(25%)", end: "invert(75%)",
+ expected: ["invert", 0.375] },
+ { start: "opacity(25%)", end: "opacity(75%)",
+ expected: ["opacity", 0.375] },
+ { start: "saturate(25%)", end: "saturate(75%)",
+ expected: ["saturate", 0.375] },
+ { start: "sepia(25%)", end: "sepia(75%)",
+ expected: ["sepia", 0.375] },
+ // function to same function (percent, number/length)
+ { start: "brightness(0.25)", end: "brightness(75%)",
+ expected: ["brightness", 0.375] },
+ { start: "contrast(25%)", end: "contrast(0.75)",
+ expected: ["contrast", 0.375] },
+ // hue-rotate with different angle values
+ { start: "hue-rotate(0deg)", end: "hue-rotate(720deg)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0rad)", end: "hue-rotate("+4*Math.PI+"rad)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0grad)", end: "hue-rotate(800grad)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0turn)", end: "hue-rotate(2turn)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0deg)", end: "hue-rotate("+4*Math.PI+"rad)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0turn)", end: "hue-rotate(800grad)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0grad)", end: "hue-rotate("+4*Math.PI+"rad)",
+ expected: ["hue-rotate", Math.PI.toFixed(5)] },
+ { start: "hue-rotate(0grad)", end: "hue-rotate(0turn)",
+ expected: ["hue-rotate", 0] },
+ // multiple matching functions, same length
+ { start: "contrast(25%) brightness(0.25) blur(25px) sepia(75%)",
+ end: "contrast(75%) brightness(0.75) blur(75px) sepia(25%)",
+ expected: ["contrast", 0.375, "brightness", 0.375, "blur", 37.5, "sepia", 0.625] },
+ { start: "invert(25%) brightness(0.25) blur(25px) invert(50%) brightness(0.5) blur(50px)",
+ end: "invert(75%) brightness(0.75) blur(75px)",
+ expected: ["invert", 0.375, "brightness", 0.375, "blur", 37.5, "invert", 0.375, "brightness", 0.625, "blur", 37.5] },
+ // multiple matching functions, different length
+ { start: "contrast(25%) brightness(0.5) blur(50px)",
+ end: "contrast(75%)",
+ expected: ["contrast", 0.375, "brightness", 0.625, "blur", 37.5] },
+ // mismatching filter functions
+ { start: "contrast(0%)", end: "blur(10px)",
+ expected: ["blur", 10] },
+ // not supported interpolations
+ { start: "none", end: "url('#b')",
+ expected: ["url", "\""+document.URL+"#b\""] },
+ { start: "url('#a')", end: "none",
+ expected: ["none"] },
+ { start: "url('#a')", end: "url('#b')",
+ expected: ["url", "\""+document.URL+"#b\""] },
+ { start: "url('#a')", end: "blur(10px)",
+ expected: ["blur", 10] },
+ { start: "blur(10px)", end: "url('#a')",
+ expected: ["url", "\""+document.URL+"#a\""] },
+ { start: "blur(0px) url('#a')", end: "blur(20px)",
+ expected: ["blur", 20] },
+ { start: "blur(0px)", end: "blur(20px) url('#a')",
+ expected: ["blur", 20, "url", "\""+document.URL+"#a\""] },
+ { start: "contrast(0.25) brightness(0.25) blur(25px)",
+ end: "contrast(0.75) url('#a')",
+ expected: ["contrast", 0.75, "url", "\""+document.URL+"#a\""] },
+ { start: "contrast(0.25) brightness(0.25) blur(75px)",
+ end: "brightness(0.75) contrast(0.75) blur(25px)",
+ expected: ["brightness", 0.75, "contrast", 0.75, "blur", 25] },
+ { start: "contrast(0.25) brightness(0.25) blur(25px)",
+ end: "contrast(0.75) brightness(0.75) contrast(0.75)",
+ expected: ["contrast", 0.75, "brightness", 0.75, "contrast", 0.75] },
+ // drop-shadow animation
+ { start: "none",
+ end: "drop-shadow(rgb(0, 0, 0) 4px 4px 0px)",
+ expected: ["drop-shadow", "rgba(0, 0, 0, 0.25) 1px 1px 0px"] },
+ { start: "drop-shadow(rgb(0, 0, 0) 0px 0px 0px)",
+ end: "drop-shadow(rgb(0, 0, 0) 4px 4px 0px)",
+ expected: ["drop-shadow", "rgb(0, 0, 0) 1px 1px 0px"] },
+ { start: "drop-shadow(#038000 4px 4px)",
+ end: "drop-shadow(8px 8px 8px red)",
+ expected: ["drop-shadow", "rgb(66, 96, 0) 5px 5px 2px"] },
+ { start: "blur(25px) drop-shadow(8px 8px)",
+ end: "blur(75px)",
+ expected: ["blur", 37.5, "drop-shadow", "rgb(0, 0, 0) 6px 6px 0px"] },
+ { start: "blur(75px)",
+ end: "blur(25px) drop-shadow(8px 8px)",
+ expected: ["blur", 62.5, "drop-shadow", "rgb(0, 0, 0) 2px 2px 0px"] },
+ { start: "drop-shadow(2px 2px blue)",
+ end: "none",
+ expected: ["drop-shadow", "rgba(0, 0, 255, 0.75) 1.5px 1.5px 0px"] },
+];
+
var prop;
for (prop in supported_properties) {
// Test that prop is in the property database.
ok(prop in gCSSProperties, "property " + prop + " in gCSSProperties");
// Test that the entry has at least one test function.
ok(supported_properties[prop].length > 0,
"property " + prop + " must have at least one test function");
@@ -990,16 +1141,98 @@ function test_border_color_transition(pr
is(cs.getPropertyValue(prop), "rgb(96, 48, 32)",
"color-valued property " + prop + ": interpolation of initial value");
check_distance(prop, "rgb(128, 64, 0)", "rgb(96, 48, 32)", "initial");
div.style.removeProperty("color");
}
+function filter_function_list_equals(computedValStr, expectedList)
+{
+ // Check simple case "none"
+ if (computedValStr == "none" && computedValStr == expectedList[0]) {
+ return true;
+ }
+
+ // The regular expression does not filter out the last parenthesis.
+ // Remove last character for now.
+ is(computedValStr.substring(computedValStr.length - 1, computedValStr.length),
+ ')', "Check if last character is close-paren");
+ computedValStr = computedValStr.substring(0, computedValStr.length - 1);
+
+ var reg = /\)*\s*(blur|brightness|contrast|grayscale|hue\-rotate|invert|opacity|saturate|sepia|drop\-shadow|url)\(/
+ var matches = computedValStr.split(reg);
+ // First item must be empty. All other items are of functionName, functionValue.
+ if (!matches || matches.shift() != "") {
+ ok(false, "computed style of 'filter' isn't in the format we expect");
+ return false;
+ }
+
+ // Odd items are the function name, even items the function value.
+ if (!matches.length || matches.length % 2 ||
+ expectedList.length != matches.length) {
+ ok(false, "computed style of 'filter' isn't in the format we expect");
+ return false;
+ }
+ for (var i = 0; i < matches.length; i += 2) {
+ var functionName = matches[i];
+ var functionValue = matches[i+1];
+ var expected = expectedList[i+1]
+ var tolerance = 0;
+ // Check if we have the expected function.
+ if (functionName != expectedList[i]) {
+ return false;
+ }
+ if (functionName == "blur") {
+ // Last two characters must be "px".
+ if (functionValue.search("px") != functionValue.length - 2) {
+ return false;
+ }
+ functionValue = functionValue.substring(0, functionValue.length - 2);
+ } else if (functionName == "hue-rotate") {
+ // Last two characters must be "rad".
+ if (functionValue.search("rad") != functionValue.length - 3) {
+ return false;
+ }
+ tolerance = 0.001;
+ functionValue = functionValue.substring(0, functionValue.length - 3);
+ } else if (functionName == "drop-shadow" || functionName == "url") {
+ if (functionValue != expected) {
+ return false;
+ }
+ continue;
+ }
+ // Check if string is not a number or difference is not in tolerance level.
+ if (isNaN(functionValue) ||
+ Math.abs(parseFloat(functionValue) - expected) > tolerance) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function test_filter_transition(prop) {
+ if (!SpecialPowers.getBoolPref("layout.css.filters.enabled")) {
+ return;
+ }
+ for (var i in filterTests) {
+ var test = filterTests[i];
+ div.style.setProperty("transition-property", "none", "");
+ div.style.setProperty(prop, test.start, "");
+ cs.getPropertyValue(prop);
+ div.style.setProperty("transition-property", prop, "");
+ div.style.setProperty(prop, test.end, "");
+ var actual = cs.getPropertyValue(prop);
+ ok(filter_function_list_equals(actual, test.expected),
+ "Filter property is " + actual + " expected values of " +
+ test.expected);
+ }
+}
+
function test_shadow_transition(prop) {
var spreadStr = (prop == "box-shadow") ? " 0px" : "";
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "none", "");
is(cs.getPropertyValue(prop), "none",
"shadow-valued property " + prop + ": computed value before transition");
div.style.setProperty("transition-property", prop, "");
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -5415,19 +5415,16 @@ nsSVGTextFrame2::SetupCairoStroke(gfxCon
SVGTextObjectPaint* aThisObjectPaint)
{
const nsStyleSVG *style = aFrame->StyleSVG();
if (style->mStroke.mType == eStyleSVGPaintType_None) {
aThisObjectPaint->SetStrokeOpacity(0.0f);
return false;
}
- gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
- aContext->IdentityMatrix();
-
nsSVGUtils::SetupCairoStrokeGeometry(aFrame, aContext, aOuterObjectPaint);
float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource,
style->mStrokeOpacity,
aOuterObjectPaint);
SetupInheritablePaint(aContext, aFrame, opacity, aOuterObjectPaint,
aThisObjectPaint->mStrokePaint, &nsStyleSVG::mStroke,
nsSVGEffects::StrokeProperty());
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -55,16 +55,17 @@ static char *RCSSTRING __UNUSED__="$Id:
#include "stun_client_ctx.h"
#include "stun_server_ctx.h"
#include "turn_client_ctx.h"
#include "ice_ctx.h"
#include "ice_candidate.h"
#include "ice_reg.h"
#include "ice_util.h"
#include "nr_socket_turn.h"
+#include "nr_socket.h"
static int next_automatic_preference = 224;
static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
#ifdef USE_TURN
@@ -377,18 +378,22 @@ int nr_ice_candidate_compute_priority(nr
}
else {
ABORT(r);
}
}
}
else {
char key_of_interface[MAXIFNAME + 41];
+ nr_transport_addr addr;
- if(r=nr_transport_addr_fmt_ifname_addr_string(&cand->base,key_of_interface,
+ if(r=nr_socket_getaddr(cand->isock->sock, &addr))
+ ABORT(r);
+
+ if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
sizeof(key_of_interface))) {
ABORT(r);
}
if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
key_of_interface,&interface_preference)) {
ABORT(r);
}
}
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -582,16 +582,17 @@
'./src/sipcc/include/ccapi_device_listener.h',
'./src/sipcc/include/ccapi_feature_info.h',
'./src/sipcc/include/ccapi_line.h',
'./src/sipcc/include/ccapi_line_info.h',
'./src/sipcc/include/ccapi_line_listener.h',
'./src/sipcc/include/ccapi_service.h',
'./src/sipcc/include/ccapi_types.h',
'./src/sipcc/include/ccsdp.h',
+ './src/sipcc/include/ccsdp_rtcp_fb.h',
'./src/sipcc/include/config_api.h',
'./src/sipcc/include/dns_util.h',
'./src/sipcc/include/plat_api.h',
'./src/sipcc/include/reset_api.h',
'./src/sipcc/include/sll_lite.h',
'./src/sipcc/include/vcm.h',
'./src/sipcc/include/xml_parser_defines.h',
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -2,17 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CODEC_CONFIG_H_
#define CODEC_CONFIG_H_
#include <string>
-
+#include "ccsdp_rtcp_fb.h"
namespace mozilla {
/**
* Minimalistic Audio Codec Config Params
*/
struct AudioCodecConfig
{
@@ -51,21 +51,37 @@ struct AudioCodecConfig
struct VideoCodecConfig
{
/*
* The data-types for these properties mimic the
* corresponding webrtc::VideoCodec data-types.
*/
int mType;
std::string mName;
+ uint32_t mRtcpFbTypes;
- /* When we have resolution negotiation information (RFC 6236)
- * it will be stored here.
- */
+ VideoCodecConfig(int type,
+ std::string name,
+ int rtcpFbTypes): mType(type),
+ mName(name),
+ mRtcpFbTypes(rtcpFbTypes)
+ {
+ }
+
- VideoCodecConfig(int type, std::string name): mType(type),
- mName(name)
+ bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
+ {
+ return mRtcpFbTypes & sdp_rtcp_fb_nack_to_bitmap(type);
+ }
+
+ bool RtcpFbIsSet(sdp_rtcp_fb_ack_type_e type) const
{
+ return mRtcpFbTypes & sdp_rtcp_fb_ack_to_bitmap(type);
+ }
+
+ bool RtcpFbIsSet(sdp_rtcp_fb_ccm_type_e type) const
+ {
+ return mRtcpFbTypes & sdp_rtcp_fb_ccm_to_bitmap(type);
}
};
}
#endif
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -1,15 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CSFLog.h"
#include "nspr.h"
+// For rtcp-fb constants
+#include "ccsdp.h"
+
#include "VideoConduit.h"
#include "AudioConduit.h"
#include "webrtc/video_engine/include/vie_errors.h"
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidJNIWrapper.h"
#endif
@@ -240,32 +243,16 @@ MediaConduitErrorCode WebrtcVideoConduit
}
// Turn on RTCP and loss feedback reporting.
if(mPtrRTP->SetRTCPStatus(mChannel, webrtc::kRtcpCompound_RFC4585) != 0)
{
CSFLogError(logTag, "%s RTCPStatus Failed %d ", __FUNCTION__,
mPtrViEBase->LastError());
return kMediaConduitRTCPStatusError;
}
- // Enable pli as key frame request method.
- if(mPtrRTP->SetKeyFrameRequestMethod(mChannel,
- webrtc::kViEKeyFrameRequestPliRtcp) != 0)
- {
- CSFLogError(logTag, "%s KeyFrameRequest Failed %d ", __FUNCTION__,
- mPtrViEBase->LastError());
- return kMediaConduitKeyFrameRequestError;
- }
- // Enable lossless transport
- // XXX Note: We may want to disable this or limit it
- if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
- {
- CSFLogError(logTag, "%s NACKStatus Failed %d ", __FUNCTION__,
- mPtrViEBase->LastError());
- return kMediaConduitNACKStatusError;
- }
CSFLogError(logTag, "%s Initialization Done", __FUNCTION__);
return kMediaConduitNoError;
}
void
WebrtcVideoConduit::SyncTo(WebrtcAudioConduit *aConduit)
{
CSFLogDebug(logTag, "%s Synced to %p", __FUNCTION__, aConduit);
@@ -413,28 +400,37 @@ WebrtcVideoConduit::ConfigureSendMediaCo
}
CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
mPtrViEBase->LastError());
return kMediaConduitUnknownError;
}
mSendingWidth = 0;
mSendingHeight = 0;
+ if(codecConfig->RtcpFbIsSet(SDP_RTCP_FB_NACK_BASIC)) {
+ CSFLogDebug(logTag, "Enabling NACK (send) for video stream\n");
+ if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
+ {
+ CSFLogError(logTag, "%s NACKStatus Failed %d ", __FUNCTION__,
+ mPtrViEBase->LastError());
+ return kMediaConduitNACKStatusError;
+ }
+ }
+
if(mPtrViEBase->StartSend(mChannel) == -1)
{
CSFLogError(logTag, "%s Start Send Error %d ", __FUNCTION__,
mPtrViEBase->LastError());
return kMediaConduitUnknownError;
}
//Copy the applied codec for future reference
delete mCurSendCodecConfig;
- mCurSendCodecConfig = new VideoCodecConfig(codecConfig->mType,
- codecConfig->mName);
+ mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
mPtrRTP->SetRembStatus(mChannel, true, false);
// by now we should be successfully started the transmission
mEngineTransmitting = true;
return kMediaConduitNoError;
}
@@ -467,28 +463,49 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
}
if(codecConfigList.empty())
{
CSFLogError(logTag, "%s Zero number of codecs to configure", __FUNCTION__);
return kMediaConduitMalformedArgument;
}
+ webrtc::ViEKeyFrameRequestMethod kf_request = webrtc::kViEKeyFrameRequestNone;
+ bool use_nack_basic = false;
+
//Try Applying the codecs in the list
// we treat as success if atleast one codec was applied and reception was
// started successfully.
for(std::vector<VideoCodecConfig*>::size_type i=0;i < codecConfigList.size();i++)
{
//if the codec param is invalid or diplicate, return error
if((condError = ValidateCodecConfig(codecConfigList[i],false)) != kMediaConduitNoError)
{
return condError;
}
+ // Check for the keyframe request type: PLI is preferred
+ // over FIR, and FIR is preferred over none.
+ if (codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_NACK_PLI))
+ {
+ kf_request = webrtc::kViEKeyFrameRequestPliRtcp;
+ } else if(kf_request == webrtc::kViEKeyFrameRequestNone &&
+ codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_CCM_FIR))
+ {
+ kf_request = webrtc::kViEKeyFrameRequestFirRtcp;
+ }
+
+ // Check whether NACK is requested
+ if(codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_NACK_BASIC))
+ {
+ use_nack_basic = true;
+ }
+
webrtc::VideoCodec video_codec;
+
mEngineReceiving = false;
memset(&video_codec, 0, sizeof(webrtc::VideoCodec));
//Retrieve pre-populated codec structure for our codec.
for(int idx=0; idx < mPtrViECodec->NumberOfCodecs(); idx++)
{
if(mPtrViECodec->GetCodec(idx, video_codec) == 0)
{
payloadName = video_codec.plName;
@@ -518,16 +535,61 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
}//end for
if(!success)
{
CSFLogError(logTag, "%s Setting Receive Codec Failed ", __FUNCTION__);
return kMediaConduitInvalidReceiveCodec;
}
+ // XXX Currently, we gather up all of the feedback types that the remote
+ // party indicated it supports for all video codecs and configure the entire
+ // conduit based on those capabilities. This is technically out of spec,
+ // as these values should be configured on a per-codec basis. However,
+ // the video engine only provides this API on a per-conduit basis, so that's
+ // how we have to do it. The approach of considering the remote capablities
+ // for the entire conduit to be a union of all remote codec capabilities
+ // (rather than the more conservative approach of using an intersection)
+ // is made to provide as many feedback mechanisms as are likely to be
+ // processed by the remote party (and should be relatively safe, since the
+ // remote party is required to ignore feedback types that it does not
+ // understand).
+ //
+ // Note that our configuration uses this union of remote capabilites as
+ // input to the configuration. It is not isomorphic to the configuration.
+ // For example, it only makes sense to have one frame request mechanism
+ // active at a time; so, if the remote party indicates more than one
+ // supported mechanism, we're only configuring the one we most prefer.
+ //
+ // See http://code.google.com/p/webrtc/issues/detail?id=2331
+
+ if (kf_request != webrtc::kViEKeyFrameRequestNone)
+ {
+ CSFLogDebug(logTag, "Enabling %s frame requests for video stream\n",
+ (kf_request == webrtc::kViEKeyFrameRequestPliRtcp ?
+ "PLI" : "FIR"));
+ if(mPtrRTP->SetKeyFrameRequestMethod(mChannel, kf_request) != 0)
+ {
+ CSFLogError(logTag, "%s KeyFrameRequest Failed %d ", __FUNCTION__,
+ mPtrViEBase->LastError());
+ return kMediaConduitKeyFrameRequestError;
+ }
+ }
+
+ if(use_nack_basic)
+ {
+ CSFLogDebug(logTag, "Enabling NACK (recv) for video stream\n");
+ if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
+ {
+ CSFLogError(logTag, "%s NACKStatus Failed %d ", __FUNCTION__,
+ mPtrViEBase->LastError());
+ return kMediaConduitNACKStatusError;
+ }
+ }
+
//Start Receive on the video engine
if(mPtrViEBase->StartReceive(mChannel) == -1)
{
error = mPtrViEBase->LastError();
CSFLogError(logTag, "%s Start Receive Error %d ", __FUNCTION__, error);
return kMediaConduitUnknownError;
}
@@ -784,18 +846,17 @@ WebrtcVideoConduit::CodecConfigToWebRTCC
cinst.minBitrate = 200;
cinst.startBitrate = 300;
cinst.maxBitrate = 2000;
}
bool
WebrtcVideoConduit::CopyCodecToDB(const VideoCodecConfig* codecInfo)
{
- VideoCodecConfig* cdcConfig = new VideoCodecConfig(codecInfo->mType,
- codecInfo->mName);
+ VideoCodecConfig* cdcConfig = new VideoCodecConfig(*codecInfo);
mRecvCodecList.push_back(cdcConfig);
return true;
}
/**
* Checks if the codec is already in Conduit's database
*/
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -1481,17 +1481,18 @@ static int vcmRxStartICE_m(cc_mcapid_t m
return VCM_ERROR;
mozilla::VideoCodecConfig *config_raw;
for(int i=0; i <num_payloads; i++)
{
config_raw = new mozilla::VideoCodecConfig(
payloads[i].remote_rtp_pt,
- ccsdpCodecName(payloads[i].codec_type));
+ ccsdpCodecName(payloads[i].codec_type),
+ payloads[i].video.rtcp_fb_types);
configs.push_back(config_raw);
}
if (conduit->ConfigureRecvMediaCodecs(configs))
return VCM_ERROR;
// Now we have all the pieces, create the pipeline
mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
@@ -2112,17 +2113,18 @@ static int vcmTxStartICE_m(cc_mcapid_t m
// Now we have all the pieces, create the pipeline
stream->StorePipeline(pc_track_id, pipeline);
} else if (CC_IS_VIDEO(mcap_id)) {
mozilla::VideoCodecConfig *config_raw;
config_raw = new mozilla::VideoCodecConfig(
payload->remote_rtp_pt,
- ccsdpCodecName(payload->codec_type));
+ ccsdpCodecName(payload->codec_type),
+ payload->video.rtcp_fb_types);
// Take possession of this pointer
mozilla::ScopedDeletePtr<mozilla::VideoCodecConfig> config(config_raw);
// Instantiate an appropriate conduit
mozilla::RefPtr<mozilla::VideoSessionConduit> conduit =
mozilla::VideoSessionConduit::Create();
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -4537,31 +4537,31 @@ gsmsdp_add_rtcp_fb (int level, sdp_t *sd
for (pt_index = 1; pt_index <= num_pts; pt_index++) {
pt_codec = sdp_get_media_payload_type (sdp_p, level, pt_index,
&indicator);
if ((pt_codec & 0xFF) == codec) {
int pt = GET_DYN_PAYLOAD_TYPE_VALUE(pt_codec);
/* Add requested a=rtcp-fb:nack attributes */
for (j = 0; j < SDP_MAX_RTCP_FB_NACK; j++) {
- if (types & SDP_RTCP_FB_NACK_TO_BITMAP(j)) {
+ if (types & sdp_rtcp_fb_nack_to_bitmap(j)) {
gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
}
}
/* Add requested a=rtcp-fb:ack attributes */
for (j = 0; j < SDP_MAX_RTCP_FB_ACK; j++) {
- if (types & SDP_RTCP_FB_ACK_TO_BITMAP(j)) {
+ if (types & sdp_rtcp_fb_ack_to_bitmap(j)) {
gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
}
}
/* Add requested a=rtcp-fb:ccm attributes */
for (j = 0; j < SDP_MAX_RTCP_FB_CCM; j++) {
- if (types & SDP_RTCP_FB_CCM_TO_BITMAP(j)) {
+ if (types & sdp_rtcp_fb_ccm_to_bitmap(j)) {
gsmsdp_set_rtcp_fb_ccm_attribute(level, sdp_p, pt, j);
}
}
}
}
return CC_CAUSE_OK;
}
@@ -4621,52 +4621,52 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_s
fb_types = 0;
/* a=rtcp-fb:nack */
i = 1;
do {
nack_type = sdp_attr_get_rtcp_fb_nack(cc_sdp_p->dest_sdp,
level, remote_pt, i);
if (nack_type >= 0 && nack_type < SDP_MAX_RTCP_FB_NACK) {
- fb_types |= SDP_RTCP_FB_NACK_TO_BITMAP(nack_type);
+ fb_types |= sdp_rtcp_fb_nack_to_bitmap(nack_type);
}
i++;
} while (nack_type != SDP_RTCP_FB_NACK_NOT_FOUND);
/* a=rtcp-fb:ack */
i = 1;
do {
ack_type = sdp_attr_get_rtcp_fb_ack(cc_sdp_p->dest_sdp,
level, remote_pt, i);
if (ack_type >= 0 && ack_type < SDP_MAX_RTCP_FB_ACK) {
- fb_types |= SDP_RTCP_FB_ACK_TO_BITMAP(ack_type);
+ fb_types |= sdp_rtcp_fb_ack_to_bitmap(ack_type);
}
i++;
} while (ack_type != SDP_RTCP_FB_ACK_NOT_FOUND);
/* a=rtcp-fb:ccm */
i = 1;
do {
ccm_type = sdp_attr_get_rtcp_fb_ccm(cc_sdp_p->dest_sdp,
level, remote_pt, i);
if (ccm_type >= 0 && ccm_type < SDP_MAX_RTCP_FB_CCM) {
- fb_types |= SDP_RTCP_FB_CCM_TO_BITMAP(ccm_type);
+ fb_types |= sdp_rtcp_fb_ccm_to_bitmap(ccm_type);
}
i++;
} while (ccm_type != SDP_RTCP_FB_CCM_NOT_FOUND);
/*
* Mask out the types that we do not support
*/
switch (codec) {
case RTP_VP8:
fb_types &=
- SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
- SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
- SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR);
+ sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) |
+ sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
+ sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR);
break;
default:
fb_types = 0;
}
/*
* Now, in our local SDP, set rtcp-fb types that both we and the
* remote party support
@@ -5584,19 +5584,19 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
if (media->support_direction != SDP_DIRECTION_INACTIVE) {
gsmsdp_set_local_sdp_direction(dcb_p, media, media->direction);
/* Add supported rtcp-fb types */
if (media_cap->type == SDP_MEDIA_VIDEO) {
gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_VP8,
- SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
- SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
- SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR));
+ sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) |
+ sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
+ sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR));
}
/* setup and connection attributes */
gsmsdp_set_setup_attribute(level, dcb_p->sdp->src_sdp, media->setup);
/* This is a new media line so we should send connection:new */
gsmsdp_set_connection_attribute(level, dcb_p->sdp->src_sdp,
SDP_CONNECTION_NEW);
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -469,74 +469,24 @@ typedef enum {
typedef enum {
SDP_RTCP_UNICAST_MODE_REFLECTION,
SDP_RTCP_UNICAST_MODE_RSI,
SDP_RTCP_MAX_UNICAST_MODE,
SDP_RTCP_UNICAST_MODE_NOT_PRESENT
} sdp_rtcp_unicast_mode_e;
-/* a=rtcp-fb enumerations */
-
-typedef enum {
- SDP_RTCP_FB_ANY = -1,
- SDP_RTCP_FB_ACK = 0,
- SDP_RTCP_FB_CCM,
- SDP_RTCP_FB_NACK,
- SDP_RTCP_FB_TRR_INT,
- SDP_MAX_RTCP_FB,
- SDP_RTCP_FB_UNKNOWN
-} sdp_rtcp_fb_type_e;
-
-typedef enum {
- SDP_RTCP_FB_NACK_NOT_FOUND = -1,
- SDP_RTCP_FB_NACK_BASIC = 0,
- SDP_RTCP_FB_NACK_SLI,
- SDP_RTCP_FB_NACK_PLI,
- SDP_RTCP_FB_NACK_RPSI,
- SDP_RTCP_FB_NACK_APP,
- SDP_RTCP_FB_NACK_RAI,
- SDP_RTCP_FB_NACK_TLLEI,
- SDP_RTCP_FB_NACK_PSLEI,
- SDP_RTCP_FB_NACK_ECN,
- SDP_MAX_RTCP_FB_NACK,
- SDP_RTCP_FB_NACK_UNKNOWN
-} sdp_rtcp_fb_nack_type_e;
-
-typedef enum {
- SDP_RTCP_FB_ACK_NOT_FOUND = -1,
- SDP_RTCP_FB_ACK_RPSI = 0,
- SDP_RTCP_FB_ACK_APP,
- SDP_MAX_RTCP_FB_ACK,
- SDP_RTCP_FB_ACK_UNKNOWN
-} sdp_rtcp_fb_ack_type_e;
-
-typedef enum {
- SDP_RTCP_FB_CCM_NOT_FOUND = -1,
- SDP_RTCP_FB_CCM_FIR = 0,
- SDP_RTCP_FB_CCM_TMMBR,
- SDP_RTCP_FB_CCM_TSTR,
- SDP_RTCP_FB_CCM_VBCM,
- SDP_MAX_RTCP_FB_CCM,
- SDP_RTCP_FB_CCM_UNKNOWN
-} sdp_rtcp_fb_ccm_type_e;
-
typedef enum {
SDP_CONNECTION_NOT_FOUND = -1,
SDP_CONNECTION_NEW = 0,
SDP_CONNECTION_EXISTING,
SDP_MAX_CONNECTION,
SDP_CONNECTION_UNKNOWN
} sdp_connection_type_e;
-#define SDP_RTCP_FB_NACK_TO_BITMAP(type) (1 << (type))
-#define SDP_RTCP_FB_ACK_TO_BITMAP(type) (1 << (SDP_MAX_RTCP_FB_NACK + (type)))
-#define SDP_RTCP_FB_CCM_TO_BITMAP(type) (1 << (SDP_MAX_RTCP_FB_NACK + \
- SDP_MAX_RTCP_FB_ACK + (type)))
-
/*
* sdp_srtp_fec_order_t
* This type defines the order in which to perform FEC
* (Forward Error Correction) and SRTP Encryption/Authentication.
*/
typedef enum sdp_srtp_fec_order_t_ {
SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */
SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */
--- a/media/webrtc/signaling/src/sipcc/include/ccsdp.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp.h
@@ -42,16 +42,17 @@
* attribute is specified for.
* </pre>
*/
#ifndef __CCSDP_H__
#define __CCSDP_H__
#include "cpr_types.h"
+#include "ccsdp_rtcp_fb.h"
#define SIPSDP_ILBC_MODE20 20
/**
* Return codes for sdp helper APIs
*/
typedef enum rtp_ptype_
{
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp_rtcp_fb.h
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __CCSDP_RTCP_FB_H__
+#define __CCSDP_RTCP_FB_H__
+
+/* a=rtcp-fb enumerations */
+
+typedef enum {
+ SDP_RTCP_FB_ANY = -1,
+ SDP_RTCP_FB_ACK = 0,
+ SDP_RTCP_FB_CCM,
+ SDP_RTCP_FB_NACK,
+ SDP_RTCP_FB_TRR_INT,
+ SDP_MAX_RTCP_FB,
+ SDP_RTCP_FB_UNKNOWN
+} sdp_rtcp_fb_type_e;
+
+typedef enum {
+ SDP_RTCP_FB_NACK_NOT_FOUND = -1,
+ SDP_RTCP_FB_NACK_BASIC = 0,
+ SDP_RTCP_FB_NACK_SLI,
+ SDP_RTCP_FB_NACK_PLI,
+ SDP_RTCP_FB_NACK_RPSI,
+ SDP_RTCP_FB_NACK_APP,
+ SDP_RTCP_FB_NACK_RAI,
+ SDP_RTCP_FB_NACK_TLLEI,
+ SDP_RTCP_FB_NACK_PSLEI,
+ SDP_RTCP_FB_NACK_ECN,
+ SDP_MAX_RTCP_FB_NACK,
+ SDP_RTCP_FB_NACK_UNKNOWN
+} sdp_rtcp_fb_nack_type_e;
+
+typedef enum {
+ SDP_RTCP_FB_ACK_NOT_FOUND = -1,
+ SDP_RTCP_FB_ACK_RPSI = 0,
+ SDP_RTCP_FB_ACK_APP,
+ SDP_MAX_RTCP_FB_ACK,
+ SDP_RTCP_FB_ACK_UNKNOWN
+} sdp_rtcp_fb_ack_type_e;
+
+typedef enum {
+ SDP_RTCP_FB_CCM_NOT_FOUND = -1,
+ SDP_RTCP_FB_CCM_FIR = 0,
+ SDP_RTCP_FB_CCM_TMMBR,
+ SDP_RTCP_FB_CCM_TSTR,
+ SDP_RTCP_FB_CCM_VBCM,
+ SDP_MAX_RTCP_FB_CCM,
+ SDP_RTCP_FB_CCM_UNKNOWN
+} sdp_rtcp_fb_ccm_type_e;
+
+#ifdef __cplusplus
+static_assert(SDP_MAX_RTCP_FB_NACK +
+ SDP_MAX_RTCP_FB_ACK +
+ SDP_MAX_RTCP_FB_CCM < 32,
+ "rtcp-fb Bitmap is larger than 32 bits&quo