mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
ec1d78bd1b
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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),
|
@ -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
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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}"
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
104
content/html/content/test/file_fullscreen-utils.js
Normal file
104
content/html/content/test/file_fullscreen-utils.js
Normal 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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 += \
|
||||
|
@ -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) {
|
||||
|
307
docshell/test/chrome/bug754029_window.xul
Normal file
307
docshell/test/chrome/bug754029_window.xul
Normal 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>
|
43
docshell/test/chrome/test_bug754029.xul
Normal file
43
docshell/test/chrome/test_bug754029.xul
Normal 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>
|
@ -46,6 +46,7 @@ MOCHITEST_FILES = \
|
||||
frame3.html \
|
||||
goback.html \
|
||||
file_bug534178.html \
|
||||
file_bug754029.html \
|
||||
$(NULL)
|
||||
|
||||
ifneq (mobile/android,$(MOZ_BUILD_APP))
|
||||
|
84
docshell/test/navigation/file_bug754029.html
Normal file
84
docshell/test/navigation/file_bug754029.html
Normal 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>
|
@ -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;
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -656,3 +656,8 @@ void
|
||||
BluetoothOppManager::OnConnectError()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::OnDisconnect()
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -218,3 +218,8 @@ void
|
||||
BluetoothScoManager::OnConnectError()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothScoManager::OnDisconnect()
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -175,7 +175,7 @@ BluetoothServiceChildProcess::GetDevicePath(const nsAString& aAdapterPath,
|
||||
|
||||
aDevicePath = path;
|
||||
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -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)
|
||||
});
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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()
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
83
js/src/jit-test/tests/basic/bug791465.js
Normal file
83
js/src/jit-test/tests/basic/bug791465.js
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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]].
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -1610,7 +1610,7 @@ nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyleImage::RequestDecode() const
|
||||
nsStyleImage::StartDecoding() const
|
||||
{
|
||||
if ((mType == eStyleImageType_Image) && mImage)
|
||||
return mImage->StartDecoding();
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)",
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 »">
|
||||
<!ENTITY abouthome_about_apps2 "Get apps from the Mozilla Marketplace and discover the best the Web has to offer »">
|
||||
<!ENTITY abouthome_about_apps3 "Get apps from the Firefox Marketplace and discover the best the Web has to offer »">
|
||||
<!-- 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">
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 ".">
|
||||
|
@ -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++; \
|
||||
|
@ -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;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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"});
|
||||
}
|
||||
};
|
||||
|
@ -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"})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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 ||
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
86
toolkit/mozapps/update/test/unit/test_bug794211.js
Normal file
86
toolkit/mozapps/update/test/unit/test_bug794211.js
Normal 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
Loading…
Reference in New Issue
Block a user