merge fx-team to m-c

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

View File

@ -231,14 +231,17 @@ AccStateChangeEvent::
AccStateChangeEvent:: AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, PRUint64 aState, PRBool aIsEnabled): 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) mState(aState), mIsEnabled(aIsEnabled)
{ {
} }
AccStateChangeEvent:: AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, PRUint64 aState) : 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 // Use GetAccessibleForNode() because we do not want to store an accessible
// since it leads to problems with delayed events in the case when // since it leads to problems with delayed events in the case when

View File

@ -57,6 +57,7 @@
#include "nsWhitespaceTokenizer.h" #include "nsWhitespaceTokenizer.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
namespace dom = mozilla::dom;
using namespace mozilla::a11y; using namespace mozilla::a11y;
void void
@ -335,6 +336,24 @@ nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
return PR_TRUE; 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 * nsAccessible *
nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole) nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole)
{ {

View File

@ -50,7 +50,7 @@
#include "nsAccessibilityService.h" #include "nsAccessibilityService.h"
#include "nsCoreUtils.h" #include "nsCoreUtils.h"
#include "nsIContent.h" #include "mozilla/dom/Element.h"
#include "nsIDocShell.h" #include "nsIDocShell.h"
#include "nsIDOMNode.h" #include "nsIDOMNode.h"
#include "nsIPersistentProperties2.h" #include "nsIPersistentProperties2.h"
@ -150,6 +150,11 @@ public:
*/ */
static PRBool HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom); 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. * Return document accessible for the given presshell.
*/ */

View File

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

View File

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

View File

@ -567,7 +567,11 @@ protected:
*/ */
PRUint32 mLoadEventType; 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; nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;

View File

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

View File

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

View File

@ -602,10 +602,11 @@ function eventQueue(aEventType)
this.isAlreadyCaught = function eventQueue_isAlreadyCaught(aIdx, aEvent) this.isAlreadyCaught = function eventQueue_isAlreadyCaught(aIdx, aEvent)
{ {
// We don't have stored info about handled event other than its type and // 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 // target, thus we should filter text change and state change events since
// on the same element because of complex changes. // they may occur on the same element because of complex changes.
return this.compareEvents(aIdx, aEvent) && return this.compareEvents(aIdx, aEvent) &&
!(aEvent instanceof nsIAccessibleTextChangeEvent); !(aEvent instanceof nsIAccessibleTextChangeEvent) &&
!(aEvent instanceof nsIAccessibleStateChangeEvent);
} }
this.checkEvent = function eventQueue_checkEvent(aIdx, aEvent) 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. // Private implementation details.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -26,52 +26,103 @@
*/ */
var gQueue = null; var gQueue = null;
// Debug stuff. //gA11yEventDumpID = "eventdump"; // debugging
//gA11yEventDumpID = "eventdump"; //gA11yEventDumpToConsole = true; // debugging
// gA11yEventDumpToConsole = true;
function expandNode(aNodeOrID, bExpand) function expandNode(aID, aIsExpanded)
{ {
this.DOMNode = getNode(aNodeOrID); this.DOMNode = getNode(aID);
this.invoke = function expandNode_invoke() { this.eventSeq = [
// Note: this should fire an EVENT_STATE_CHANGE new expandedStateChecker(aIsExpanded, this.DOMNode)
this.DOMNode.setAttribute("aria-expanded", bExpand); ];
this.invoke = function expandNode_invoke()
{
this.DOMNode.setAttribute("aria-expanded",
(aIsExpanded ? "true" : "false"));
}; };
this.check = function expandNode_check() { this.getID = function expandNode_getID()
testStates(aNodeOrID, {
bExpand ? STATE_EXPANDED : STATE_COLLAPSED, return prettyName(aID) + " aria-expanded changed to '" + aIsExpanded + "'";
EXT_STATE_EXPANDABLE);
};
this.getID = function expandNode_getID() {
return prettyName(aNodeOrID) + " aria-expanded changed";
}; };
} }
function busyify(aNodeOrID, aBusy) function busyify(aID, aIsBusy)
{ {
this.DOMNode = getNode(aNodeOrID); this.DOMNode = getNode(aID);
this.invoke = function busyify_invoke() { this.eventSeq = [
this.DOMNode.setAttribute("aria-busy", aBusy); 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) { this.getID = function busyify_getID()
testStates(aNodeOrID, {
(aBusy ? STATE_BUSY : 0), 0, return prettyName(aID) + " aria-busy changed to '" + aIsBusy + "'";
(aBusy ? 0 : STATE_BUSY), 0); };
}
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() { this.getID = function setAttrOfMixedType_getID()
return prettyName(aNodeOrID) + " aria-busy changed to " + aBusy; {
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() function doTests()
{ {
gQueue = new eventQueue(EVENT_STATE_CHANGE); gQueue = new eventQueue();
gQueue.push(new expandNode("section", true)); gQueue.push(new expandNode("section", true));
gQueue.push(new expandNode("section", false)); gQueue.push(new expandNode("section", false));
@ -80,6 +131,10 @@
gQueue.push(new busyify("aria_doc", true)); gQueue.push(new busyify("aria_doc", true));
gQueue.push(new busyify("aria_doc", false)); gQueue.push(new busyify("aria_doc", false));
buildQueueForAttrOfMixedType(gQueue, "pressable", setPressed);
buildQueueForAttrOfMixedType(gQueue, "checkable", setChecked);
gQueue.invoke(); // Will call SimpleTest.finish(); gQueue.invoke(); // Will call SimpleTest.finish();
} }
@ -94,13 +149,18 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=551684" 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"> title="No statechange event for aria-expanded on native HTML elements, is fired on ARIA widgets">
Mozilla Bug 551684 Mozilla Bug 551684
</a> </a><br>
<a target="_blank" <a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=648133" href="https://bugzilla.mozilla.org/show_bug.cgi?id=648133"
title="fire state change event for aria-busy" title="fire state change event for aria-busy"
Mozilla Bug 648133 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> </a>
<p id="display"></p> <p id="display"></p>
<div id="content" style="display: none"></div> <div id="content" style="display: none"></div>
<pre id="test"> <pre id="test">
@ -113,5 +173,11 @@
<!-- aria-busy --> <!-- aria-busy -->
<div id="aria_doc" role="document" tabindex="0">A document</div> <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> </body>
</html> </html>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -123,9 +123,6 @@ CSRCS = \
DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD 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 ifdef MOZ_ANGLE
# libEGL depends on (links against!) libGLESv2! # libEGL depends on (links against!) libGLESv2!

View File

@ -12,6 +12,8 @@ In this order:
angle-r702.patch - this is ANGLE r702 angle-r702.patch - this is ANGLE r702
angle-limit-identifiers-to-250-chars.patch - see bug 675625 angle-limit-identifiers-to-250-chars.patch - see bug 675625
angle-r712.patch - this is ANGLE r712 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. In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,8 +48,8 @@ BlendState ComponentAlphaBlend
SrcBlend = One; SrcBlend = One;
DestBlend = Inv_Src1_Color; DestBlend = Inv_Src1_Color;
BlendOp = Add; BlendOp = Add;
SrcBlendAlpha = Zero; SrcBlendAlpha = Src1_Alpha;
DestBlendAlpha = One; DestBlendAlpha = Inv_Src1_Alpha;
BlendOpAlpha = Add; BlendOpAlpha = Add;
RenderTargetWriteMask[0] = 0x0F; // All 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.vSrc = tRGB.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords);
result.vAlpha = 1.0 - tRGBWhite.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) + result.vSrc; result.vAlpha = 1.0 - tRGBWhite.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) + result.vSrc;
result.vAlpha.a = result.vAlpha.g;
result.vSrc *= fLayerOpacity; result.vSrc *= fLayerOpacity;
result.vAlpha *= fLayerOpacity; result.vAlpha *= fLayerOpacity;
return result; return result;

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -98,7 +98,7 @@ public:
} // anon namespace } // anon namespace
nsFontMetrics::nsFontMetrics() 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, nsDeviceContext *aContext,
gfxUserFontSet *aUserFontSet) gfxUserFontSet *aUserFontSet)
{ {
NS_ABORT_IF_FALSE(mP2A == -1, "already initialized"); NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
mFont = aFont; mFont = aFont;
mLanguage = aLanguage; mLanguage = aLanguage;

View File

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

View File

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

View File

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

View File

@ -186,7 +186,7 @@ NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
// but trying to find where we were in a constantly changing list is basically // but trying to find where we were in a constantly changing list is basically
// impossible. // 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 // 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. // we get the list, we do a loop to keep trying until we get it.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -327,7 +327,8 @@ typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> CompartmentVector;
} }
struct JSRuntime { struct JSRuntime
{
/* Default compartment. */ /* Default compartment. */
JSCompartment *atomsCompartment; JSCompartment *atomsCompartment;
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
@ -340,6 +341,20 @@ struct JSRuntime {
/* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */ /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
JSRuntimeState state; 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. */ /* Context create/destroy callback. */
JSContextCallback cxCallback; JSContextCallback cxCallback;
@ -1334,11 +1349,11 @@ class AutoCheckRequestDepth {
# define CHECK_REQUEST(cx) \ # define CHECK_REQUEST(cx) \
JS_ASSERT((cx)->thread()); \ JS_ASSERT((cx)->thread()); \
JS_ASSERT((cx)->thread()->data.requestDepth || (cx)->thread() == (cx)->runtime->gcThread); \ JS_ASSERT((cx)->thread()->data.requestDepth || (cx)->thread() == (cx)->runtime->gcThread); \
JS_ASSERT(cx->runtime->onOwnerThread()); \
AutoCheckRequestDepth _autoCheckRequestDepth(cx); AutoCheckRequestDepth _autoCheckRequestDepth(cx);
#else #else
# define CHECK_REQUEST(cx) ((void) 0) # define CHECK_REQUEST(cx) ((void) 0)
# define CHECK_REQUEST_THREAD(cx) ((void) 0)
#endif #endif
static inline JSAtom ** static inline JSAtom **

View File

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

View File

@ -154,19 +154,6 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
JSScript *script = fp->script(); JSScript *script = fp->script();
jsbytecode *start = script->code; 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); JS_ASSERT(target >= start && target < start + script->length);
JSObject *blockChain = NULL; JSObject *blockChain = NULL;

View File

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

View File

@ -130,7 +130,6 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj,
const js::Shape **shapep, PropertyCacheEntry **entryp) const js::Shape **shapep, PropertyCacheEntry **entryp)
{ {
JS_ASSERT(obj->slotSpan() >= JSSLOT_FREE(obj->getClass())); JS_ASSERT(obj->slotSpan() >= JSSLOT_FREE(obj->getClass()));
JS_ASSERT(obj->isExtensible());
uint32 kshape = obj->shape(); uint32 kshape = obj->shape();
PropertyCacheEntry *entry = &table[hash(pc, kshape)]; PropertyCacheEntry *entry = &table[hash(pc, kshape)];
*entryp = entry; *entryp = entry;
@ -142,6 +141,10 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj,
if (entry->kpc == pc && if (entry->kpc == pc &&
entry->kshape == kshape && entry->kshape == kshape &&
entry->vshape() == rt->protoHazardShape) { 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(pchits++);
PCMETER(inipchits++); PCMETER(inipchits++);
JS_ASSERT(entry->vcapTag() == 0); JS_ASSERT(entry->vcapTag() == 0);

View File

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

View File

@ -414,7 +414,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
masm.forceFlushConstantPool(); masm.forceFlushConstantPool();
stubcc.masm.forceFlushConstantPool(); stubcc.masm.forceFlushConstantPool();
#endif #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() + size_t codeSize = masm.size() +
stubcc.size() + stubcc.size() +

View File

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

View File

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

View File

@ -1111,7 +1111,7 @@ Quit(JSContext *cx, uintN argc, jsval *vp)
gQuitting = JS_TRUE; gQuitting = JS_TRUE;
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
if (gWorkerThreadPool) if (gWorkerThreadPool)
js::workers::terminateAll(JS_GetRuntime(cx), gWorkerThreadPool); js::workers::terminateAll(gWorkerThreadPool);
#endif #endif
return JS_FALSE; return JS_FALSE;
} }
@ -3233,245 +3233,6 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp)
return !gCanceled; 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 static bool
InitWatchdog(JSRuntime *rt) InitWatchdog(JSRuntime *rt)
{ {
@ -3656,7 +3417,7 @@ CancelExecution(JSRuntime *rt)
gExitCode = EXITCODE_TIMEOUT; gExitCode = EXITCODE_TIMEOUT;
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
if (gWorkerThreadPool) if (gWorkerThreadPool)
js::workers::terminateAll(rt, gWorkerThreadPool); js::workers::terminateAll(gWorkerThreadPool);
#endif #endif
JS_TriggerAllOperationCallbacks(rt); JS_TriggerAllOperationCallbacks(rt);
@ -4197,7 +3958,6 @@ static JSFunctionSpec shell_functions[] = {
#endif #endif
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
JS_FN("sleep", Sleep_fn, 1,0), JS_FN("sleep", Sleep_fn, 1,0),
JS_FN("scatter", Scatter, 1,0),
#endif #endif
JS_FN("snarf", Snarf, 0,0), JS_FN("snarf", Snarf, 0,0),
JS_FN("read", Snarf, 0,0), JS_FN("read", Snarf, 0,0),
@ -4337,7 +4097,6 @@ static const char *const shell_help_messages[] = {
#endif #endif
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
"sleep(dt) Sleep for dt seconds", "sleep(dt) Sleep for dt seconds",
"scatter(fns) Call functions concurrently (ignoring errors)",
#endif #endif
"snarf(filename) Read filename into returned string", "snarf(filename) Read filename into returned string",
"read(filename) Synonym for snarf", "read(filename) Synonym for snarf",

View File

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

View File

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

View File

@ -34,6 +34,7 @@ script findReferences-01.js
script findReferences-02.js script findReferences-02.js
script findReferences-03.js script findReferences-03.js
script findReferences-04.js script findReferences-04.js
script regress-613452.js
script regress-627859.js script regress-627859.js
script regress-627984-1.js script regress-627984-1.js
script regress-627984-2.js script regress-627984-2.js
@ -52,7 +53,4 @@ script weakmap.js
script regress-645160.js script regress-645160.js
script regress-650753.js script regress-650753.js
script regress-668438.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 script regress-677924.js

View File

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

View File

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

View File

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

View File

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

View File

@ -9,10 +9,10 @@ if (typeof Worker != 'undefined') {
JSTest.waitForExplicitFinish(); JSTest.waitForExplicitFinish();
var w = Worker(workerDir + "worker-fib-child.js"); var w = Worker(workerDir + "worker-fib-child.js");
w.onmessage = function (event) { w.onmessage = function (event) {
reportCompare("55", event.data, "worker-fib"); reportCompare("21", event.data, "worker-fib");
JSTest.testFinished(); 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 { } else {
reportCompare(0, 0, "Test skipped. Shell workers required."); reportCompare(0, 0, "Test skipped. Shell workers required.");
} }

View File

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

View File

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

View File

@ -532,6 +532,34 @@ nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
return NS_OK; 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 nsresult
nsXPConnect::FinishTraverse() nsXPConnect::FinishTraverse()
{ {
@ -2444,7 +2472,9 @@ nsXPConnect::GetRuntime(JSRuntime **runtime)
if(!runtime) if(!runtime)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
*runtime = GetRuntime()->GetJSRuntime(); JSRuntime *rt = GetRuntime()->GetJSRuntime();
JS_AbortIfWrongThread(rt);
*runtime = rt;
return NS_OK; return NS_OK;
} }

View File

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

View File

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

View File

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

View File

@ -766,6 +766,34 @@ ElementForStyleContext(nsIContent* aParentContent,
return content->AsElement(); 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 nsresult
nsFrameManager::ReparentStyleContext(nsIFrame* aFrame) nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
{ {
@ -831,7 +859,8 @@ nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
} }
#endif #endif
nsIFrame *prevContinuation = aFrame->GetPrevContinuation(); nsIFrame *prevContinuation =
GetPrevContinuationWithPossiblySameStyle(aFrame);
nsStyleContext *prevContinuationContext; nsStyleContext *prevContinuationContext;
PRBool copyFromContinuation = PRBool copyFromContinuation =
prevContinuation && prevContinuation &&
@ -1147,12 +1176,35 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
nextContinuationContext->GetParent(), nextContinuationContext->GetParent(),
"continuations should have the same style context"); "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 #endif
// do primary context // do primary context
nsRefPtr<nsStyleContext> newContext; nsRefPtr<nsStyleContext> newContext;
nsIFrame *prevContinuation = aFrame->GetPrevContinuation(); nsIFrame *prevContinuation =
GetPrevContinuationWithPossiblySameStyle(aFrame);
nsStyleContext *prevContinuationContext; nsStyleContext *prevContinuationContext;
PRBool copyFromContinuation = PRBool copyFromContinuation =
prevContinuation && prevContinuation &&
@ -1171,7 +1223,15 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
"non pseudo-element frame without content node"); "non pseudo-element frame without content node");
newContext = styleSet->ResolveStyleForNonElement(parentContext); 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 = newContext =
styleSet->ReparentStyleContext(oldContext, parentContext, styleSet->ReparentStyleContext(oldContext, parentContext,
ElementForStyleContext(aParentContent, ElementForStyleContext(aParentContent,

View File

@ -83,7 +83,11 @@
#endif #endif
// Size to use for PLArena block allocations. // 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 // Freed memory is filled with a poison value, which we arrange to
// form a pointer either to an always-unmapped region of the address // form a pointer either to an always-unmapped region of the address

View File

@ -591,7 +591,7 @@ public:
} }
static PRInt32 AppUnitsPerCSSPixel() { return nsDeviceContext::AppUnitsPerCSSPixel(); } 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 PRInt32 AppUnitsPerCSSInch() { return nsDeviceContext::AppUnitsPerCSSInch(); }
static nscoord CSSPixelsToAppUnits(PRInt32 aPixels) static nscoord CSSPixelsToAppUnits(PRInt32 aPixels)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -386,6 +386,12 @@ var Browser = {
let event = document.createEvent("Events"); let event = document.createEvent("Events");
event.initEvent("UIReady", true, false); event.initEvent("UIReady", true, false);
window.dispatchEvent(event); 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() { _alertShown: function _alertShown() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -87,6 +87,8 @@ HISTOGRAM(SHUTDOWN_OK, 0, 1, 2, BOOLEAN, "Did the browser start after a successf
HISTOGRAM(IMAGE_DECODE_LATENCY, 50, 5000000, 100, EXPONENTIAL, "Time spent decoding an image chunk (us)") HISTOGRAM(IMAGE_DECODE_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_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 * Networking telemetry

View File

@ -11,8 +11,6 @@
* for the specific language governing rights and limitations under the * for the specific language governing rights and limitations under the
* License. * License.
* *
* The Original Code is the nsTryToClose component.
*
* The Initial Developer of the Original Code is * The Initial Developer of the Original Code is
* the Mozilla Foundation * the Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011 * 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/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.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 // When modifying the payload in incompatible ways, please bump this version number
const PAYLOAD_VERSION = 1; const PAYLOAD_VERSION = 1;
@ -49,7 +48,7 @@ const PAYLOAD_VERSION = 1;
const PREF_SERVER = "toolkit.telemetry.server"; const PREF_SERVER = "toolkit.telemetry.server";
const PREF_ENABLED = "toolkit.telemetry.enabled"; const PREF_ENABLED = "toolkit.telemetry.enabled";
// Do not gather data more than once a minute // Do not gather data more than once a minute
const TELEMETRY_INTERVAL = 60; const TELEMETRY_INTERVAL = 60000;
// Delay before intializing telemetry (ms) // Delay before intializing telemetry (ms)
const TELEMETRY_DELAY = 60000; const TELEMETRY_DELAY = 60000;
// about:memory values to turn into histograms // about:memory values to turn into histograms
@ -65,6 +64,8 @@ const MEM_HISTOGRAMS = {
"page-faults-hard": "PAGE_FAULTS_HARD" "page-faults-hard": "PAGE_FAULTS_HARD"
}; };
var gLastMemoryPoll = null;
function getLocale() { function getLocale() {
return Cc["@mozilla.org/chrome/chrome-registry;1"]. return Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry). getService(Ci.nsIXULChromeRegistry).
@ -220,6 +221,54 @@ TelemetryPing.prototype = {
h.add(val); 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 * Pull values from about:memory into corresponding histograms
*/ */
@ -286,10 +335,11 @@ TelemetryPing.prototype = {
this.gatherMemory(); this.gatherMemory();
let payload = { let payload = {
ver: PAYLOAD_VERSION, ver: PAYLOAD_VERSION,
info: getMetadata(reason), info: this.getMetadata(reason),
simpleMeasurements: getSimpleMeasurements(), simpleMeasurements: getSimpleMeasurements(),
histograms: getHistograms() histograms: getHistograms()
}; };
let isTestPing = (reason == "test-ping"); let isTestPing = (reason == "test-ping");
// Generate a unique id once per session so the server can cope with duplicate submissions. // Generate a unique id once per session so the server can cope with duplicate submissions.
// Use a deterministic url for testing. // Use a deterministic url for testing.
@ -329,19 +379,15 @@ TelemetryPing.prototype = {
attachObservers: function attachObservers() { attachObservers: function attachObservers() {
if (!this._initialized) if (!this._initialized)
return; return;
let idleService = Cc["@mozilla.org/widget/idleservice;1"]. Services.obs.addObserver(this, "cycle-collector-begin", false);
getService(Ci.nsIIdleService);
idleService.addIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.addObserver(this, "idle-daily", false); Services.obs.addObserver(this, "idle-daily", false);
}, },
detachObservers: function detachObservers() { detachObservers: function detachObservers() {
if (!this._initialized) if (!this._initialized)
return; 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, "idle-daily");
Services.obs.removeObserver(this, "cycle-collector-begin");
}, },
/** /**
@ -395,14 +441,22 @@ TelemetryPing.prototype = {
var server = this._server; var server = this._server;
switch (aTopic) { switch (aTopic) {
case "Add-ons":
this._addons = aData;
break;
case "profile-after-change": case "profile-after-change":
this.setup(); this.setup();
break; break;
case "profile-before-change": case "profile-before-change":
this.uninstall(); this.uninstall();
break; break;
case "idle": case "cycle-collector-begin":
this.gatherMemory(); let now = new Date();
if (!gLastMemoryPoll
|| (TELEMETRY_INTERVAL <= now - gLastMemoryPoll)) {
gLastMemoryPoll = now;
this.gatherMemory();
}
break; break;
case "private-browsing": case "private-browsing":
Telemetry.canRecord = aData == "exit"; Telemetry.canRecord = aData == "exit";

View File

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

View File

@ -66,7 +66,7 @@ MockObjectRegisterer.prototype = {
*/ */
register: function MOR_register() { register: function MOR_register() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (this._originalCID) if (this._originalFactory)
throw new Exception("Invalid object state when calling register()"); throw new Exception("Invalid object state when calling register()");
// Define a factory that creates a new object using the given constructor. // 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); 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, componentRegistrar.registerFactory(this._cid,
"", "",
this._contractID, this._contractID,
@ -98,7 +101,7 @@ MockObjectRegisterer.prototype = {
*/ */
unregister: function MOR_unregister() { unregister: function MOR_unregister() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (!this._originalCID) if (!this._originalFactory)
throw new Exception("Invalid object state when calling unregister()"); throw new Exception("Invalid object state when calling unregister()");
// Free references to the mock factory. // Free references to the mock factory.
@ -107,23 +110,23 @@ MockObjectRegisterer.prototype = {
this._mockFactory); this._mockFactory);
// Restore the original factory. // Restore the original factory.
componentRegistrar.registerFactory(this._originalCID, componentRegistrar.registerFactory(this._cid,
"", "",
this._contractID, this._contractID,
null); this._originalFactory);
// Allow registering a mock factory again later. // Allow registering a mock factory again later.
this._cid = null; this._cid = null;
this._originalCID = null; this._originalFactory = null;
this._mockFactory = null; this._mockFactory = null;
}, },
// --- Private methods and properties --- // --- 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. * The CID under which the mock contractID was registered.

View File

@ -1246,7 +1246,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
info_ptr->process_kernel_time = info_ptr->process_kernel_time =
static_cast<u_int32_t>(usage.ru_stime.tv_sec); 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])); u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
size_t size; size_t size;
if (!sysctl(mib, mibsize, NULL, &size, NULL, 0)) { if (!sysctl(mib, mibsize, NULL, &size, NULL, 0)) {

View File

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

View File

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

View File

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

View File

@ -457,19 +457,6 @@ AndroidGeckoEvent::Init(int x1, int y1, int x2, int y2)
mRect.SetEmpty(); 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 void
AndroidGeckoSurfaceView::Init(jobject jobj) AndroidGeckoSurfaceView::Init(jobject jobj)
{ {

View File

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

View File

@ -74,7 +74,6 @@ PRLogModuleInfo *gWidgetLog = nsnull;
nsDeviceMotionSystem *gDeviceMotionSystem = nsnull; nsDeviceMotionSystem *gDeviceMotionSystem = nsnull;
nsIGeolocationUpdate *gLocationCallback = nsnull; nsIGeolocationUpdate *gLocationCallback = nsnull;
nsAutoPtr<mozilla::AndroidGeckoEvent> gLastSizeChange;
nsAppShell *nsAppShell::gAppShell = nsnull; nsAppShell *nsAppShell::gAppShell = nsnull;
@ -381,15 +380,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
break; 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: default:
nsWindow::OnGlobalAndroidEvent(curEvent); nsWindow::OnGlobalAndroidEvent(curEvent);
} }
@ -399,13 +389,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
return true; return true;
} }
void
nsAppShell::ResendLastResizeEvent(nsWindow* aDest) {
if (gLastSizeChange) {
nsWindow::OnGlobalAndroidEvent(gLastSizeChange);
}
}
AndroidGeckoEvent* AndroidGeckoEvent*
nsAppShell::GetNextEvent() nsAppShell::GetNextEvent()
{ {

View File

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

View File

@ -448,6 +448,14 @@ nsWindow::Resize(PRInt32 aX,
PRBool needSizeDispatch = aWidth != mBounds.width || aHeight != mBounds.height; 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.x = aX;
mBounds.y = aY; mBounds.y = aY;
mBounds.width = aWidth; mBounds.width = aWidth;
@ -578,8 +586,6 @@ nsWindow::BringToFront()
nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this); nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
DispatchEvent(&event); DispatchEvent(&event);
// force a window resize
nsAppShell::gAppShell->ResendLastResizeEvent(this);
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1)); nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
} }
@ -732,19 +738,11 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
return; return;
switch (ae->Type()) { 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: { case AndroidGeckoEvent::SIZE_CHANGED: {
int nw = ae->P0().x; int nw = ae->P0().x;
int nh = ae->P0().y; int nh = ae->P0().y;
if (ae->Type() == AndroidGeckoEvent::FORCED_RESIZE || nw != gAndroidBounds.width || if (nw != gAndroidBounds.width ||
nh != gAndroidBounds.height) { nh != gAndroidBounds.height) {
gAndroidBounds.width = nw; gAndroidBounds.width = nw;

View File

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