merge fx-team to m-c

This commit is contained in:
Rob Campbell 2011-08-12 10:55:14 -03:00
commit 953d05c62f
109 changed files with 8565 additions and 8247 deletions

View File

@ -231,14 +231,17 @@ AccStateChangeEvent::
AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, PRUint64 aState, PRBool aIsEnabled):
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode),
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
eAutoDetect, eAllowDupes),
mState(aState), mIsEnabled(aIsEnabled)
{
}
AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, PRUint64 aState) :
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode), mState(aState)
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
eAutoDetect, eAllowDupes),
mState(aState)
{
// Use GetAccessibleForNode() because we do not want to store an accessible
// since it leads to problems with delayed events in the case when

View File

@ -57,6 +57,7 @@
#include "nsWhitespaceTokenizer.h"
#include "nsComponentManagerUtils.h"
namespace dom = mozilla::dom;
using namespace mozilla::a11y;
void
@ -335,6 +336,24 @@ nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
return PR_TRUE;
}
nsIAtom*
nsAccUtils::GetARIAToken(dom::Element* aElement, nsIAtom* aAttr)
{
if (!nsAccUtils::HasDefinedARIAToken(aElement, aAttr))
return nsAccessibilityAtoms::_empty;
static nsIContent::AttrValuesArray tokens[] =
{ &nsAccessibilityAtoms::_false, &nsAccessibilityAtoms::_true,
&nsAccessibilityAtoms::mixed, nsnull};
PRInt32 idx = aElement->FindAttrValueIn(kNameSpaceID_None,
aAttr, tokens, eCaseMatters);
if (idx >= 0)
return *(tokens[idx]);
return nsnull;
}
nsAccessible *
nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole)
{

View File

@ -50,7 +50,7 @@
#include "nsAccessibilityService.h"
#include "nsCoreUtils.h"
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
#include "nsIDocShell.h"
#include "nsIDOMNode.h"
#include "nsIPersistentProperties2.h"
@ -150,6 +150,11 @@ public:
*/
static PRBool HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom);
/**
* Return atomic value of ARIA attribute of boolean or NMTOKEN type.
*/
static nsIAtom* GetARIAToken(mozilla::dom::Element* aElement, nsIAtom* aAttr);
/**
* Return document accessible for the given presshell.
*/

View File

@ -65,6 +65,7 @@ ACCESSIBILITY_ATOM(image, "image")
ACCESSIBILITY_ATOM(menu, "menu")
ACCESSIBILITY_ATOM(menuButton, "menu-button")
ACCESSIBILITY_ATOM(multiple, "multiple")
ACCESSIBILITY_ATOM(mixed, "mixed")
ACCESSIBILITY_ATOM(open, "open")
ACCESSIBILITY_ATOM(password, "password")
ACCESSIBILITY_ATOM(radio, "radio")

View File

@ -84,8 +84,6 @@ using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// Static member initialization
PRUint64 nsDocAccessible::gLastFocusedAccessiblesState = 0;
static nsIAtom** kRelationAttrs[] =
{
&nsAccessibilityAtoms::aria_labelledby,
@ -918,21 +916,33 @@ nsDocAccessible::AttributeWillChange(nsIDocument *aDocument,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute, PRInt32 aModType)
{
// XXX TODO: bugs 467143, 472142, 472143.
// Here we will want to cache whatever state we are potentially interested in,
// such as the existence of aria-pressed for button (so we know if we need to
// newly expose it as a toggle button) etc.
nsAccessible* accessible = GetAccessible(aElement);
if (!accessible) {
if (aElement != mContent)
return;
accessible = this;
}
// Update dependent IDs cache. Take care of elements that are accessible
// because dependent IDs cache doesn't contain IDs from non accessible
// elements.
if (aModType == nsIDOMMutationEvent::MODIFICATION ||
aModType == nsIDOMMutationEvent::REMOVAL) {
nsAccessible* accessible = GetAccessible(aElement);
if (accessible)
RemoveDependentIDsFor(accessible, aAttribute);
else if (aElement == mContent)
RemoveDependentIDsFor(this, aAttribute);
if (aModType != nsIDOMMutationEvent::ADDITION)
RemoveDependentIDsFor(accessible, aAttribute);
// Store the ARIA attribute old value so that it can be used after
// attribute change. Note, we assume there's no nested ARIA attribute
// changes. If this happens then we should end up with keeping a stack of
// old values.
// XXX TODO: bugs 472142, 472143.
// Here we will want to cache whatever attribute values we are interested
// in, such as the existence of aria-pressed for button (so we know if we
// need to newly expose it as a toggle button) etc.
if (aAttribute == nsAccessibilityAtoms::aria_checked ||
aAttribute == nsAccessibilityAtoms::aria_pressed) {
mARIAAttrOldValue = (aModType != nsIDOMMutationEvent::ADDITION) ?
nsAccUtils::GetARIAToken(aElement, aAttribute) : nsnull;
}
}
@ -976,10 +986,6 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument,
aModType == nsIDOMMutationEvent::ADDITION) {
AddDependentIDsFor(accessible, aAttribute);
}
// If it was the focused node, cache the new state.
if (aElement == gLastFocusedNode)
gLastFocusedAccessiblesState = accessible->State();
}
// nsDocAccessible protected member
@ -1045,8 +1051,8 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
}
if (aAttribute == nsAccessibilityAtoms::aria_busy) {
PRBool isOn = !aContent->AttrValueIs(aNameSpaceID, aAttribute,
nsAccessibilityAtoms::_true, eCaseMatters);
PRBool isOn = aContent->AttrValueIs(aNameSpaceID, aAttribute,
nsAccessibilityAtoms::_true, eCaseMatters);
nsRefPtr<AccEvent> event = new AccStateChangeEvent(aContent, states::BUSY, isOn);
FireDelayedAccessibleEvent(event);
return;
@ -1158,24 +1164,18 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
aAttribute == nsAccessibilityAtoms::aria_pressed) {
const PRUint32 kState = (aAttribute == nsAccessibilityAtoms::aria_checked) ?
states::CHECKED : states::PRESSED;
nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, kState);
nsRefPtr<AccEvent> event = new AccStateChangeEvent(aContent, kState);
FireDelayedAccessibleEvent(event);
if (aContent == gLastFocusedNode) {
// State changes for MIXED state currently only supported for focused item, because
// otherwise we would need access to the old attribute value in this listener.
// This is because we don't know if the previous value of aria-checked or aria-pressed was "mixed"
// without caching that info.
nsAccessible *accessible = event->GetAccessible();
if (accessible) {
PRBool wasMixed = (gLastFocusedAccessiblesState & states::MIXED) != 0;
PRBool isMixed =
(accessible->State() & states::MIXED) != 0;
if (wasMixed != isMixed) {
nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::MIXED, isMixed);
FireDelayedAccessibleEvent(event);
}
nsAccessible* accessible = event->GetAccessible();
if (accessible) {
bool wasMixed = (mARIAAttrOldValue == nsAccessibilityAtoms::mixed);
bool isMixed = aContent->AttrValueIs(kNameSpaceID_None, aAttribute,
nsAccessibilityAtoms::mixed, eCaseMatters);
if (isMixed != wasMixed) {
nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::MIXED, isMixed);
FireDelayedAccessibleEvent(event);
}
}
return;

View File

@ -567,7 +567,11 @@ protected:
*/
PRUint32 mLoadEventType;
static PRUint64 gLastFocusedAccessiblesState;
/**
* Keep the ARIA attribute old value that is initialized by
* AttributeWillChange and used by AttributeChanged notifications.
*/
nsIAtom* mARIAAttrOldValue;
nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;

View File

@ -355,8 +355,6 @@ nsRootAccessible::FireAccessibleFocusEvent(nsAccessible* aFocusAccessible,
nsDocAccessible* focusDocument = focusAccessible->GetDocAccessible();
NS_ASSERTION(focusDocument, "No document while accessible is in document?!");
gLastFocusedAccessiblesState = focusAccessible->State();
// Fire menu start/end events for ARIA menus.
if (focusAccessible->ARIARole() == nsIAccessibleRole::ROLE_MENUITEM) {
// The focus is inside a menu.
@ -668,7 +666,6 @@ nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
}
else if (eventType.EqualsLiteral("blur")) {
NS_IF_RELEASE(gLastFocusedNode);
gLastFocusedAccessiblesState = 0;
}
else if (eventType.EqualsLiteral("AlertActive")) {
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);

View File

@ -807,8 +807,11 @@ STDMETHODIMP nsAccessibleWrap::accNavigate(
/* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt)
{
__try {
if (!pvarEndUpAt)
return E_INVALIDARG;
nsAccessible *xpAccessibleStart = GetXPAccessibleFor(varStart);
if (!xpAccessibleStart)
if (!xpAccessibleStart || IsDefunct())
return E_FAIL;
VariantInit(pvarEndUpAt);

View File

@ -602,10 +602,11 @@ function eventQueue(aEventType)
this.isAlreadyCaught = function eventQueue_isAlreadyCaught(aIdx, aEvent)
{
// We don't have stored info about handled event other than its type and
// target, thus we should filter text change events since they may occur
// on the same element because of complex changes.
// target, thus we should filter text change and state change events since
// they may occur on the same element because of complex changes.
return this.compareEvents(aIdx, aEvent) &&
!(aEvent instanceof nsIAccessibleTextChangeEvent);
!(aEvent instanceof nsIAccessibleTextChangeEvent) &&
!(aEvent instanceof nsIAccessibleStateChangeEvent);
}
this.checkEvent = function eventQueue_checkEvent(aIdx, aEvent)
@ -1041,6 +1042,72 @@ function caretMoveChecker(aCaretOffset)
}
}
/**
* State change checker.
*/
function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
aTargetOrFunc, aTargetFuncArg)
{
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
aTargetFuncArg);
this.check = function stateChangeChecker_check(aEvent)
{
var event = null;
try {
var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
} catch (e) {
ok(false, "State change event was expected");
}
if (!event)
return;
is(event.state, aState, "Wrong state of the statechange event.");
is(event.isExtraState(), aIsExtraState,
"Wrong extra state bit of the statechange event.");
is(event.isEnabled(), aIsEnabled,
"Wrong state of statechange event state");
var state = aIsEnabled ? (aIsExtraState ? 0 : aState) : 0;
var extraState = aIsEnabled ? (aIsExtraState ? aState : 0) : 0;
var unxpdState = aIsEnabled ? 0 : (aIsExtraState ? 0 : aState);
var unxpdExtraState = aIsEnabled ? 0 : (aIsExtraState ? aState : 0);
testStates(event.accessible, state, extraState, unxpdState, unxpdExtraState);
}
}
/**
* Expanded state change checker.
*/
function expandedStateChecker(aIsEnabled, aTargetOrFunc, aTargetFuncArg)
{
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
aTargetFuncArg);
this.check = function expandedStateChecker_check(aEvent)
{
var event = null;
try {
var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
} catch (e) {
ok(false, "State change event was expected");
}
if (!event)
return;
is(event.state, STATE_EXPANDED, "Wrong state of the statechange event.");
is(event.isExtraState(), false,
"Wrong extra state bit of the statechange event.");
is(event.isEnabled(), aIsEnabled,
"Wrong state of statechange event state");
testStates(event.accessible,
(aIsEnabled ? STATE_EXPANDED : STATE_COLLAPSED));
}
}
////////////////////////////////////////////////////////////////////////////////
// Private implementation details.
////////////////////////////////////////////////////////////////////////////////

View File

@ -26,52 +26,103 @@
*/
var gQueue = null;
// Debug stuff.
//gA11yEventDumpID = "eventdump";
// gA11yEventDumpToConsole = true;
//gA11yEventDumpID = "eventdump"; // debugging
//gA11yEventDumpToConsole = true; // debugging
function expandNode(aNodeOrID, bExpand)
function expandNode(aID, aIsExpanded)
{
this.DOMNode = getNode(aNodeOrID);
this.DOMNode = getNode(aID);
this.invoke = function expandNode_invoke() {
// Note: this should fire an EVENT_STATE_CHANGE
this.DOMNode.setAttribute("aria-expanded", bExpand);
this.eventSeq = [
new expandedStateChecker(aIsExpanded, this.DOMNode)
];
this.invoke = function expandNode_invoke()
{
this.DOMNode.setAttribute("aria-expanded",
(aIsExpanded ? "true" : "false"));
};
this.check = function expandNode_check() {
testStates(aNodeOrID,
bExpand ? STATE_EXPANDED : STATE_COLLAPSED,
EXT_STATE_EXPANDABLE);
};
this.getID = function expandNode_getID() {
return prettyName(aNodeOrID) + " aria-expanded changed";
this.getID = function expandNode_getID()
{
return prettyName(aID) + " aria-expanded changed to '" + aIsExpanded + "'";
};
}
function busyify(aNodeOrID, aBusy)
function busyify(aID, aIsBusy)
{
this.DOMNode = getNode(aNodeOrID);
this.DOMNode = getNode(aID);
this.invoke = function busyify_invoke() {
this.DOMNode.setAttribute("aria-busy", aBusy);
this.eventSeq = [
new stateChangeChecker(STATE_BUSY, kOrdinalState, aIsBusy, this.DOMNode)
];
this.invoke = function busyify_invoke()
{
this.DOMNode.setAttribute("aria-busy", (aIsBusy ? "true" : "false"));
};
this.check = function busyify_check(event) {
testStates(aNodeOrID,
(aBusy ? STATE_BUSY : 0), 0,
(aBusy ? 0 : STATE_BUSY), 0);
this.getID = function busyify_getID()
{
return prettyName(aID) + " aria-busy changed to '" + aIsBusy + "'";
};
}
function setAttrOfMixedType(aID, aAttr, aState, aValue)
{
this.DOMNode = getNode(aID);
this.eventSeq = [
new stateChangeChecker(aState, kOrdinalState,
aValue == "true", this.DOMNode)
];
if (hasState(aID, STATE_MIXED) || aValue == "mixed") {
this.eventSeq.push(
new stateChangeChecker(STATE_MIXED, kOrdinalState,
aValue == "mixed", this.DOMNode)
);
}
this.invoke = function setAttrOfMixedType_invoke()
{
this.DOMNode.setAttribute(aAttr, aValue);
};
this.getID = function busyify_getID() {
return prettyName(aNodeOrID) + " aria-busy changed to " + aBusy;
this.getID = function setAttrOfMixedType_getID()
{
return prettyName(aID) + " " + aAttr + " changed to '" + aValue + "'";
};
}
function setPressed(aID, aValue)
{
this.__proto__ =
new setAttrOfMixedType(aID, "aria-pressed", STATE_PRESSED, aValue);
}
function setChecked(aID, aValue)
{
this.__proto__ =
new setAttrOfMixedType(aID, "aria-checked", STATE_CHECKED, aValue);
}
function buildQueueForAttrOfMixedType(aQueue, aID, aInvokerFunc)
{
var list = [ "", "undefined", "false", "true", "mixed" ];
for (var i = 0; i < list.length; i++) {
for (var j = i + 1; j < list.length; j++) {
// XXX: changes from/to "undefined"/"" shouldn't fire state change
// events, bug 472142.
aQueue.push(new aInvokerFunc(aID, list[i]));
aQueue.push(new aInvokerFunc(aID, list[j]));
}
}
}
function doTests()
{
gQueue = new eventQueue(EVENT_STATE_CHANGE);
gQueue = new eventQueue();
gQueue.push(new expandNode("section", true));
gQueue.push(new expandNode("section", false));
@ -80,6 +131,10 @@
gQueue.push(new busyify("aria_doc", true));
gQueue.push(new busyify("aria_doc", false));
buildQueueForAttrOfMixedType(gQueue, "pressable", setPressed);
buildQueueForAttrOfMixedType(gQueue, "checkable", setChecked);
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -94,13 +149,18 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=551684"
title="No statechange event for aria-expanded on native HTML elements, is fired on ARIA widgets">
Mozilla Bug 551684
</a>
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=648133"
title="fire state change event for aria-busy"
Mozilla Bug 648133
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=467143"
title="mixed state change event is fired for focused accessible only"
Mozilla Bug 467143
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
@ -113,5 +173,11 @@
<!-- aria-busy -->
<div id="aria_doc" role="document" tabindex="0">A document</div>
<!-- aria-pressed -->
<div id="pressable" role="button"></div>
<!-- aria-checked -->
<div id="checkable" role="checkbox"></div>
</body>
</html>

View File

@ -45,6 +45,8 @@ const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION;
const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL;
const kOrdinalState = 0;
const kExtraState = 1;
////////////////////////////////////////////////////////////////////////////////
// Test functions

View File

@ -6039,8 +6039,6 @@ i*86)
;;
x86_64)
MOZ_DIRECTX_SDK_CPU_SUFFIX=x64
# currently we disable ANGLE in 64bit builds
MOZ_ANGLE=
;;
esac
@ -7866,7 +7864,7 @@ dnl done during packaging with omnijar.
if test "$MOZ_CHROME_FILE_FORMAT" = "omni"; then
MOZ_OMNIJAR=1
AC_DEFINE(MOZ_OMNIJAR)
if test "$OS_ARCH" = "WINNT" -o "$OS_ARCH" = "OS2"; then
if test "$OS_ARCH" = "WINNT" -o "$OS_ARCH" = "OS2" -o "$OS_TARGET" = "Android"; then
MOZ_CHROME_FILE_FORMAT=flat
else
MOZ_CHROME_FILE_FORMAT=symlink

View File

@ -984,9 +984,6 @@ nsDOMEvent::GetEventPopupControlState(nsEvent *aEvent)
if (::PopupAllowedForEvent("change"))
abuse = openControlled;
break;
case NS_XUL_COMMAND:
abuse = openControlled;
break;
}
}
break;

View File

@ -216,11 +216,11 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
mDecodeThreadIdle(PR_FALSE),
mStopAudioThread(PR_TRUE),
mQuickBuffering(PR_FALSE),
mEventManager(aDecoder),
mIsRunning(PR_FALSE),
mRunAgain(PR_FALSE),
mDispatchedRunEvent(PR_FALSE),
mDecodeThreadWaiting(PR_FALSE)
mDecodeThreadWaiting(PR_FALSE),
mEventManager(aDecoder)
{
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");

View File

@ -83,7 +83,6 @@ class nsSHEntryShared : public nsIBFCacheEntry,
nsExpirationState *GetExpirationState() { return &mExpirationState; }
static already_AddRefed<nsSHEntryShared> Duplicate(nsSHEntryShared *aEntry);
void SetDocIdentifier(PRUint64 aDocIdentifier);
void RemoveFromExpirationTracker();
void Expire();

View File

@ -1942,7 +1942,8 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
presContext->AppUnitsToDevPixels(pt.y));
#ifndef NP_NO_CARBON
nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
::Point carbonPt = { ptPx.y + geckoScreenCoords.y, ptPx.x + geckoScreenCoords.x };
::Point carbonPt = { static_cast<short>(ptPx.y + geckoScreenCoords.y),
static_cast<short>(ptPx.x + geckoScreenCoords.x) };
if (eventModel == NPEventModelCarbon) {
if (event && anEvent.eventStructType == NS_MOUSE_EVENT) {
static_cast<EventRecord*>(event)->where = carbonPt;

View File

@ -51,6 +51,7 @@ _BROWSER_FILES = \
browser_ConsoleAPITests.js \
test-console-api.html \
browser_autofocus_preference.js \
browser_popup_blocker_save_open_panel.js \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -0,0 +1,101 @@
/**
* In this test, we call the save panel with CTRL+S. When shown, we load a
* webpage that is going to open malicious popups. These popups should be
* disallowed.
*/
var gLoaded = false;
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockObjects.js",
this);
function MockFilePicker() { }
MockFilePicker.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
init: function() { },
appendFilters: function(val) { },
appendFilter: function(val) { },
// constants
modeOpen: 0,
modeSave: 1,
modeGetFolder: 2,
modeOpenMultiple: 3,
returnOK: 0,
returnCancel: 1,
returnReplace: 2,
filterAll: 1,
filterHTML: 2,
filterText: 4,
filterImages: 8,
filterXML: 16,
filterXUL: 32,
filterApps: 64,
filterAllowURLs: 128,
filterAudio: 256,
filterVideo: 512,
// properties
defaultExtension: "",
defaultString: "",
get displayDirectory() { return null; },
set displayDirectory(val) { },
file: null,
get files() { return null; },
get fileURL() { return null; },
filterIndex: 0,
show: function() {
gBrowser.selectedTab.linkedBrowser.addEventListener("load", function () {
gBrowser.selectedTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
executeSoon(function() {
gLoaded = true;
});
}, true);
gBrowser.selectedTab.linkedBrowser.loadURI("data:text/html,<!DOCTYPE html><html><body onload='window.open(\"about:blank\", \"\", \"width=200,height=200\");'></body></html>");
let curThread = Components.classes["@mozilla.org/thread-manager;1"]
.getService().currentThread;
while (!gLoaded) {
curThread.processNextEvent(true);
}
return this.returnCancel;
},
};
function test() {
waitForExplicitFinish();
var mockFilePickerRegisterer =
new MockObjectRegisterer("@mozilla.org/filepicker;1", MockFilePicker);
mockFilePickerRegisterer.register();
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var gDisableLoadPref = prefs.getBoolPref("dom.disable_open_during_load");
prefs.setBoolPref("dom.disable_open_during_load", true);
gBrowser.addEventListener("DOMPopupBlocked", function() {
gBrowser.removeEventListener("DOMPopupBlocked", arguments.callee, true);
ok(true, "The popup has been blocked");
prefs.setBoolPref("dom.disable_open_during_load", gDisableLoadPref);
mockFilePickerRegisterer.unregister();
finish();
}, true)
if (navigator.platform.indexOf("Mac") == 0) {
// MacOS use metaKey instead of ctrlKey.
EventUtils.synthesizeKey("s", { metaKey: true, });
} else {
EventUtils.synthesizeKey("s", { ctrlKey: true, });
}
}

View File

@ -123,9 +123,6 @@ CSRCS = \
DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD
# ANGLE only on Win32 for now, the solution isn't set up
# for 64-bit yet. This is handled by MOZ_ANGLE which the configure script
# leaves undefined in the 64-bit case.
ifdef MOZ_ANGLE
# libEGL depends on (links against!) libGLESv2!

View File

@ -12,6 +12,8 @@ In this order:
angle-r702.patch - this is ANGLE r702
angle-limit-identifiers-to-250-chars.patch - see bug 675625
angle-r712.patch - this is ANGLE r712
angle-win64.patch - Win64 support. This is ANGLE r697
angle-r707.patch - this is ANGLE r707 for Win64 bug fix
In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.

View File

@ -0,0 +1,45 @@
diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.cpp b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
--- a/gfx/angle/src/libGLESv2/VertexDataManager.cpp
+++ b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
@@ -714,17 +714,17 @@ void StaticVertexBuffer::reserveRequired
{
// Already allocated
}
else UNREACHABLE(); // Static vertex buffers can't be resized
mRequiredSpace = 0;
}
-UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
+std::size_t StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
{
for (unsigned int element = 0; element < mCache.size(); element++)
{
if (mCache[element].type == attribute.mType && mCache[element].size == attribute.mSize && mCache[element].normalized == attribute.mNormalized)
{
if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
{
return mCache[element].streamOffset;
diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.h b/gfx/angle/src/libGLESv2/VertexDataManager.h
--- a/gfx/angle/src/libGLESv2/VertexDataManager.h
+++ b/gfx/angle/src/libGLESv2/VertexDataManager.h
@@ -88,17 +88,17 @@ class StaticVertexBuffer : public ArrayV
{
public:
explicit StaticVertexBuffer(IDirect3DDevice9 *device);
~StaticVertexBuffer();
void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
void reserveRequiredSpace();
- UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
+ std::size_t lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
private:
struct VertexElement
{
GLenum type;
GLint size;
bool normalized;
int attributeOffset;

235
gfx/angle/angle-win64.patch Normal file
View File

@ -0,0 +1,235 @@
diff --git a/gfx/angle/src/libEGL/Surface.cpp b/gfx/angle/src/libEGL/Surface.cpp
--- a/gfx/angle/src/libEGL/Surface.cpp
+++ b/gfx/angle/src/libEGL/Surface.cpp
@@ -285,17 +285,17 @@ void Surface::subclassWindow()
DWORD processId;
DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
{
return;
}
SetLastError(0);
- LONG oldWndProc = SetWindowLong(mWindow, GWL_WNDPROC, reinterpret_cast<LONG>(SurfaceWindowProc));
+ LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
{
mWindowSubclassed = false;
return;
}
SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
@@ -305,27 +305,27 @@ void Surface::subclassWindow()
void Surface::unsubclassWindow()
{
if(!mWindowSubclassed)
{
return;
}
// un-subclass
- LONG parentWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc));
+ LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
// Check the windowproc is still SurfaceWindowProc.
// If this assert fails, then it is likely the application has subclassed the
// hwnd as well and did not unsubclass before destroying its EGL context. The
// application should be modified to either subclass before initializing the
// EGL context, or to unsubclass before destroying the EGL context.
if(parentWndFunc)
{
- LONG prevWndFunc = SetWindowLong(mWindow, GWL_WNDPROC, parentWndFunc);
- ASSERT(prevWndFunc == reinterpret_cast<LONG>(SurfaceWindowProc));
+ LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
+ ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
}
RemoveProp(mWindow, kSurfaceProperty);
RemoveProp(mWindow, kParentWndProc);
mWindowSubclassed = false;
}
bool Surface::checkForOutOfDateSwapChain()
diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.cpp b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
--- a/gfx/angle/src/libGLESv2/VertexDataManager.cpp
+++ b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
@@ -50,24 +50,24 @@ VertexDataManager::~VertexDataManager()
delete mStreamingBuffer;
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
delete mCurrentValueBuffer[i];
}
}
-UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
+std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
{
Buffer *buffer = attribute.mBoundBuffer.get();
int inputStride = attribute.stride();
int elementSize = attribute.typeSize();
const FormatConverter &converter = formatConverter(attribute);
- UINT streamOffset = 0;
+ std::size_t streamOffset = 0;
void *output = NULL;
if (vertexBuffer)
{
output = vertexBuffer->map(attribute, spaceRequired(attribute, count), &streamOffset);
}
@@ -198,17 +198,17 @@ GLenum VertexDataManager::prepareVertexD
return GL_INVALID_OPERATION;
}
const FormatConverter &converter = formatConverter(attribs[i]);
StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
- UINT streamOffset = -1;
+ std::size_t streamOffset = -1;
if (staticBuffer)
{
streamOffset = staticBuffer->lookupAttribute(attribs[i]);
if (streamOffset == -1)
{
// Convert the entire buffer
@@ -666,17 +666,17 @@ void StreamingVertexBuffer::reserveRequi
StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY)
{
}
StaticVertexBuffer::~StaticVertexBuffer()
{
}
-void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
+void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset)
{
void *mapPtr = NULL;
if (mVertexBuffer)
{
HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
if (FAILED(result))
diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.h b/gfx/angle/src/libGLESv2/VertexDataManager.h
--- a/gfx/angle/src/libGLESv2/VertexDataManager.h
+++ b/gfx/angle/src/libGLESv2/VertexDataManager.h
@@ -30,17 +30,17 @@ struct TranslatedAttribute
UINT stride; // 0 means not to advance the read pointer at all
IDirect3DVertexBuffer9 *vertexBuffer;
};
class VertexBuffer
{
public:
- VertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags);
virtual ~VertexBuffer();
void unmap();
IDirect3DVertexBuffer9 *getBuffer() const;
protected:
IDirect3DDevice9 *const mDevice;
@@ -55,60 +55,60 @@ class ConstantVertexBuffer : public Vert
public:
ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w);
~ConstantVertexBuffer();
};
class ArrayVertexBuffer : public VertexBuffer
{
public:
- ArrayVertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags);
~ArrayVertexBuffer();
- UINT size() const { return mBufferSize; }
- virtual void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset) = 0;
+ std::size_t size() const { return mBufferSize; }
+ virtual void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) = 0;
virtual void reserveRequiredSpace() = 0;
void addRequiredSpace(UINT requiredSpace);
protected:
- UINT mBufferSize;
- UINT mWritePosition;
- UINT mRequiredSpace;
+ std::size_t mBufferSize;
+ std::size_t mWritePosition;
+ std::size_t mRequiredSpace;
};
class StreamingVertexBuffer : public ArrayVertexBuffer
{
public:
- StreamingVertexBuffer(IDirect3DDevice9 *device, UINT initialSize);
+ StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize);
~StreamingVertexBuffer();
- void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
void reserveRequiredSpace();
};
class StaticVertexBuffer : public ArrayVertexBuffer
{
public:
explicit StaticVertexBuffer(IDirect3DDevice9 *device);
~StaticVertexBuffer();
- void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
void reserveRequiredSpace();
UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
private:
struct VertexElement
{
GLenum type;
GLint size;
bool normalized;
int attributeOffset;
- UINT streamOffset;
+ std::size_t streamOffset;
};
std::vector<VertexElement> mCache;
};
class VertexDataManager
{
public:
@@ -117,18 +117,18 @@ class VertexDataManager
void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
private:
DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
- UINT spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
- UINT writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
+ std::size_t spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
+ std::size_t writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
Context *const mContext;
IDirect3DDevice9 *const mDevice;
StreamingVertexBuffer *mStreamingBuffer;
bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];
ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];

View File

@ -143,8 +143,8 @@ DEFFILE = $(srcdir)/libEGL.def
include $(topsrcdir)/config/rules.mk
EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/x86/d3d9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/x86/dxguid.lib" \
EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/dxguid.lib" \
"$(DIST)/lib/libGLESv2.lib" \
dwmapi.lib \
delayimp.lib \

View File

@ -290,7 +290,7 @@ void Surface::subclassWindow()
}
SetLastError(0);
LONG oldWndProc = SetWindowLong(mWindow, GWL_WNDPROC, reinterpret_cast<LONG>(SurfaceWindowProc));
LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
{
mWindowSubclassed = false;
@ -310,7 +310,7 @@ void Surface::unsubclassWindow()
}
// un-subclass
LONG parentWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc));
LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
// Check the windowproc is still SurfaceWindowProc.
// If this assert fails, then it is likely the application has subclassed the
@ -319,8 +319,8 @@ void Surface::unsubclassWindow()
// EGL context, or to unsubclass before destroying the EGL context.
if(parentWndFunc)
{
LONG prevWndFunc = SetWindowLong(mWindow, GWL_WNDPROC, parentWndFunc);
ASSERT(prevWndFunc == reinterpret_cast<LONG>(SurfaceWindowProc));
LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
}
RemoveProp(mWindow, kSurfaceProperty);

View File

@ -156,6 +156,6 @@ DEFFILE = $(srcdir)/libGLESv2.def
include $(topsrcdir)/config/rules.mk
EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/x86/d3d9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/x86/d3dx9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/x86/D3DCompiler.lib"
EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3dx9.lib" \
"$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/D3DCompiler.lib"

View File

@ -55,14 +55,14 @@ VertexDataManager::~VertexDataManager()
}
}
UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
{
Buffer *buffer = attribute.mBoundBuffer.get();
int inputStride = attribute.stride();
int elementSize = attribute.typeSize();
const FormatConverter &converter = formatConverter(attribute);
UINT streamOffset = 0;
std::size_t streamOffset = 0;
void *output = NULL;
@ -203,7 +203,7 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
UINT streamOffset = -1;
std::size_t streamOffset = -1;
if (staticBuffer)
{
@ -671,7 +671,7 @@ StaticVertexBuffer::~StaticVertexBuffer()
{
}
void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset)
{
void *mapPtr = NULL;
@ -719,7 +719,7 @@ void StaticVertexBuffer::reserveRequiredSpace()
mRequiredSpace = 0;
}
UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
std::size_t StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
{
for (unsigned int element = 0; element < mCache.size(); element++)
{

View File

@ -35,7 +35,7 @@ struct TranslatedAttribute
class VertexBuffer
{
public:
VertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags);
virtual ~VertexBuffer();
void unmap();
@ -60,27 +60,27 @@ class ConstantVertexBuffer : public VertexBuffer
class ArrayVertexBuffer : public VertexBuffer
{
public:
ArrayVertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags);
~ArrayVertexBuffer();
UINT size() const { return mBufferSize; }
virtual void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset) = 0;
std::size_t size() const { return mBufferSize; }
virtual void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) = 0;
virtual void reserveRequiredSpace() = 0;
void addRequiredSpace(UINT requiredSpace);
protected:
UINT mBufferSize;
UINT mWritePosition;
UINT mRequiredSpace;
std::size_t mBufferSize;
std::size_t mWritePosition;
std::size_t mRequiredSpace;
};
class StreamingVertexBuffer : public ArrayVertexBuffer
{
public:
StreamingVertexBuffer(IDirect3DDevice9 *device, UINT initialSize);
StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize);
~StreamingVertexBuffer();
void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
void reserveRequiredSpace();
};
@ -90,10 +90,10 @@ class StaticVertexBuffer : public ArrayVertexBuffer
explicit StaticVertexBuffer(IDirect3DDevice9 *device);
~StaticVertexBuffer();
void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
void reserveRequiredSpace();
UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
std::size_t lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
private:
struct VertexElement
@ -103,7 +103,7 @@ class StaticVertexBuffer : public ArrayVertexBuffer
bool normalized;
int attributeOffset;
UINT streamOffset;
std::size_t streamOffset;
};
std::vector<VertexElement> mCache;
@ -122,8 +122,8 @@ class VertexDataManager
private:
DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
UINT spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
UINT writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
std::size_t spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
std::size_t writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
Context *const mContext;
IDirect3DDevice9 *const mDevice;

View File

@ -94,7 +94,8 @@ class ShadowableLayer;
*/
class BasicImplData {
public:
BasicImplData() : mHidden(PR_FALSE), mOperator(gfxContext::OPERATOR_OVER)
BasicImplData() : mHidden(PR_FALSE),
mClipToVisibleRegion(PR_FALSE), mOperator(gfxContext::OPERATOR_OVER)
{
MOZ_COUNT_CTOR(BasicImplData);
}
@ -114,6 +115,8 @@ public:
/**
* Like Paint() but called for ThebesLayers with the additional parameters
* they need.
* If mClipToVisibleRegion is set, then the layer must clip to its
* effective visible region (snapped or unsnapped, it doesn't matter).
*/
virtual void PaintThebes(gfxContext* aContext,
LayerManager::DrawThebesLayerCallback aCallback,
@ -157,8 +160,12 @@ public:
}
gfxContext::GraphicsOperator GetOperator() const { return mOperator; }
PRBool GetClipToVisibleRegion() { return mClipToVisibleRegion; }
void SetClipToVisibleRegion(PRBool aClip) { mClipToVisibleRegion = aClip; }
protected:
PRPackedBool mHidden;
PRPackedBool mClipToVisibleRegion;
gfxContext::GraphicsOperator mOperator;
};
@ -664,7 +671,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
aContext->Save();
PRBool needsClipToVisibleRegion = PR_FALSE;
PRBool needsClipToVisibleRegion = GetClipToVisibleRegion();
PRBool needsGroup =
opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER;
nsRefPtr<gfxContext> groupContext;
@ -766,7 +773,10 @@ BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
// If the entire buffer is valid, we can just draw the whole thing,
// no need to clip. But we'll still clip if clipping is cheap ---
// that might let us copy a smaller region of the buffer.
// Also clip to the visible region if we're told to.
if (!aLayer->GetValidRegion().Contains(BufferRect()) ||
(ToData(aLayer)->GetClipToVisibleRegion() &&
!aLayer->GetVisibleRegion().Contains(BufferRect())) ||
IsClippingCheap(aTarget, aLayer->GetEffectiveVisibleRegion())) {
// We don't want to draw invalid stuff, so we need to clip. Might as
// well clip to the smallest area possible --- the visible region.
@ -1375,6 +1385,7 @@ TransformIntRect(nsIntRect& aRect, const gfxMatrix& aMatrix,
* It can't be used as is by accelerated layers because of intermediate surfaces.
* This must set the hidden flag to true or false on *all* layers in the subtree.
* It also sets the operator for all layers to "OVER".
* It clears mClipToVisibleRegion on all layers.
* @param aClipRect the cliprect, in the root coordinate system. We assume
* that any layer drawing is clipped to this rect. It is therefore not
* allowed to add to the opaque region outside that rect.
@ -1423,6 +1434,7 @@ MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect,
BasicImplData* data = ToData(aLayer);
data->SetOperator(gfxContext::OPERATOR_OVER);
data->SetClipToVisibleRegion(PR_FALSE);
if (!aLayer->AsContainerLayer()) {
gfxMatrix transform;
@ -1513,8 +1525,11 @@ ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect)
data->SetOperator(gfxContext::OPERATOR_SOURCE);
container->ForceIntermediateSurface();
} else {
// Tell the children to clip to their visible regions so our assumption
// that they don't paint outside their visible regions is valid!
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
ToData(child)->SetClipToVisibleRegion(PR_TRUE);
ApplyDoubleBuffering(child, newVisibleRect);
}
}
@ -1637,14 +1652,16 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
BasicContainerLayer* container = static_cast<BasicContainerLayer*>(aLayer);
PRBool needsGroup = aLayer->GetFirstChild() &&
container->UseIntermediateSurface();
BasicImplData* data = ToData(aLayer);
PRBool needsClipToVisibleRegion =
data->GetClipToVisibleRegion() && !aLayer->AsThebesLayer();
NS_ASSERTION(needsGroup || !aLayer->GetFirstChild() ||
container->GetOperator() == gfxContext::OPERATOR_OVER,
"non-OVER operator should have forced UseIntermediateSurface");
// If needsSaveRestore is false, we should still save and restore
// the CTM
PRBool needsSaveRestore = needsGroup || clipRect;
PRBool needsSaveRestore = needsGroup || clipRect || needsClipToVisibleRegion;
gfxMatrix savedMatrix;
if (needsSaveRestore) {
aTarget->Save();
@ -1666,8 +1683,15 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
effectiveTransform.Is2D(&transform);
aTarget->SetMatrix(transform);
PRBool pushedTargetOpaqueRect = PR_FALSE;
const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
// If needsGroup is true, we'll clip to the visible region after we've popped the group
if (needsClipToVisibleRegion && !needsGroup) {
gfxUtils::ClipToRegion(aTarget, visibleRegion);
// Don't need to clip to visible region again
needsClipToVisibleRegion = PR_FALSE;
}
PRBool pushedTargetOpaqueRect = PR_FALSE;
nsRefPtr<gfxASurface> currentSurface = aTarget->CurrentSurface();
const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
@ -1682,7 +1706,6 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
pushedTargetOpaqueRect = PR_TRUE;
}
PRBool needsClipToVisibleRegion = PR_FALSE;
nsRefPtr<gfxContext> groupTarget;
if (needsGroup) {
groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
@ -1694,7 +1717,6 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
/* Only paint ourself, or our children - This optimization relies on this! */
Layer* child = aLayer->GetFirstChild();
if (!child) {
BasicImplData* data = ToData(aLayer);
#ifdef MOZ_LAYERS_HAVE_LOG
MOZ_LAYERS_LOG(("%s (0x%p) is covered: %i\n", __FUNCTION__,
(void*)aLayer, data->IsHidden()));

View File

@ -48,8 +48,8 @@ BlendState ComponentAlphaBlend
SrcBlend = One;
DestBlend = Inv_Src1_Color;
BlendOp = Add;
SrcBlendAlpha = Zero;
DestBlendAlpha = One;
SrcBlendAlpha = Src1_Alpha;
DestBlendAlpha = Inv_Src1_Alpha;
BlendOpAlpha = Add;
RenderTargetWriteMask[0] = 0x0F; // All
};
@ -172,6 +172,7 @@ PS_OUTPUT ComponentAlphaShader(const VS_OUTPUT aVertex) : SV_Target
result.vSrc = tRGB.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords);
result.vAlpha = 1.0 - tRGBWhite.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) + result.vSrc;
result.vAlpha.a = result.vAlpha.g;
result.vSrc *= fLayerOpacity;
result.vAlpha *= fLayerOpacity;
return result;

File diff suppressed because it is too large Load Diff

View File

@ -115,7 +115,7 @@ public:
* is usually a factor of AppUnitsPerCSSPixel(), although that is
* not guaranteed.
*/
PRInt32 AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; }
PRUint32 AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; }
/**
* Convert device pixels which is used for gfx/thebes to nearest
@ -311,7 +311,7 @@ protected:
nscoord mWidth;
nscoord mHeight;
PRUint32 mDepth;
PRInt32 mAppUnitsPerDevPixel;
PRUint32 mAppUnitsPerDevPixel;
PRInt32 mAppUnitsPerDevNotScaledPixel;
PRInt32 mAppUnitsPerPhysicalInch;
float mPixelScale;

View File

@ -98,7 +98,7 @@ public:
} // anon namespace
nsFontMetrics::nsFontMetrics()
: mDeviceContext(nsnull), mP2A(-1), mTextRunRTL(PR_FALSE)
: mDeviceContext(nsnull), mP2A(0), mTextRunRTL(PR_FALSE)
{
}
@ -113,7 +113,7 @@ nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
nsDeviceContext *aContext,
gfxUserFontSet *aUserFontSet)
{
NS_ABORT_IF_FALSE(mP2A == -1, "already initialized");
NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
mFont = aFont;
mLanguage = aLanguage;

View File

@ -227,7 +227,7 @@ public:
gfxFontGroup* GetThebesFontGroup() { return mFontGroup; }
gfxUserFontSet* GetUserFontSet() { return mFontGroup->GetUserFontSet(); }
PRInt32 AppUnitsPerDevPixel() { return mP2A; }
PRUint32 AppUnitsPerDevPixel() { return mP2A; }
protected:
const gfxFont::Metrics& GetMetrics() const;
@ -236,7 +236,7 @@ protected:
nsRefPtr<gfxFontGroup> mFontGroup;
nsCOMPtr<nsIAtom> mLanguage;
nsDeviceContext *mDeviceContext;
PRInt32 mP2A;
PRUint32 mP2A;
PRPackedBool mTextRunRTL;
};

View File

@ -70,7 +70,7 @@ public:
// These accessors will never return null.
gfxContext *ThebesContext() { return mThebes; }
nsDeviceContext *DeviceContext() { return mDeviceContext; }
PRInt32 AppUnitsPerDevPixel() { return mP2A; }
PRUint32 AppUnitsPerDevPixel() { return mP2A; }
// Graphics state

View File

@ -830,8 +830,8 @@ gfxHarfBuzzShaper::InitTextRun(gfxContext *aContext,
// Ligature features are enabled by default in the generic shaper,
// so we explicitly turn them off if necessary (for letter-spacing)
if (disableLigatures) {
hb_feature_t ligaOff = { HB_TAG('l','i','g','a'), 0, 0, -1 };
hb_feature_t cligOff = { HB_TAG('c','l','i','g'), 0, 0, -1 };
hb_feature_t ligaOff = { HB_TAG('l','i','g','a'), 0, 0, UINT_MAX };
hb_feature_t cligOff = { HB_TAG('c','l','i','g'), 0, 0, UINT_MAX };
features.AppendElement(ligaOff);
features.AppendElement(cligOff);
}
@ -852,7 +852,7 @@ gfxHarfBuzzShaper::InitTextRun(gfxContext *aContext,
}
if (j == features.Length()) {
const gfxFontFeature& f = cssFeatures->ElementAt(i);
hb_feature_t hbf = { f.mTag, f.mValue, 0, -1 };
hb_feature_t hbf = { f.mTag, f.mValue, 0, UINT_MAX };
features.AppendElement(hbf);
}
}

View File

@ -186,7 +186,7 @@ NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
// but trying to find where we were in a constantly changing list is basically
// impossible.
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, int(geteuid()) };
// Since more processes could start between when we get the size and when
// we get the list, we do a loop to keep trying until we get it.

View File

@ -182,15 +182,15 @@ class Time {
// like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
// additions and changes to prevent errors.
struct Exploded {
int year; // Four digit year "2007"
int month; // 1-based month (values 1 = January, etc.)
int day_of_week; // 0-based day of week (0 = Sunday, etc.)
int day_of_month; // 1-based day of month (1-31)
int hour; // Hour within the current day (0-23)
int minute; // Minute within the current hour (0-59)
int second; // Second within the current minute (0-59 plus leap
// seconds which may take it up to 60).
int millisecond; // Milliseconds within the current second (0-999)
int year; // Four digit year "2007"
signed char month; // 1-based month (values 1 = January, etc.)
signed char day_of_week; // 0-based day of week (0 = Sunday, etc.)
signed char day_of_month; // 1-based day of month (1-31)
signed char hour; // Hour within the current day (0-23)
signed char minute; // Minute within the current hour (0-59)
signed char second; // Second within the current minute (0-59 plus
// leap seconds which may take it up to 60).
int millisecond; // Milliseconds within the current second (0-999)
};
// Contains the NULL time. Use Time::Now() to get the current time.

View File

@ -5347,6 +5347,8 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// Assert that we're on the thread we were created from.
JS_ASSERT(cinfo->cxThread == JS_GetContextThread(cx));
JS_AbortIfWrongThread(JS_GetRuntime(cx));
JSAutoRequest ar(cx);
JSAutoEnterCompartment ac;

View File

@ -80,8 +80,6 @@ CPPSRCS = \
testScriptObject.cpp \
testSetProperty.cpp \
testStringBuffer.cpp \
testThreadGC.cpp \
testThreads.cpp \
testTrap.cpp \
testUTF8.cpp \
testVersion.cpp \

View File

@ -1,195 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*/
#ifdef JS_THREADSAFE
#include "tests.h"
#include "prthread.h"
#include "jscntxt.h"
/*
* We test that if a GC callback cancels the GC on a child thread the GC can
* still proceed on the main thread even if the child thread continue to
* run uninterrupted.
*/
struct SharedData {
enum ChildState {
CHILD_STARTING,
CHILD_RUNNING,
CHILD_DONE,
CHILD_ERROR
};
JSRuntime *const runtime;
PRThread *const mainThread;
PRLock *const lock;
PRCondVar *const signal;
ChildState childState;
bool childShouldStop;
JSContext *childContext;
SharedData(JSRuntime *rt, bool *ok)
: runtime(rt),
mainThread(PR_GetCurrentThread()),
lock(PR_NewLock()),
signal(lock ? PR_NewCondVar(lock) : NULL),
childState(CHILD_STARTING),
childShouldStop(false),
childContext(NULL)
{
JS_ASSERT(!*ok);
*ok = !!signal;
}
~SharedData() {
if (signal)
PR_DestroyCondVar(signal);
if (lock)
PR_DestroyLock(lock);
}
};
static SharedData *shared;
static JSBool
CancelNonMainThreadGCCallback(JSContext *cx, JSGCStatus status)
{
return status != JSGC_BEGIN || PR_GetCurrentThread() == shared->mainThread;
}
static JSBool
StopChildOperationCallback(JSContext *cx)
{
bool shouldStop;
PR_Lock(shared->lock);
shouldStop = shared->childShouldStop;
PR_Unlock(shared->lock);
return !shouldStop;
}
static JSBool
NotifyMainThreadAboutBusyLoop(JSContext *cx, uintN argc, jsval *vp)
{
PR_Lock(shared->lock);
JS_ASSERT(shared->childState == SharedData::CHILD_STARTING);
shared->childState = SharedData::CHILD_RUNNING;
shared->childContext = cx;
PR_NotifyCondVar(shared->signal);
PR_Unlock(shared->lock);
return true;
}
static void
ChildThreadMain(void *arg)
{
JS_ASSERT(!arg);
bool error = true;
JSContext *cx = JS_NewContext(shared->runtime, 8192);
if (cx) {
JS_SetOperationCallback(cx, StopChildOperationCallback);
JSAutoRequest ar(cx);
JSObject *global = JS_NewCompartmentAndGlobalObject(cx, JSAPITest::basicGlobalClass(),
NULL);
if (global) {
JS_SetGlobalObject(cx, global);
if (JS_InitStandardClasses(cx, global) &&
JS_DefineFunction(cx, global, "notify", NotifyMainThreadAboutBusyLoop, 0, 0)) {
jsval rval;
static const char code[] = "var i = 0; notify(); for (var i = 0; ; ++i);";
JSBool ok = JS_EvaluateScript(cx, global, code, strlen(code),
__FILE__, __LINE__, &rval);
if (!ok && !JS_IsExceptionPending(cx)) {
/* Evaluate should only return via the callback cancellation. */
error = false;
}
}
}
}
PR_Lock(shared->lock);
shared->childState = error ? SharedData::CHILD_DONE : SharedData::CHILD_ERROR;
shared->childContext = NULL;
PR_NotifyCondVar(shared->signal);
PR_Unlock(shared->lock);
if (cx)
JS_DestroyContextNoGC(cx);
}
BEGIN_TEST(testThreadGC_bug590533)
{
/*
* Test the child thread busy running while the current thread calls
* the GC both with JSRuntime->gcIsNeeded set and unset.
*/
bool ok = TestChildThread(true);
CHECK(ok);
ok = TestChildThread(false);
CHECK(ok);
return ok;
}
bool TestChildThread(bool setGCIsNeeded)
{
bool ok = false;
shared = new SharedData(rt, &ok);
CHECK(ok);
JSGCCallback oldGCCallback = JS_SetGCCallback(cx, CancelNonMainThreadGCCallback);
PRThread *thread =
PR_CreateThread(PR_USER_THREAD, ChildThreadMain, NULL,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
if (!thread)
return false;
PR_Lock(shared->lock);
while (shared->childState == SharedData::CHILD_STARTING)
PR_WaitCondVar(shared->signal, PR_INTERVAL_NO_TIMEOUT);
JS_ASSERT(shared->childState != SharedData::CHILD_DONE);
ok = (shared->childState == SharedData::CHILD_RUNNING);
PR_Unlock(shared->lock);
CHECK(ok);
if (setGCIsNeeded) {
/*
* Use JS internal API to set the GC trigger flag after we know
* that the child is in a request and is about to run an infinite
* loop. Then run the GC with JSRuntime->gcIsNeeded flag set.
*/
js::AutoLockGC lock(rt);
js::TriggerGC(rt);
}
JS_GC(cx);
PR_Lock(shared->lock);
shared->childShouldStop = true;
while (shared->childState == SharedData::CHILD_RUNNING) {
JS_TriggerOperationCallback(shared->childContext);
PR_WaitCondVar(shared->signal, PR_INTERVAL_NO_TIMEOUT);
}
JS_ASSERT(shared->childState != SharedData::CHILD_STARTING);
ok = (shared->childState == SharedData::CHILD_DONE);
PR_Unlock(shared->lock);
JS_SetGCCallback(cx, oldGCCallback);
PR_JoinThread(thread);
delete shared;
shared = NULL;
return true;
}
END_TEST(testThreadGC_bug590533)
#endif

View File

@ -1,174 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*/
#ifdef JS_THREADSAFE
#include "tests.h"
#include "prthread.h"
struct ThreadData {
JSRuntime *rt;
JSObject *obj;
const char *code;
bool ok;
};
BEGIN_TEST(testThreads_bug561444)
{
const char *code = "<a><b/></a>.b.@c = '';";
EXEC(code);
jsrefcount rc = JS_SuspendRequest(cx);
{
ThreadData data = {rt, global, code, false};
PRThread *thread =
PR_CreateThread(PR_USER_THREAD, threadMain, &data,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
CHECK(thread);
PR_JoinThread(thread);
CHECK(data.ok);
}
JS_ResumeRequest(cx, rc);
return true;
}
static void threadMain(void *arg) {
ThreadData *d = (ThreadData *) arg;
JSContext *cx = JS_NewContext(d->rt, 8192);
if (!cx)
return;
JS_BeginRequest(cx);
{
JSAutoEnterCompartment ac;
jsval v;
d->ok = ac.enter(cx, d->obj) &&
JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__,
&v);
}
JS_DestroyContext(cx);
}
END_TEST(testThreads_bug561444)
const PRUint32 NATIVE_STACK_SIZE = 64 * 1024;
const PRUint32 NATIVE_STACK_HEADROOM = 8 * 1024;
template <class T>
class Repeat {
size_t n;
const T &t;
public:
Repeat(size_t n, const T &t) : n(n), t(t) {}
bool operator()() const {
for (size_t i = 0; i < n; i++)
if (!t())
return false;
return true;
}
};
template <class T> Repeat<T> repeat(size_t n, const T &t) { return Repeat<T>(n, t); }
/* Class of callable that does something in n parallel threads. */
template <class T>
class Parallel {
size_t n;
const T &t;
struct pair { const Parallel *self; bool ok; };
static void threadMain(void *arg) {
pair *p = (pair *) arg;
if (!p->self->t())
p->ok = false;
}
public:
Parallel(size_t n, const T &t) : n(n), t(t) {}
bool operator()() const {
pair p = {this, true};
PRThread **thread = new PRThread *[n];
if (!thread)
return false;
size_t i;
for (i = 0; i < n; i++) {
thread[i] = PR_CreateThread(PR_USER_THREAD, threadMain, &p, PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD, PR_JOINABLE_THREAD, NATIVE_STACK_SIZE);
if (thread[i] == NULL) {
p.ok = false;
break;
}
}
while (i--)
PR_JoinThread(thread[i]);
delete[] thread;
return p.ok;
}
};
template <class T> Parallel<T> parallel(size_t n, const T &t) { return Parallel<T>(n, t); }
/* Class of callable that creates a compartment and runs some code in it. */
class eval {
JSRuntime *rt;
const char *code;
public:
eval(JSRuntime *rt, const char *code) : rt(rt), code(code) {}
bool operator()() const {
JSContext *cx = JS_NewContext(rt, 8192);
if (!cx)
return false;
JS_SetNativeStackQuota(cx, NATIVE_STACK_SIZE - NATIVE_STACK_HEADROOM);
bool ok = false;
{
JSAutoRequest ar(cx);
JSObject *global =
JS_NewCompartmentAndGlobalObject(cx, JSAPITest::basicGlobalClass(), NULL);
if (global) {
JS_SetGlobalObject(cx, global);
jsval rval;
ok = JS_InitStandardClasses(cx, global) &&
JS_EvaluateScript(cx, global, code, strlen(code), "", 0, &rval);
}
}
JS_DestroyContextMaybeGC(cx);
return ok;
}
};
BEGIN_TEST(testThreads_bug604782)
{
jsrefcount rc = JS_SuspendRequest(cx);
bool ok = repeat(20, parallel(3, eval(rt, "for(i=0;i<1000;i++);")))();
JS_ResumeRequest(cx, rc);
CHECK(ok);
return true;
}
END_TEST(testThreads_bug604782)
BEGIN_TEST(testThreads_bug609103)
{
const char *code =
"var x = {};\n"
"for (var i = 0; i < 10000; i++)\n"
" x = {next: x};\n";
jsrefcount rc = JS_SuspendRequest(cx);
bool ok = parallel(2, eval(rt, code))();
JS_ResumeRequest(cx, rc);
CHECK(ok);
return true;
}
END_TEST(testThreads_bug609103)
#endif

View File

@ -596,6 +596,7 @@ JS_GetTypeName(JSContext *cx, JSType type)
JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, v1, v2);
return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
}
@ -603,6 +604,7 @@ JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
JS_PUBLIC_API(JSBool)
JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, v1, v2);
return LooselyEqual(cx, Valueify(v1), Valueify(v2), equal);
}
@ -610,6 +612,7 @@ JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, v1, v2);
return SameValue(cx, Valueify(v1), Valueify(v2), same);
}
@ -647,6 +650,10 @@ JSRuntime::JSRuntime()
bool
JSRuntime::init(uint32 maxbytes)
{
#ifdef JS_THREADSAFE
ownerThread_ = js_CurrentThreadId();
#endif
#ifdef JS_METHODJIT_SPEW
JMCheckLogging();
#endif
@ -742,6 +749,28 @@ JSRuntime::~JSRuntime()
#endif
}
#ifdef JS_THREADSAFE
void
JSRuntime::setOwnerThread()
{
JS_ASSERT(ownerThread_ == (void *)-1);
ownerThread_ = js_CurrentThreadId();
}
void
JSRuntime::clearOwnerThread()
{
JS_ASSERT(onOwnerThread());
ownerThread_ = (void *)-1;
}
JS_FRIEND_API(bool)
JSRuntime::onOwnerThread() const
{
return ownerThread_ == js_CurrentThreadId();
}
#endif
JS_PUBLIC_API(JSRuntime *)
JS_NewRuntime(uint32 maxbytes)
{
@ -1998,12 +2027,14 @@ JS_ComputeThis(JSContext *cx, jsval *vp)
JS_PUBLIC_API(void *)
JS_malloc(JSContext *cx, size_t nbytes)
{
CHECK_REQUEST(cx);
return cx->malloc_(nbytes);
}
JS_PUBLIC_API(void *)
JS_realloc(JSContext *cx, void *p, size_t nbytes)
{
CHECK_REQUEST(cx);
return cx->realloc_(p, nbytes);
}
@ -5332,12 +5363,16 @@ JS_GetFlatStringChars(JSFlatString *str)
JS_PUBLIC_API(JSBool)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
{
CHECK_REQUEST(cx);
return CompareStrings(cx, str1, str2, result);
}
JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
{
CHECK_REQUEST(cx);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
@ -5523,6 +5558,8 @@ JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
const JSStructuredCloneCallbacks *optionalCallbacks,
void *closure)
{
CHECK_REQUEST(cx);
if (version > JS_STRUCTURED_CLONE_VERSION) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
return false;
@ -5539,6 +5576,8 @@ JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp,
const JSStructuredCloneCallbacks *optionalCallbacks,
void *closure)
{
CHECK_REQUEST(cx);
const JSStructuredCloneCallbacks *callbacks =
optionalCallbacks ?
optionalCallbacks :
@ -6113,6 +6152,8 @@ JS_GetContextThread(JSContext *cx)
JS_PUBLIC_API(jsword)
JS_SetContextThread(JSContext *cx)
{
JS_AbortIfWrongThread(cx->runtime);
#ifdef JS_THREADSAFE
JS_ASSERT(!cx->outstandingRequests);
if (cx->thread()) {
@ -6130,9 +6171,36 @@ JS_SetContextThread(JSContext *cx)
return 0;
}
extern JS_PUBLIC_API(void)
JS_ClearRuntimeThread(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
rt->clearOwnerThread();
#endif
}
extern JS_PUBLIC_API(void)
JS_SetRuntimeThread(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
rt->setOwnerThread();
#endif
}
extern JS_PUBLIC_API(void)
JS_AbortIfWrongThread(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
if (!rt->onOwnerThread())
JS_Assert("rt->onOwnerThread()", __FILE__, __LINE__);
#endif
}
JS_PUBLIC_API(jsword)
JS_ClearContextThread(JSContext *cx)
{
JS_AbortIfWrongThread(cx->runtime);
#ifdef JS_THREADSAFE
/*
* cx must have exited all requests it entered and, if cx is associated

View File

@ -3729,6 +3729,51 @@ JS_SetContextThread(JSContext *cx);
extern JS_PUBLIC_API(jsword)
JS_ClearContextThread(JSContext *cx);
/*
* A JS runtime always has an "owner thread". The owner thread is set when the
* runtime is created (to the current thread) and practically all entry points
* into the JS engine check that a runtime (or anything contained in the
* runtime: context, compartment, object, etc) is only touched by its owner
* thread. Embeddings may check this invariant outside the JS engine by calling
* JS_AbortIfWrongThread (which will abort if not on the owner thread, even for
* non-debug builds).
*
* It is possible to "move" a runtime between threads. This is accomplished by
* calling JS_ClearRuntimeThread on a runtime's owner thread and then calling
* JS_SetRuntimeThread on the new owner thread. The runtime must not be
* accessed between JS_ClearRuntimeThread and JS_SetRuntimeThread. Also, the
* caller is responsible for synchronizing the calls to Set/Clear.
*/
extern JS_PUBLIC_API(void)
JS_AbortIfWrongThread(JSRuntime *rt);
extern JS_PUBLIC_API(void)
JS_ClearRuntimeThread(JSRuntime *rt);
extern JS_PUBLIC_API(void)
JS_SetRuntimeThread(JSRuntime *rt);
#ifdef __cplusplus
JS_END_EXTERN_C
class JSAutoSetRuntimeThread
{
JSRuntime *runtime;
public:
JSAutoSetRuntimeThread(JSRuntime *runtime) : runtime(runtime) {
JS_SetRuntimeThread(runtime);
}
~JSAutoSetRuntimeThread() {
JS_ClearRuntimeThread(runtime);
}
};
JS_BEGIN_EXTERN_C
#endif
/************************************************************************/
/*

View File

@ -316,6 +316,8 @@ static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
JSContext *
js_NewContext(JSRuntime *rt, size_t stackChunkSize)
{
JS_AbortIfWrongThread(rt);
JSContext *cx;
JSBool first;
JSContextCallback cxCallback;
@ -427,13 +429,14 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
void
js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
{
JSRuntime *rt;
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);
JSContextCallback cxCallback;
JSBool last;
JS_ASSERT(!cx->enumerators);
rt = cx->runtime;
#ifdef JS_THREADSAFE
/*
* For API compatibility we allow to destroy contexts without a thread in

View File

@ -327,7 +327,8 @@ typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> CompartmentVector;
}
struct JSRuntime {
struct JSRuntime
{
/* Default compartment. */
JSCompartment *atomsCompartment;
#ifdef JS_THREADSAFE
@ -340,6 +341,20 @@ struct JSRuntime {
/* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
JSRuntimeState state;
/* See comment for JS_AbortIfWrongThread in jsapi.h. */
#ifdef JS_THREADSAFE
public:
void clearOwnerThread();
void setOwnerThread();
JS_FRIEND_API(bool) onOwnerThread() const;
private:
void *ownerThread_;
public:
#else
public:
bool onOwnerThread() const { return true; }
#endif
/* Context create/destroy callback. */
JSContextCallback cxCallback;
@ -1334,11 +1349,11 @@ class AutoCheckRequestDepth {
# define CHECK_REQUEST(cx) \
JS_ASSERT((cx)->thread()); \
JS_ASSERT((cx)->thread()->data.requestDepth || (cx)->thread() == (cx)->runtime->gcThread); \
JS_ASSERT(cx->runtime->onOwnerThread()); \
AutoCheckRequestDepth _autoCheckRequestDepth(cx);
#else
# define CHECK_REQUEST(cx) ((void) 0)
# define CHECK_REQUEST_THREAD(cx) ((void) 0)
#endif
static inline JSAtom **

View File

@ -235,7 +235,7 @@ Arena::finalize(JSContext *cx)
newListTail->first = newFreeSpanStart;
newListTail->last = thing - sizeof(T);
newListTail = newListTail->nextSpanUnchecked(sizeof(T));
newFreeSpanStart = NULL;
newFreeSpanStart = 0;
}
} else {
if (!newFreeSpanStart)
@ -1905,6 +1905,7 @@ void
MaybeGC(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
JS_ASSERT(rt->onOwnerThread());
if (rt->gcZeal()) {
GCREASON(MAYBEGC);
@ -2671,6 +2672,7 @@ void
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);
/*
* Don't collect garbage if the runtime isn't up, and cx is not the last
@ -2856,6 +2858,8 @@ JSCompartment *
NewCompartment(JSContext *cx, JSPrincipals *principals)
{
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);
JSCompartment *compartment = cx->new_<JSCompartment>(rt);
if (compartment && compartment->init()) {
// Any compartment with the trusted principals -- and there can be

View File

@ -154,19 +154,6 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
JSScript *script = fp->script();
jsbytecode *start = script->code;
/*
* If the debugger asks for the scope chain at a pc where we are about to
* fix it up, advance target past the fixup. See bug 672804.
*/
JSOp op = js_GetOpcode(cx, script, target);
while (op == JSOP_NOP || op == JSOP_INDEXBASE || op == JSOP_INDEXBASE1 ||
op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3 ||
op == JSOP_BLOCKCHAIN || op == JSOP_NULLBLOCKCHAIN)
{
target += js_CodeSpec[op].length;
op = js_GetOpcode(cx, script, target);
}
JS_ASSERT(target >= start && target < start + script->length);
JSObject *blockChain = NULL;

View File

@ -350,7 +350,7 @@ inline void
JSObject::setArrayLength(uint32 length)
{
JS_ASSERT(isArray());
setPrivate((void*) length);
setPrivate((void*)(size_t)length);
}
inline uint32

View File

@ -130,7 +130,6 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj,
const js::Shape **shapep, PropertyCacheEntry **entryp)
{
JS_ASSERT(obj->slotSpan() >= JSSLOT_FREE(obj->getClass()));
JS_ASSERT(obj->isExtensible());
uint32 kshape = obj->shape();
PropertyCacheEntry *entry = &table[hash(pc, kshape)];
*entryp = entry;
@ -142,6 +141,10 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj,
if (entry->kpc == pc &&
entry->kshape == kshape &&
entry->vshape() == rt->protoHazardShape) {
// If obj is not extensible, we cannot have a cache hit. This happens
// for sharp-variable expressions like (#1={x: Object.seal(#1#)}).
JS_ASSERT(obj->isExtensible());
PCMETER(pchits++);
PCMETER(inipchits++);
JS_ASSERT(entry->vcapTag() == 0);

View File

@ -395,7 +395,6 @@ ForceFrame::enter()
LeaveTrace(context);
JS_ASSERT(context->compartment == target->compartment());
JSCompartment *destination = context->compartment;
JSObject *scopeChain = target->getGlobal();
JS_ASSERT(scopeChain->isNative());

View File

@ -414,7 +414,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
masm.forceFlushConstantPool();
stubcc.masm.forceFlushConstantPool();
#endif
JaegerSpew(JSpew_Insns, "## Fast code (masm) size = %u, Slow code (stubcc) size = %u.\n", masm.size(), stubcc.size());
JaegerSpew(JSpew_Insns, "## Fast code (masm) size = %lu, Slow code (stubcc) size = %lu.\n",
(unsigned long) masm.size(), (unsigned long) stubcc.size());
size_t codeSize = masm.size() +
stubcc.size() +

View File

@ -696,8 +696,8 @@ class CallCompiler : public BaseCompiler
linker.link(notCompiled, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset));
JSC::CodeLocationLabel cs = linker.finalize();
JaegerSpew(JSpew_PICs, "generated CALL stub %p (%d bytes)\n", cs.executableAddress(),
masm.size());
JaegerSpew(JSpew_PICs, "generated CALL stub %p (%lu bytes)\n", cs.executableAddress(),
(unsigned long) masm.size());
Repatcher repatch(from);
JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset);
@ -726,7 +726,8 @@ class CallCompiler : public BaseCompiler
JSC::CodeLocationLabel(jit->fastEntry));
JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %p)\n",
ic.funGuard.executableAddress(), ic.fastGuardedObject);
ic.funGuard.executableAddress(),
static_cast<void*>(ic.fastGuardedObject));
return true;
}
@ -769,8 +770,8 @@ class CallCompiler : public BaseCompiler
linker.link(done, ic.funGuard.labelAtOffset(ic.hotPathOffset));
JSC::CodeLocationLabel cs = linker.finalize();
JaegerSpew(JSpew_PICs, "generated CALL closure stub %p (%d bytes)\n",
cs.executableAddress(), masm.size());
JaegerSpew(JSpew_PICs, "generated CALL closure stub %p (%lu bytes)\n",
cs.executableAddress(), (unsigned long) masm.size());
Repatcher repatch(from);
repatch.relink(ic.funJump, cs);
@ -944,8 +945,8 @@ class CallCompiler : public BaseCompiler
linker.link(funGuard, ic.slowPathStart);
JSC::CodeLocationLabel cs = linker.finalize();
JaegerSpew(JSpew_PICs, "generated native CALL stub %p (%d bytes)\n",
cs.executableAddress(), masm.size());
JaegerSpew(JSpew_PICs, "generated native CALL stub %p (%lu bytes)\n",
cs.executableAddress(), (unsigned long) masm.size());
Repatcher repatch(jit);
repatch.relink(ic.funJump, cs);

View File

@ -2221,9 +2221,9 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
CodeLocationLabel cs = buffer.finalize();
#if DEBUG
char *chars = DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(),
cx->fp()->script()->filename, CurrentLine(cx));
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%lx (\"%s\") shape 0x%x (%s: %d)\n",
js_CodeName[op], cs.executableAddress(), (unsigned long) JSID_TO_ATOM(id), chars,
holder->shape(), cx->fp()->script()->filename, CurrentLine(cx));
cx->free_(chars);
#endif

View File

@ -1111,7 +1111,7 @@ Quit(JSContext *cx, uintN argc, jsval *vp)
gQuitting = JS_TRUE;
#ifdef JS_THREADSAFE
if (gWorkerThreadPool)
js::workers::terminateAll(JS_GetRuntime(cx), gWorkerThreadPool);
js::workers::terminateAll(gWorkerThreadPool);
#endif
return JS_FALSE;
}
@ -3233,245 +3233,6 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp)
return !gCanceled;
}
typedef struct ScatterThreadData ScatterThreadData;
typedef struct ScatterData ScatterData;
typedef enum ScatterStatus {
SCATTER_WAIT,
SCATTER_GO,
SCATTER_CANCEL
} ScatterStatus;
struct ScatterData {
ScatterThreadData *threads;
jsval *results;
PRLock *lock;
PRCondVar *cvar;
ScatterStatus status;
};
struct ScatterThreadData {
jsint index;
ScatterData *shared;
PRThread *thr;
JSContext *cx;
jsval fn;
};
static void
DoScatteredWork(JSContext *cx, ScatterThreadData *td)
{
jsval *rval = &td->shared->results[td->index];
if (!JS_CallFunctionValue(cx, NULL, td->fn, 0, NULL, rval)) {
*rval = JSVAL_VOID;
JS_GetPendingException(cx, rval);
JS_ClearPendingException(cx);
}
}
static void
RunScatterThread(void *arg)
{
int stackDummy;
ScatterThreadData *td;
ScatterStatus st;
JSContext *cx;
if (PR_FAILURE == PR_SetThreadPrivate(gStackBaseThreadIndex, &stackDummy))
return;
td = (ScatterThreadData *)arg;
cx = td->cx;
/* Wait for our signal. */
PR_Lock(td->shared->lock);
while ((st = td->shared->status) == SCATTER_WAIT)
PR_WaitCondVar(td->shared->cvar, PR_INTERVAL_NO_TIMEOUT);
PR_Unlock(td->shared->lock);
if (st == SCATTER_CANCEL)
return;
/* We are good to go. */
JS_SetContextThread(cx);
JS_SetNativeStackQuota(cx, gMaxStackSize);
JS_BeginRequest(cx);
DoScatteredWork(cx, td);
JS_EndRequest(cx);
JS_ClearContextThread(cx);
}
/*
* scatter(fnArray) - Call each function in `fnArray` without arguments, each
* in a different thread. When all threads have finished, return an array: the
* return values. Errors are not propagated; if any of the function calls
* fails, the corresponding element in the results array gets the exception
* object, if any, else (undefined).
*/
static JSBool
Scatter(JSContext *cx, uintN argc, jsval *vp)
{
jsuint i;
jsuint n; /* number of threads */
JSObject *inArr;
JSObject *arr;
JSObject *global;
ScatterData sd;
JSBool ok;
sd.lock = NULL;
sd.cvar = NULL;
sd.results = NULL;
sd.threads = NULL;
sd.status = SCATTER_WAIT;
if (argc == 0 || JSVAL_IS_PRIMITIVE(JS_ARGV(cx, vp)[0])) {
JS_ReportError(cx, "the first argument must be an object");
goto fail;
}
inArr = JSVAL_TO_OBJECT(JS_ARGV(cx, vp)[0]);
ok = JS_GetArrayLength(cx, inArr, &n);
if (!ok)
goto out;
if (n == 0)
goto success;
sd.lock = PR_NewLock();
if (!sd.lock)
goto fail;
sd.cvar = PR_NewCondVar(sd.lock);
if (!sd.cvar)
goto fail;
sd.results = (jsval *) malloc(n * sizeof(jsval));
if (!sd.results)
goto fail;
for (i = 0; i < n; i++) {
sd.results[i] = JSVAL_VOID;
ok = JS_AddValueRoot(cx, &sd.results[i]);
if (!ok) {
while (i-- > 0)
JS_RemoveValueRoot(cx, &sd.results[i]);
free(sd.results);
sd.results = NULL;
goto fail;
}
}
sd.threads = (ScatterThreadData *) malloc(n * sizeof(ScatterThreadData));
if (!sd.threads)
goto fail;
for (i = 0; i < n; i++) {
sd.threads[i].index = i;
sd.threads[i].shared = &sd;
sd.threads[i].thr = NULL;
sd.threads[i].cx = NULL;
sd.threads[i].fn = JSVAL_NULL;
ok = JS_AddValueRoot(cx, &sd.threads[i].fn);
if (ok && !JS_GetElement(cx, inArr, i, &sd.threads[i].fn)) {
JS_RemoveValueRoot(cx, &sd.threads[i].fn);
ok = JS_FALSE;
}
if (!ok) {
while (i-- > 0)
JS_RemoveValueRoot(cx, &sd.threads[i].fn);
free(sd.threads);
sd.threads = NULL;
goto fail;
}
}
global = JS_GetGlobalObject(cx);
for (i = 1; i < n; i++) {
JSContext *newcx = NewContext(JS_GetRuntime(cx));
if (!newcx)
goto fail;
{
JSAutoRequest req(newcx);
JS_SetGlobalObject(newcx, global);
}
JS_ClearContextThread(newcx);
sd.threads[i].cx = newcx;
}
for (i = 1; i < n; i++) {
PRThread *t = PR_CreateThread(PR_USER_THREAD,
RunScatterThread,
&sd.threads[i],
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
if (!t) {
/* Failed to start thread. */
PR_Lock(sd.lock);
sd.status = SCATTER_CANCEL;
PR_NotifyAllCondVar(sd.cvar);
PR_Unlock(sd.lock);
while (i-- > 1)
PR_JoinThread(sd.threads[i].thr);
goto fail;
}
sd.threads[i].thr = t;
}
PR_Lock(sd.lock);
sd.status = SCATTER_GO;
PR_NotifyAllCondVar(sd.cvar);
PR_Unlock(sd.lock);
DoScatteredWork(cx, &sd.threads[0]);
{
JSAutoSuspendRequest suspended(cx);
for (i = 1; i < n; i++) {
PR_JoinThread(sd.threads[i].thr);
}
}
success:
arr = JS_NewArrayObject(cx, n, sd.results);
if (!arr)
goto fail;
*vp = OBJECT_TO_JSVAL(arr);
ok = JS_TRUE;
out:
if (sd.threads) {
JSContext *acx;
for (i = 0; i < n; i++) {
JS_RemoveValueRoot(cx, &sd.threads[i].fn);
acx = sd.threads[i].cx;
if (acx) {
JS_SetContextThread(acx);
DestroyContext(acx, true);
}
}
free(sd.threads);
}
if (sd.results) {
for (i = 0; i < n; i++)
JS_RemoveValueRoot(cx, &sd.results[i]);
free(sd.results);
}
if (sd.cvar)
PR_DestroyCondVar(sd.cvar);
if (sd.lock)
PR_DestroyLock(sd.lock);
return ok;
fail:
ok = JS_FALSE;
goto out;
}
static bool
InitWatchdog(JSRuntime *rt)
{
@ -3656,7 +3417,7 @@ CancelExecution(JSRuntime *rt)
gExitCode = EXITCODE_TIMEOUT;
#ifdef JS_THREADSAFE
if (gWorkerThreadPool)
js::workers::terminateAll(rt, gWorkerThreadPool);
js::workers::terminateAll(gWorkerThreadPool);
#endif
JS_TriggerAllOperationCallbacks(rt);
@ -4197,7 +3958,6 @@ static JSFunctionSpec shell_functions[] = {
#endif
#ifdef JS_THREADSAFE
JS_FN("sleep", Sleep_fn, 1,0),
JS_FN("scatter", Scatter, 1,0),
#endif
JS_FN("snarf", Snarf, 0,0),
JS_FN("read", Snarf, 0,0),
@ -4337,7 +4097,6 @@ static const char *const shell_help_messages[] = {
#endif
#ifdef JS_THREADSAFE
"sleep(dt) Sleep for dt seconds",
"scatter(fns) Call functions concurrently (ignoring errors)",
#endif
"snarf(filename) Read filename into returned string",
"read(filename) Synonym for snarf",

View File

@ -170,6 +170,7 @@ class WorkerParent {
}
void disposeChildren();
void notifyTerminating();
};
template <class T>
@ -528,11 +529,12 @@ class ThreadPool
return ok;
}
void terminateAll(JSRuntime *rt) {
void terminateAll() {
// See comment about JS_ATOMIC_SET in the implementation of
// JS_TriggerOperationCallback.
JS_ATOMIC_SET(&terminating, 1);
JS_TriggerAllOperationCallbacks(rt);
if (mq)
mq->notifyTerminating();
}
/* This context is used only to free memory. */
@ -593,6 +595,7 @@ class Worker : public WorkerParent
ThreadPool *threadPool;
WorkerParent *parent;
JSObject *object; // Worker object exposed to parent
JSRuntime *runtime;
JSContext *context;
JSLock *lock;
Queue<Event *, SystemAllocPolicy> events; // owning pointers to pending events
@ -603,7 +606,7 @@ class Worker : public WorkerParent
static JSClass jsWorkerClass;
Worker()
: threadPool(NULL), parent(NULL), object(NULL),
: threadPool(NULL), parent(NULL), object(NULL), runtime(NULL),
context(NULL), lock(NULL), current(NULL), terminated(false), terminateFlag(0) {}
bool init(JSContext *parentcx, WorkerParent *parent, JSObject *obj) {
@ -616,13 +619,24 @@ class Worker : public WorkerParent
this->object = obj;
lock = JS_NEW_LOCK();
return lock &&
createRuntime(parentcx) &&
createContext(parentcx, parent) &&
JS_SetPrivate(parentcx, obj, this);
}
bool createRuntime(JSContext *parentcx) {
runtime = JS_NewRuntime(1L * 1024L * 1024L);
if (!runtime) {
JS_ReportOutOfMemory(parentcx);
return false;
}
JS_ClearRuntimeThread(runtime);
return true;
}
bool createContext(JSContext *parentcx, WorkerParent *parent) {
JSRuntime *rt = JS_GetRuntime(parentcx);
context = JS_NewContext(rt, 8192);
JSAutoSetRuntimeThread guard(runtime);
context = JS_NewContext(runtime, 8192);
if (!context)
return false;
@ -754,11 +768,17 @@ class Worker : public WorkerParent
JS_DESTROY_LOCK(lock);
lock = NULL;
}
if (runtime)
JS_SetRuntimeThread(runtime);
if (context) {
JS_SetContextThread(context);
JS_DestroyContextNoGC(context);
context = NULL;
}
if (runtime) {
JS_DestroyRuntime(runtime);
runtime = NULL;
}
object = NULL;
// Do not call parent->removeChild(). This is called either from
@ -797,6 +817,11 @@ class Worker : public WorkerParent
JS_TriggerOperationCallback(context);
}
void notifyTerminating() {
setTerminateFlag();
WorkerParent::notifyTerminating();
}
void processOneEvent();
/* Trace method to be called from C++. */
@ -977,6 +1002,14 @@ WorkerParent::disposeChildren()
}
}
void
WorkerParent::notifyTerminating()
{
AutoLock hold(getLock());
for (ChildSet::Range r = children.all(); !r.empty(); r.popFront())
r.front()->notifyTerminating();
}
bool
MainQueue::shouldStop()
{
@ -1110,7 +1143,8 @@ Worker::processOneEvent()
Event::Result result;
{
JSAutoRequest req(context);
JSAutoSetRuntimeThread asrt(JS_GetRuntime(context));
JSAutoRequest ar(context);
result = event->process(context);
}
@ -1126,7 +1160,8 @@ Worker::processOneEvent()
}
}
if (result == Event::fail && !checkTermination()) {
JSAutoRequest req(context);
JSAutoSetRuntimeThread asrt(JS_GetRuntime(context));
JSAutoRequest ar(context);
Event *err = ErrorEvent::create(context, this);
if (err && !parent->post(err)) {
JS_ReportOutOfMemory(context);
@ -1260,9 +1295,9 @@ js::workers::init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject
}
void
js::workers::terminateAll(JSRuntime *rt, ThreadPool *tp)
js::workers::terminateAll(ThreadPool *tp)
{
tp->terminateAll(rt);
tp->terminateAll();
}
void

View File

@ -61,13 +61,13 @@ namespace js {
};
/*
* Initialize workers. This defines the Worker constructor on global.
* Requires request. rootp must point to a GC root.
*
* On success, *rootp receives a pointer to an object, and init returns
* Initialize workers. This defines the Worker constructor on global.
* Requires request. rootp must point to a GC root.
*
* On success, *rootp receives a pointer to an object, and init returns
* a non-null value. The caller must keep the object rooted and must
* pass it to js::workers::finish later.
*/
*/
ThreadPool *init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject **rootp);
/* Asynchronously signal for all workers to terminate.
@ -75,7 +75,7 @@ namespace js {
* Call this before calling finish() to shut down without waiting for
* all messages to be proceesed.
*/
void terminateAll(JSRuntime *rt, ThreadPool *tp);
void terminateAll(ThreadPool *tp);
/*
* Finish running any workers, shut down the thread pool, and free all

View File

@ -34,6 +34,7 @@ script findReferences-01.js
script findReferences-02.js
script findReferences-03.js
script findReferences-04.js
script regress-613452.js
script regress-627859.js
script regress-627984-1.js
script regress-627984-2.js
@ -52,7 +53,4 @@ script weakmap.js
script regress-645160.js
script regress-650753.js
script regress-668438.js
require-or(debugMode,skip) script regress-672804-1.js
require-or(debugMode,skip) script regress-672804-2.js
require-or(debugMode,skip) script regress-672804-3.js
script regress-677924.js

View File

@ -0,0 +1,13 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
for (var i = 0; i < 2; i++) {
try {
(#1={x: Object.seal(#1#)}); // do not assert
} catch (exc) {}
}
for (var i = 0; i < 2; i++)
(#1={x: (#1#.x = 1, Object.seal(#1#))}); // do not assert
reportCompare(0, 0, 'ok');

View File

@ -1,12 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var a = 0;
function f() {
let (a = let (x = 1) x) {}
}
trap(f, 3, 'assertEq(evalInFrame(1, "a"), 0)');
f();
reportCompare(0, 0, 'ok');

View File

@ -1,12 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var a = 0;
function f() {
let (a = let (x = 1) x) {}
}
trap(f, 4, 'assertEq(evalInFrame(1, "a"), 0)');
f();
reportCompare(0, 0, 'ok');

View File

@ -1,11 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var e = [], x = {b: []};
function f() {
let (a = [[] for (x in e)], {b: []} = x) {}
}
trap(f, 4, '');
f();
reportCompare(0, 0, 'ok');

View File

@ -9,10 +9,10 @@ if (typeof Worker != 'undefined') {
JSTest.waitForExplicitFinish();
var w = Worker(workerDir + "worker-fib-child.js");
w.onmessage = function (event) {
reportCompare("55", event.data, "worker-fib");
reportCompare("21", event.data, "worker-fib");
JSTest.testFinished();
};
w.postMessage("10\t" + workerDir); // 0 1 1 2 3 5 8 13 21 34 55
w.postMessage("8\t" + workerDir); // 0 1 1 2 3 5 8 13 21
} else {
reportCompare(0, 0, "Test skipped. Shell workers required.");
}

View File

@ -17,7 +17,7 @@ def set_limits():
try:
import resource
GB = 2**30
resource.setrlimit(resource.RLIMIT_AS, (1*GB, 1*GB))
resource.setrlimit(resource.RLIMIT_AS, (2*GB, 2*GB))
except:
return

View File

@ -762,6 +762,8 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
JSPrincipals* jsPrincipals = nsnull;
JSCLContextHelper cx(this);
JS_AbortIfWrongThread(JS_GetRuntime(cx));
// preserve caller's compartment
js::PreserveCompartment pc(cx);

View File

@ -532,6 +532,34 @@ nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
return NS_OK;
}
void
nsXPConnect::NotifyLeaveMainThread()
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Off main thread");
JS_ClearRuntimeThread(mRuntime->GetJSRuntime());
}
void
nsXPConnect::NotifyEnterCycleCollectionThread()
{
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "On main thread");
JS_SetRuntimeThread(mRuntime->GetJSRuntime());
}
void
nsXPConnect::NotifyLeaveCycleCollectionThread()
{
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "On main thread");
JS_ClearRuntimeThread(mRuntime->GetJSRuntime());
}
void
nsXPConnect::NotifyEnterMainThread()
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Off main thread");
JS_SetRuntimeThread(mRuntime->GetJSRuntime());
}
nsresult
nsXPConnect::FinishTraverse()
{
@ -2444,7 +2472,9 @@ nsXPConnect::GetRuntime(JSRuntime **runtime)
if(!runtime)
return NS_ERROR_NULL_POINTER;
*runtime = GetRuntime()->GetJSRuntime();
JSRuntime *rt = GetRuntime()->GetJSRuntime();
JS_AbortIfWrongThread(rt);
*runtime = rt;
return NS_OK;
}

View File

@ -502,6 +502,7 @@ XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
NS_IMETHODIMP
XPCCallContext::GetJSContext(JSContext * *aJSContext)
{
JS_AbortIfWrongThread(JS_GetRuntime(mJSContext));
*aJSContext = mJSContext;
return NS_OK;
}

View File

@ -3544,6 +3544,8 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
const char *filename, PRInt32 lineNo,
JSVersion jsVersion, PRBool returnStringOnly, jsval *rval)
{
JS_AbortIfWrongThread(JS_GetRuntime(cx));
#ifdef DEBUG
// NB: The "unsafe" unwrap here is OK because we must be called from chrome.
{

View File

@ -546,6 +546,10 @@ public:
nsCycleCollectionTraversalCallback &cb);
// nsCycleCollectionLanguageRuntime
virtual void NotifyLeaveMainThread();
virtual void NotifyEnterCycleCollectionThread();
virtual void NotifyLeaveCycleCollectionThread();
virtual void NotifyEnterMainThread();
virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
bool explainExpectedLiveGarbage);
virtual nsresult FinishTraverse();

View File

@ -766,6 +766,34 @@ ElementForStyleContext(nsIContent* aParentContent,
return content->AsElement();
}
static nsIFrame*
GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
{
// Account for {ib} splits when looking for "prevContinuation". In
// particular, for the first-continuation of a part of an {ib} split we
// want to use the special prevsibling of the special prevsibling of
// aFrame, which should have the same style context as aFrame itself.
// In particular, if aFrame is the first continuation of an inline part
// of an {ib} split then its special prevsibling is a block, and the
// special prevsibling of _that_ is an inline, just like aFrame.
// Similarly, if aFrame is the first continuation of a block part of an
// {ib} split (an {ib} wrapper block), then its special prevsibling is
// an inline and the special prevsibling of that is either another {ib}
// wrapper block block or null.
nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
if (!prevContinuation && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
// We're the first continuation, so we can just get the frame
// property directly
prevContinuation = static_cast<nsIFrame*>(
aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
if (prevContinuation) {
prevContinuation = static_cast<nsIFrame*>(
prevContinuation->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
}
}
return prevContinuation;
}
nsresult
nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
{
@ -831,7 +859,8 @@ nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
}
#endif
nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
nsIFrame *prevContinuation =
GetPrevContinuationWithPossiblySameStyle(aFrame);
nsStyleContext *prevContinuationContext;
PRBool copyFromContinuation =
prevContinuation &&
@ -1147,12 +1176,35 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
nextContinuationContext->GetParent(),
"continuations should have the same style context");
}
// And assert the same thing for {ib} splits. See the comments in
// GetPrevContinuationWithPossiblySameStyle for an explanation of
// why we step two forward in the special sibling chain.
if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
!aFrame->GetPrevContinuation()) {
nsIFrame *nextIBSibling = static_cast<nsIFrame*>(
aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
if (nextIBSibling) {
nextIBSibling = static_cast<nsIFrame*>(
nextIBSibling->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
}
if (nextIBSibling) {
nsStyleContext *nextIBSiblingContext =
nextIBSibling->GetStyleContext();
NS_ASSERTION(oldContext == nextIBSiblingContext ||
oldContext->GetPseudo() !=
nextIBSiblingContext->GetPseudo() ||
oldContext->GetParent() !=
nextIBSiblingContext->GetParent(),
"continuations should have the same style context");
}
}
}
#endif
// do primary context
nsRefPtr<nsStyleContext> newContext;
nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
nsIFrame *prevContinuation =
GetPrevContinuationWithPossiblySameStyle(aFrame);
nsStyleContext *prevContinuationContext;
PRBool copyFromContinuation =
prevContinuation &&
@ -1171,7 +1223,15 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
"non pseudo-element frame without content node");
newContext = styleSet->ResolveStyleForNonElement(parentContext);
}
else if (!aRestyleHint) {
else if (!aRestyleHint && !prevContinuation) {
// Unfortunately, if prevContinuation is non-null then we may have
// already stolen the restyle tracker entry for this element while
// processing prevContinuation. So we don't know whether aRestyleHint
// should really be 0 here or whether it should be eRestyle_Self. Be
// pessimistic and force an actual reresolve in that situation. The good
// news is that in the common case when prevContinuation is non-null we
// just used prevContinuationContext anyway and aren't reaching this code
// to start with.
newContext =
styleSet->ReparentStyleContext(oldContext, parentContext,
ElementForStyleContext(aParentContent,

View File

@ -83,7 +83,11 @@
#endif
// Size to use for PLArena block allocations.
static const size_t ARENA_PAGE_SIZE = 4096;
// XXX: This should be 8192; the subtracted elements are a hack that's
// required to ensure the allocation requests are power-of-two-sized and thus
// avoid lots of wasted memory caused by the heap allocator rounding up request
// sizes. Bug 676457 will fix it properly.
static const size_t ARENA_PAGE_SIZE = 8192 - sizeof(PLArena) - PL_ARENA_CONST_ALIGN_MASK;
// Freed memory is filled with a poison value, which we arrange to
// form a pointer either to an always-unmapped region of the address

View File

@ -591,7 +591,7 @@ public:
}
static PRInt32 AppUnitsPerCSSPixel() { return nsDeviceContext::AppUnitsPerCSSPixel(); }
PRInt32 AppUnitsPerDevPixel() const { return mDeviceContext->AppUnitsPerDevPixel(); }
PRUint32 AppUnitsPerDevPixel() const { return mDeviceContext->AppUnitsPerDevPixel(); }
static PRInt32 AppUnitsPerCSSInch() { return nsDeviceContext::AppUnitsPerCSSInch(); }
static nscoord CSSPixelsToAppUnits(PRInt32 aPixels)

View File

@ -2585,12 +2585,11 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
nsRect scrolledRect = GetScrolledRect();
nsPoint current = GetScrollPosition() - scrolledRect.TopLeft();
nsPoint dest;
dest.x = GetCoordAttribute(mHScrollbarBox, nsGkAtoms::curpos,
-scrolledRect.x) +
dest.x = GetCoordAttribute(mHScrollbarBox, nsGkAtoms::curpos, current.x) +
scrolledRect.x;
dest.y = GetCoordAttribute(mVScrollbarBox, nsGkAtoms::curpos,
-scrolledRect.y) +
dest.y = GetCoordAttribute(mVScrollbarBox, nsGkAtoms::curpos, current.y) +
scrolledRect.y;
// If we have an async scroll pending don't stomp on that by calling ScrollTo.

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<body style="color: green">
<div style="display: inline;">
Line 1
<div>Line 2</div>
Line 3
<div>Line 4</div>
Line 5
</div>
</body>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body style="color: red">
<div id="x" style="display: inline; visibility: hidden">
Line 1
<div>Line 2</div>
Line 3
<div>Line 4</div>
Line 5
</div><script type="text/javascript">
document.body.offsetWidth;
document.getElementById("x").style.visibility = "visible";
document.body.style.color = "green";
</script>
</body>

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<style>
body::first-line { color: purple; }
</style>
<body style="width: 0; color: green"><span>This is some text</span>
</body>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<style>
body::first-line { color: purple; }
</style>
<body style="width: 0; color: red"><span id="x" style="visibility: hidden">This is some text</span>
<script type="text/javascript">
document.body.offsetWidth;
document.getElementById("x").style.visibility = "visible";
document.body.style.color = "green";
</script>
</body>

View File

@ -1654,3 +1654,5 @@ fails-if(layersGPUAccelerated&&cocoaWidget) == 654950-1.html 654950-1-ref.html #
!= 669015-1.xul 669015-1-notref.xul
== 668319-1.xul about:blank
== 670442-1.html 670442-1-ref.html
== 670467-1.html 670467-1-ref.html
== 670467-2.html 670467-2-ref.html

View File

@ -1893,8 +1893,7 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
rv = GetToken(PR_TRUE);
if (!rv)
break;
rv = mToken.mType == eCSSToken_Dimension &&
mToken.mIntegerValid && mToken.mNumber > 0.0f;
rv = mToken.mType == eCSSToken_Dimension && mToken.mNumber > 0.0f;
if (!rv) {
UngetToken();
break;

View File

@ -462,8 +462,8 @@ function run() {
feature = features[i];
expression_should_be_parseable(feature + ": 3dpi");
expression_should_be_parseable(feature + ":3dpi");
expression_should_not_be_parseable(feature + ": 3.0dpi");
expression_should_not_be_parseable(feature + ": 3.4dpi");
expression_should_be_parseable(feature + ": 3.0dpi");
expression_should_be_parseable(feature + ": 3.4dpi");
expression_should_be_parseable(feature + "\t: 120dpcm");
expression_should_not_be_parseable(feature + ": 0dpi");
expression_should_not_be_parseable(feature + ": -3dpi");

View File

@ -125,6 +125,7 @@ const AnimatedZoom = {
let event = document.createEvent("Events");
event.initEvent("AnimatedZoomEnd", true, true);
window.dispatchEvent(event);
browser._updateCSSViewport();
},
isZooming: function isZooming() {

View File

@ -386,6 +386,12 @@ var Browser = {
let event = document.createEvent("Events");
event.initEvent("UIReady", true, false);
window.dispatchEvent(event);
// If we have an opener this was not the first window opened and will not
// receive an initial resize event. instead we fire the resize handler manually
// Bug 610834
if (window.opener)
resizeHandler({ target: window });
},
_alertShown: function _alertShown() {

View File

@ -201,6 +201,7 @@ toolbarbutton.urlbar-button {
#urlbar-favicon {
width: 32px;
height: 32px;
image-rendering: -moz-crisp-edges;
}
#urlbar-favicon[src=""] {
@ -730,6 +731,7 @@ placeitem > .bookmark-manage > image {
width: 32px;
height: 32px;
max-height: 32px;
image-rendering: -moz-crisp-edges;
/* margin-top = (1 - title's line-height) * title's font-size */
margin-top: @autocomplete_item_container_image_padding@;
margin-bottom: 0;

View File

@ -190,6 +190,7 @@ toolbarbutton.urlbar-button {
#urlbar-favicon {
width: 32px;
height: 32px;
image-rendering: -moz-crisp-edges;
}
#urlbar-favicon[src=""] {
@ -696,6 +697,7 @@ placeitem > .bookmark-manage > image {
width: 32px;
height: 32px;
max-height: 32px;
image-rendering: -moz-crisp-edges;
/* margin-top = (1 - title's line-height) * title's font-size */
margin-top: @autocomplete_item_container_image_padding@;
margin-bottom: 0;

View File

@ -2497,6 +2497,10 @@ RasterImage::Draw(gfxContext *aContext,
mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
}
if (!mDecoded) {
mDrawStartTime = TimeStamp::Now();
}
// If a synchronous draw is requested, flush anything that might be sitting around
if (aFlags & FLAG_SYNC_DECODE) {
nsresult rv = SyncDecode();
@ -2515,6 +2519,12 @@ RasterImage::Draw(gfxContext *aContext,
frame->Draw(aContext, aFilter, aUserSpaceToImageSpace, aFill, padding, aSubimage);
if (mDecoded && !mDrawStartTime.IsNull()) {
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, PRInt32(drawLatency.ToMicroseconds()));
// clear the value of mDrawStartTime
mDrawStartTime = TimeStamp();
}
return NS_OK;
}
@ -2709,6 +2719,7 @@ imgDecodeWorker::Run()
// Loop control
bool haveMoreData = true;
PRInt32 chunkCount = 0;
TimeStamp start = TimeStamp::Now();
TimeStamp deadline = start + TimeDuration::FromMilliseconds(gMaxMSBeforeYield);
@ -2720,6 +2731,7 @@ imgDecodeWorker::Run()
(TimeStamp::Now() < deadline)) {
// Decode a chunk of data
chunkCount++;
rv = image->DecodeSomeData(maxBytes);
if (NS_FAILED(rv)) {
image->DoError();
@ -2732,8 +2744,10 @@ imgDecodeWorker::Run()
}
TimeDuration decodeLatency = TimeStamp::Now() - start;
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_LATENCY, PRInt32(decodeLatency.ToMicroseconds()));
if (chunkCount) {
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_LATENCY, PRInt32(decodeLatency.ToMicroseconds()));
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, chunkCount);
}
// accumulate the total decode time
mDecodeTime += decodeLatency;

View File

@ -533,6 +533,7 @@ private: // data
nsresult WriteToDecoder(const char *aBuffer, PRUint32 aCount);
nsresult DecodeSomeData(PRUint32 aMaxBytes);
PRBool IsDecodeFinished();
TimeStamp mDrawStartTime;
// Decoder shutdown
enum eShutdownIntent {

View File

@ -255,6 +255,7 @@ HistoryStore.prototype = {
let cb = Async.makeSyncCallback();
let updatePlacesCallback = {
handleResult: function handleResult() {},
handleError: function handleError(resultCode, placeInfo) {
failed.push(placeInfo.guid);
}

View File

@ -87,6 +87,8 @@ HISTOGRAM(SHUTDOWN_OK, 0, 1, 2, BOOLEAN, "Did the browser start after a successf
HISTOGRAM(IMAGE_DECODE_LATENCY, 50, 5000000, 100, EXPONENTIAL, "Time spent decoding an image chunk (us)")
HISTOGRAM(IMAGE_DECODE_TIME, 50, 50000000, 100, EXPONENTIAL, "Time spent decoding an image (us)")
HISTOGRAM(IMAGE_DECODE_ON_DRAW_LATENCY, 50, 50000000, 100, EXPONENTIAL, "Time from starting a decode to it showing up on the screen (us)")
HISTOGRAM(IMAGE_DECODE_CHUNKS, 1, 500, 50, EXPONENTIAL, "Number of chunks per decode attempt")
/**
* Networking telemetry

View File

@ -11,8 +11,6 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the nsTryToClose component.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
@ -42,6 +40,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
// When modifying the payload in incompatible ways, please bump this version number
const PAYLOAD_VERSION = 1;
@ -49,7 +48,7 @@ const PAYLOAD_VERSION = 1;
const PREF_SERVER = "toolkit.telemetry.server";
const PREF_ENABLED = "toolkit.telemetry.enabled";
// Do not gather data more than once a minute
const TELEMETRY_INTERVAL = 60;
const TELEMETRY_INTERVAL = 60000;
// Delay before intializing telemetry (ms)
const TELEMETRY_DELAY = 60000;
// about:memory values to turn into histograms
@ -65,6 +64,8 @@ const MEM_HISTOGRAMS = {
"page-faults-hard": "PAGE_FAULTS_HARD"
};
var gLastMemoryPoll = null;
function getLocale() {
return Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry).
@ -220,6 +221,54 @@ TelemetryPing.prototype = {
h.add(val);
},
/**
* Descriptive metadata
*
* @param reason
* The reason for the telemetry ping, this will be included in the
* returned metadata,
* @return The metadata as a JS object
*/
getMetadata: function getMetadata(reason) {
let ai = Services.appinfo;
let ret = {
reason: reason,
OS: ai.OS,
appID: ai.ID,
appVersion: ai.version,
appName: ai.name,
appBuildID: ai.appBuildID,
platformBuildID: ai.platformBuildID,
};
// sysinfo fields are not always available, get what we can.
let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware"];
for each (let field in fields) {
let value;
try {
value = sysInfo.getProperty(field);
} catch (e) {
continue
}
if (field == "memsize") {
// Send RAM size in megabytes. Rounding because sysinfo doesn't
// always provide RAM in multiples of 1024.
value = Math.round(value / 1024 / 1024)
}
ret[field] = value
}
let theme = LightweightThemeManager.currentTheme;
if (theme)
ret.persona = theme.id;
if (this._addons)
ret.addons = this._addons;
return ret;
},
/**
* Pull values from about:memory into corresponding histograms
*/
@ -286,10 +335,11 @@ TelemetryPing.prototype = {
this.gatherMemory();
let payload = {
ver: PAYLOAD_VERSION,
info: getMetadata(reason),
info: this.getMetadata(reason),
simpleMeasurements: getSimpleMeasurements(),
histograms: getHistograms()
};
let isTestPing = (reason == "test-ping");
// Generate a unique id once per session so the server can cope with duplicate submissions.
// Use a deterministic url for testing.
@ -329,19 +379,15 @@ TelemetryPing.prototype = {
attachObservers: function attachObservers() {
if (!this._initialized)
return;
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.addIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.addObserver(this, "cycle-collector-begin", false);
Services.obs.addObserver(this, "idle-daily", false);
},
detachObservers: function detachObservers() {
if (!this._initialized)
return;
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.removeIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.removeObserver(this, "idle-daily");
Services.obs.removeObserver(this, "cycle-collector-begin");
},
/**
@ -395,14 +441,22 @@ TelemetryPing.prototype = {
var server = this._server;
switch (aTopic) {
case "Add-ons":
this._addons = aData;
break;
case "profile-after-change":
this.setup();
break;
case "profile-before-change":
this.uninstall();
break;
case "idle":
this.gatherMemory();
case "cycle-collector-begin":
let now = new Date();
if (!gLastMemoryPoll
|| (TELEMETRY_INTERVAL <= now - gLastMemoryPoll)) {
gLastMemoryPoll = now;
this.gatherMemory();
}
break;
case "private-browsing":
Telemetry.canRecord = aData == "exit";

View File

@ -10,6 +10,7 @@
do_load_httpd_js();
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
const PATH = "/submit/telemetry/test-ping";
const SERVER = "http://localhost:4444";
@ -21,6 +22,7 @@ const BinaryInputStream = Components.Constructor(
"setInputStream");
var httpserver = new nsHttpServer();
var gFinished = false;
function telemetry_ping () {
const TelemetryPing = Cc["@mozilla.org/base/telemetry-ping;1"].getService(Ci.nsIObserver);
@ -46,27 +48,12 @@ function telemetryObserver(aSubject, aTopic, aData) {
telemetry_ping();
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
Services.obs.addObserver(nonexistentServerObserver, "telemetry-test-xhr-complete", false);
telemetry_ping();
// spin the event loop
do_test_pending();
}
function readBytesFromInputStream(inputStream, count) {
if (!count) {
count = inputStream.available();
}
return new BinaryInputStream(inputStream).readBytes(count);
}
function checkHistograms(request, response) {
// do not need the http server anymore
httpserver.stop(do_test_finished);
let s = request.bodyInputStream
let payload = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
.decode(readBytesFromInputStream(s))
.decodeFromStream(s, s.available())
do_check_eq(request.getHeader("content-type"), "application/json; charset=UTF-8");
do_check_true(payload.simpleMeasurements.uptime >= 0)
@ -102,6 +89,7 @@ function checkHistograms(request, response) {
let tc = payload.histograms[TELEMETRY_SUCCESS]
do_check_eq(uneval(tc),
uneval(expected_tc));
gFinished = true;
}
// copied from toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@ -152,3 +140,34 @@ function createAppInfo(id, name, version, platformVersion) {
registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
}
function dummyTheme(id) {
return {
id: id,
name: Math.random().toString(),
headerURL: "http://lwttest.invalid/a.png",
footerURL: "http://lwttest.invalid/b.png",
textcolor: Math.random().toString(),
accentcolor: Math.random().toString()
};
}
function run_test() {
// Addon manager needs a profile directory
do_get_profile();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
// try to make LightweightThemeManager do stuff
let gInternalManager = Cc["@mozilla.org/addons/integration;1"]
.getService(Ci.nsIObserver)
.QueryInterface(Ci.nsITimerCallback);
gInternalManager.observe(null, "addons-startup", null);
LightweightThemeManager.currentTheme = dummyTheme("1234");
Services.obs.addObserver(nonexistentServerObserver, "telemetry-test-xhr-complete", false);
telemetry_ping();
// spin the event loop
do_test_pending();
// ensure that test runs to completion
do_register_cleanup(function () do_check_true(gFinished))
}

View File

@ -66,7 +66,7 @@ MockObjectRegisterer.prototype = {
*/
register: function MOR_register() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (this._originalCID)
if (this._originalFactory)
throw new Exception("Invalid object state when calling register()");
// Define a factory that creates a new object using the given constructor.
@ -79,14 +79,17 @@ MockObjectRegisterer.prototype = {
}
};
this._cid = Components.classes["@mozilla.org/uuid-generator;1"].
getService(Components.interfaces.nsIUUIDGenerator).generateUUID();
// Preserve the original CID
var componentRegistrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
this._originalCID = componentRegistrar.contractIDToCID(this._contractID);
// Replace the original factory with the mock one.
// Get the component CID.
this._cid = componentRegistrar.contractIDToCID(this._contractID);
// ... and make sure we correctly replace the original factory with the mock one.
this._originalFactory = Components.manager.getClassObject(Components.classes[this._contractID],
Components.interfaces.nsIFactory);
componentRegistrar.unregisterFactory(this._cid, this._originalFactory);
componentRegistrar.registerFactory(this._cid,
"",
this._contractID,
@ -98,7 +101,7 @@ MockObjectRegisterer.prototype = {
*/
unregister: function MOR_unregister() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (!this._originalCID)
if (!this._originalFactory)
throw new Exception("Invalid object state when calling unregister()");
// Free references to the mock factory.
@ -107,23 +110,23 @@ MockObjectRegisterer.prototype = {
this._mockFactory);
// Restore the original factory.
componentRegistrar.registerFactory(this._originalCID,
componentRegistrar.registerFactory(this._cid,
"",
this._contractID,
null);
this._originalFactory);
// Allow registering a mock factory again later.
this._cid = null;
this._originalCID = null;
this._originalFactory = null;
this._mockFactory = null;
},
// --- Private methods and properties ---
/**
* The CID of the component being replaced.
* The factory of the component being replaced.
*/
_originalCID: null,
_originalFactory: null,
/**
* The CID under which the mock contractID was registered.

View File

@ -1246,7 +1246,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
info_ptr->process_kernel_time =
static_cast<u_int32_t>(usage.ru_stime.tv_sec);
}
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, info_ptr->process_id };
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, static_cast<int>(info_ptr->process_id) };
u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
size_t size;
if (!sysctl(mib, mibsize, NULL, &size, NULL, 0)) {

View File

@ -151,7 +151,7 @@ class UntypedMDRVA {
// Return size and position
inline MDLocationDescriptor location() const {
MDLocationDescriptor location = { static_cast<int>(size_), position_ };
MDLocationDescriptor location = { static_cast<u_int32_t>(size_), position_ };
return location;
}

View File

@ -1738,6 +1738,9 @@ var XPIProvider = {
Services.appinfo.annotateCrashReport("Add-ons", data);
}
catch (e) { }
const TelemetryPing = Cc["@mozilla.org/base/telemetry-ping;1"].getService(Ci.nsIObserver);
TelemetryPing.observe(null, "Add-ons", data);
},
/**

View File

@ -253,7 +253,7 @@ public: // NOT in nsIViewManager, so private to the view module
// pending updates.
void PostPendingUpdate() { RootViewManager()->mHasPendingUpdates = PR_TRUE; }
PRInt32 AppUnitsPerDevPixel() const
PRUint32 AppUnitsPerDevPixel() const
{
return mContext->AppUnitsPerDevPixel();
}

View File

@ -457,19 +457,6 @@ AndroidGeckoEvent::Init(int x1, int y1, int x2, int y2)
mRect.SetEmpty();
}
void
AndroidGeckoEvent::Init(AndroidGeckoEvent *aResizeEvent)
{
NS_ASSERTION(aResizeEvent->Type() == SIZE_CHANGED, "Init called on non-SIZE_CHANGED event");
mType = FORCED_RESIZE;
mTime = aResizeEvent->mTime;
mP0.x = aResizeEvent->mP0.x;
mP0.y = aResizeEvent->mP0.y;
mP1.x = aResizeEvent->mP1.x;
mP1.y = aResizeEvent->mP1.y;
}
void
AndroidGeckoSurfaceView::Init(jobject jobj)
{

View File

@ -386,14 +386,10 @@ public:
AndroidGeckoEvent(JNIEnv *jenv, jobject jobj) {
Init(jenv, jobj);
}
AndroidGeckoEvent(AndroidGeckoEvent *aResizeEvent) {
Init(aResizeEvent);
}
void Init(JNIEnv *jenv, jobject jobj);
void Init(int aType);
void Init(int x1, int y1, int x2, int y2);
void Init(AndroidGeckoEvent *aResizeEvent);
int Action() { return mAction; }
int Type() { return mType; }
@ -491,7 +487,6 @@ public:
SURFACE_CREATED = 13,
SURFACE_DESTROYED = 14,
GECKO_EVENT_SYNC = 15,
FORCED_RESIZE = 16,
dummy_java_enum_list_end
};

View File

@ -74,7 +74,6 @@ PRLogModuleInfo *gWidgetLog = nsnull;
nsDeviceMotionSystem *gDeviceMotionSystem = nsnull;
nsIGeolocationUpdate *gLocationCallback = nsnull;
nsAutoPtr<mozilla::AndroidGeckoEvent> gLastSizeChange;
nsAppShell *nsAppShell::gAppShell = nsnull;
@ -381,15 +380,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
break;
}
case AndroidGeckoEvent::SIZE_CHANGED: {
// store the last resize event to dispatch it to new windows with a FORCED_RESIZE event
if (curEvent != gLastSizeChange) {
gLastSizeChange = new AndroidGeckoEvent(curEvent);
}
nsWindow::OnGlobalAndroidEvent(curEvent);
break;
}
default:
nsWindow::OnGlobalAndroidEvent(curEvent);
}
@ -399,13 +389,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
return true;
}
void
nsAppShell::ResendLastResizeEvent(nsWindow* aDest) {
if (gLastSizeChange) {
nsWindow::OnGlobalAndroidEvent(gLastSizeChange);
}
}
AndroidGeckoEvent*
nsAppShell::GetNextEvent()
{

View File

@ -52,8 +52,6 @@ bool ProcessNextEvent();
void NotifyEvent();
}
class nsWindow;
class nsAppShell :
public nsBaseAppShell
{
@ -83,7 +81,6 @@ public:
void CallObserver(const nsAString &aObserverKey, const nsAString &aTopic, const nsAString &aData);
void RemoveObserver(const nsAString &aObserverKey);
void NotifyObservers(nsISupports *aSupports, const char *aTopic, const PRUnichar *aData);
void ResendLastResizeEvent(nsWindow* aDest);
protected:
virtual void ScheduleNativeEventCallback();

View File

@ -448,6 +448,14 @@ nsWindow::Resize(PRInt32 aX,
PRBool needSizeDispatch = aWidth != mBounds.width || aHeight != mBounds.height;
if (IsTopLevel()) {
ALOG("... ignoring Resize sizes on toplevel window");
aX = 0;
aY = 0;
aWidth = gAndroidBounds.width;
aHeight = gAndroidBounds.height;
}
mBounds.x = aX;
mBounds.y = aY;
mBounds.width = aWidth;
@ -578,8 +586,6 @@ nsWindow::BringToFront()
nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
DispatchEvent(&event);
// force a window resize
nsAppShell::gAppShell->ResendLastResizeEvent(this);
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
}
@ -732,19 +738,11 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
return;
switch (ae->Type()) {
case AndroidGeckoEvent::FORCED_RESIZE:
win->mBounds.width = 0;
win->mBounds.height = 0;
// also resize the children
for (PRUint32 i = 0; i < win->mChildren.Length(); i++) {
win->mChildren[i]->mBounds.width = 0;
win->mChildren[i]->mBounds.height = 0;
}
case AndroidGeckoEvent::SIZE_CHANGED: {
int nw = ae->P0().x;
int nh = ae->P0().y;
if (ae->Type() == AndroidGeckoEvent::FORCED_RESIZE || nw != gAndroidBounds.width ||
if (nw != gAndroidBounds.width ||
nh != gAndroidBounds.height) {
gAndroidBounds.width = nw;

View File

@ -166,13 +166,6 @@ typedef struct _nsCocoaWindowList {
- (void)sendToplevelDeactivateEvents;
@end
struct UnifiedGradientInfo {
float titlebarHeight;
float toolbarHeight;
BOOL windowIsMain;
BOOL drawTitlebar; // NO for toolbar, YES for titlebar
};
@class ToolbarWindow;
// NSColor subclass that allows us to draw separate colors both in the titlebar

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