mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to m-c
This commit is contained in:
commit
953d05c62f
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -984,9 +984,6 @@ nsDOMEvent::GetEventPopupControlState(nsEvent *aEvent)
|
||||
if (::PopupAllowedForEvent("change"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_XUL_COMMAND:
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -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.");
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
101
dom/tests/browser/browser_popup_blocker_save_open_panel.js
Normal file
101
dom/tests/browser/browser_popup_blocker_save_open_panel.js
Normal 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, });
|
||||
}
|
||||
}
|
@ -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!
|
||||
|
@ -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.
|
||||
|
||||
|
45
gfx/angle/angle-r707.patch
Normal file
45
gfx/angle/angle-r707.patch
Normal 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
235
gfx/angle/angle-win64.patch
Normal 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];
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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()));
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -80,8 +80,6 @@ CPPSRCS = \
|
||||
testScriptObject.cpp \
|
||||
testSetProperty.cpp \
|
||||
testStringBuffer.cpp \
|
||||
testThreadGC.cpp \
|
||||
testThreads.cpp \
|
||||
testTrap.cpp \
|
||||
testUTF8.cpp \
|
||||
testVersion.cpp \
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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 **
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -350,7 +350,7 @@ inline void
|
||||
JSObject::setArrayLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isArray());
|
||||
setPrivate((void*) length);
|
||||
setPrivate((void*)(size_t)length);
|
||||
}
|
||||
|
||||
inline uint32
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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() +
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
13
js/src/tests/js1_8_5/extensions/regress-613452.js
Normal file
13
js/src/tests/js1_8_5/extensions/regress-613452.js
Normal 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');
|
@ -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');
|
@ -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');
|
@ -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');
|
@ -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.");
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -502,6 +502,7 @@ XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
|
||||
NS_IMETHODIMP
|
||||
XPCCallContext::GetJSContext(JSContext * *aJSContext)
|
||||
{
|
||||
JS_AbortIfWrongThread(JS_GetRuntime(mJSContext));
|
||||
*aJSContext = mJSContext;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -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.
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
10
layout/reftests/bugs/670467-1-ref.html
Normal file
10
layout/reftests/bugs/670467-1-ref.html
Normal 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>
|
14
layout/reftests/bugs/670467-1.html
Normal file
14
layout/reftests/bugs/670467-1.html
Normal 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>
|
6
layout/reftests/bugs/670467-2-ref.html
Normal file
6
layout/reftests/bugs/670467-2-ref.html
Normal 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>
|
11
layout/reftests/bugs/670467-2.html
Normal file
11
layout/reftests/bugs/670467-2.html
Normal 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>
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -125,6 +125,7 @@ const AnimatedZoom = {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("AnimatedZoomEnd", true, true);
|
||||
window.dispatchEvent(event);
|
||||
browser._updateCSSViewport();
|
||||
},
|
||||
|
||||
isZooming: function isZooming() {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -255,6 +255,7 @@ HistoryStore.prototype = {
|
||||
|
||||
let cb = Async.makeSyncCallback();
|
||||
let updatePlacesCallback = {
|
||||
handleResult: function handleResult() {},
|
||||
handleError: function handleError(resultCode, placeInfo) {
|
||||
failed.push(placeInfo.guid);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user