Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-10-13 19:26:29 -04:00
commit ec1d78bd1b
106 changed files with 2935 additions and 1903 deletions

View File

@ -10,18 +10,14 @@
using namespace mozilla::a11y;
NativeRootAccessibleWrap::NativeRootAccessibleWrap(AtkObject* aAccessible):
RootAccessible(nullptr, nullptr, nullptr)
GtkWindowAccessible::GtkWindowAccessible(AtkObject* aAccessible) :
DummyAccessible()
{
// XXX: mark the object as defunct to ensure no single internal method is
// running on it.
mFlags |= eIsDefunct;
g_object_ref(aAccessible);
mAtkObject = aAccessible;
}
NativeRootAccessibleWrap::~NativeRootAccessibleWrap()
GtkWindowAccessible::~GtkWindowAccessible()
{
g_object_unref(mAtkObject);
mAtkObject = nullptr;

View File

@ -7,6 +7,7 @@
#ifndef mozilla_a11y_RootAccessibleWrap_h__
#define mozilla_a11y_RootAccessibleWrap_h__
#include "BaseAccessibles.h"
#include "RootAccessible.h"
namespace mozilla {
@ -14,16 +15,16 @@ namespace a11y {
typedef RootAccessible RootAccessibleWrap;
/* NativeRootAccessibleWrap is the accessible class for gtk+ native window.
* The instance of NativeRootAccessibleWrap is a child of MaiAppRoot instance.
/* GtkWindowAccessible is the accessible class for gtk+ native window.
* The instance of GtkWindowAccessible is a child of MaiAppRoot instance.
* It is added into root when the toplevel window is created, and removed
* from root when the toplevel window is destroyed.
*/
class NativeRootAccessibleWrap : public RootAccessible
class GtkWindowAccessible MOZ_FINAL : public DummyAccessible
{
public:
NativeRootAccessibleWrap(AtkObject* aAccessible);
virtual ~NativeRootAccessibleWrap();
GtkWindowAccessible(AtkObject* aAccessible);
virtual ~GtkWindowAccessible();
};
} // namespace a11y

View File

@ -9,9 +9,6 @@
#include "Accessible-inl.h"
#include "ApplicationAccessibleWrap.h"
#include "ARIAGridAccessibleWrap.h"
#ifdef MOZ_ACCESSIBILITY_ATK
#include "AtkSocketAccessible.h"
#endif
#include "DocAccessible-inl.h"
#include "FocusManager.h"
#include "HTMLCanvasAccessible.h"
@ -34,11 +31,16 @@
#include "RootAccessibleWrap.h"
#include "States.h"
#include "Statistics.h"
#ifdef XP_WIN
#include "nsHTMLWin32ObjectAccessible.h"
#endif
#include "TextLeafAccessibleWrap.h"
#ifdef MOZ_ACCESSIBILITY_ATK
#include "AtkSocketAccessible.h"
#endif
#ifdef XP_WIN
#include "HTMLWin32ObjectAccessible.h"
#endif
#ifdef A11Y_LOG
#include "Logging.h"
#endif
@ -333,9 +335,8 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
aFrame->GetPluginPort(&pluginPort);
Accessible* accessible =
new nsHTMLWin32ObjectOwnerAccessible(aContent,
GetDocAccessible(aPresShell),
pluginPort);
new HTMLWin32ObjectOwnerAccessible(aContent, GetDocAccessible(aPresShell),
pluginPort);
NS_ADDREF(accessible);
return accessible;
@ -1669,13 +1670,11 @@ nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
if (!applicationAcc)
return nullptr;
nsRefPtr<NativeRootAccessibleWrap> nativeRootAcc =
new NativeRootAccessibleWrap(static_cast<AtkObject*>(aAtkAccessible));
if (!nativeRootAcc)
return nullptr;
GtkWindowAccessible* nativeWnd =
new GtkWindowAccessible(static_cast<AtkObject*>(aAtkAccessible));
if (applicationAcc->AppendChild(nativeRootAcc))
return nativeRootAcc;
if (applicationAcc->AppendChild(nativeWnd))
return nativeWnd;
#endif
return nullptr;

View File

@ -164,11 +164,8 @@ nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
}
uint32_t
nsCoreUtils::GetAccessKeyFor(nsIContent *aContent)
nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
{
if (!aContent)
return 0;
// Accesskeys are registered by @accesskey attribute only. At first check
// whether it is presented on the given element to avoid the slow
// nsEventStateManager::GetRegisteredAccessKey() method.

View File

@ -259,7 +259,10 @@ Accessible::Name(nsString& aName)
{
aName.Truncate();
GetARIAName(aName);
if (!HasOwnContent())
return eNameOK;
ARIAName(aName);
if (!aName.IsEmpty())
return eNameOK;
@ -317,7 +320,7 @@ Accessible::Description(nsString& aDescription)
// 3. it doesn't have an accName; or
// 4. its title attribute already equals to its accName nsAutoString name;
if (mContent->IsNodeOfType(nsINode::eTEXT))
if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT))
return;
nsTextEquivUtils::
@ -366,6 +369,9 @@ Accessible::GetAccessKey(nsAString& aAccessKey)
KeyBinding
Accessible::AccessKey() const
{
if (!HasOwnContent())
return KeyBinding();
uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent);
if (!key && mContent->IsElement()) {
Accessible* label = nullptr;
@ -678,7 +684,7 @@ Accessible::NativeState()
if (!IsInDocument())
state |= states::STALE;
if (mContent->IsElement()) {
if (HasOwnContent() && mContent->IsElement()) {
nsEventStates elementState = mContent->AsElement()->State();
if (elementState.HasState(NS_EVENT_STATE_INVALID))
@ -702,7 +708,7 @@ Accessible::NativeState()
// XXX we should look at layout for non XUL box frames, but need to decide
// how that interacts with ARIA.
if (mContent->IsXUL() && frame->IsBoxFrame()) {
if (HasOwnContent() && mContent->IsXUL() && frame->IsBoxFrame()) {
const nsStyleXUL* xulStyle = frame->GetStyleXUL();
if (xulStyle && frame->IsBoxFrame()) {
// In XUL all boxes are either vertical or horizontal
@ -715,9 +721,9 @@ Accessible::NativeState()
}
// Check if a XUL element has the popup attribute (an attached popup menu).
if (mContent->IsXUL() && mContent->HasAttr(kNameSpaceID_None,
nsGkAtoms::popup))
state |= states::HASPOPUP;
if (HasOwnContent() && mContent->IsXUL() &&
mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
state |= states::HASPOPUP;
// Bypass the link states specialization for non links.
if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
@ -943,8 +949,6 @@ Accessible::GetBounds(int32_t* aX, int32_t* aY,
if (IsDefunct())
return NS_ERROR_FAILURE;
nsIPresShell* presShell = mDoc->PresShell();
// This routine will get the entire rectangle for all the frames in this node.
// -------------------------------------------------------------------------
// Primary Frame for node
@ -956,7 +960,7 @@ Accessible::GetBounds(int32_t* aX, int32_t* aY,
GetBoundsRect(unionRectTwips, &boundingFrame); // Unions up all primary frames for this node and all siblings after it
NS_ENSURE_STATE(boundingFrame);
nsPresContext* presContext = presShell->GetPresContext();
nsPresContext* presContext = mDoc->PresContext();
*aX = presContext->AppUnitsToDevPixels(unionRectTwips.x);
*aY = presContext->AppUnitsToDevPixels(unionRectTwips.y);
*aWidth = presContext->AppUnitsToDevPixels(unionRectTwips.width);
@ -977,6 +981,9 @@ Accessible::SetSelected(bool aSelect)
if (IsDefunct())
return NS_ERROR_FAILURE;
if (!HasOwnContent())
return NS_OK;
Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
if (select) {
if (select->State() & states::MULTISELECTABLE) {
@ -1224,8 +1231,7 @@ Accessible::GetAttributes(nsIPersistentProperties **aAttributes)
attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRoles, oldValueUnused);
}
nsCOMPtr<nsIAccessibleValue> supportsValue = do_QueryInterface(static_cast<nsIAccessible*>(this));
if (supportsValue) {
if (HasNumericValue()) {
// We support values, so expose the string value as well, via the valuetext object attribute
// We test for the value interface because we don't want to expose traditional get_accValue()
// information such as URL's on links and documents, or text in an input
@ -1270,7 +1276,7 @@ Accessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
{
// If the accessible isn't primary for its node (such as list item bullet or
// xul tree item then don't calculate content based attributes.
if (!IsPrimaryForNode())
if (!HasOwnContent())
return NS_OK;
// Attributes set by this method will not be used to override attributes on a sub-document accessible
@ -2430,8 +2436,9 @@ Accessible::Shutdown()
////////////////////////////////////////////////////////////////////////////////
// Accessible public methods
nsresult
Accessible::GetARIAName(nsAString& aName)
// Accessible protected
void
Accessible::ARIAName(nsAString& aName)
{
nsAutoString label;
@ -2449,8 +2456,6 @@ Accessible::GetARIAName(nsAString& aName)
label.CompressWhitespace();
aName = label;
}
return NS_OK;
}
nsresult

View File

@ -146,11 +146,6 @@ public:
return DOMNode;
}
/**
* Returns the accessible name specified by ARIA.
*/
nsresult GetARIAName(nsAString& aName);
/**
* Maps ARIA state attributes to state of accessible. Note the given state
* argument should hold states for accessible before you pass it into this
@ -693,13 +688,15 @@ public:
bool IsInDocument() const { return !(mFlags & eIsNotInDocument); }
/**
* Return true if the accessible is primary accessible for the given DOM node.
*
* Accessible hierarchy may be complex for single DOM node, in this case
* these accessibles share the same DOM node. The primary accessible "owns"
* that DOM node in terms it gets stored in the accessible to node map.
*/
bool IsPrimaryForNode() const { return !(mFlags & eSharedNode); }
* Return true if the accessible should be contained by document node map.
*/
bool IsNodeMapEntry() const
{ return HasOwnContent() && !(mFlags & eNotNodeMapEntry); }
/**
* Return true if the accessible has associated DOM content.
*/
bool HasOwnContent() const { return mContent && !(mFlags & eSharedNode); }
/**
* Return true if the accessible has a numeric value.
@ -757,7 +754,8 @@ protected:
eIsDefunct = 1 << 2, // accessible is defunct
eIsNotInDocument = 1 << 3, // accessible is not in document
eSharedNode = 1 << 4, // accessible shares DOM node from another accessible
eHasNumericValue = 1 << 5 // accessible has a numeric value
eNotNodeMapEntry = 1 << 5, // accessible shouldn't be in document node map
eHasNumericValue = 1 << 6 // accessible has a numeric value
};
/**
@ -765,23 +763,23 @@ protected:
* @note keep these flags in sync with ChildrenFlags and StateFlags
*/
enum AccessibleTypes {
eApplicationAccessible = 1 << 6,
eAutoCompleteAccessible = 1 << 7,
eAutoCompletePopupAccessible = 1 << 8,
eComboboxAccessible = 1 << 9,
eDocAccessible = 1 << 10,
eHyperTextAccessible = 1 << 11,
eHTMLFileInputAccessible = 1 << 12,
eHTMLListItemAccessible = 1 << 13,
eImageAccessible = 1 << 14,
eImageMapAccessible = 1 << 15,
eListControlAccessible = 1 << 16,
eMenuButtonAccessible = 1 << 17,
eMenuPopupAccessible = 1 << 18,
eRootAccessible = 1 << 19,
eTextLeafAccessible = 1 << 20,
eXULDeckAccessible = 1 << 21,
eXULTreeAccessible = 1 << 22
eApplicationAccessible = 1 << 7,
eAutoCompleteAccessible = 1 << 8,
eAutoCompletePopupAccessible = 1 << 9,
eComboboxAccessible = 1 << 10,
eDocAccessible = 1 << 11,
eHyperTextAccessible = 1 << 12,
eHTMLFileInputAccessible = 1 << 13,
eHTMLListItemAccessible = 1 << 14,
eImageAccessible = 1 << 15,
eImageMapAccessible = 1 << 16,
eListControlAccessible = 1 << 17,
eMenuButtonAccessible = 1 << 18,
eMenuPopupAccessible = 1 << 19,
eRootAccessible = 1 << 20,
eTextLeafAccessible = 1 << 21,
eXULDeckAccessible = 1 << 22,
eXULTreeAccessible = 1 << 23
};
//////////////////////////////////////////////////////////////////////////////
@ -795,6 +793,11 @@ protected:
//////////////////////////////////////////////////////////////////////////////
// Name helpers
/**
* Returns the accessible name specified by ARIA.
*/
void ARIAName(nsAString& aName);
/**
* Compute the name of HTML node.
*/

View File

@ -26,7 +26,7 @@ using namespace mozilla::a11y;
ApplicationAccessible::ApplicationAccessible() :
AccessibleWrap(nullptr, nullptr)
{
mFlags |= (eApplicationAccessible | eSharedNode);
mFlags |= eApplicationAccessible;
}
////////////////////////////////////////////////////////////////////////////////
@ -370,22 +370,6 @@ ApplicationAccessible::GetSiblingAtOffset(int32_t aOffset,
////////////////////////////////////////////////////////////////////////////////
// nsIAccessible
NS_IMETHODIMP
ApplicationAccessible::GetDOMNode(nsIDOMNode** aDOMNode)
{
NS_ENSURE_ARG_POINTER(aDOMNode);
*aDOMNode = nullptr;
return NS_OK;
}
NS_IMETHODIMP
ApplicationAccessible::GetDocument(nsIAccessibleDocument** aDocument)
{
NS_ENSURE_ARG_POINTER(aDocument);
*aDocument = nullptr;
return NS_OK;
}
NS_IMETHODIMP
ApplicationAccessible::GetRootDocument(nsIAccessibleDocument** aRootDocument)
{

View File

@ -28,7 +28,7 @@ namespace a11y {
*/
class ApplicationAccessible : public AccessibleWrap,
public nsIAccessibleApplication
public nsIAccessibleApplication
{
public:
@ -38,8 +38,6 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetDOMNode(nsIDOMNode** aDOMNode);
NS_IMETHOD GetDocument(nsIAccessibleDocument** aDocument);
NS_IMETHOD GetRootDocument(nsIAccessibleDocument** aRootDocument);
NS_IMETHOD ScrollTo(uint32_t aScrollType);
NS_IMETHOD ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY);

View File

@ -237,3 +237,30 @@ EnumRoleAccessible::NativeRole()
{
return mRole;
}
////////////////////////////////////////////////////////////////////////////////
// DummyAccessible
////////////////////////////////////////////////////////////////////////////////
uint64_t
DummyAccessible::NativeState()
{
return 0;
}
uint64_t
DummyAccessible::NativeInteractiveState() const
{
return 0;
}
uint64_t
DummyAccessible::NativeLinkState() const
{
return 0;
}
bool
DummyAccessible::NativelyUnavailable() const
{
return false;
}

View File

@ -107,6 +107,23 @@ protected:
a11y::role mRole;
};
/**
* A wrapper accessible around native accessible to connect it with
* crossplatform accessible tree.
*/
class DummyAccessible : public AccessibleWrap
{
public:
DummyAccessible() : AccessibleWrap(nullptr, nullptr) { }
virtual ~DummyAccessible() { }
virtual uint64_t NativeState() MOZ_OVERRIDE MOZ_FINAL;
virtual uint64_t NativeInteractiveState() const MOZ_OVERRIDE MOZ_FINAL;
virtual uint64_t NativeLinkState() const MOZ_OVERRIDE MOZ_FINAL;
virtual bool NativelyUnavailable() const MOZ_OVERRIDE MOZ_FINAL;
};
} // namespace a11y
} // namespace mozilla

View File

@ -84,7 +84,7 @@ DocAccessible::
mVirtualCursor(nullptr),
mPresShell(aPresShell)
{
mFlags |= eDocAccessible;
mFlags |= eDocAccessible | eNotNodeMapEntry;
if (mPresShell)
mPresShell->SetAccDocument(this);
@ -271,10 +271,11 @@ DocAccessible::Description(nsString& aDescription)
if (mParent)
mParent->Description(aDescription);
if (aDescription.IsEmpty())
if (HasOwnContent() && aDescription.IsEmpty()) {
nsTextEquivUtils::
GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
aDescription);
}
}
// Accessible public method
@ -1390,7 +1391,7 @@ DocAccessible::BindToDocument(Accessible* aAccessible,
return false;
// Put into DOM node cache.
if (aAccessible->IsPrimaryForNode())
if (aAccessible->IsNodeMapEntry())
mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible);
// Put into unique ID cache.
@ -1423,7 +1424,7 @@ DocAccessible::UnbindFromDocument(Accessible* aAccessible)
}
// Remove an accessible from node-to-accessible map if it exists there.
if (aAccessible->IsPrimaryForNode() &&
if (aAccessible->IsNodeMapEntry() &&
mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
mNodeToAccessibleMap.Remove(aAccessible->GetNode());
@ -2047,7 +2048,7 @@ DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
for (uint32_t idx = 0; idx < count; idx++)
UncacheChildrenInSubtree(aRoot->ContentChildAt(idx));
if (aRoot->IsPrimaryForNode() &&
if (aRoot->IsNodeMapEntry() &&
mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
mNodeToAccessibleMap.Remove(aRoot->GetNode());
}

View File

@ -152,9 +152,9 @@ HTMLAreaAccessible::
HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HTMLLinkAccessible(aContent, aDoc)
{
// Make HTML area DOM element not accessible. HTML image map accessible
// Make HTML area DOM element not accessible. HTML image map accessible
// manages its tree itself.
mFlags |= eSharedNode;
mFlags |= eNotNodeMapEntry;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -3,7 +3,7 @@
* 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 "nsHTMLWin32ObjectAccessible.h"
#include "HTMLWin32ObjectAccessible.h"
#include "Role.h"
#include "States.h"
@ -11,39 +11,39 @@
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// nsHTMLWin32ObjectOwnerAccessible
// HTMLWin32ObjectOwnerAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLWin32ObjectOwnerAccessible::
nsHTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
DocAccessible* aDoc, void* aHwnd) :
HTMLWin32ObjectOwnerAccessible::
HTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
DocAccessible* aDoc, void* aHwnd) :
AccessibleWrap(aContent, aDoc), mHwnd(aHwnd)
{
// Our only child is a nsHTMLWin32ObjectAccessible object.
mNativeAccessible = new nsHTMLWin32ObjectAccessible(mHwnd);
// Our only child is a HTMLWin32ObjectAccessible object.
mNativeAccessible = new HTMLWin32ObjectAccessible(mHwnd);
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLWin32ObjectOwnerAccessible: nsAccessNode implementation
// HTMLWin32ObjectOwnerAccessible: nsAccessNode implementation
void
nsHTMLWin32ObjectOwnerAccessible::Shutdown()
HTMLWin32ObjectOwnerAccessible::Shutdown()
{
AccessibleWrap::Shutdown();
mNativeAccessible = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLWin32ObjectOwnerAccessible: Accessible implementation
// HTMLWin32ObjectOwnerAccessible: Accessible implementation
role
nsHTMLWin32ObjectOwnerAccessible::NativeRole()
HTMLWin32ObjectOwnerAccessible::NativeRole()
{
return roles::EMBEDDED_OBJECT;
}
bool
nsHTMLWin32ObjectOwnerAccessible::NativelyUnavailable() const
HTMLWin32ObjectOwnerAccessible::NativelyUnavailable() const
{
// XXX: No HWND means this is windowless plugin which is not accessible in
// the meantime.
@ -51,10 +51,10 @@ nsHTMLWin32ObjectOwnerAccessible::NativelyUnavailable() const
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLWin32ObjectOwnerAccessible: Accessible protected implementation
// HTMLWin32ObjectOwnerAccessible: Accessible protected implementation
void
nsHTMLWin32ObjectOwnerAccessible::CacheChildren()
HTMLWin32ObjectOwnerAccessible::CacheChildren()
{
if (mNativeAccessible)
AppendChild(mNativeAccessible);
@ -62,22 +62,18 @@ nsHTMLWin32ObjectOwnerAccessible::CacheChildren()
////////////////////////////////////////////////////////////////////////////////
// nsHTMLWin32ObjectAccessible
// HTMLWin32ObjectAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd) :
LeafAccessible(nullptr, nullptr)
HTMLWin32ObjectAccessible::HTMLWin32ObjectAccessible(void* aHwnd) :
DummyAccessible()
{
// XXX: Mark it as defunct to make sure no single Accessible method is
// running on it. We need to allow accessible without DOM nodes.
mFlags |= eIsDefunct;
mHwnd = aHwnd;
if (mHwnd) {
// The plugin is not windowless. In this situation we use
// use its inner child owned by the plugin so that we don't get
// in an infinite loop, where the WM_GETOBJECT's get forwarded
// back to us and create another nsHTMLWin32ObjectAccessible
// back to us and create another HTMLWin32ObjectAccessible
HWND childWnd = ::GetWindow((HWND)aHwnd, GW_CHILD);
if (childWnd) {
mHwnd = childWnd;
@ -85,10 +81,8 @@ nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd) :
}
}
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLWin32ObjectAccessible, Accessible)
NS_IMETHODIMP
nsHTMLWin32ObjectAccessible::GetNativeInterface(void** aNativeAccessible)
HTMLWin32ObjectAccessible::GetNativeInterface(void** aNativeAccessible)
{
if (mHwnd) {
::AccessibleObjectFromWindow(static_cast<HWND>(mHwnd),

View File

@ -3,25 +3,28 @@
* 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 _nsHTMLWin32ObjectAccessible_H_
#define _nsHTMLWin32ObjectAccessible_H_
#ifndef mozilla_a11y_HTMLWin32ObjectAccessible_h_
#define mozilla_a11y_HTMLWin32ObjectAccessible_h_
#include "BaseAccessibles.h"
struct IAccessible;
class nsHTMLWin32ObjectOwnerAccessible : public AccessibleWrap
namespace mozilla {
namespace a11y {
class HTMLWin32ObjectOwnerAccessible : public AccessibleWrap
{
public:
// This will own the nsHTMLWin32ObjectAccessible. We create this where the
// This will own the HTMLWin32ObjectAccessible. We create this where the
// <object> or <embed> exists in the tree, so that get_accNextSibling() etc.
// will still point to Gecko accessible sibling content. This is necessary
// because the native plugin accessible doesn't know where it exists in the
// Mozilla tree, and returns null for previous and next sibling. This would
// have the effect of cutting off all content after the plugin.
nsHTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
HTMLWin32ObjectOwnerAccessible(nsIContent* aContent,
DocAccessible* aDoc, void* aHwnd);
virtual ~nsHTMLWin32ObjectOwnerAccessible() {}
virtual ~HTMLWin32ObjectOwnerAccessible() {}
// nsAccessNode
virtual void Shutdown();
@ -48,14 +51,11 @@ protected:
* object returned by us in Accessible::NewAccessible() that gets the IAccessible
* from the windows system from the window handle.
*/
class nsHTMLWin32ObjectAccessible : public mozilla::a11y::LeafAccessible
class HTMLWin32ObjectAccessible : public DummyAccessible
{
public:
nsHTMLWin32ObjectAccessible(void* aHwnd);
virtual ~nsHTMLWin32ObjectAccessible() {}
NS_DECL_ISUPPORTS_INHERITED
HTMLWin32ObjectAccessible(void* aHwnd);
virtual ~HTMLWin32ObjectAccessible() {}
NS_IMETHOD GetNativeInterface(void** aNativeAccessible) MOZ_OVERRIDE;
@ -63,4 +63,7 @@ protected:
void* mHwnd;
};
#endif
} // namespace a11y
} // namespace mozilla
#endif

View File

@ -21,10 +21,10 @@ CPPSRCS = \
ARIAGridAccessibleWrap.cpp \
DocAccessibleWrap.cpp \
HTMLTableAccessibleWrap.cpp \
HTMLWin32ObjectAccessible.cpp \
HyperTextAccessibleWrap.cpp \
ImageAccessibleWrap.cpp \
nsAccessNodeWrap.cpp \
nsHTMLWin32ObjectAccessible.cpp \
nsWinUtils.cpp \
Compatibility.cpp \
EnumVariant.cpp \

View File

@ -468,10 +468,6 @@ pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
// Interval at which update manifest is fetched. In units of seconds.
pref("app.update.interval", 86400); // 1 day
// First interval to elapse before checking for update. In units of
// milliseconds. Capped at 10 seconds.
pref("app.update.timerFirstInterval", 3600000); // 1 hour
pref("app.update.timerMinimumDelay", 3600); // 1 hour in seconds
// Don't throttle background updates.
pref("app.update.download.backgroundInterval", 0);

View File

@ -259,12 +259,17 @@ function getJSON(element) {
}
}
// If Gecko knows about the inputmode attribute, use that value.
// Otherwise, query the attribute explicitly, but be sure to convert
// to lowercase
let inputmode = element.inputmode || element.getAttribute('inputmode');
// Gecko supports the inputmode attribute on text fields (but not textareas).
// But it doesn't recognize "verbatim" and other modes that we're interested
// in in Gaia, and the inputmode property returns "auto" for any value
// that gecko does not support. So we must query the inputmode attribute
// with getAttribute() rather than just using the inputmode property here.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=746142
let inputmode = element.getAttribute('inputmode');
if (inputmode) {
inputmode = inputmode.toLowerCase();
} else {
inputmode = '';
}
return {

View File

@ -788,6 +788,14 @@ window.addEventListener('ContentStart', function ss_onContentStart() {
"ipc:content-shutdown", false);
})();
window.addEventListener('ContentStart', function update_onContentStart() {
let updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"]
.createInstance(Ci.nsIUpdatePrompt);
let content = shell.contentBrowser.contentWindow;
content.addEventListener("mozContentEvent", updatePrompt.wrappedJSObject);
});
(function geolocationStatusTracker() {
let gGeolocationActiveCount = 0;

View File

@ -35,7 +35,10 @@ XPCOMUtils.defineLazyServiceGetter(Services, "aus",
XPCOMUtils.defineLazyServiceGetter(Services, "idle",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
function UpdatePrompt() { }
function UpdatePrompt() {
this.wrappedJSObject = this;
}
UpdatePrompt.prototype = {
classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
@ -43,6 +46,7 @@ UpdatePrompt.prototype = {
Ci.nsIRequestObserver,
Ci.nsIProgressEventSink,
Ci.nsIObserver]),
_xpcom_factory: XPCOMUtils.generateSingletonFactory(UpdatePrompt),
_update: null,
_applyPromptTimer: null,
@ -56,8 +60,7 @@ UpdatePrompt.prototype = {
checkForUpdates: function UP_checkForUpdates() { },
showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) {
if (!this.sendUpdateEvent("update-available", aUpdate,
this.handleAvailableResult)) {
if (!this.sendUpdateEvent("update-available", aUpdate)) {
log("Unable to prompt for available update, forcing download");
this.downloadUpdate(aUpdate);
@ -105,10 +108,8 @@ UpdatePrompt.prototype = {
Services.obs.addObserver(this, "quit-application", false);
},
showApplyPrompt: function UP_showApplyPrompt(aUpdate) {
if (!this.sendUpdateEvent("update-prompt-apply", aUpdate,
this.handleApplyPromptResult)) {
if (!this.sendUpdateEvent("update-prompt-apply", aUpdate)) {
log("Unable to prompt, forcing restart");
this.restartProcess();
return;
@ -119,7 +120,7 @@ UpdatePrompt.prototype = {
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
},
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate, aCallback) {
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
let detail = {
displayVersion: aUpdate.displayVersion,
detailsURL: aUpdate.detailsURL
@ -140,10 +141,10 @@ UpdatePrompt.prototype = {
detail.updateType = patch.type;
this._update = aUpdate;
return this.sendChromeEvent(aType, detail, aCallback);
return this.sendChromeEvent(aType, detail);
},
sendChromeEvent: function UP_sendChromeEvent(aType, aDetail, aCallback) {
sendChromeEvent: function UP_sendChromeEvent(aType, aDetail) {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
if (!browser) {
log("Warning: Couldn't send update event " + aType +
@ -151,36 +152,9 @@ UpdatePrompt.prototype = {
return false;
}
let content = browser.getContentWindow();
if (!content) {
log("Warning: Couldn't send update event " + aType +
": no content window");
return false;
}
let detail = aDetail || {};
detail.type = aType;
if (!aCallback) {
browser.shell.sendChromeEvent(detail);
return true;
}
let resultType = aType + "-result";
let handleContentEvent = (function(e) {
if (!e.detail) {
return;
}
let detail = e.detail;
if (detail.type == resultType) {
aCallback.call(this, detail);
content.removeEventListener("mozContentEvent", handleContentEvent);
this._update = null;
}
}).bind(this);
content.addEventListener("mozContentEvent", handleContentEvent);
browser.shell.sendChromeEvent(detail);
return true;
},
@ -208,6 +182,7 @@ UpdatePrompt.prototype = {
break;
case "restart":
this.finishUpdate();
this._update = null;
break;
}
},
@ -274,6 +249,40 @@ UpdatePrompt.prototype = {
}
},
forceUpdateCheck: function UP_forceUpdateCheck() {
log("Forcing update check");
let checker = Cc["@mozilla.org/updates/update-checker;1"]
.createInstance(Ci.nsIUpdateChecker);
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
checker.checkForUpdates(Services.aus, true);
},
handleEvent: function UP_handleEvent(evt) {
if (evt.type !== "mozContentEvent") {
return;
}
let detail = evt.detail;
if (!detail) {
return;
}
switch (detail.type) {
case "force-update-check":
this.forceUpdateCheck();
break;
case "update-available-result":
this.handleAvailableResult(detail);
this._update = null;
break;
case "update-prompt-apply-result":
this.handleApplyPromptResult(detail);
break;
}
},
// nsIObserver
observe: function UP_observe(aSubject, aTopic, aData) {
@ -289,6 +298,8 @@ UpdatePrompt.prototype = {
}
},
// nsITimerCallback
notify: function UP_notify(aTimer) {
if (aTimer == this._applyPromptTimer) {
log("Timed out waiting for result, restarting");

View File

@ -14,7 +14,7 @@ function test()
];
function setLocation(i, url) {
gBrowser.getBrowserForTab(tabs[i]).contentWindow.location = url;
gBrowser.getBrowserForTab(tabs[i]).contentWindow.location.assign(url);
}
function moveTabTo(a, b) {
gBrowser.swapBrowsersAndCloseOther(gBrowser.tabs[b], gBrowser.tabs[a]);

View File

@ -166,13 +166,13 @@ function test() {
// navigating back maintains the focus in the urlbar.
browser1.addEventListener("pageshow", _browser_tabfocus_navigation_test_eventOccured, true);
button1.focus();
browser1.contentWindow.location = testPage3;
browser1.contentWindow.location.assign(testPage3);
}
browser1.addEventListener("load", check, true);
browser2.addEventListener("load", check, true);
browser1.contentWindow.location = testPage1;
browser2.contentWindow.location = testPage2;
browser1.contentWindow.location.assign(testPage1);
browser2.contentWindow.location.assign(testPage2);
}
var _browser_tabfocus_test_lastfocus;

View File

@ -101,12 +101,19 @@ PrivateBrowsingService.prototype = {
.usePrivateBrowsing = aFlag;
},
_onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
_adjustPBFlagOnExistingWindows: function PBS__adjustPBFlagOnExistingWindows() {
var windowsEnum = Services.wm.getEnumerator(null);
while (windowsEnum.hasMoreElements()) {
var window = windowsEnum.getNext();
this._setPerWindowPBFlag(window, this._inPrivateBrowsing);
}
},
_onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
// If we're about to enter PB mode, adjust the flags now
if (this._inPrivateBrowsing) {
this._adjustPBFlagOnExistingWindows();
}
// nothing needs to be done here if we're enabling at startup
if (!this._autoStarted) {
@ -180,6 +187,11 @@ PrivateBrowsingService.prototype = {
}
else
this._saveSession = false;
// If we're about to leave PB mode, adjust the flags now
if (!this._inPrivateBrowsing) {
this._adjustPBFlagOnExistingWindows();
}
},
_onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {

View File

@ -33,7 +33,7 @@ let tab, browser, hudId, hud, hudBox, filterBox, outputNode, cs;
function addTab(aURL)
{
gBrowser.selectedTab = gBrowser.addTab();
content.location = aURL;
content.location.assign(aURL);
tab = gBrowser.selectedTab;
browser = gBrowser.getBrowserForTab(tab);
}

View File

@ -74,6 +74,9 @@ class JarMaker(object):
self.useJarfileManifest = useJarfileManifest
self.useChromeManifest = useChromeManifest
self.pp = Preprocessor()
self.topsourcedir = None
self.sourcedirs = []
self.localedirs = None
def getCommandLineParser(self):
'''Get a optparse.OptionParser for jarmaker.
@ -102,22 +105,8 @@ class JarMaker(object):
help="top source directory")
p.add_option('-c', '--l10n-src', type="string", action="append",
help="localization directory")
p.add_option('--l10n-base', type="string", action="append", default=[],
help="base directory to be used for localization (multiple)")
p.add_option('-j', type="string",
help="jarfile directory")
# backwards compat, not needed
p.add_option('-a', action="store_false", default=True,
help="NOT SUPPORTED, turn auto-registration of chrome off (installed-chrome.txt)")
p.add_option('-d', type="string",
help="UNUSED, chrome directory")
p.add_option('-o', help="cross compile for auto-registration, ignored")
p.add_option('-l', action="store_true",
help="ignored (used to switch off locks)")
p.add_option('-x', action="store_true",
help="force Unix")
p.add_option('-z', help="backwards compat, ignored")
p.add_option('-p', help="backwards compat, ignored")
return p
def processIncludes(self, includes):
@ -182,16 +171,21 @@ class JarMaker(object):
finally:
lock = None
def makeJar(self, infile=None,
jardir='',
sourcedirs=[], topsourcedir='', localedirs=None):
def makeJar(self, infile, jardir):
'''makeJar is the main entry point to JarMaker.
It takes the input file, the output directory, the source dirs and the
top source dir as argument, and optionally the l10n dirs.
'''
# making paths absolute, guess srcdir if file and add to sourcedirs
_normpath = lambda p: os.path.normpath(os.path.abspath(p))
self.topsourcedir = _normpath(self.topsourcedir)
self.sourcedirs = [_normpath(p) for p in self.sourcedirs]
if self.localedirs:
self.localedirs = [_normpath(p) for p in self.localedirs]
if isinstance(infile, basestring):
logging.info("processing " + infile)
self.sourcedirs.append(_normpath(os.path.dirname(infile)))
pp = self.pp.clone()
pp.out = StringIO()
pp.do_include(infile)
@ -205,68 +199,13 @@ class JarMaker(object):
if m.group('jarfile') is None:
# comment
continue
self.processJarSection(m.group('jarfile'), lines,
jardir, sourcedirs, topsourcedir,
localedirs)
self.processJarSection(m.group('jarfile'), lines, jardir)
except StopIteration:
# we read the file
pass
return
def makeJars(self, infiles, l10nbases,
jardir='',
sourcedirs=[], topsourcedir='', localedirs=None):
'''makeJars is the second main entry point to JarMaker.
It takes an iterable sequence of input file names, the l10nbases,
the output directory, the source dirs and the
top source dir as argument, and optionally the l10n dirs.
It iterates over all inputs, guesses srcdir and l10ndir from the
path and topsourcedir and calls into makeJar.
The l10ndirs are created by guessing the relativesrcdir, and resolving
that against the l10nbases. l10nbases can either be path strings, or
callables. In the latter case, that will be called with the
relativesrcdir as argument, and is expected to return a path string.
This logic is disabled if the jar.mn path is not inside the topsrcdir.
'''
topsourcedir = os.path.normpath(os.path.abspath(topsourcedir))
def resolveL10nBase(relpath):
def _resolve(base):
if isinstance(base, basestring):
return os.path.join(base, relpath)
if callable(base):
return base(relpath)
return base
return _resolve
for infile in infiles:
srcdir = os.path.normpath(os.path.abspath(os.path.dirname(infile)))
l10ndir = srcdir
if os.path.basename(srcdir) == 'locales':
l10ndir = os.path.dirname(l10ndir)
l10ndirs = None
# srcdir may not be a child of topsourcedir, in which case
# we assume that the caller passed in suitable sourcedirs,
# and just skip passing in localedirs
if srcdir.startswith(topsourcedir):
rell10ndir = l10ndir[len(topsourcedir):].lstrip(os.sep)
l10ndirs = map(resolveL10nBase(rell10ndir), l10nbases)
if localedirs is not None:
l10ndirs += [os.path.normpath(os.path.abspath(s))
for s in localedirs]
srcdirs = [os.path.normpath(os.path.abspath(s))
for s in sourcedirs] + [srcdir]
self.makeJar(infile=infile,
sourcedirs=srcdirs, topsourcedir=topsourcedir,
localedirs=l10ndirs,
jardir=jardir)
def processJarSection(self, jarfile, lines,
jardir, sourcedirs, topsourcedir, localedirs):
def processJarSection(self, jarfile, lines, jardir):
'''Internal method called by makeJar to actually process a section
of a jar.mn file.
@ -328,30 +267,27 @@ class JarMaker(object):
jf.close()
lines.pushback(l)
return
self._processEntryLine(m, sourcedirs, topsourcedir, localedirs,
outHelper, jf)
self._processEntryLine(m, outHelper, jf)
finally:
if jf is not None:
jf.close()
return
def _processEntryLine(self, m,
sourcedirs, topsourcedir, localedirs,
outHelper, jf):
def _processEntryLine(self, m, outHelper, jf):
out = m.group('output')
src = m.group('source') or os.path.basename(out)
# pick the right sourcedir -- l10n, topsrc or src
if m.group('locale'):
src_base = localedirs
src_base = self.localedirs
elif src.startswith('/'):
# path/in/jar/file_name.xul (/path/in/sourcetree/file_name.xul)
# refers to a path relative to topsourcedir, use that as base
# and strip the leading '/'
src_base = [topsourcedir]
src_base = [self.topsourcedir]
src = src[1:]
else:
# use srcdirs and the objdir (current working dir) for relative paths
src_base = sourcedirs + [os.getcwd()]
src_base = self.sourcedirs + [os.getcwd()]
# check if the source file exists
realsrc = None
for _srcdir in src_base:
@ -458,12 +394,15 @@ def main():
(options, args) = p.parse_args()
jm.processIncludes(options.I)
jm.outputFormat = options.f
jm.sourcedirs = options.s
jm.topsourcedir = options.t
if options.e:
jm.useChromeManifest = True
jm.useJarfileManifest = False
if options.bothManifests:
jm.useChromeManifest = True
jm.useJarfileManifest = True
jm.localedirs = options.l10n_src
noise = logging.INFO
if options.verbose is not None:
noise = (options.verbose and logging.DEBUG) or logging.WARN
@ -475,15 +414,10 @@ def main():
topsrc = options.t
topsrc = os.path.normpath(os.path.abspath(topsrc))
if not args:
jm.makeJar(infile=sys.stdin,
sourcedirs=options.s, topsourcedir=topsrc,
localedirs=options.l10n_src,
jardir=options.j)
infile = sys.stdin
else:
jm.makeJars(args, options.l10n_base,
jardir=options.j,
sourcedirs=options.s, topsourcedir=topsrc,
localedirs=options.l10n_src)
infile, = args
jm.makeJar(infile, options.j)
if __name__ == "__main__":
main()

View File

@ -137,7 +137,7 @@ class TestJarMaker(unittest.TestCase):
"""
Unit tests for JarMaker.py
"""
debug = True # set to True to debug failing tests on disk
debug = False # set to True to debug failing tests on disk
def setUp(self):
self.tmpdir = mkdtemp()
self.srcdir = os.path.join(self.tmpdir, 'src')
@ -152,15 +152,19 @@ class TestJarMaker(unittest.TestCase):
def tearDown(self):
if self.debug:
print self.tmpdir
else:
elif sys.platform != "win32":
# can't clean up on windows
rmtree(self.tmpdir)
def _jar_and_compare(self, *args, **kwargs):
def _jar_and_compare(self, infile, **kwargs):
jm = JarMaker(outputFormat='jar')
kwargs['jardir'] = os.path.join(self.builddir, 'chrome')
jardir = os.path.join(self.builddir, 'chrome')
if 'topsourcedir' not in kwargs:
kwargs['topsourcedir'] = self.srcdir
jm.makeJars(*args, **kwargs)
for attr in ('topsourcedir', 'sourcedirs'):
if attr in kwargs:
setattr(jm, attr, kwargs[attr])
jm.makeJar(infile, jardir)
cwd = os.getcwd()
os.chdir(self.builddir)
try:
@ -214,8 +218,7 @@ class TestJarMaker(unittest.TestCase):
'''Test a simple jar.mn'''
self._create_simple_setup()
# call JarMaker
rv = self._jar_and_compare((os.path.join(self.srcdir,'jar.mn'),),
tuple(),
rv = self._jar_and_compare(os.path.join(self.srcdir,'jar.mn'),
sourcedirs = [self.srcdir])
self.assertTrue(not rv, rv)
@ -226,56 +229,16 @@ class TestJarMaker(unittest.TestCase):
self._create_simple_setup()
jm = JarMaker(outputFormat='symlink')
kwargs = {
'sourcedirs': [self.srcdir],
'topsourcedir': self.srcdir,
'jardir': os.path.join(self.builddir, 'chrome'),
}
jm.makeJars((os.path.join(self.srcdir,'jar.mn'),), tuple(), **kwargs)
jm.sourcedirs = [self.srcdir]
jm.topsourcedir = self.srcdir
jardir = os.path.join(self.builddir, 'chrome')
jm.makeJar(os.path.join(self.srcdir,'jar.mn'), jardir)
# All we do is check that srcdir/bar points to builddir/chrome/test/dir/foo
srcbar = os.path.join(self.srcdir, 'bar')
destfoo = os.path.join(self.builddir, 'chrome', 'test', 'dir', 'foo')
self.assertTrue(is_symlink_to(destfoo, srcbar),
"%s is not a symlink to %s" % (destfoo, srcbar))
def test_k_multi_relative_jar(self):
'''Test the API for multiple l10n jars, with different relative paths'''
# create app src content
def _mangle(relpath):
'method we use to map relpath to srcpaths'
return os.path.join(self.srcdir, 'other-' + relpath)
jars = []
for relpath in ('foo', 'bar'):
ldir = os.path.join(self.srcdir, relpath, 'locales')
os.makedirs(ldir)
jp = os.path.join(ldir, 'jar.mn')
jars.append(jp)
open(jp, 'w').write('''ab-CD.jar:
% locale app ab-CD %app
app/''' + relpath + ' (%' + relpath + ''')
''')
ldir = _mangle(relpath)
os.mkdir(ldir)
open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
# create reference
mf = open(os.path.join(self.refdir, 'chrome.manifest'), 'w')
mf.write('manifest chrome/ab-CD.manifest\n')
mf.close()
chrome_ref = os.path.join(self.refdir, 'chrome')
os.mkdir(chrome_ref)
mf = open(os.path.join(chrome_ref, 'ab-CD.manifest'), 'wb')
mf.write('locale app ab-CD jar:ab-CD.jar!/app\n')
mf.close()
ldir = os.path.join(chrome_ref, 'ab-CD.jar', 'app')
os.makedirs(ldir)
for relpath in ('foo', 'bar'):
open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
# call JarMaker
difference = self._jar_and_compare(jars,
(_mangle,),
sourcedirs = [])
self.assertTrue(not difference, difference)
if __name__ == '__main__':
mozunit.main()

View File

@ -8866,7 +8866,9 @@ fi
if test -n "$MOZ_WEBRTC"; then
AC_MSG_RESULT("generating WebRTC Makefiles...")
WEBRTC_CONFIG="-D build_with_mozilla=1 --include ${srcdir}/media/webrtc/webrtc_config.gypi"
dnl Any --include files must also appear in -D FORCED_INCLUDE_FILE= entries
dnl so that regeneration via dependencies works correctly
WEBRTC_CONFIG="-D build_with_mozilla=1 --include ${srcdir}/media/webrtc/webrtc_config.gypi -D FORCED_INCLUDE_FILE=${srcdir}/media/webrtc/webrtc_config.gypi"
GYP_WEBRTC_OPTIONS="--format=mozmake ${WEBRTC_CONFIG} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"

View File

@ -243,6 +243,7 @@ MOCHITEST_FILES = \
test_bug677463.html \
test_bug682886.html \
test_bug717819.html \
file_fullscreen-utils.js \
file_fullscreen-api.html \
file_fullscreen-api-keys.html \
test_fullscreen-api.html \

View File

@ -9,6 +9,7 @@ Test that restricted key pressed drop documents out of DOM full-screen mode.
<head>
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body {
background-color: black;
@ -51,7 +52,6 @@ function checkKeyEffect() {
if (gKeyTestIndex < keyList.length) {
setTimeout(testNextKey, 0);
} else {
document.mozCancelFullScreen();
opener.nextTest();
}
}
@ -59,8 +59,8 @@ function checkKeyEffect() {
function testTrustedKeyEvents() {
document.body.focus();
gKeyReceived = false;
addFullscreenChangeContinuation("exit", checkKeyEffect);
synthesizeKey(gKeyName, {});
setTimeout(checkKeyEffect, 0);
}
function testScriptInitiatedKeyEvents() {
@ -92,7 +92,7 @@ function testScriptInitiatedKeyEvents() {
function testNextKey() {
if (!document.mozFullScreen) {
document.addEventListener("mozfullscreenchange", reallyTestNextKey, false);
addFullscreenChangeContinuation("enter", reallyTestNextKey);
document.body.mozRequestFullScreen();
}
else {
@ -101,8 +101,6 @@ function testNextKey() {
}
function reallyTestNextKey() {
document.removeEventListener("mozfullscreenchange", reallyTestNextKey, false);
ok(document.mozFullScreen, "Must be in full-screen mode");
gKeyName = keyList[gKeyTestIndex].code;

View File

@ -10,6 +10,7 @@ Test DOM full-screen API.
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body {
background-color: black;
@ -43,9 +44,7 @@ var outOfDocElement = null;
var inDocElement = null;
var container = null;
var button = null;
var fullScreenChangeCount = 0;
var fullscreendenied = false;
var fullScreenErrorRun = false;
function sendMouseClick(element) {
synthesizeMouseAtCenter(element, {});
@ -59,181 +58,165 @@ function fullScreenElement() {
return document.getElementById('full-screen-element');
}
function fullScreenChange(event) {
switch (fullScreenChangeCount) {
case 0: {
ok(document.mozFullScreen, "1. Should be in full-screen mode (first time)");
is(event.target, document, "2. Event target should be full-screen document #1");
is(document.mozFullScreenElement, fullScreenElement(), "3. Full-screen element should be div element.");
ok(document.mozFullScreenElement.mozMatchesSelector(":-moz-full-screen"), "4. FSE should match :-moz-full-screen");
var fse = fullScreenElement();
fse.parentNode.removeChild(fse);
is(document.mozFullScreenElement, null, "5. Full-screen element should be null after removing.");
ok(!document.mozFullScreen, "6. Should have left full-screen mode when we remove full-screen element");
document.body.appendChild(fse);
ok(!document.mozFullScreen, "7. Should not return to full-screen mode when re-adding former FSE");
is(document.mozFullScreenElement, null, "8. Full-screen element should still be null after re-adding former FSE.");
break;
}
case 1: {
ok(!document.mozFullScreen, "9. Should have left full-screen mode (first time)");
is(event.target, document, "10. Event target should be full-screen document #2");
is(document.mozFullScreenElement, null, "11. Full-screen element should be null.");
iframe = document.createElement("iframe");
iframe.mozAllowFullScreen = true;
document.body.appendChild(iframe);
iframe.src = iframeContents;
break;
}
case 2: {
ok(document.mozFullScreen, "12. Should be back in full-screen mode (second time)");
is(event.target, document, "13. Event target should be full-screen document #3");
is(document.mozFullScreenElement, iframe, "14. Full-screen element should be iframe element.");
is(iframe.contentDocument.mozFullScreenElement, iframe.contentDocument.body, "15. Full-screen element in subframe should be body");
// The iframe's body is full-screen. Cancel full-screen in the subdocument to return
// the full-screen element to the previous full-screen element. This causes
// a fullscreenchange event.
document.mozCancelFullScreen();
break;
}
case 3: {
ok(!document.mozFullScreen, "16. Should have left full-screen when removing FSE ancestor.");
is(document.mozFullScreenElement, null, "17. Full-screen element should have rolled back.");
is(iframe.contentDocument.mozFullScreenElement, null, "18. Full-screen element in subframe should be null");
fullScreenElement().mozRequestFullScreen();
break;
}
case 4: {
ok(document.mozFullScreen, "19. Should be back in full-screen mode (second time)");
is(event.target, document, "20. Event target should be full-screen document #3");
is(document.mozFullScreenElement, fullScreenElement(), "21. Full-screen element should be div.");
// Transplant the FSE into subdoc. Should exit full-screen.
var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
var fse = fullScreenElement();
_innerFrame.contentDocument.body.appendChild(fse);
ok(!document.mozFullScreen, "22. Should exit full-screen after transplanting FSE");
is(document.mozFullScreenElement, null, "23. Full-screen element transplanted, should be null.");
is(iframe.contentDocument.mozFullScreenElement, null, "24. Full-screen element in outer frame should be null.");
is(_innerFrame.contentDocument.mozFullScreenElement, null, "25. Full-screen element in inner frame should be null.");
ok(!iframe.contentDocument.mozFullScreen, "26. Outer frame should not acquire full-screen status.");
ok(!_innerFrame.contentDocument.mozFullScreen, "27. Inner frame should not acquire full-screen status.");
document.body.appendChild(fse);
break;
}
case 5: {
ok(!document.mozFullScreen, "28. Should be back in non-full-screen mode (second time)");
is(event.target, document, "29. Event target should be full-screen document #4");
is(document.mozFullScreenElement, null, "30. Full-screen element should be null.");
document.body.removeChild(iframe);
iframe = null;
// Do a request out of document. It should be denied.
// Continue test in the following mozfullscreenerror handler.
outOfDocElement = document.createElement("div");
var f =
function(e) {
document.removeEventListener("mozfullscreenerror", f, false);
ok(!document.mozFullScreen, "31. Requests for full-screen from not-in-doc elements should fail.");
fullScreenErrorRun = true;
container = document.createElement("div");
inDocElement = document.createElement("div");
container.appendChild(inDocElement);
fullScreenElement().appendChild(container);
inDocElement.mozRequestFullScreen();
};
document.addEventListener("mozfullscreenerror", f, false);
outOfDocElement.mozRequestFullScreen();
break;
}
case 6: {
ok(document.mozFullScreen, "32. Should still be in full-screen mode (third time)");
is(event.target, document, "33. Event target should be full-screen document #5");
ok(fullScreenErrorRun, "34. Should have run fullscreenerror handler from previous case.");
is(document.mozFullScreenElement, inDocElement, "35. FSE should be inDocElement.");
var n = container;
do {
ok(n.mozMatchesSelector(":-moz-full-screen-ancestor"), "Ancestor " + n + " should match :-moz-full-screen-ancestor")
n = n.parentNode;
} while (n && n.mozMatchesSelector);
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
container.parentNode.removeChild(container);
ok(!document.mozFullScreen, "36. Should exit full-screen mode after removing full-screen element ancestor from document");
is(document.mozFullScreenElement, null, "37. Should not have a full-screen element again.");
break;
}
case 7: {
ok(!document.mozFullScreen, "38. Should be back in non-full-screen mode (third time)");
setRequireTrustedContext(true);
fullscreendenied = false;
fullScreenElement().mozRequestFullScreen();
setTimeout(
function() {
ok(fullscreendenied, "Request for fullscreen should have been denied because calling context isn't trusted");
ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
fullScreenElement().appendChild(button);
sendMouseClick(button);
}, 0);
break;
}
case 8: {
ok(document.mozFullScreen, "Moved to full-screen after mouse click");
document.mozCancelFullScreen();
ok(document.mozFullScreen, "Should still be in full-screen mode, because calling context isn't trusted.");
setRequireTrustedContext(false);
document.mozCancelFullScreen();
ok(!document.mozFullScreen, "Should have left full-screen mode.");
break;
}
case 9: {
ok(!document.mozFullScreen, "Should have left full-screen mode (last time).");
SpecialPowers.setBoolPref("full-screen-api.enabled", false);
is(document.mozFullScreenEnabled, false, "document.mozFullScreenEnabled should be false if full-screen-api.enabled is false");
fullscreendenied = false;
fullScreenElement().mozRequestFullScreen();
setTimeout(
function() {
ok(!document.mozFullScreen, "Should still be in normal mode, because pref is not enabled.");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
is(document.mozFullScreenEnabled, true, "document.mozFullScreenEnabled should be true if full-screen-api.enabled is true");
iframe = document.createElement("iframe");
fullScreenElement().appendChild(iframe);
iframe.src = iframeContents;
ok(!document.mozFullScreen, "Should still be in normal mode, because iframe did not have mozallowfullscreen attribute.");
fullScreenElement().removeChild(iframe);
iframe = null;
// Set timeout for calling finish(), so that any pending "mozfullscreenchange" events
// would have a chance to fire.
setTimeout(function(){opener.nextTest();}, 0);
}, 0);
break;
}
default: {
ok(false, "Should not receive any more fullscreenchange events!");
}
}
fullScreenChangeCount++;
function enter1(event) {
ok(document.mozFullScreen, "1. Should be in full-screen mode (first time)");
is(event.target, document, "2. Event target should be full-screen document #1");
is(document.mozFullScreenElement, fullScreenElement(), "3. Full-screen element should be div element.");
ok(document.mozFullScreenElement.mozMatchesSelector(":-moz-full-screen"), "4. FSE should match :-moz-full-screen");
var fse = fullScreenElement();
addFullscreenChangeContinuation("exit", exit1);
fse.parentNode.removeChild(fse);
is(document.mozFullScreenElement, null, "5. Full-screen element should be null after removing.");
ok(!document.mozFullScreen, "6. Should have left full-screen mode when we remove full-screen element");
document.body.appendChild(fse);
ok(!document.mozFullScreen, "7. Should not return to full-screen mode when re-adding former FSE");
is(document.mozFullScreenElement, null, "8. Full-screen element should still be null after re-adding former FSE.");
}
document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
document.addEventListener("mozfullscreenchange", fullScreenChange, false);
function exit1(event) {
ok(!document.mozFullScreen, "9. Should have left full-screen mode (first time)");
is(event.target, document, "10. Event target should be full-screen document #2");
is(document.mozFullScreenElement, null, "11. Full-screen element should be null.");
iframe = document.createElement("iframe");
iframe.mozAllowFullScreen = true;
addFullscreenChangeContinuation("enter", enter2);
document.body.appendChild(iframe);
iframe.src = iframeContents;
}
function enter2(event) {
ok(document.mozFullScreen, "12. Should be back in full-screen mode (second time)");
is(event.target, document, "13. Event target should be full-screen document #3");
is(document.mozFullScreenElement, iframe, "14. Full-screen element should be iframe element.");
is(iframe.contentDocument.mozFullScreenElement, iframe.contentDocument.body, "15. Full-screen element in subframe should be body");
// The iframe's body is full-screen. Cancel full-screen in the subdocument to return
// the full-screen element to the previous full-screen element. This causes
// a fullscreenchange event.
addFullscreenChangeContinuation("exit", exit2);
document.mozCancelFullScreen();
}
function exit2(event) {
ok(!document.mozFullScreen, "16. Should have left full-screen when canceling fullscreen in ancestor document.");
is(document.mozFullScreenElement, null, "17. Full-screen element should have rolled back.");
is(iframe.contentDocument.mozFullScreenElement, null, "18. Full-screen element in subframe should be null");
addFullscreenChangeContinuation("enter", enter3);
fullScreenElement().mozRequestFullScreen();
}
function enter3(event) {
ok(document.mozFullScreen, "19. Should be back in full-screen mode (second time)");
is(event.target, document, "20. Event target should be full-screen document #3");
is(document.mozFullScreenElement, fullScreenElement(), "21. Full-screen element should be div.");
// Transplant the FSE into subdoc. Should exit full-screen.
addFullscreenChangeContinuation("exit", exit3);
var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
var fse = fullScreenElement();
_innerFrame.contentDocument.body.appendChild(fse);
ok(!document.mozFullScreen, "22. Should exit full-screen after transplanting FSE");
is(document.mozFullScreenElement, null, "23. Full-screen element transplanted, should be null.");
is(iframe.contentDocument.mozFullScreenElement, null, "24. Full-screen element in outer frame should be null.");
is(_innerFrame.contentDocument.mozFullScreenElement, null, "25. Full-screen element in inner frame should be null.");
ok(!iframe.contentDocument.mozFullScreen, "26. Outer frame should not acquire full-screen status.");
ok(!_innerFrame.contentDocument.mozFullScreen, "27. Inner frame should not acquire full-screen status.");
document.body.appendChild(fse);
}
function exit3(event) {
ok(!document.mozFullScreen, "28. Should be back in non-full-screen mode (second time)");
is(event.target, document, "29. Event target should be full-screen document #4");
is(document.mozFullScreenElement, null, "30. Full-screen element should be null.");
document.body.removeChild(iframe);
iframe = null;
// Do a request out of document. It should be denied.
// Continue test in the following mozfullscreenerror handler.
outOfDocElement = document.createElement("div");
addFullscreenErrorContinuation(error1);
outOfDocElement.mozRequestFullScreen();
}
function error1(event) {
ok(!document.mozFullScreen, "31. Requests for full-screen from not-in-doc elements should fail.");
container = document.createElement("div");
inDocElement = document.createElement("div");
container.appendChild(inDocElement);
fullScreenElement().appendChild(container);
addFullscreenChangeContinuation("enter", enter4);
inDocElement.mozRequestFullScreen();
}
function enter4(event) {
ok(document.mozFullScreen, "32. Should still be in full-screen mode (third time)");
is(event.target, document, "33. Event target should be full-screen document #5");
is(document.mozFullScreenElement, inDocElement, "35. FSE should be inDocElement.");
var n = container;
do {
ok(n.mozMatchesSelector(":-moz-full-screen-ancestor"), "Ancestor " + n + " should match :-moz-full-screen-ancestor")
n = n.parentNode;
} while (n && n.mozMatchesSelector);
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
addFullscreenChangeContinuation("exit", exit4);
container.parentNode.removeChild(container);
ok(!document.mozFullScreen, "36. Should exit full-screen mode after removing full-screen element ancestor from document");
is(document.mozFullScreenElement, null, "37. Should not have a full-screen element again.");
}
function exit4(event) {
ok(!document.mozFullScreen, "38. Should be back in non-full-screen mode (third time)");
setRequireTrustedContext(true);
addFullscreenErrorContinuation(error2);
fullScreenElement().mozRequestFullScreen();
}
function error2(event) {
ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
fullScreenElement().appendChild(button);
addFullscreenChangeContinuation("enter", enter5);
sendMouseClick(button);
}
function enter5(event) {
ok(document.mozFullScreen, "Moved to full-screen after mouse click");
addFullscreenChangeContinuation("exit", exit5);
document.mozCancelFullScreen();
ok(document.mozFullScreen, "Should still be in full-screen mode, because calling context isn't trusted.");
setRequireTrustedContext(false);
document.mozCancelFullScreen();
ok(!document.mozFullScreen, "Should have left full-screen mode.");
}
function exit5(event) {
ok(!document.mozFullScreen, "Should have left full-screen mode (last time).");
SpecialPowers.setBoolPref("full-screen-api.enabled", false);
is(document.mozFullScreenEnabled, false, "document.mozFullScreenEnabled should be false if full-screen-api.enabled is false");
addFullscreenErrorContinuation(error3);
fullScreenElement().mozRequestFullScreen();
}
function error3(event) {
ok(!document.mozFullScreen, "Should still be in normal mode, because pref is not enabled.");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
is(document.mozFullScreenEnabled, true, "document.mozFullScreenEnabled should be true if full-screen-api.enabled is true");
opener.nextTest();
}
function begin() {
addFullscreenChangeContinuation("enter", enter1);
fullScreenElement().mozRequestFullScreen();
}

View File

@ -9,6 +9,7 @@ Test DOM full-screen API.
<head>
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body {
background-color: black;
@ -29,10 +30,6 @@ function is(a, b, msg) {
opener.is(a, b, "[denied] " + msg);
}
var fullscreendenied = false;
document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
var gotFullScreenChange = false;
function begin() {
@ -46,46 +43,42 @@ function begin() {
// Request full-screen from a non trusted context (this script isn't a user
// generated event!).
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
fullscreendenied = false;
document.body.mozRequestFullScreen();
setTimeout(
addFullscreenErrorContinuation(
function() {
ok(!document.mozFullScreen, "Should not grant request in non-trusted context");
ok(fullscreendenied, "Request in non-trusted event handler should be denied");
// Test requesting full-screen mode in a long-running user-generated event handler.
// The request in the key handler should not be granted.
window.addEventListener("keypress", keyHandler, false);
synthesizeKey("VK_A", {});
}, 0);
});
document.body.mozRequestFullScreen();
}
function keyHandler(event) {
window.removeEventListener("keypress", keyHandler, false);
// Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
// our request for full-screen mode should be rejected.
var end = (new Date()).getTime() + 2000;
while ((new Date()).getTime() < end) {
; // Wait...
}
fullscreendenied = false;
document.body.mozRequestFullScreen();
setTimeout(
addFullscreenErrorContinuation(
function() {
ok(fullscreendenied, "Request in long running event handler should be denied");
ok(!document.mozFullScreen, "Should not grant request in long-running event handler.");
// Disable the requirement for trusted contexts only, so the tests are easier
// to write.
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// Create an iframe without a mozallowfullscreen attribute, whose contents requests
// full-screen. The request should be denied, and we should not receive a fullscreenchange
// event in this document.
var iframe = document.createElement("iframe");
iframe.src = "file_fullscreen-denied-inner.html";
document.body.appendChild(iframe);
}, 0);
});
document.body.mozRequestFullScreen();
}
function finish() {

View File

@ -10,6 +10,8 @@ exit DOM full-screen mode.
<head>
<title>Test for Bug 700764</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body:-moz-full-screen, div:-moz-full-screen {
background-color: red;
@ -35,14 +37,12 @@ function finish() {
function fullscreenchange1(event) {
ok(document.mozFullScreen, "Should have entered full-screen mode");
is(document.mozFullScreenElement, document.body, "FSE should be doc");
document.removeEventListener("mozfullscreenchange", fullscreenchange1, false);
document.addEventListener("mozfullscreenchange", fullscreenchange2, false);
addFullscreenChangeContinuation("exit", fullscreenchange2);
ok(!document.getElementById("subdoc").contentWindow.escKeySent, "Should not yet have sent ESC key press.");
document.getElementById("subdoc").contentWindow.startTest();
}
function fullscreenchange2(event) {
document.removeEventListener("mozfullscreenchange", fullscreenchange2, false);
ok(document.getElementById("subdoc").contentWindow.escKeySent, "Should have sent ESC key press.");
ok(!document.getElementById("subdoc").contentWindow.escKeyReceived, "ESC key press to exit should not be delivered.");
ok(!document.mozFullScreen, "Should have left full-screen mode on ESC key press");
@ -50,7 +50,7 @@ function fullscreenchange2(event) {
}
function begin() {
document.addEventListener("mozfullscreenchange", fullscreenchange1, false);
addFullscreenChangeContinuation("enter", fullscreenchange1);
document.body.mozRequestFullScreen();
}

View File

@ -15,6 +15,7 @@ Test plugins with DOM full-screen API:
<head>
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body:-moz-full-screen, div:-moz-full-screen {
background-color: red;
@ -80,29 +81,26 @@ function startTest() {
if (isMacOs) {
// Running on MacOS, all plugins are effectively windowless, request for full-screen should be granted.
// Continue test in the (mac-specific) "mozfullscreenchange" handler.
document.addEventListener("mozfullscreenchange", macFullScreenChange, false);
return;
addFullscreenChangeContinuation("enter", macFullScreenChange1);
} else {
// Non-MacOS, request should be denied, carry on the test after receiving error event.
document.addEventListener("mozfullscreenerror", nonMacTest, false);
addFullscreenErrorContinuation(nonMacTest);
}
}
function nonMacTest() {
document.removeEventListener("mozfullscreenerror", nonMacTest, false);
ok(!document.mozFullScreen, "Request for full-screen with focused windowed plugin should be denied.");
// Focus a regular html element, and re-request full-screen, request should be granted.
e("windowless-plugin").focus();
document.addEventListener("mozfullscreenchange", nonMacTest2, false);
addFullscreenChangeContinuation("enter", nonMacTest2);
document.body.mozRequestFullScreen();
}
function nonMacTest2() {
document.removeEventListener("mozfullscreenchange", nonMacTest2, false);
ok(document.mozFullScreen, "Request for full-screen with non-plugin focused should be granted.");
// Focus a windowed plugin, full-screen should be revoked.
document.addEventListener("mozfullscreenchange", nonMacTest3, false);
addFullscreenChangeContinuation("exit", nonMacTest3);
e("windowed-plugin").focus();
}
@ -120,36 +118,27 @@ function createWindowedPlugin() {
return p;
}
function macFullScreenChange(event) {
switch (fullScreenChangeCount) {
case 0: {
ok(document.mozFullScreen, "Requests for full-screen with focused windowed plugins should be granted on MacOS");
// Create a new windowed plugin, and add that to the document. Should *not* exit full-screen mode on MacOS.
windowedPlugin = createWindowedPlugin();
document.body.appendChild(windowedPlugin);
// Focus windowed plugin. Should not exit full-screen mode on MacOS.
windowedPlugin.focus();
setTimeout(
function() {
ok(document.mozFullScreen, "Adding & focusing a windowed plugin to document should not cause full-screen to exit on MacOS.");
document.mozCancelFullScreen();
}, 0);
break;
}
case 1: {
ok(!document.mozFullScreen, "Should have left full-screen mode after calling document.mozCancelFullScreen().");
opener.nextTest();
break;
}
default: {
ok(false, "Should not receive any more fullscreenchange events!");
}
}
fullScreenChangeCount++;
function macFullScreenChange1(event) {
ok(document.mozFullScreen, "Requests for full-screen with focused windowed plugins should be granted on MacOS");
// Create a new windowed plugin, and add that to the document. Should *not* exit full-screen mode on MacOS.
windowedPlugin = createWindowedPlugin();
document.body.appendChild(windowedPlugin);
// Focus windowed plugin. Should not exit full-screen mode on MacOS.
windowedPlugin.focus();
setTimeout(
function() {
ok(document.mozFullScreen, "Adding & focusing a windowed plugin to document should not cause full-screen to exit on MacOS.");
addFullscreenChangeContinuation("exit", macFullScreenChange2);
document.mozCancelFullScreen();
}, 0);
}
function macFullScreenChange2(event) {
ok(!document.mozFullScreen, "Should have left full-screen mode after calling document.mozCancelFullScreen().");
opener.nextTest();
}
</script>

View File

@ -19,6 +19,8 @@ Tests:
<head>
<title>Test for Bug 700764</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
</head>
<body>
@ -36,18 +38,28 @@ Tests:
function ok(condition, msg) {
opener.ok(condition, "[rollback] " + msg);
if (!condition) {
opener.finish();
}
}
function is(a, b, msg) {
opener.is(a, b, "[rollback] " + msg);
if (a != b) {
opener.finish();
}
}
function addListener(type, f) {
document.addEventListener("mozfullscreen" + type, f, false);
function enterFullscreen(element, callback) {
addFullscreenChangeContinuation("enter", callback);
element.focus();
element.mozRequestFullScreen();
}
function removeListener(type, f) {
document.removeEventListener("mozfullscreen" + type, f, false);
function revertFullscreen(doc, callback) {
ok(doc.mozFullScreenElement != null, "Should only exit fullscreen on a fullscreen doc");
addFullscreenChangeContinuation("exit", callback, doc);
doc.mozCancelFullScreen();
}
function e(id) {
@ -60,67 +72,52 @@ function requestFullscreen(element) {
}
function begin() {
addListener("change", change1);
e("fse").mozRequestFullScreen();
enterFullscreen(e("fse"), change1);
}
function change1() {
removeListener("change", change1);
addListener("error", error1);
is(document.mozFullScreenElement, e("fse"), "Body should be FSE");
// Request full-screen from element not descendent from current FSE.
addFullscreenErrorContinuation(error1);
requestFullscreen(e("non-fse"));
}
function error1() {
removeListener("error", error1);
addListener("change", change2);
is(document.mozFullScreenElement, e("fse"), "FSE should not change");
var iframe = e("subdoc");
requestFullscreen(iframe.contentDocument.body);
enterFullscreen(iframe.contentDocument.body, change2);
}
function change2() {
removeListener("change", change2);
var iframe = e("subdoc");
is(document.mozFullScreenElement, iframe, "Subdoc container should be FSE.");
is(iframe.contentDocument.mozFullScreenElement, iframe.contentDocument.body, "Subdoc body should be FSE in subdoc");
addListener("change", change3);
iframe.contentDocument.mozCancelFullScreen();
revertFullscreen(document, change3);
}
function change3() {
removeListener("change", change3);
is(document.mozFullScreenElement, e("fse"), "FSE should rollback to FSE.");
addListener("change", change4);
document.mozCancelFullScreen();
revertFullscreen(document, change4);
}
function change4() {
removeListener("change", change4);
is(document.mozFullScreenElement, null, "Should have left full-screen entirely");
addListener("change", change5);
requestFullscreen(e("fse"));
enterFullscreen(e("fse"), change5);
}
function change5() {
removeListener("change", change5);
addListener("change", change6);
is(document.mozFullScreenElement, e("fse"), "FSE should be e('fse')");
requestFullscreen(e("fse-inner"));
enterFullscreen(e("fse-inner"), change6);
}
function change6() {
removeListener("change", change6);
addListener("change", change7);
addFullscreenChangeContinuation("exit", change7);
var element = e('fse-inner');
is(document.mozFullScreenElement, element, "FSE should be e('fse-inner')");
element.parentNode.removeChild(element);
}
function change7() {
removeListener("change", change7);
is(document.mozFullScreenElement, null, "Should have fully exited full-screen mode when removed FSE from doc");
opener.nextTest();
}

View File

@ -0,0 +1,104 @@
// Remember the window size in non-fullscreen mode.
var normalSize = new function() {
this.w = window.outerWidth;
this.h = window.outerHeight;
}();
// Returns true if the window occupies the entire screen.
// Note this only returns true once the transition from normal to
// fullscreen mode is complete.
function inFullscreenMode() {
return window.outerWidth == window.screen.width &&
window.outerHeight == window.screen.height;
}
// Returns true if the window is in normal mode, i.e. non fullscreen mode.
// Note this only returns true once the transition from fullscreen back to
// normal mode is complete.
function inNormalMode() {
return window.outerWidth == normalSize.w &&
window.outerHeight == normalSize.h;
}
function ok(condition, msg) {
opener.ok(condition, "[rollback] " + msg);
if (!condition) {
opener.finish();
}
}
// On Linux we sometimes receive fullscreenchange events before the window
// has finished transitioning to fullscreen. This can cause problems and
// test failures, so work around it on Linux until we can get a proper fix.
const workAroundFullscreenTransition = navigator.userAgent.indexOf("Linux") != -1;
// Adds a listener that will be called once a fullscreen transition
// is complete. When type==='enter', callback is called when we've
// received a fullscreenchange event, and the fullscreen transition is
// complete. When type==='exit', callback is called when we've
// received a fullscreenchange event and the window dimensions match
// the window dimensions when the window opened (so don't resize the
// window while running your test!). inDoc is the document which
// the listeners are added on, if absent, the listeners are added to
// the current document.
function addFullscreenChangeContinuation(type, callback, inDoc) {
var doc = inDoc || document;
var listener = null;
if (type === "enter") {
// when entering fullscreen, ensure we don't call 'callback' until the
// enter transition is complete.
listener = function(event) {
doc.removeEventListener("mozfullscreenchange", listener, false);
if (!workAroundFullscreenTransition) {
callback(event);
return;
}
if (!inFullscreenMode()) {
opener.todo(false, "fullscreenchange before entering fullscreen complete! " +
" window.fullScreen=" + window.fullScreen +
" normal=(" + normalSize.w + "," + normalSize.h + ")" +
" outerWidth=" + window.outerWidth + " width=" + window.screen.width +
" outerHeight=" + window.outerHeight + " height=" + window.screen.height);
setTimeout(function(){listener(event);}, 100);
return;
}
setTimeout(function(){callback(event)}, 0);
};
} else if (type === "exit") {
listener = function(event) {
doc.removeEventListener("mozfullscreenchange", listener, false);
if (!workAroundFullscreenTransition) {
callback(event);
return;
}
if (!document.mozFullScreenElement && !inNormalMode()) {
opener.todo(false, "fullscreenchange before exiting fullscreen complete! " +
" window.fullScreen=" + window.fullScreen +
" normal=(" + normalSize.w + "," + normalSize.h + ")" +
" outerWidth=" + window.outerWidth + " width=" + window.screen.width +
" outerHeight=" + window.outerHeight + " height=" + window.screen.height);
// 'document' (*not* 'doc') has no fullscreen element, so we're trying
// to completely exit fullscreen mode. Wait until the transition
// to normal mode is complete before calling callback.
setTimeout(function(){listener(event);}, 100);
return;
}
opener.info("[rollback] Exited fullscreen");
setTimeout(function(){callback(event);}, 0);
};
} else {
throw "'type' must be either 'enter', or 'exit'.";
}
doc.addEventListener("mozfullscreenchange", listener, false);
}
// Calls |callback| when the next fullscreenerror is dispatched to inDoc||document.
function addFullscreenErrorContinuation(callback, inDoc) {
var doc = inDoc || document;
var listener = function(event) {
doc.removeEventListener("mozfullscreenerror", listener, false);
setTimeout(function(){callback(event);}, 0);
};
doc.addEventListener("mozfullscreenerror", listener, false);
}

View File

@ -1390,16 +1390,6 @@ nsDocShell::LoadURI(nsIURI * aURI,
}
} // parent
} //parentDS
else {
// This is the root docshell. If we got here while
// executing an onLoad Handler,this load will not go
// into session history.
bool inOnLoadHandler=false;
GetIsExecutingOnLoadHandler(&inOnLoadHandler);
if (inOnLoadHandler) {
loadType = LOAD_NORMAL_REPLACE;
}
}
} // !shEntry
if (shEntry) {
@ -6487,7 +6477,7 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
// Notify the ContentViewer that the Document has finished loading. This
// will cause any OnLoad(...) and PopState(...) handlers to fire.
// will cause any OnLoad(...) handlers to fire.
if (!mEODForCurrentDocument && mContentViewer) {
mIsExecutingOnLoadHandler = true;
mContentViewer->LoadComplete(aStatus);

View File

@ -95,6 +95,8 @@ MOCHITEST_CHROME_FILES = \
test_mozFrameType.xul \
mozFrameType_window.xul \
test_bug789773.xul \
test_bug754029.xul \
bug754029_window.xul \
$(NULL)
MOCHITEST_CHROME_FILES += \

View File

@ -109,7 +109,7 @@ function step1B(aWebProgress, aRequest, aLocation, aFlags) {
function step2A() {
gListener.callback = step2B;
content.location = kSecureURI;
content.location.assign(kSecureURI);
}
function step2B(aWebProgress, aRequest, aLocation, aFlags) {
@ -139,7 +139,7 @@ function step2B(aWebProgress, aRequest, aLocation, aFlags) {
function step3A() {
gListener.callback = step3B;
content.location += "#foo";
content.location.assign("#foo");
}
function step3B(aWebProgress, aRequest, aLocation, aFlags) {

View File

@ -0,0 +1,307 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="754029Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="600"
height="600"
onload="startup();"
title="bug 754029 test">
<script type="application/javascript" src="docshell_helpers.js"></script>
<script type="application/javascript"><![CDATA[
const _kDocshellTestNavURI =
"http://test1.example.org:80/tests/docshell/test/navigation/";
const kBlankURI = _kDocshellTestNavURI + "blank.html";
const kRedirectURI = _kDocshellTestNavURI + "file_bug754029.html";
function startup() {
var browser = document.getElementById("content");
browser.addEventListener("load", contentOnLoad, true);
content.location.href = kBlankURI + "?start";
}
function contentOnLoad(aEvent) {
is(aEvent.originalTarget.nodeName, "#document", "Loading a document.");
var browser = document.getElementById("content");
var sessionHistory = browser.sessionHistory;
var _contentLoadURI = function (aHref) {content.location.href = aHref;}
function contentLoadURI(aHref) {
setTimeout(_contentLoadURI, 0, aHref);
}
function indexToSearch(aSessionHistory, aIndex) {
return "?" + aSessionHistory.getEntryAtIndex(aIndex, false)
.URI
.QueryInterface(Components.interfaces.nsIURL)
.query;
}
switch(content.location.search) {
case "?start":
// Expected SH entries are:
// 1 * <blank.html ?start>
is(content.history.length, 1, "Initial <about:blank> is replaced.");
// Requesting <file_bug754029.html?test1>
contentLoadURI(kRedirectURI + "?test1");
break;
/*****************************************************************************
* Test 1: Load a JS redirecting page; |location.href = ...| is directly in
* <script></script> tag.
*
* Expected Result: The redirected page should replace the redirecting page's
* session history.
****************************************************************************/
case "?test1":
// We can't catch this onload, because redirection is earlier than
// firing load event. That is OK.
// Expected SH entries are:
// 0 <?start>
// 1 * <?test1>
break;
case "?result1":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 * <?result1>
is(sessionHistory.count, 2, "<?result1>: SH's length");
is(sessionHistory.index, 1, "<?result1>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?result1",
"Check if the current SH entry is <?result1>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?start",
"Check if the previous SH entry is not <?test1> but <?start>");
// Requesting <file_bug754029.html?test2>
contentLoadURI(kRedirectURI + "?test2");
break;
/*****************************************************************************
* Test 2: Load a JS redirecting page; |location.href = ...| is in
* "load" event handler.
*
* Expected Result: Replace
****************************************************************************/
case "?test2":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// 2 * <?test2>
is(sessionHistory.count, 3, "<?test2>: SH's length");
is(sessionHistory.index, 2, "<?test2>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?test2",
"Check if the current SH entry is <?test2>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?result1",
"Check if the previous SH entry is <?result1>");
break;
case "?result2":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// x <?test2> // replaced.
// 2 * <?result2>
is(sessionHistory.count, 3, "<?result2>: SH's length");
is(sessionHistory.index, 2, "<?result2>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?result2",
"Check if the current SH entry is <?result2>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?result1",
"Check if the previous SH entry is not <?test2> but <?resutl1>");
contentLoadURI(kRedirectURI + "?test3");
break;
/*****************************************************************************
* Test 3: Load a JS redirecting page; |location.href = ...| is in
* setTimeout(...)'s call back.
*
* Expected Result: Not replace
****************************************************************************/
case "?test3":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// x <?test2> // replaced.
// 2 <?result2>
// 3 * <?test3>
is(sessionHistory.count, 4, "<?test3>: SH's length");
is(sessionHistory.index, 3, "<?test3>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?test3",
"Check if the current SH entry is <?test3>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?result2",
"Check if the previous SH entry is <?result2>");
break;
case "?result3":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// x <?test2> // replaced.
// 2 <?result2>
// 3 <?test3> // not replaced.
// 4 * <?result3>
is(sessionHistory.count, 5, "<?result3>: SH's length");
is(sessionHistory.index, 4, "<?result3>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?result3",
"Check if the current SH entry is <?result3>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?test3",
"Check if <?test3> exists.");
contentLoadURI(kRedirectURI + "?test4");
break;
/*****************************************************************************
* Test 4: Load a JS redirecting page; setTimeout(...)'s callback
* is inserting a new script element into the document. And the
* inserted script contains |location.href = ...|.
*
* See also:
* https://bugzilla.mozilla.org/attachment.cgi?id=622899
*
* Expected Result: Not replace
****************************************************************************/
case "?test4":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// x <?test2> // replaced.
// 2 <?result2>
// 3 <?test3> // not replaced
// 4 <?result3>
// 5 * <?test4>
is(sessionHistory.count, 6, "<?test4>: SH's length");
is(sessionHistory.index, 5, "<?test4>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?test4",
"Check if the current SH entry is <?test4>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?result3",
"Check if the previous SH entry is <?result3>");
break;
case "?result4":
// Expected SH entries are:
// 0 <?start>
// x <?test1> // replaced.
// 1 <?result1>
// x <?test2> // replaced.
// 2 <?result2>
// 3 <?test3> // not replaced.
// 4 <?result3>
// 5 <?test4> // not replaced.
// 6 * <?result4>
is(sessionHistory.count, 7, "<?test4>: SH's length");
is(sessionHistory.index, 6, "<?test4>: Current entry's index");
is(indexToSearch(sessionHistory, sessionHistory.index),
"?result4",
"Check if the current SH entry is <?test4>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?test4",
"Check if <?test4> exists.");
contentLoadURI(kRedirectURI + "?testDOMContentLoaded");
break;
/*****************************************************************************
* Test 5: Setting location.href in onDOMContentLoaded() should REPLACE.
****************************************************************************/
case "?testDOMContentLoaded":
break;
case "?resultDOMContentLoaded":
is(indexToSearch(sessionHistory, sessionHistory.index),
"?resultDOMContentLoaded",
"Check if the current SH entry is <?resultDOMContentLoaded>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?result4",
"Check if the perevious entry is not <?testDOMContentLoaded> but " +
"<?result4>.");
contentLoadURI(kRedirectURI + "?testPageshow");
break;
/*****************************************************************************
* Test 6: Setting location.href in onpageshow() should REPLACE.
****************************************************************************/
case "?testPageshow":
break;
case "?resultPageshow":
is(indexToSearch(sessionHistory, sessionHistory.index),
"?resultPageshow",
"Check if the current SH entry is <?resultPageshow>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?resultDOMContentLoaded",
"Check if the perevious entry is not <?testPageshow> but " +
"<?resultDOMContentLoaded>.");
contentLoadURI(kRedirectURI + "?testReadystatechange");
break;
/*****************************************************************************
* Test 7: Setting location.href in onreadystatechange() should REPLACE.
****************************************************************************/
case "?testReadystatechange":
break;
case "?resultReadystatechange":
is(indexToSearch(sessionHistory, sessionHistory.index),
"?resultReadystatechange",
"Check if the current SH entry is <?resultReadystatechange>");
is(indexToSearch(sessionHistory, sessionHistory.index - 1),
"?resultPageshow",
"Check if the perevious entry is not <?testReadystatechange> but " +
"<?resultPageshow>.");
finish();
break;
}
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet
href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=754029.xul
-->
<window title="Mozilla Bug 754029"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 754029</title>
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=754029">
Mozilla Bug 754029</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<script class="testbody" type="application/javascript">
<![CDATA[
/** Test for Bug 754029 **/
SimpleTest.waitForExplicitFinish();
window.open("bug754029_window.xul", "bug754029",
"chrome,width=600,height=600");
]]>
</script>
</window>

View File

@ -46,6 +46,7 @@ MOCHITEST_FILES = \
frame3.html \
goback.html \
file_bug534178.html \
file_bug754029.html \
$(NULL)
ifneq (mobile/android,$(MOZ_BUILD_APP))

View File

@ -0,0 +1,84 @@
<html>
<head>
<meta http-equiv="content-type" Content="text/html; charset=utf-8">
</head>
<body>
<script>
// inline <script> tag redirection.
function test1() {
location.href = "blank.html?result1";
}
// onload() handler redirection.
function test2() {
addEventListener("load",
function(aEvent) {
location.href = "blank.html?result2";
},
false);
}
// setTimeout() 100 milisec redirection.
function test3() {
setTimeout(function() {
location.href = "blank.html?result3";
},
100);
}
// setTimeout() 100 milisec + inline <script> tag redirection.
function test4() {
setTimeout(function() {
var ns = document.createElement("script");
var nt = document.createTextNode(
"location = 'blank.html?result4'"
);
ns.appendChild(nt);
document.documentElement.appendChild(ns);
},
100);
}
// DOMContentLoaded
function testDOMContentLoaded() {
addEventListener("DOMContentLoaded",
function(aEvent) {
location.href = "blank.html?resultDOMContentLoaded";
},
false);
}
// pageshow
function testPageshow() {
addEventListener("pageshow",
function(aEvent) {
location.href = "blank.html?resultPageshow";
},
false);
}
// readystatechange for "complete"
function testReadystatechange() {
document.onreadystatechange =
function() {
if ("complete" == document.readyState) {
location.href = "blank.html?resultReadystatechange";
}
};
}
switch(location.search) {
case "?test1": test1(); break;
case "?test2": test2(); break;
case "?test3": test3(); break;
case "?test4": test4(); break;
case "?testDOMContentLoaded": testDOMContentLoaded(); break;
case "?testPageshow" : testPageshow(); break;
case "?testReadystatechange": testReadystatechange(); break;
default: throw "Unexpected!";
}
</script>
</body>
</html>

View File

@ -35,6 +35,7 @@
#include "nsJSUtils.h"
#include "jsfriendapi.h"
#include "nsContentUtils.h"
#include "nsEventStateManager.h"
static nsresult
GetContextFromStack(nsIJSContextStack *aStack, JSContext **aContext)
@ -521,8 +522,71 @@ nsLocation::SetHref(const nsAString& aHref)
if (NS_FAILED(GetContextFromStack(stack, &cx)))
return NS_ERROR_FAILURE;
// According to HTML5 spec, |location.href = ...| must act as if
// it were |location.replace(...)| before the page load finishes.
//
// http://www.w3.org/TR/2011/WD-html5-20110113/history.html#location
//
// > The href attribute must return the current address of the
// > associated Document object, as an absolute URL.
// >
// > On setting, if the Location object's associated Document
// > object has completely loaded, then the user agent must act
// > as if the assign() method had been called with the new value
// > as its argument. Otherwise, the user agent must act as if
// > the replace() method had been called with the new value as its
// > argument.
//
// Note: The spec says the condition is "Document object has completely
// loaded", but that may break some websites. If the user was
// willing to move from one page to another, and was able to do
// so, we should not overwrite the session history entry even
// if the loading has not finished yet.
//
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=17041
//
// See bug 39938, bug 72197, bug 178729 and bug 754029.
// About other browsers:
// http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2010-July/027372.html
bool replace = false;
if (!nsEventStateManager::IsHandlingUserInput()) {
// "completely loaded" is defined at:
//
// http://www.w3.org/TR/2012/WD-html5-20120329/the-end.html#completely-loaded
//
// > 7. document readiness to "complete", and fire "load".
// >
// > 8. "pageshow"
// >
// > 9. ApplicationCache
// >
// > 10. Print in the pending list.
// >
// > 12. Queue a task to mark the Document as completely loaded.
//
// Since Gecko doesn't (yet) have a flag corresponding to no. "12.
// ... completely loaded", here the logic is a little tricky.
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
nsCOMPtr<nsIDocument> document(do_GetInterface(docShell));
if (document) {
replace =
nsIDocument::READYSTATE_COMPLETE != document->GetReadyStateEnum();
// nsIDocShell::isExecutingOnLoadHandler is true while
// the document is handling "load", "pageshow",
// "readystatechange" for "complete" and "beforeprint"/"afterprint".
//
// Maybe this API property needs a better name.
if (!replace) {
docShell->GetIsExecutingOnLoadHandler(&replace);
}
}
}
if (cx) {
rv = SetHrefWithContext(cx, aHref, false);
rv = SetHrefWithContext(cx, aHref, replace);
} else {
rv = GetHref(oldHref);
@ -532,7 +596,7 @@ nsLocation::SetHref(const nsAString& aHref)
rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
if (oldUri) {
rv = SetHrefWithBase(aHref, oldUri, false);
rv = SetHrefWithBase(aHref, oldUri, replace);
}
}
}
@ -563,8 +627,6 @@ nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
nsresult result;
nsCOMPtr<nsIURI> newUri;
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
nsAutoCString docCharset;
if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), aBase);
@ -572,41 +634,7 @@ nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
result = NS_NewURI(getter_AddRefs(newUri), aHref, nullptr, aBase);
if (newUri) {
/* Check with the scriptContext if it is currently processing a script tag.
* If so, this must be a <script> tag with a location.href in it.
* we want to do a replace load, in such a situation.
* In other cases, for example if a event handler or a JS timer
* had a location.href in it, we want to do a normal load,
* so that the new url will be appended to Session History.
* This solution is tricky. Hopefully it isn't going to bite
* anywhere else. This is part of solution for bug # 39938, 72197
*
*/
bool inScriptTag=false;
// Get JSContext from stack.
nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
if (stack) {
JSContext *cx;
result = GetContextFromStack(stack, &cx);
if (cx) {
nsIScriptContext *scriptContext =
nsJSUtils::GetDynamicScriptContext(cx);
if (scriptContext) {
if (scriptContext->GetProcessingScriptTag()) {
// Now check to make sure that the script is running in our window,
// since we only want to replace if the location is set by a
// <script> tag in the same window. See bug 178729.
nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
}
}
} //cx
} // stack
return SetURI(newUri, aReplace || inScriptTag);
return SetURI(newUri, aReplace);
}
return result;

View File

@ -558,7 +558,7 @@ BluetoothHfpManager::Connect(const nsAString& aDeviceObjectPath,
nsCOMPtr<nsIRILContentHelper> ril =
do_GetService("@mozilla.org/ril/content-helper;1");
NS_ENSURE_TRUE(ril, NS_ERROR_UNEXPECTED);
NS_ENSURE_TRUE(ril, false);
ril->EnumerateCalls(mListener->GetCallback());
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
@ -783,3 +783,9 @@ BluetoothHfpManager::OnConnectError()
// If connecting for some reason didn't work, restart listening
Listen();
}
void
BluetoothHfpManager::OnDisconnect()
{
NS_WARNING("GOT DISCONNECT!");
}

View File

@ -46,6 +46,7 @@ private:
void NotifySettings(const bool aConnected);
virtual void OnConnectSuccess() MOZ_OVERRIDE;
virtual void OnConnectError() MOZ_OVERRIDE;
virtual void OnDisconnect() MOZ_OVERRIDE;
int mCurrentVgs;
int mCurrentCallIndex;

View File

@ -656,3 +656,8 @@ void
BluetoothOppManager::OnConnectError()
{
}
void
BluetoothOppManager::OnDisconnect()
{
}

View File

@ -80,6 +80,7 @@ private:
void ReplyToPut(bool aFinal);
virtual void OnConnectSuccess() MOZ_OVERRIDE;
virtual void OnConnectError() MOZ_OVERRIDE;
virtual void OnDisconnect() MOZ_OVERRIDE;
bool mConnected;
int mConnectionId;

View File

@ -218,3 +218,8 @@ void
BluetoothScoManager::OnConnectError()
{
}
void
BluetoothScoManager::OnDisconnect()
{
}

View File

@ -39,6 +39,7 @@ private:
void CreateScoSocket(const nsAString& aDevicePath);
virtual void OnConnectSuccess() MOZ_OVERRIDE;
virtual void OnConnectError() MOZ_OVERRIDE;
virtual void OnDisconnect() MOZ_OVERRIDE;
bool mConnected;
};

View File

@ -714,7 +714,7 @@ SetJsObject(JSContext* aContext,
JSString* JsData = JS_NewStringCopyN(aContext,
NS_ConvertUTF16toUTF8(data).get(),
data.Length());
NS_ENSURE_TRUE(JsData, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(JsData, false);
v = STRING_TO_JSVAL(JsData);
} else if (aData[i].value().type() == BluetoothValue::Tuint32_t) {
int data = aData[i].value().get_uint32_t();

View File

@ -117,7 +117,7 @@ mozilla::dom::bluetooth::SetJsObject(JSContext* aContext,
JSString* JsData = JS_NewStringCopyN(aContext,
NS_ConvertUTF16toUTF8(data).get(),
data.Length());
NS_ENSURE_TRUE(JsData, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(JsData, false);
v = STRING_TO_JSVAL(JsData);
} else if (aData[i].value().type() == BluetoothValue::Tuint32_t) {
int data = aData[i].value().get_uint32_t();

View File

@ -175,7 +175,7 @@ BluetoothServiceChildProcess::GetDevicePath(const nsAString& aAdapterPath,
aDevicePath = path;
return NS_OK;
return true;
}
nsresult

View File

@ -437,18 +437,18 @@ ContactManager.prototype = {
this.removeRequest(msg.requestID);
},
askPermission: function (aAccess, aReqeust, aAllowCallback, aCancelCallback) {
askPermission: function (aAccess, aRequest, aAllowCallback, aCancelCallback) {
if (DEBUG) debug("askPermission for contacts");
let requestID = this.getRequestId({
request: aReqeust,
request: aRequest,
allow: function() {
aAllowCallback();
}.bind(this),
cancel : function() {
if (aCancelCallback) {
aCancelCallback()
} else if (request) {
Services.DOMRequest.fireError(request, "Not Allowed");
} else if (aRequest) {
Services.DOMRequest.fireError(aRequest, "Not Allowed");
}
}.bind(this)
});

View File

@ -487,7 +487,7 @@ class ThreadLocalJSRuntime
JSObject* mGlobal;
static JSClass sGlobalClass;
static const unsigned sRuntimeHeapSize = 256 * 1024;
static const unsigned sRuntimeHeapSize = 512 * 1024;
ThreadLocalJSRuntime()
: mRuntime(NULL), mContext(NULL), mGlobal(NULL)

View File

@ -2552,9 +2552,15 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
if (!StoringSourceData())
return NS_OK;
// If we've already got a full decoder running, we have nothing to do
if (mDecoder && !mDecoder->IsSizeDecode())
// If we've already got a full decoder running, we'll spend a bit of time
// decoding because the caller want's an image soon.
if (mDecoder && !mDecoder->IsSizeDecode()) {
if (!mDecoded && !mInDecoder && mHasSourceData && aDecodeType == SOMEWHAT_SYNCHRONOUS) {
SAMPLE_LABEL_PRINTF("RasterImage", "DecodeABitOf", "%s", GetURIString());
DecodeWorker::Singleton()->DecodeABitOf(this);
}
return NS_OK;
}
// mFinishing protects against the case when we enter RequestDecode from
// ShutdownDecoder -- in that case, we're done with the decode, we're just

View File

@ -343,7 +343,7 @@ void imgRequest::AdjustPriority(imgRequestProxy *proxy, int32_t delta)
if (!GetStatusTracker().FirstConsumerIs(proxy))
return;
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mRequest);
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mChannel);
if (p)
p->AdjustPriority(delta);
}

View File

@ -582,7 +582,7 @@ AsyncChannel::MaybeHandleError(Result code, const char* channelName)
if (MsgProcessed == code)
return true;
const char* errorMsg;
const char* errorMsg = nullptr;
switch (code) {
case MsgNotKnown:
errorMsg = "Unknown message: not processed";
@ -618,7 +618,7 @@ AsyncChannel::MaybeHandleError(Result code, const char* channelName)
void
AsyncChannel::ReportConnectionError(const char* channelName) const
{
const char* errorMsg;
const char* errorMsg = nullptr;
switch (mChannelState) {
case ChannelClosed:
errorMsg = "Closed channel: cannot send/recv";

View File

@ -265,6 +265,8 @@ public:
mImpl->mConsumer->NotifySuccess();
} else if (mEvent == CONNECT_ERROR) {
mImpl->mConsumer->NotifyError();
} else if (mEvent == DISCONNECT) {
mImpl->mConsumer->NotifyDisconnect();
}
return NS_OK;
}
@ -326,6 +328,26 @@ private:
UnixSocketRawData* mData;
};
class SocketCloseTask : public nsRunnable
{
public:
SocketCloseTask(UnixSocketImpl* aImpl)
: mImpl(aImpl)
{
MOZ_ASSERT(aImpl);
}
NS_IMETHOD
Run()
{
mImpl->mConsumer->CloseSocket();
return NS_OK;
}
private:
UnixSocketImpl* mImpl;
};
class StartImplReadingTask : public Task
{
public:
@ -559,19 +581,21 @@ UnixSocketConsumer::SendSocketData(const nsACString& aStr)
void
UnixSocketConsumer::CloseSocket()
{
// Needed due to refcount change
MOZ_ASSERT(NS_IsMainThread());
if (!mImpl) {
return;
}
UnixSocketImpl* impl = mImpl;
// To make sure the owner doesn't die on the IOThread, remove pointer here
mImpl = nullptr;
// Line it up to be destructed on the IO Thread
impl->mConsumer.forget();
impl->StopTask();
// To make sure the owner doesn't die on the IOThread, remove pointer here
// Line it up to be destructed on the IO Thread
// Kill our pointer to it
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
NewRunnableFunction(DestroyImpl,
impl));
NotifyDisconnect();
}
void
@ -608,7 +632,8 @@ UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
mIncoming.forget();
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
mConsumer->CloseSocket();
nsRefPtr<SocketCloseTask> t = new SocketCloseTask(this);
NS_DispatchToMainThread(t);
return;
}
mIncoming->mData[ret] = 0;
@ -683,6 +708,15 @@ UnixSocketConsumer::NotifyError()
mConnectionStatus = SOCKET_DISCONNECTED;
OnConnectError();
}
void
UnixSocketConsumer::NotifyDisconnect()
{
MOZ_ASSERT(NS_IsMainThread());
mConnectionStatus = SOCKET_DISCONNECTED;
OnDisconnect();
}
bool
UnixSocketConsumer::ConnectSocket(UnixSocketConnector* aConnector,
const char* aAddress)

View File

@ -193,6 +193,10 @@ public:
*/
virtual void OnConnectError() = 0;
/**
* Callback for socket disconnect. Will be run on main thread.
*/
virtual void OnDisconnect() = 0;
/**
* Called by implementation to notify consumer of success.
@ -204,6 +208,10 @@ public:
*/
void NotifyError();
/**
* Called by implementation to notify consumer of disconnect.
*/
void NotifyDisconnect();
private:
UnixSocketImpl* mImpl;
SocketConnectionStatus mConnectionStatus;

View File

@ -882,7 +882,8 @@ pm_linux.$(OBJ_SUFFIX): CXXFLAGS += $(LINUX_HEADERS_INCLUDES)
endif
# Prepare self-hosted JS code for embedding
export:: selfhosted.out.h
export:: selfhosting
selfhosting:: selfhosted.out.h
selfhosting_srcs := \
$(srcdir)/builtin/array.js \

View File

@ -43,10 +43,9 @@ def main():
messages_file = sys.argv[2]
macros_file = sys.argv[3]
source_files = sys.argv[4:]
combined_file = 'combined.js'
combined_file = 'selfhosted.js'
replaceErrorMsgs(source_files, messages_file, combined_file)
js2c.JS2C([combined_file, macros_file], [output_file], { 'TYPE': 'CORE', 'COMPRESSION': 'off', 'DEBUG':debug })
os.remove(combined_file)
if __name__ == "__main__":
main()

View File

@ -1857,7 +1857,13 @@ Parser::processDirectives(ParseNode *stmts)
bool isDirective = IsEscapeFreeStringLiteral(directive);
JSAtom *atom = directive.atom();
TokenKind next = tokenStream.peekTokenSameLine();
if (next != TOK_EOF && next != TOK_EOL && next != TOK_SEMI && next != TOK_RC) {
// We need to check whether the directive ends explicitly or implicitly
// due to ASI. In the latter case, the expression must not continue on
// the next line.
if (next != TOK_EOF && next != TOK_SEMI && next != TOK_RC &&
(next != TOK_EOL || TokenContinuesStringExpression(tokenStream.peekToken())))
{
freeTree(stringNode);
if (next == TOK_ERROR)
return false;

View File

@ -181,6 +181,41 @@ TokenKindIsAssignment(TokenKind tt)
return TOK_ASSIGNMENT_START <= tt && tt <= TOK_ASSIGNMENT_LAST;
}
inline bool
TokenContinuesStringExpression(TokenKind tt)
{
switch (tt) {
// comma expression
case TOK_COMMA:
// conditional expression
case TOK_HOOK:
// binary expression
case TOK_OR:
case TOK_AND:
case TOK_BITOR:
case TOK_BITXOR:
case TOK_BITAND:
case TOK_PLUS:
case TOK_MINUS:
case TOK_STAR:
case TOK_DIV:
case TOK_MOD:
case TOK_IN:
case TOK_INSTANCEOF:
// member expression
case TOK_DOT:
case TOK_LB:
case TOK_LP:
case TOK_DBLDOT:
return true;
default:
return TokenKindIsEquality(tt) ||
TokenKindIsRelational(tt) ||
TokenKindIsShift(tt) ||
TokenKindIsAssignment(tt);
}
}
inline bool
TokenKindIsDecl(TokenKind tt)
{

View File

@ -0,0 +1,83 @@
load(libdir + "asserts.js");
function xmlAllowed() {
return (typeof options == "function") &&
(options() + "").contains("allow_xml");
}
var valid_strict_funs = [
// directive ends on next line
function () {
"use strict"
;
},
function () {
"use strict"
},
// directive ends on same line
function () { "use strict"; },
function () { "use strict" },
];
for (var f of valid_strict_funs) {
assertThrowsInstanceOf(function() { f.caller }, TypeError);
}
var binary_ops = [
"||", "&&",
"|", "^", "&",
"==", "!=", "===", "!==",
"<", "<=", ">", ">=", "in", "instanceof",
"<<", ">>", ">>>",
"+", "-",
"*", "/", "%",
];
var invalid_strict_funs = [
function () {
"use strict"
, "not";
},
function () {
"use strict"
? 1 : 0;
},
function () {
"use strict"
.length;
},
function () {
"use strict"
[0];
},
function () {
"use strict"
();
},
...(xmlAllowed() ? [Function("'use strict'\n..not")] : []),
...[Function("'use strict'\n " + op + " 'not'") for (op of binary_ops)],
];
for (var f of invalid_strict_funs) {
f.caller;
}
var assignment_ops = [
"=", "+=", "-=",
"|=", "^=", "&=",
"<<=", ">>=", ">>>=",
"*=", "/=", "%=",
];
var invalid_strict_funs_referror = [
...[("'use strict'\n " + op + " 'not'") for (op of assignment_ops)],
];
// assignment with string literal as LHS is an early error, therefore we
// can only test for ReferenceError
for (var f of invalid_strict_funs_referror) {
assertThrowsInstanceOf(function() { Function(f) }, ReferenceError);
}

View File

@ -5001,6 +5001,16 @@ JS_DefineFunctions(JSContext *cx, JSObject *objArg, JSFunctionSpec *fs)
fun->setExtendedSlot(0, PrivateValue(fs));
}
/*
* During creation of the self-hosting global, we ignore all
* self-hosted functions, as that means we're currently setting up
* the global object that that the self-hosted code is then compiled
* in. Self-hosted functions can access each other via their names,
* but not via the builtin classes they get installed into.
*/
if (fs->selfHostedName && cx->runtime->isSelfHostedGlobal(cx->global()))
return JS_TRUE;
fun = js_DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags, fs->selfHostedName);
if (!fun)
return JS_FALSE;

View File

@ -242,6 +242,7 @@ selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep
{
PrintError(cx, stderr, message, report, true);
}
static JSClass self_hosting_global_class = {
"self-hosting-global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub,
@ -249,6 +250,85 @@ static JSClass self_hosting_global_class = {
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, NULL
};
static JSBool
intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue val(cx, args[0]);
RootedObject obj(cx, ToObject(cx, val));
if (!obj)
return false;
args.rval().set(OBJECT_TO_JSVAL(obj));
return true;
}
static JSBool
intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
double result;
if (!ToInteger(cx, args[0], &result))
return false;
args.rval().set(DOUBLE_TO_JSVAL(result));
return true;
}
static JSBool
intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Value val = args[0];
bool isCallable = val.isObject() && val.toObject().isCallable();
args.rval().set(BOOLEAN_TO_JSVAL(isCallable));
return true;
}
static JSBool
intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
uint32_t errorNumber = args[0].toInt32();
char *errorArgs[3] = {NULL, NULL, NULL};
for (unsigned i = 1; i < 4 && i < args.length(); i++) {
RootedValue val(cx, args[i]);
if (val.isInt32() || val.isString()) {
errorArgs[i - 1] = JS_EncodeString(cx, ToString(cx, val));
} else {
ptrdiff_t spIndex = cx->stack.spIndexOf(val.address());
errorArgs[i - 1] = DecompileValueGenerator(cx, spIndex, val, NullPtr(), 1);
}
}
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
errorArgs[0], errorArgs[1], errorArgs[2]);
for (unsigned i = 0; i < 3; i++)
js_free(errorArgs[i]);
return false;
}
static JSBool
intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
JS_ASSERT(args[0].isObject());
RootedObject obj(cx, &args[0].toObject());
JS_ASSERT(obj->isFunction());
obj->toFunction()->flags |= JSFUN_SELF_HOSTED_CTOR;
return true;
}
JSFunctionSpec intrinsic_functions[] = {
JS_FN("ToObject", intrinsic_ToObject, 1,0),
JS_FN("ToInteger", intrinsic_ToInteger, 1,0),
JS_FN("IsCallable", intrinsic_IsCallable, 1,0),
JS_FN("ThrowError", intrinsic_ThrowError, 4,0),
JS_FN("_MakeConstructible", intrinsic_MakeConstructible, 1,0),
JS_FS_END
};
bool
JSRuntime::initSelfHosting(JSContext *cx)
{
@ -257,23 +337,35 @@ JSRuntime::initSelfHosting(JSContext *cx)
if (!(selfHostedGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL)))
return false;
JS_SetGlobalObject(cx, selfHostedGlobal_);
JSAutoCompartment ac(cx, cx->global());
RootedObject shg(cx, selfHostedGlobal_);
const char *src = selfhosted::raw_sources;
uint32_t srcLen = selfhosted::GetRawScriptsSize();
if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
return false;
CompileOptions options(cx);
options.setFileAndLine("self-hosted", 1);
options.setSelfHostingMode(true);
RootedObject shg(cx, selfHostedGlobal_);
Value rv;
/*
* Set a temporary error reporter printing to stderr because it is too
* early in the startup process for any other reporter to be registered
* and we don't want errors in self-hosted code to be silently swallowed.
*/
JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
bool ok = Evaluate(cx, shg, options, src, srcLen, &rv);
Value rv;
bool ok;
char *filename = getenv("MOZ_SELFHOSTEDJS");
if (filename) {
RootedScript script(cx, Compile(cx, shg, options, filename));
if (script)
ok = Execute(cx, script, *shg.get(), &rv);
} else {
const char *src = selfhosted::raw_sources;
uint32_t srcLen = selfhosted::GetRawScriptsSize();
ok = Evaluate(cx, shg, options, src, srcLen, &rv);
}
JS_SetErrorReporter(cx, oldReporter);
JS_SetGlobalObject(cx, savedGlobal);
return ok;

View File

@ -471,6 +471,9 @@ struct JSRuntime : js::RuntimeFriendFields
bool initSelfHosting(JSContext *cx);
void markSelfHostedGlobal(JSTracer *trc);
bool isSelfHostedGlobal(js::HandleObject global) {
return global == selfHostedGlobal_;
}
JSFunction *getSelfHostedFunction(JSContext *cx, const char *name);
bool cloneSelfHostedValueById(JSContext *cx, js::HandleId id, js::HandleObject holder,
js::MutableHandleValue vp);

View File

@ -1568,6 +1568,7 @@ js_DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
obj, atom, kind);
} else {
JS_ASSERT(attrs & JSFUN_INTERPRETED);
JS_ASSERT(!cx->runtime->isSelfHostedGlobal(cx->global()));
fun = cx->runtime->getSelfHostedFunction(cx, selfHostedName);
fun->initAtom(JSID_TO_ATOM(id));
}

View File

@ -400,8 +400,7 @@ inline bool
IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp)
{
JSOp op = JSOp(*pc);
RootedPropertyName name(cx);
name = GetNameFromBytecode(cx, script, pc, op);
RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, op));
cx->global()->getIntrinsicValue(cx, name, vp);
return true;
}

View File

@ -2652,6 +2652,14 @@ js::CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto,
return clone;
}
JSObject *
js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj)
{
Rooted<TypeObject*> typeObj(cx, cx->global()->getOrCreateObjectPrototype(cx)->getNewType(cx));
RootedShape shape(cx, srcObj->lastProperty());
return NewReshapedObject(cx, typeObj, parent, srcObj->getAllocKind(), shape);
}
struct JSObject::TradeGutsReserved {
Vector<Value> avals;
Vector<Value> bvals;

View File

@ -1390,6 +1390,9 @@ ToObjectFromStack(JSContext *cx, HandleValue vp)
return ToObjectSlow(cx, vp, true);
}
extern JSObject *
CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj);
} /* namespace js */
extern void

View File

@ -1002,7 +1002,7 @@ SourceCompressorThread::waitOnCompression(SourceCompressionToken *userTok)
{
JS_ASSERT(userTok == tok);
PR_Lock(lock);
if (state == COMPRESSING)
while (state == COMPRESSING)
PR_WaitCondVar(done, PR_INTERVAL_NO_TIMEOUT);
JS_ASSERT(state == IDLE);
SourceCompressionToken *saveTok = tok;
@ -2128,7 +2128,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
enclosingScope = fun;
clone = CloneStaticBlockObject(cx, enclosingScope, innerBlock);
} else {
} else if (obj->isFunction()) {
RootedFunction innerFun(cx, obj->toFunction());
StaticScopeIter ssi(innerFun->script()->enclosingStaticScope());
@ -2139,6 +2139,14 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
enclosingScope = fun;
clone = CloneInterpretedFunction(cx, enclosingScope, innerFun);
} else {
/*
* Clone object literals emitted for the JSOP_NEWOBJECT opcode. We only emit that
* instead of the less-optimized JSOP_NEWINIT for self-hosted code or code compiled
* with JSOPTION_COMPILE_N_GO set. As we don't clone the latter type of code, this
* case should only ever be hit when cloning objects from self-hosted code.
*/
clone = CloneObjectLiteral(cx, cx->global(), obj);
}
if (!clone || !objects.append(clone))
return NULL;

View File

@ -173,84 +173,6 @@ ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args);
}
static JSBool
intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue val(cx, args[0]);
RootedObject obj(cx, ToObject(cx, val));
if (!obj)
return false;
args.rval().set(OBJECT_TO_JSVAL(obj));
return true;
}
static JSBool
intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
double result;
if (!ToInteger(cx, args[0], &result))
return false;
args.rval().set(DOUBLE_TO_JSVAL(result));
return true;
}
static JSBool
intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Value val = args[0];
bool isCallable = val.isObject() && val.toObject().isCallable();
args.rval().set(BOOLEAN_TO_JSVAL(isCallable));
return true;
}
static JSBool
intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
uint32_t errorNumber = args[0].toInt32();
char *errorArgs[3] = {NULL, NULL, NULL};
for (unsigned i = 1; i < 4 && i < args.length(); i++) {
RootedValue val(cx, args[i]);
if (val.isInt32() || val.isString()) {
errorArgs[i - 1] = JS_EncodeString(cx, ToString(cx, val));
} else {
ptrdiff_t spIndex = cx->stack.spIndexOf(val.address());
errorArgs[i - 1] = DecompileValueGenerator(cx, spIndex, val, NullPtr(), 1);
}
}
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
errorArgs[0], errorArgs[1], errorArgs[2]);
for (unsigned i = 0; i < 3; i++)
js_free(errorArgs[i]);
return false;
}
static JSBool
intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
JS_ASSERT(args[0].isObject());
RootedObject obj(cx, &args[0].toObject());
JS_ASSERT(obj->isFunction());
obj->toFunction()->flags |= JSFUN_SELF_HOSTED_CTOR;
return true;
}
JSFunctionSpec intrinsic_functions[] = {
JS_FN("ToObject", intrinsic_ToObject, 1,0),
JS_FN("ToInteger", intrinsic_ToInteger, 1,0),
JS_FN("IsCallable", intrinsic_IsCallable, 1,0),
JS_FN("ThrowError", intrinsic_ThrowError, 4,0),
JS_FN("_MakeConstructible", intrinsic_MakeConstructible, 1,0),
JS_FS_END
};
JSObject *
GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
{
@ -454,8 +376,14 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
if (!intrinsicsHolder)
return NULL;
self->setIntrinsicsHolder(intrinsicsHolder);
if (!JS_DefineFunctions(cx, intrinsicsHolder, intrinsic_functions))
/* Define a property 'global' with the current global as its value. */
RootedValue global(cx, OBJECT_TO_JSVAL(self));
if (!JSObject::defineProperty(cx, intrinsicsHolder, cx->names().global,
global, JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY))
{
return NULL;
}
/*
* The global object should have |Object.prototype| as its [[Prototype]].

View File

@ -827,12 +827,11 @@ StackSpace::sizeOf()
size_t numBytes = (trustedEnd_ - base_) * sizeof(Value);
size_t numPages = (numBytes + pageSize - 1) / pageSize;
// On Linux, mincore's third argument has type unsigned char*. On Mac, it
// has type char*.
#if defined(XP_MACOSX)
typedef char MincoreArgType;
#else
// On Linux, mincore's third argument has type unsigned char*.
#ifdef __linux__
typedef unsigned char MincoreArgType;
#else
typedef char MincoreArgType;
#endif
MincoreArgType *vec = (MincoreArgType *) js_malloc(numPages);

View File

@ -4014,19 +4014,25 @@ nsImageRenderer::~nsImageRenderer()
bool
nsImageRenderer::PrepareImage()
{
if (mImage->IsEmpty() || !mImage->IsComplete()) {
// Make sure the image is actually decoding
mImage->RequestDecode();
if (mImage->IsEmpty())
return false;
// We can not prepare the image for rendering if it is not fully loaded.
//
// Special case: If we requested a sync decode and we have an image, push
// on through
nsCOMPtr<imgIContainer> img;
if (!((mFlags & FLAG_SYNC_DECODE_IMAGES) &&
(mType == eStyleImageType_Image) &&
(NS_SUCCEEDED(mImage->GetImageData()->GetImage(getter_AddRefs(img))) && img)))
return false;
if (!mImage->IsComplete()) {
// Make sure the image is actually decoding
mImage->StartDecoding();
// check again to see if we finished
if (!mImage->IsComplete()) {
// We can not prepare the image for rendering if it is not fully loaded.
//
// Special case: If we requested a sync decode and we have an image, push
// on through because the Draw() will do a sync decode then
nsCOMPtr<imgIContainer> img;
if (!((mFlags & FLAG_SYNC_DECODE_IMAGES) &&
(mType == eStyleImageType_Image) &&
(NS_SUCCEEDED(mImage->GetImageData()->GetImage(getter_AddRefs(img))) && img)))
return false;
}
}
switch (mType) {

View File

@ -1610,7 +1610,7 @@ nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
}
nsresult
nsStyleImage::RequestDecode() const
nsStyleImage::StartDecoding() const
{
if ((mType == eStyleImageType_Image) && mImage)
return mImage->StartDecoding();

View File

@ -225,9 +225,9 @@ struct nsStyleImage {
bool* aIsEntireImage = nullptr) const;
/**
* Requests a decode on the image.
* Starts the decoding of a image.
*/
nsresult RequestDecode() const;
nsresult StartDecoding() const;
/**
* @return true if the item is definitely opaque --- i.e., paints every
* pixel within its bounds opaquely, and the bounds contains at least a pixel.

View File

@ -126,7 +126,7 @@ class NrIceCtx {
// The thread to direct method calls to
nsCOMPtr<nsIEventTarget> thread() { return sts_target_; }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx)
private:
NrIceCtx(const std::string& name, bool offerer)

View File

@ -94,7 +94,7 @@ class NrIceMediaStream {
// work for trickle ICE yet--called internally
void EmitAllCandidates();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceMediaStream);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceMediaStream)
private:
NrIceMediaStream(NrIceCtx *ctx, const std::string& name,

View File

@ -440,13 +440,20 @@ def GenerateOutput(target_list, target_dicts, data, params):
swapslashes(top),
swapslashes(src),
swapslashes(relative_srcdir))
scriptname = topsrcdir_path(__file__)
if scriptname[-4:] in ('.pyc', '.pyo'):
scriptname = scriptname[:-1]
scriptname = "$(topsrcdir)/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/mozmake.py"
# Reassemble a commandline from parts so that all the paths are correct
# NOTE: this MUST match the commandline generated in configure.in!
# since we don't see --include statements, duplicate them in FORCE_INCLUDE_FILE lines
# Being in a define, they also get used by the common.mk invocation of gyp so they
# they don't disappear in the second round of tail-swallowing
forced_includes = ""
for option in options.defines:
if option[:20] == "FORCED_INCLUDE_FILE=":
forced_includes += "--include=%s" % option[20:]
commandline = [topsrcdir_path(sys.argv[0]),
"--format=mozmake",
forced_includes,
"--depth=%s" % topsrcdir_path(options.depth),
"--generator-output=%s" % objdir_path(options.generator_output),
"--toplevel-dir=$(topsrcdir)",

View File

@ -318,12 +318,14 @@ pref("gfx.color_management.mode", 0);
// 0=fixed margin, 1=velocity bias, 2=dynamic resolution, 3=no margins, 4=prediction bias
pref("gfx.displayport.strategy", 1);
// all of the following displayport strategy prefs will be divided by 1000
// to obtain some multiplier which is then used in the strategy.
// fixed margin strategy options
pref("gfx.displayport.strategy_fm.multiplier", -1); // displayport dimension multiplier
pref("gfx.displayport.strategy_fm.danger_x", -1); // danger zone on x-axis when multiplied by viewport width
pref("gfx.displayport.strategy_fm.danger_y", -1); // danger zone on y-axis when multiplied by viewport height
// velocity bias strategy options
pref("gfx.displayport.strategy_vb.multiplier", -1); // displayport dimension multiplier
pref("gfx.displayport.strategy_vb.threshold", -1); // velocity threshold in inches/frame
@ -332,9 +334,12 @@ pref("gfx.displayport.strategy_vb.danger_x_base", -1); // danger zone on x-axis
pref("gfx.displayport.strategy_vb.danger_y_base", -1); // danger zone on y-axis when multiplied by viewport height
pref("gfx.displayport.strategy_vb.danger_x_incr", -1); // additional danger zone on x-axis when multiplied by viewport width and velocity
pref("gfx.displayport.strategy_vb.danger_y_incr", -1); // additional danger zone on y-axis when multiplied by viewport height and velocity
// prediction bias strategy options
pref("gfx.displayport.strategy_pb.threshold", -1); // velocity threshold in inches/frame
pref("gfx.java.screenshot.enabled", true);
// don't allow JS to move and resize existing windows
pref("dom.disable_window_move_resize", true);

View File

@ -191,13 +191,13 @@ size. -->
that a non-breaking space (unicode= U+00A0) should be used between this
character and the remainder of the string to prevent word wrap. -->
<!ENTITY abouthome_about_sync3 "Set up Firefox Sync to access bookmarks, history and tabs from your other devices&#x00A0;»">
<!ENTITY abouthome_about_apps2 "Get apps from the Mozilla Marketplace and discover the best the Web has to offer&#x00A0;»">
<!ENTITY abouthome_about_apps3 "Get apps from the Firefox Marketplace and discover the best the Web has to offer&#x00A0;»">
<!-- Localization note (abouthome_sync_bold_name, abouthome_apps_bold_name):
These strings are accentuated as bold text in the "abouthome_about_..."
strings above. These strings should be a subset of the strings above and
generally be the name of the product the string describes. -->
<!ENTITY abouthome_sync_bold_name "Firefox Sync">
<!ENTITY abouthome_apps_bold_name "Mozilla Marketplace">
<!ENTITY abouthome_apps_bold_name2 "Firefox Marketplace">
<!ENTITY filepicker_title "Choose File">
<!ENTITY filepicker_audio_title "Choose or record a sound">

View File

@ -180,9 +180,9 @@
<string name="abouthome_top_sites_title">&abouthome_top_sites_title;</string>
<string name="abouthome_top_sites_browse">&abouthome_top_sites_browse;</string>
<string name="abouthome_about_sync">&abouthome_about_sync3;</string>
<string name="abouthome_about_apps">&abouthome_about_apps2;</string>
<string name="abouthome_about_apps">&abouthome_about_apps3;</string>
<string name="abouthome_sync_bold_name">&abouthome_sync_bold_name;</string>
<string name="abouthome_apps_bold_name">&abouthome_apps_bold_name;</string>
<string name="abouthome_apps_bold_name">&abouthome_apps_bold_name2;</string>
<string name="filepicker_title">&filepicker_title;</string>
<string name="filepicker_audio_title">&filepicker_audio_title;</string>

View File

@ -37,7 +37,7 @@
</div>
<div id="main-container">
<div id="noapps" class="hidden">
&aboutApps.noApps.pre;<a id="marketplaceURL" pref="app.marketplaceURL">&aboutApps.noApps.middle2;</a>&aboutApps.noApps.post;
&aboutApps.noApps.pre;<a id="marketplaceURL" pref="app.marketplaceURL">&aboutApps.noApps.middle3;</a>&aboutApps.noApps.post;
</div>
<div>
<div class="spacer" id="spacer1"> </div>

View File

@ -7413,79 +7413,8 @@ var MemoryObserver = {
},
dumpMemoryStats: function(aLabel) {
// TODO once bug 788021 has landed, replace this code and just invoke that instead
// currently this code is hijacked from areweslimyet.com, original code can be found at:
// https://github.com/Nephyrin/MozAreWeSlimYet/blob/master/mozmill_endurance_test/performance.js
let memMgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
let timestamp = new Date();
let memory = {};
// These *should* be identical to the explicit/resident root node
// sum, AND the explicit/resident node explicit value (on newer builds),
// but we record all three so we can make sure the data is consistent
memory['manager_explicit'] = memMgr.explicit;
memory['manager_resident'] = memMgr.resident;
let knownHeap = 0;
function addReport(path, amount, kind, units) {
if (units !== undefined && units != Ci.nsIMemoryReporter.UNITS_BYTES)
// Unhandled. (old builds don't specify units, but use only bytes)
return;
if (memory[path])
memory[path] += amount;
else
memory[path] = amount;
if (kind !== undefined && kind == Ci.nsIMemoryReporter.KIND_HEAP
&& path.indexOf('explicit/') == 0)
knownHeap += amount;
}
// Normal reporters
let reporters = memMgr.enumerateReporters();
while (reporters.hasMoreElements()) {
let r = reporters.getNext();
r instanceof Ci.nsIMemoryReporter;
if (r.path.length) {
addReport(r.path, r.amount, r.kind, r.units);
}
}
// Multireporters
if (memMgr.enumerateMultiReporters) {
let multireporters = memMgr.enumerateMultiReporters();
while (multireporters.hasMoreElements()) {
let mr = multireporters.getNext();
mr instanceof Ci.nsIMemoryMultiReporter;
mr.collectReports(function (proc, path, kind, units, amount, description, closure) {
addReport(path, amount, kind, units);
}, null);
}
}
let heapAllocated = memory['heap-allocated'];
// Called heap-used in older builds
if (!heapAllocated) heapAllocated = memory['heap-used'];
// This is how about:memory calculates derived value heap-unclassified, which
// is necessary to get a proper explicit value.
if (knownHeap && heapAllocated)
memory['explicit/heap-unclassified'] = memory['heap-allocated'] - knownHeap;
// If the build doesn't have a resident/explicit reporter, but does have
// the memMgr.explicit/resident field, use that
if (!memory['resident'])
memory['resident'] = memory['manager_resident']
if (!memory['explicit'])
memory['explicit'] = memory['manager_explicit']
let label = "[AboutMemoryDump|" + aLabel + "] ";
dump(label + timestamp);
for (let type in memory) {
dump(label + type + " = " + memory[type]);
}
memMgr.dumpMemoryReportsToFile(aLabel, false, true);
},
};

View File

@ -100,7 +100,13 @@ BrowserCLH.prototype = {
width: width,
height: height
};
browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", args);
// Make sure webapps do not have: locationbar, personalbar, menubar, statusbar, and toolbar
let flags = "chrome,dialog=no";
if (!pinned)
flags += ",all";
browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", flags, args);
}
aCmdLine.preventDefault = true;

View File

@ -9,5 +9,5 @@
<!-- LOCALIZATION NOTE (aboutApps.noApps.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (aboutApps.noApps.post): include a starting space as needed -->
<!ENTITY aboutApps.noApps.pre "No web apps installed. Get some from the ">
<!ENTITY aboutApps.noApps.middle2 "Mozilla Marketplace">
<!ENTITY aboutApps.noApps.middle3 "Firefox Marketplace">
<!ENTITY aboutApps.noApps.post ".">

View File

@ -54,6 +54,12 @@ static int gPassedTests = 0;
#else
#include <sstream>
// Print nsresult as uint32_t
std::ostream& operator<<(std::ostream& aStream, const nsresult aInput)
{
return aStream << static_cast<uint32_t>(aInput);
}
#define do_check_eq(aExpected, aActual) \
PR_BEGIN_MACRO \
gTotalTests++; \

View File

@ -9,6 +9,7 @@ const Cr = Components.results;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
/*
* LoginManagerPromptFactory
@ -245,13 +246,15 @@ LoginManagerPrompter.prototype = {
// Whether we are in private browsing mode
get _inPrivateBrowsing() {
// The Private Browsing service might not be available.
try {
var pbs = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
return pbs.privateBrowsingEnabled;
} catch (e) {
return false;
if (this._window) {
return PrivateBrowsingUtils.isWindowPrivate(this._window);
} else {
// If we don't that we're in private browsing mode if the caller did
// not provide a window. The callers which really care about this
// will indeed pass down a window to us, and for those who don't,
// we can just assume that we don't want to save the entered login
// information.
return true;
}
},

View File

@ -515,7 +515,18 @@ AsyncFetchAndSetIconForPage::AsyncFetchAndSetIconForPage(
if (pbService) {
bool inPrivateBrowsing = false;
if (NS_SUCCEEDED(pbService->GetPrivateBrowsingEnabled(&inPrivateBrowsing))) {
MOZ_ASSERT(inPrivateBrowsing == mFaviconLoadPrivate);
// In one specific case that we know of, it is possible for these flags
// to not match (bug 801151). We mostly care about the cases where the
// global private browsing mode is on, but the favicon load is not marked
// as private, as those cases will cause privacy leaks. But because
// fixing bug 801151 properly is going to mean tons of really dirty and
// fragile work which might cause other types of problems, we fatally
// assert the condition which would be a privacy leak, and non-fatally
// assert the other side of the condition which would designate a bug,
// but not a privacy sensitive one.
MOZ_ASSERT_IF(inPrivateBrowsing && !mFaviconLoadPrivate, false);
NS_ASSERTION(inPrivateBrowsing == mFaviconLoadPrivate,
"The favicon load flag and the global PB flag do not match");
}
}
#endif

View File

@ -71,24 +71,39 @@ function FrameWorker(url, name) {
this.loaded = false;
this.frame = makeHiddenFrame();
var self = this;
Services.obs.addObserver(function injectController(doc, topic, data) {
if (!doc.defaultView || doc.defaultView != self.frame.contentWindow) {
return;
}
Services.obs.removeObserver(injectController, "document-element-inserted", false);
try {
self.createSandbox();
} catch (e) {
Cu.reportError("FrameWorker: failed to create sandbox for " + url + ". " + e);
}
}, "document-element-inserted", false);
this.frame.setAttribute("src", url);
this.load();
}
FrameWorker.prototype = {
load: function FrameWorker_loadWorker() {
var self = this;
Services.obs.addObserver(function injectController(doc, topic, data) {
if (!doc.defaultView || doc.defaultView != self.frame.contentWindow) {
return;
}
Services.obs.removeObserver(injectController, "document-element-inserted", false);
try {
self.createSandbox();
} catch (e) {
Cu.reportError("FrameWorker: failed to create sandbox for " + url + ". " + e);
}
}, "document-element-inserted", false);
this.frame.setAttribute("src", this.url);
},
reload: function FrameWorker_reloadWorker() {
// push all the ports into pending ports, they will be re-entangled
// during the call to createSandbox after the document is reloaded
for (let [portid, port] in Iterator(this.ports)) {
port._window = null;
this.pendingPorts.push(port);
}
this.ports = {};
this.loaded = false;
this.load();
},
createSandbox: function createSandbox() {
let workerWindow = this.frame.contentWindow;
let sandbox = new Cu.Sandbox(workerWindow);
@ -96,8 +111,8 @@ FrameWorker.prototype = {
// copy the window apis onto the sandbox namespace only functions or
// objects that are naturally a part of an iframe, I'm assuming they are
// safe to import this way
let workerAPI = ['MozWebSocket', 'WebSocket', 'localStorage',
'atob', 'btoa', 'clearInterval', 'clearTimeout', 'dump',
let workerAPI = ['WebSocket', 'localStorage', 'atob', 'btoa',
'clearInterval', 'clearTimeout', 'dump',
'setInterval', 'setTimeout', 'XMLHttpRequest',
'MozBlobBuilder', 'FileReader', 'Blob',
'location'];
@ -139,10 +154,10 @@ FrameWorker.prototype = {
// and we delegate ononline and onoffline events to the worker.
// See http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#workerglobalscope
this.frame.addEventListener('offline', function fw_onoffline(event) {
workerWindow.addEventListener('offline', function fw_onoffline(event) {
Cu.evalInSandbox("onoffline();", sandbox);
}, false);
this.frame.addEventListener('online', function fw_ononline(event) {
workerWindow.addEventListener('online', function fw_ononline(event) {
Cu.evalInSandbox("ononline();", sandbox);
}, false);
@ -248,15 +263,12 @@ function makeHiddenFrame() {
return iframe;
}
// public methods on WorkerHandle should conform to the SharedWorker api
function WorkerHandle(port, worker) {
this.port = port;
this._worker = worker;
}
WorkerHandle.prototype = {
get document() {
return this._worker.frame.contentDocument;
},
// XXX - workers have no .close() method, but *do* have a .terminate()
// method which we should implement. However, the worker spec doesn't define
// a callback to be made in the worker when this happens - it all just dies.

View File

@ -27,9 +27,6 @@ function WorkerAPI(provider, port) {
// used for the api.
// later we might even include an API version - version 0 for now!
this._port.postMessage({topic: "social.initialize"});
// backwards compat, remove after Aug 1.
this._port.postMessage({topic: "social.cookie-changed"});
}
WorkerAPI.prototype = {
@ -52,6 +49,13 @@ WorkerAPI.prototype = {
},
handlers: {
"social.reload-worker": function(data) {
getFrameWorkerHandle(this._provider.workerURL, null)._worker.reload();
// the frameworker is going to be reloaded, send the initialization
// so it can have the same startup sequence as if it were loaded
// the first time. This will be queued until the frameworker is ready.
this._port.postMessage({topic: "social.initialize"});
},
"social.user-profile": function (data) {
this._provider.updateUserProfile(data);
},
@ -59,7 +63,8 @@ WorkerAPI.prototype = {
this._provider.setAmbientNotification(data);
},
"social.cookies-get": function(data) {
let document = getFrameWorkerHandle(this._provider.workerURL, null).document;
let document = getFrameWorkerHandle(this._provider.workerURL, null).
_worker.frame.contentDocument;
let cookies = document.cookie.split(";");
let results = [];
cookies.forEach(function(aCookie) {

View File

@ -102,6 +102,43 @@ let tests = {
Services.cookies.add('.example.com', '/', 'cheez', 'burger', false, false, true, MAX_EXPIRY);
port.postMessage({topic: "test-initialization"});
port.postMessage({topic: "test.cookies-get"});
}
},
testWorkerReload: function(next) {
let fw = {};
Cu.import("resource://gre/modules/FrameWorker.jsm", fw);
// get a real handle to the worker so we can watch the unload event
// we watch for the unload of the worker to know it is infact being
// unloaded, after that if we get worker.connected we know that
// the worker was loaded again and ports reconnected
let reloading = false;
let worker = fw.getFrameWorkerHandle(provider.workerURL, undefined, "testWorkerReload");
let win = worker._worker.frame.contentWindow;
win.addEventListener("unload", function workerUnload(e) {
win.removeEventListener("unload", workerUnload);
ok(true, "worker unload event has fired");
reloading = true;
});
let port = provider.getWorkerPort();
ok(port, "provider has a port");
port.onmessage = function (e) {
let topic = e.data.topic;
switch (topic) {
case "test-initialization-complete":
// tell the worker to send the reload msg
port.postMessage({topic: "test-reload-init"});
break;
case "worker.connected":
// we'll get this message from the worker on every load of the worker,
// so we need to ignore it unless we have requested the reload.
if (reloading) {
ok(true, "worker reloaded and testPort was reconnected");
next();
}
break;
}
}
port.postMessage({topic: "test-initialization"});
}
};

View File

@ -33,6 +33,17 @@ onconnect = function(e) {
break;
case "social.cookies-get-response":
testerPort.postMessage({topic: "test.cookies-get-response", data: data});
break;
case "test-reload-init":
// browser_social_sidebar.js started test, tell the sidebar to
// start
apiPort.postMessage({topic: 'social.reload-worker'});
break;
}
}
// used for "test-reload-worker"
if (apiPort && apiPort != port) {
port.postMessage({topic: "worker.connected"})
}
}

View File

@ -1,3 +1,4 @@
pictures=*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp;
music=*.mp3; *.ogg; *.m4a; *.m4b; *.m4p; *.m4v; *.m4r; *.3gp; *.mp4; *.aac;
videos=*.avi; *.divx; *.flv; *.m4v; *.mkv; *.mov; *.mp4; *.mpeg; *.mpg; *.ogm; *.ogv; *.ogx; *.rm; *.rmvb; *.smil; *.webm; *.wmv; *.xvid
# Extensions we recognize for DeviceStorage storage areas
pictures=*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp
music=*.mp3; *.ogg; *.m4a; *.m4b; *.m4p; *.m4v; *.m4r; *.3gp; *.mp4; *.aac; *.m3u; *.pls
videos=*.avi; *.divx; *.flv; *.m4v; *.mkv; *.mov; *.mp4; *.mpeg; *.mpg; *.ogm; *.ogv; *.ogx; *.rm; *.rmvb; *.smil; *.webm; *.wmv; *.xvid; *.3gp

View File

@ -45,7 +45,7 @@ def get_locale_strings(path, prefix, middle, add_cr):
name, value = line.split("=", 1)
value = value.strip() # trim whitespace from the start and end
if value[-1] == "\"" and value[0] == "\"":
if value and value[-1] == "\"" and value[0] == "\"":
value = value[1:-1] # remove " from the start and end
if add_cr:

View File

@ -54,7 +54,7 @@
#define NO_INSTALLDIR_ERROR 34
#define WRITE_ERROR_ACCESS_DENIED 35
#define WRITE_ERROR_SHARING_VIOLATION 36
// #define WRITE_ERROR_SHARING_VIOLATION 36 // Replaced with errors 46-48
#define WRITE_ERROR_CALLBACK_APP 37
#define INVALID_UPDATER_STATUS_CODE 38
#define UNEXPECTED_BZIP_ERROR 39
@ -64,6 +64,9 @@
#define FILESYSTEM_MOUNT_READWRITE_ERROR 43
#define FOTA_GENERAL_ERROR 44
#define FOTA_UNKNOWN_ERROR 45
#define WRITE_ERROR_SHARING_VIOLATION_SIGNALED 46
#define WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID 47
#define WRITE_ERROR_SHARING_VIOLATION_NOPID 48
// The following error codes are only used by updater.exe
// when a fallback key exists and XPCShell tests are being run.

View File

@ -132,21 +132,26 @@ const SERVICE_UPDATER_NOT_FIXED_DRIVE = 31;
const SERVICE_COULD_NOT_LOCK_UPDATER = 32;
const SERVICE_INSTALLDIR_ERROR = 33;
const WRITE_ERROR_ACCESS_DENIED = 35;
const WRITE_ERROR_SHARING_VIOLATION = 36;
const WRITE_ERROR_CALLBACK_APP = 37;
const INVALID_UPDATER_STATUS_CODE = 38;
const UNEXPECTED_BZIP_ERROR = 39;
const UNEXPECTED_MAR_ERROR = 40;
const UNEXPECTED_BSPATCH_ERROR = 41;
const UNEXPECTED_FILE_OPERATION_ERROR = 42;
const FILESYSTEM_MOUNT_READWRITE_ERROR = 43;
const FOTA_GENERAL_ERROR = 44;
const FOTA_UNKNOWN_ERROR = 45;
const WRITE_ERROR_ACCESS_DENIED = 35;
// const WRITE_ERROR_SHARING_VIOLATION = 36; // Replaced with errors 46-48
const WRITE_ERROR_CALLBACK_APP = 37;
const INVALID_UPDATER_STATUS_CODE = 38;
const UNEXPECTED_BZIP_ERROR = 39;
const UNEXPECTED_MAR_ERROR = 40;
const UNEXPECTED_BSPATCH_ERROR = 41;
const UNEXPECTED_FILE_OPERATION_ERROR = 42;
const FILESYSTEM_MOUNT_READWRITE_ERROR = 43;
const FOTA_GENERAL_ERROR = 44;
const FOTA_UNKNOWN_ERROR = 45;
const WRITE_ERROR_SHARING_VIOLATION_SIGNALED = 46;
const WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID = 47;
const WRITE_ERROR_SHARING_VIOLATION_NOPID = 48;
const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100;
const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
const NETWORK_ERROR_OFFLINE = 111;
const DOWNLOAD_CHUNK_SIZE = 300000; // bytes
const DOWNLOAD_BACKGROUND_INTERVAL = 600; // seconds
@ -958,7 +963,9 @@ function handleUpdateFailure(update, errorCode) {
update.errorCode = parseInt(errorCode);
if (update.errorCode == WRITE_ERROR ||
update.errorCode == WRITE_ERROR_ACCESS_DENIED ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_SIGNALED ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPID ||
update.errorCode == WRITE_ERROR_CALLBACK_APP ||
update.errorCode == FILESYSTEM_MOUNT_READWRITE_ERROR ||
update.errorCode == FOTA_GENERAL_ERROR ||
@ -1490,6 +1497,11 @@ UpdateService.prototype = {
*/
_incompatAddonsCount: 0,
/**
* Whether or not the service registered the "online" observer.
*/
_registeredOnlineObserver: false,
/**
* Handle Observer Service notifications
* @param subject
@ -1505,6 +1517,9 @@ UpdateService.prototype = {
// Clean up any extant updates
this._postUpdateProcessing();
break;
case "network:offline-status-changed":
this._offlineStatusChanged(data);
break;
case "xpcom-shutdown":
Services.obs.removeObserver(this, "xpcom-shutdown");
@ -1783,6 +1798,83 @@ UpdateService.prototype = {
}
},
/**
* Register an observer when the network comes online, so we can short-circuit
* the app.update.interval when there isn't connectivity
*/
_registerOnlineObserver: function AUS__registerOnlineObserver() {
if (this._registeredOnlineObserver) {
LOG("UpdateService:_registerOnlineObserver - observer already registered");
return;
}
LOG("UpdateService:_registerOnlineObserver - waiting for the network to " +
"be online, then forcing another check");
Services.obs.addObserver(this, "network:offline-status-changed", false);
this._registeredOnlineObserver = true;
},
/**
* Called from the network:offline-status-changed observer.
*/
_offlineStatusChanged: function AUS__offlineStatusChanged(status) {
if (status !== "online") {
return;
}
Services.obs.removeObserver(this, "network:offline-status-changed");
this._registeredOnlineObserver = false;
LOG("UpdateService:_offlineStatusChanged - network is online, forcing " +
"another background check");
// the background checker is contained in notify
this.notify(null);
},
// nsIUpdateCheckListener
onProgress: function AUS_onProgress(request, position, totalSize) {
},
onCheckComplete: function AUS_onCheckComplete(request, updates, updateCount) {
this._selectAndInstallUpdate(updates);
},
onError: function AUS_onError(request, update) {
LOG("UpdateService:onError - error during background update: " +
update.statusText);
var maxErrors;
var errCount;
if (update.errorCode == NETWORK_ERROR_OFFLINE) {
// Register an online observer to try again
this._registerOnlineObserver();
return;
}
else if (update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE) {
errCount = getPref("getIntPref", PREF_APP_UPDATE_CERT_ERRORS, 0);
errCount++;
Services.prefs.setIntPref(PREF_APP_UPDATE_CERT_ERRORS, errCount);
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_CERT_MAXERRORS, 5);
}
else {
update.errorCode = BACKGROUNDCHECK_MULTIPLE_FAILURES;
errCount = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDERRORS, 0);
errCount++;
Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, errCount);
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDMAXERRORS,
10);
}
if (errCount >= maxErrors) {
var prompter = Cc["@mozilla.org/updates/update-prompt;1"].
createInstance(Ci.nsIUpdatePrompt);
prompter.showUpdateError(update);
}
},
/**
* Notified when a timer fires
* @param timer
@ -1793,55 +1885,7 @@ UpdateService.prototype = {
if (this.isDownloading || this._downloader && this._downloader.patchIsStaged)
return;
var self = this;
var listener = {
/**
* See nsIUpdateService.idl
*/
onProgress: function AUS_notify_onProgress(request, position, totalSize) {
},
/**
* See nsIUpdateService.idl
*/
onCheckComplete: function AUS_notify_onCheckComplete(request, updates,
updateCount) {
self._selectAndInstallUpdate(updates);
},
/**
* See nsIUpdateService.idl
*/
onError: function AUS_notify_onError(request, update) {
LOG("UpdateService:notify:listener - error during background update: " +
update.statusText);
var maxErrors;
var errCount;
if (update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE) {
errCount = getPref("getIntPref", PREF_APP_UPDATE_CERT_ERRORS, 0);
errCount++;
Services.prefs.setIntPref(PREF_APP_UPDATE_CERT_ERRORS, errCount);
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_CERT_MAXERRORS, 5);
}
else {
update.errorCode = BACKGROUNDCHECK_MULTIPLE_FAILURES;
errCount = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDERRORS, 0);
errCount++;
Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, errCount);
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDMAXERRORS,
10);
}
if (errCount >= maxErrors) {
var prompter = Cc["@mozilla.org/updates/update-prompt;1"].
createInstance(Ci.nsIUpdatePrompt);
prompter.showUpdateError(update);
}
}
};
this.backgroundChecker.checkForUpdates(listener, false);
this.backgroundChecker.checkForUpdates(this, false);
},
/**
@ -2301,6 +2345,7 @@ UpdateService.prototype = {
_xpcom_factory: UpdateServiceFactory,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIApplicationUpdateService,
Ci.nsIUpdateCheckListener,
Ci.nsIAddonUpdateCheckListener,
Ci.nsITimerCallback,
Ci.nsIObserver])
@ -2837,6 +2882,11 @@ Checker.prototype = {
// "looks" fine but there was probably an XML error or a bogus file.
var update = new Update(null);
update.statusText = getStatusTextFromCode(status, 200);
if (status == Cr.NS_ERROR_OFFLINE) {
// We use a separate constant here because nsIUpdate.errorCode is signed
update.errorCode = NETWORK_ERROR_OFFLINE;
}
this._callback.onError(request, update);
this._request = null;
@ -3506,7 +3556,9 @@ UpdatePrompt.prototype = {
if (update.state == STATE_FAILED &&
(update.errorCode == WRITE_ERROR ||
update.errorCode == WRITE_ERROR_ACCESS_DENIED ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_SIGNALED ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID ||
update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPID ||
update.errorCode == WRITE_ERROR_CALLBACK_APP ||
update.errorCode == FILESYSTEM_MOUNT_READWRITE_ERROR ||
update.errorCode == FOTA_GENERAL_ERROR ||

View File

@ -91,7 +91,8 @@ XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() {
return AUS_Cc["@mozilla.org/updates/update-service;1"].
getService(AUS_Ci.nsIApplicationUpdateService).
QueryInterface(AUS_Ci.nsITimerCallback).
QueryInterface(AUS_Ci.nsIObserver);
QueryInterface(AUS_Ci.nsIObserver).
QueryInterface(AUS_Ci.nsIUpdateCheckListener);
});
XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager",

View File

@ -114,6 +114,9 @@ var gTestserver;
var gXHR;
var gXHRCallback;
var gUpdatePrompt;
var gUpdatePromptCallback;
var gCheckFunc;
var gResponseBody;
var gResponseStatusCode = 200;
@ -1502,6 +1505,7 @@ function overrideXHR(callback) {
gXHR.contractID, gXHR);
}
/**
* Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
* and onload nsIDomEventListener handleEvent.
@ -1566,6 +1570,63 @@ xhr.prototype = {
get wrappedJSObject() { return this; }
};
function overrideUpdatePrompt(callback) {
var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
gUpdatePrompt = new UpdatePrompt();
gUpdatePromptCallback = callback;
registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription,
gUpdatePrompt.contractID, gUpdatePrompt);
}
function UpdatePrompt() {
var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded",
"showUpdateError", "showUpdateHistory", "showUpdateInstalled"];
fns.forEach(function(promptFn) {
UpdatePrompt.prototype[promptFn] = function() {
if (!gUpdatePromptCallback) {
return;
}
var callback = gUpdatePromptCallback[promptFn];
if (!callback) {
return;
}
callback.apply(gUpdatePromptCallback,
Array.prototype.slice.call(arguments));
}
});
}
UpdatePrompt.prototype = {
flags: AUS_Ci.nsIClassInfo.SINGLETON,
implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
getHelperForLanguage: function(language) null,
getInterfaces: function(count) {
var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt];
count.value = interfaces.length;
return interfaces;
},
classDescription: "UpdatePrompt",
contractID: "@mozilla.org/updates/update-prompt;1",
classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"),
createInstance: function (outer, aIID) {
if (outer == null)
return gUpdatePrompt.QueryInterface(aIID);
throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
},
QueryInterface: function(aIID) {
if (aIID.equals(AUS_Ci.nsIClassInfo) ||
aIID.equals(AUS_Ci.nsISupports) ||
aIID.equals(AUS_Ci.nsIUpdatePrompt))
return gUpdatePrompt;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
},
};
/* Update check listener */
const updateCheckListener = {
onProgress: function UCL_onProgress(request, position, totalSize) {
@ -1586,12 +1647,13 @@ const updateCheckListener = {
onError: function UCL_onError(request, update) {
gRequestURL = request.channel.originalURI.spec;
gStatusCode = request.status;
gStatusText = update.statusText;
logTestInfo("url = " + gRequestURL + ", " +
"request.status = " + gStatusCode + ", " +
"update.statusText = " + gStatusText);
// Use a timeout to allow the XHR to complete
do_execute_soon(gCheckFunc);
do_execute_soon(gCheckFunc.bind(null, request, update));
},
QueryInterface: function(aIID) {

View File

@ -0,0 +1,86 @@
/* 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/.
*/
/* Offline retry test (Bug 794211) */
// Needs to be in sync w/ nsUpdateService.js
const NETWORK_ERROR_OFFLINE = 111;
function run_test() {
do_test_pending();
do_register_cleanup(end_test);
DEBUG_AUS_TEST = true;
logTestInfo("test when an update check fails because the network is " +
"offline that we check again when the network comes online. " +
"(Bug 794211)");
removeUpdateDirsAndFiles();
setUpdateURLOverride();
Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false);
overrideXHR(null);
overrideUpdatePrompt(updatePrompt);
standardInit();
do_execute_soon(run_test_pt1);
}
function run_test_pt1() {
gResponseBody = null;
gCheckFunc = check_test_pt1;
gXHRCallback = xhr_pt1;
gUpdateChecker.checkForUpdates(updateCheckListener, true);
}
function xhr_pt1() {
gXHR.status = AUS_Cr.NS_ERROR_OFFLINE;
gXHR.onerror({ target: gXHR });
}
function check_test_pt1(request, update) {
do_check_eq(gStatusCode, AUS_Cr.NS_ERROR_OFFLINE);
do_check_eq(update.errorCode, NETWORK_ERROR_OFFLINE);
// Forward the error to AUS, which should register the online observer
gAUS.onError(request, update);
// Trigger another check by notifying the offline status observer
gXHRCallback = xhr_pt2;
Services.obs.notifyObservers(gAUS, "network:offline-status-changed", "online");
}
var updatePrompt = {
showUpdateAvailable: function(update) {
check_test_pt2(update);
}
};
function xhr_pt2() {
var patches = getLocalPatchString();
var updates = getLocalUpdateString(patches);
var responseBody = getLocalUpdatesXMLString(updates);
gXHR.status = 200;
gXHR.responseText = responseBody;
try {
var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
createInstance(AUS_Ci.nsIDOMParser);
gXHR.responseXML = parser.parseFromString(responseBody, "application/xml");
}
catch(e) { }
gXHR.onload({ target: gXHR });
}
function check_test_pt2(update) {
// We just verify that there are updates to know the check succeeded.
do_check_neq(update, null);
do_check_eq(update.name, "App Update Test");
do_test_finished();
}
function end_test() {
cleanUp();
}

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