merge fx-team to m-c

This commit is contained in:
Rob Campbell 2012-05-16 12:03:18 -07:00
commit 781fd2f3b9
390 changed files with 10395 additions and 4591 deletions

View file

@ -177,7 +177,7 @@ EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
endif endif
SYMBOL_INDEX_NAME = \ SYMBOL_INDEX_NAME = \
$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)$(EXTRA_BUILDID)-symbols.txt $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)$(EXTRA_BUILDID)-symbols.txt
buildsymbols: buildsymbols:
ifdef MOZ_CRASHREPORTER ifdef MOZ_CRASHREPORTER

View file

@ -42,6 +42,7 @@
#include "Accessible-inl.h" #include "Accessible-inl.h"
#include "nsAccUtils.h" #include "nsAccUtils.h"
#include "nsHyperTextAccessible.h" #include "nsHyperTextAccessible.h"
#include "nsDocAccessible.h"
#include "States.h" #include "States.h"
#include "nsArrayUtils.h" #include "nsArrayUtils.h"
@ -217,6 +218,10 @@ nsAccessiblePivot::MoveNext(nsIAccessibleTraversalRule* aRule, bool* aResult)
NS_ENSURE_ARG(aResult); NS_ENSURE_ARG(aResult);
NS_ENSURE_ARG(aRule); NS_ENSURE_ARG(aRule);
if (mPosition && (mPosition->IsDefunct() ||
!mPosition->Document()->IsInDocument(mPosition)))
return NS_ERROR_NOT_IN_TREE;
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsAccessible* accessible = SearchForward(mPosition, aRule, false, &rv); nsAccessible* accessible = SearchForward(mPosition, aRule, false, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -234,6 +239,10 @@ nsAccessiblePivot::MovePrevious(nsIAccessibleTraversalRule* aRule, bool* aResult
NS_ENSURE_ARG(aResult); NS_ENSURE_ARG(aResult);
NS_ENSURE_ARG(aRule); NS_ENSURE_ARG(aRule);
if (mPosition && (mPosition->IsDefunct() ||
!mPosition->Document()->IsInDocument(mPosition)))
return NS_ERROR_NOT_IN_TREE;
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsAccessible* accessible = SearchBackward(mPosition, aRule, false, &rv); nsAccessible* accessible = SearchBackward(mPosition, aRule, false, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -250,6 +259,10 @@ nsAccessiblePivot::MoveFirst(nsIAccessibleTraversalRule* aRule, bool* aResult)
{ {
NS_ENSURE_ARG(aResult); NS_ENSURE_ARG(aResult);
NS_ENSURE_ARG(aRule); NS_ENSURE_ARG(aRule);
if (mRoot && mRoot->IsDefunct())
return NS_ERROR_NOT_IN_TREE;
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsAccessible* accessible = SearchForward(mRoot, aRule, true, &rv); nsAccessible* accessible = SearchForward(mRoot, aRule, true, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -267,6 +280,9 @@ nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule, bool* aResult)
NS_ENSURE_ARG(aResult); NS_ENSURE_ARG(aResult);
NS_ENSURE_ARG(aRule); NS_ENSURE_ARG(aRule);
if (mRoot && mRoot->IsDefunct())
return NS_ERROR_NOT_IN_TREE;
*aResult = false; *aResult = false;
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsAccessible* lastAccessible = mRoot; nsAccessible* lastAccessible = mRoot;
@ -334,6 +350,9 @@ nsAccessiblePivot::RemoveObserver(nsIAccessiblePivotObserver* aObserver)
bool bool
nsAccessiblePivot::IsRootDescendant(nsAccessible* aAccessible) nsAccessiblePivot::IsRootDescendant(nsAccessible* aAccessible)
{ {
if (!mRoot || mRoot->IsDefunct())
return false;
nsAccessible* accessible = aAccessible; nsAccessible* accessible = aAccessible;
do { do {
if (accessible == mRoot) if (accessible == mRoot)

View file

@ -49,6 +49,10 @@
class nsAccessible; class nsAccessible;
class nsIAccessibleTraversalRule; class nsIAccessibleTraversalRule;
// raised when current pivot's position is needed but it is not in the tree.
#define NS_ERROR_NOT_IN_TREE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 0x26)
/** /**
* Class represents an accessible pivot. * Class represents an accessible pivot.
*/ */

View file

@ -88,9 +88,6 @@ nsHTMLSelectListAccessible::NativeState()
role role
nsHTMLSelectListAccessible::NativeRole() nsHTMLSelectListAccessible::NativeRole()
{ {
if (mParent && mParent->Role() == roles::COMBOBOX)
return roles::COMBOBOX_LIST;
return roles::LISTBOX; return roles::LISTBOX;
} }
@ -710,6 +707,12 @@ nsHTMLComboboxListAccessible::IsPrimaryForNode() const
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsHTMLComboboxAccessible: nsAccessible // nsHTMLComboboxAccessible: nsAccessible
role
nsHTMLComboboxListAccessible::NativeRole()
{
return roles::COMBOBOX_LIST;
}
PRUint64 PRUint64
nsHTMLComboboxListAccessible::NativeState() nsHTMLComboboxListAccessible::NativeState()
{ {

View file

@ -258,6 +258,7 @@ public:
virtual bool IsPrimaryForNode() const; virtual bool IsPrimaryForNode() const;
// nsAccessible // nsAccessible
virtual mozilla::a11y::role NativeRole();
virtual PRUint64 NativeState(); virtual PRUint64 NativeState();
virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame); virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);

View file

@ -48,14 +48,14 @@ var AccessFu = {
} catch (x) { } catch (x) {
} }
this.processPreferences(accessPref); this._processPreferences(accessPref);
}, },
/** /**
* Start AccessFu mode, this primarily means controlling the virtual cursor * Start AccessFu mode, this primarily means controlling the virtual cursor
* with arrow keys. * with arrow keys.
*/ */
enable: function enable() { _enable: function _enable() {
if (this._enabled) if (this._enabled)
return; return;
this._enabled = true; this._enabled = true;
@ -79,7 +79,7 @@ var AccessFu = {
/** /**
* Disable AccessFu and return to default interaction mode. * Disable AccessFu and return to default interaction mode.
*/ */
disable: function disable() { _disable: function _disable() {
if (!this._enabled) if (!this._enabled)
return; return;
this._enabled = false; this._enabled = false;
@ -98,7 +98,7 @@ var AccessFu = {
this.chromeWin.removeEventListener('TabOpen', this, true); this.chromeWin.removeEventListener('TabOpen', this, true);
}, },
processPreferences: function processPreferences(aPref) { _processPreferences: function _processPreferences(aPref) {
if (Services.appinfo.OS == 'Android') { if (Services.appinfo.OS == 'Android') {
if (aPref == ACCESSFU_AUTO) { if (aPref == ACCESSFU_AUTO) {
if (!this._observingSystemSettings) { if (!this._observingSystemSettings) {
@ -118,9 +118,9 @@ var AccessFu = {
} }
if (aPref == ACCESSFU_ENABLE) if (aPref == ACCESSFU_ENABLE)
this.enable(); this._enable();
else else
this.disable(); this._disable();
}, },
addPresenter: function addPresenter(presenter) { addPresenter: function addPresenter(presenter) {
@ -171,19 +171,19 @@ var AccessFu = {
switch (aTopic) { switch (aTopic) {
case 'Accessibility:Settings': case 'Accessibility:Settings':
if (JSON.parse(aData).enabled) if (JSON.parse(aData).enabled)
this.enable(); this._enable();
else else
this.disable(); this._disable();
break; break;
case 'nsPref:changed': case 'nsPref:changed':
if (aData == 'accessfu') if (aData == 'accessfu')
this.processPreferences(this.prefsBranch.getIntPref('accessfu')); this._processPreferences(this.prefsBranch.getIntPref('accessfu'));
break; break;
case 'accessible-event': case 'accessible-event':
let event; let event;
try { try {
event = aSubject.QueryInterface(Ci.nsIAccessibleEvent); event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
this.handleAccEvent(event); this._handleAccEvent(event);
} catch (ex) { } catch (ex) {
dump(ex); dump(ex);
return; return;
@ -191,7 +191,7 @@ var AccessFu = {
} }
}, },
handleAccEvent: function handleAccEvent(aEvent) { _handleAccEvent: function _handleAccEvent(aEvent) {
switch (aEvent.eventType) { switch (aEvent.eventType) {
case Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED: case Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED:
{ {
@ -199,6 +199,21 @@ var AccessFu = {
QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor; QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
let event = aEvent. let event = aEvent.
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent); QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
let position = pivot.position;
let doc = aEvent.DOMNode;
if (doc instanceof Ci.nsIDOMDocument && position.DOMNode) {
// Set the caret to the start of the pivot position, and move
// the focus in the same manner as browse with caret mode.
// This blurs the focus on the previous pivot position (if it
// was activated), and keeps us in a predictable spot for tab
// focus.
let sel = doc.getSelection();
sel.collapse(position.DOMNode, 0);
Cc["@mozilla.org/focus-manager;1"]
.getService(Ci.nsIFocusManager).moveFocus(
doc.defaultView, null, Ci.nsIFocusManager.MOVEFOCUS_CARET, 0);
}
let newContext = this.getNewContext(event.oldAccessible, let newContext = this.getNewContext(event.oldAccessible,
pivot.position); pivot.position);
@ -251,13 +266,13 @@ var AccessFu = {
let state = {}; let state = {};
docAcc.getState(state, {}); docAcc.getState(state, {});
if (state.value & Ci.nsIAccessibleStates.STATE_BUSY && if (state.value & Ci.nsIAccessibleStates.STATE_BUSY &&
this.isNotChromeDoc(docAcc)) this._isNotChromeDoc(docAcc))
this.presenters.forEach( this.presenters.forEach(
function(p) { p.tabStateChanged(docAcc, 'loading'); } function(p) { p.tabStateChanged(docAcc, 'loading'); }
); );
delete this._pendingDocuments[aEvent.DOMNode]; delete this._pendingDocuments[aEvent.DOMNode];
} }
if (this.isBrowserDoc(docAcc)) if (this._isBrowserDoc(docAcc))
// A new top-level content document has been attached // A new top-level content document has been attached
this.presenters.forEach( this.presenters.forEach(
function(p) { p.tabStateChanged(docAcc, 'newdoc'); } function(p) { p.tabStateChanged(docAcc, 'newdoc'); }
@ -267,7 +282,7 @@ var AccessFu = {
} }
case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE: case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE:
{ {
if (this.isNotChromeDoc(aEvent.accessible)) { if (this._isNotChromeDoc(aEvent.accessible)) {
this.presenters.forEach( this.presenters.forEach(
function(p) { function(p) {
p.tabStateChanged(aEvent.accessible, 'loaded'); p.tabStateChanged(aEvent.accessible, 'loaded');
@ -296,7 +311,7 @@ var AccessFu = {
} }
case Ci.nsIAccessibleEvent.EVENT_FOCUS: case Ci.nsIAccessibleEvent.EVENT_FOCUS:
{ {
if (this.isBrowserDoc(aEvent.accessible)) { if (this._isBrowserDoc(aEvent.accessible)) {
// The document recieved focus, call tabSelected to present current tab. // The document recieved focus, call tabSelected to present current tab.
this.presenters.forEach( this.presenters.forEach(
function(p) { p.tabSelected(aEvent.accessible); }); function(p) { p.tabSelected(aEvent.accessible); });
@ -342,7 +357,7 @@ var AccessFu = {
* @param {nsIAccessible} aDocAcc the accessible to check. * @param {nsIAccessible} aDocAcc the accessible to check.
* @return {boolean} true if this is a top-level content document. * @return {boolean} true if this is a top-level content document.
*/ */
isBrowserDoc: function isBrowserDoc(aDocAcc) { _isBrowserDoc: function _isBrowserDoc(aDocAcc) {
let parent = aDocAcc.parent; let parent = aDocAcc.parent;
if (!parent) if (!parent)
return false; return false;
@ -360,7 +375,7 @@ var AccessFu = {
* @param {nsIDOMDocument} aDocument the document to check. * @param {nsIDOMDocument} aDocument the document to check.
* @return {boolean} true if this is not a chrome document. * @return {boolean} true if this is not a chrome document.
*/ */
isNotChromeDoc: function isNotChromeDoc(aDocument) { _isNotChromeDoc: function _isNotChromeDoc(aDocument) {
let location = aDocument.DOMNode.location; let location = aDocument.DOMNode.location;
if (!location) if (!location)
return false; return false;

View file

@ -52,7 +52,9 @@ Presenter.prototype = {
/** /**
* Text has changed, either by the user or by the system. TODO. * Text has changed, either by the user or by the system. TODO.
*/ */
textChanged: function textChanged(aIsInserted, aStartOffset, aLength, aText, aModifiedText) {}, textChanged: function textChanged(aIsInserted, aStartOffset,
aLength, aText,
aModifiedText) {},
/** /**
* Text selection has changed. TODO. * Text selection has changed. TODO.
@ -95,228 +97,236 @@ Presenter.prototype = {
function VisualPresenter() {} function VisualPresenter() {}
VisualPresenter.prototype = new Presenter(); VisualPresenter.prototype = {
__proto__: Presenter.prototype,
/** /**
* The padding in pixels between the object and the highlight border. * The padding in pixels between the object and the highlight border.
*/ */
VisualPresenter.prototype.BORDER_PADDING = 2; BORDER_PADDING: 2,
VisualPresenter.prototype.attach = function(aWindow) { attach: function VisualPresenter_attach(aWindow) {
this.chromeWin = aWindow; this.chromeWin = aWindow;
// Add stylesheet // Add stylesheet
let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css'; let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
this.stylesheet = aWindow.document.createProcessingInstruction( this.stylesheet = aWindow.document.createProcessingInstruction(
'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"'); 'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
aWindow.document.insertBefore(this.stylesheet, aWindow.document.firstChild); aWindow.document.insertBefore(this.stylesheet, aWindow.document.firstChild);
// Add highlight box // Add highlight box
this.highlightBox = this.chromeWin.document. this.highlightBox = this.chromeWin.document.
createElementNS('http://www.w3.org/1999/xhtml', 'div'); createElementNS('http://www.w3.org/1999/xhtml', 'div');
this.chromeWin.document.documentElement.appendChild(this.highlightBox); this.chromeWin.document.documentElement.appendChild(this.highlightBox);
this.highlightBox.id = 'virtual-cursor-box'; this.highlightBox.id = 'virtual-cursor-box';
// Add highlight inset for inner shadow // Add highlight inset for inner shadow
let inset = this.chromeWin.document. let inset = this.chromeWin.document.
createElementNS('http://www.w3.org/1999/xhtml', 'div'); createElementNS('http://www.w3.org/1999/xhtml', 'div');
inset.id = 'virtual-cursor-inset'; inset.id = 'virtual-cursor-inset';
this.highlightBox.appendChild(inset); this.highlightBox.appendChild(inset);
}; },
VisualPresenter.prototype.detach = function() { detach: function VisualPresenter_detach() {
this.chromeWin.document.removeChild(this.stylesheet); this.chromeWin.document.removeChild(this.stylesheet);
this.highlightBox.parentNode.removeChild(this.highlightBox); this.highlightBox.parentNode.removeChild(this.highlightBox);
this.highlightBox = this.stylesheet = null; this.highlightBox = this.stylesheet = null;
}; },
VisualPresenter.prototype.viewportChanged = function() { viewportChanged: function VisualPresenter_viewportChanged() {
if (this._currentObject) if (this._currentObject)
this.highlight(this._currentObject); this._highlight(this._currentObject);
}; },
VisualPresenter.prototype.pivotChanged = function(aObject, aNewContext) { pivotChanged: function VisualPresenter_pivotChanged(aObject, aNewContext) {
this._currentObject = aObject; this._currentObject = aObject;
if (!aObject) { if (!aObject) {
this.hide(); this._hide();
return; return;
}
try {
aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
this._highlight(aObject);
} catch (e) {
dump('Error getting bounds: ' + e);
return;
}
},
tabSelected: function VisualPresenter_tabSelected(aDocObj) {
let vcPos = aDocObj ? aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).
virtualCursor.position : null;
this.pivotChanged(vcPos);
},
tabStateChanged: function VisualPresenter_tabStateChanged(aDocObj,
aPageState) {
if (aPageState == 'newdoc')
this.pivotChanged(null);
},
// Internals
_hide: function _hide() {
this.highlightBox.style.display = 'none';
},
_highlight: function _highlight(aObject) {
let vp = (Services.appinfo.OS == 'Android') ?
this.chromeWin.BrowserApp.selectedTab.getViewport() :
{ zoom: 1.0, offsetY: 0 };
let bounds = this._getBounds(aObject, vp.zoom);
// First hide it to avoid flickering when changing the style.
this.highlightBox.style.display = 'none';
this.highlightBox.style.top = bounds.top + 'px';
this.highlightBox.style.left = bounds.left + 'px';
this.highlightBox.style.width = bounds.width + 'px';
this.highlightBox.style.height = bounds.height + 'px';
this.highlightBox.style.display = 'block';
},
_getBounds: function _getBounds(aObject, aZoom, aStart, aEnd) {
let objX = {}, objY = {}, objW = {}, objH = {};
if (aEnd >= 0 && aStart >= 0 && aEnd != aStart) {
// TODO: Get bounds for text ranges. Leaving this blank until we have
// proper text navigation in the virtual cursor.
}
aObject.getBounds(objX, objY, objW, objH);
// Can't specify relative coords in nsIAccessible.getBounds, so we do it.
let docX = {}, docY = {};
let docRoot = aObject.rootDocument.QueryInterface(Ci.nsIAccessible);
docRoot.getBounds(docX, docY, {}, {});
let rv = {
left: Math.round((objX.value - docX.value - this.BORDER_PADDING) * aZoom),
top: Math.round((objY.value - docY.value - this.BORDER_PADDING) * aZoom),
width: Math.round((objW.value + (this.BORDER_PADDING * 2)) * aZoom),
height: Math.round((objH.value + (this.BORDER_PADDING * 2)) * aZoom)
};
return rv;
} }
try {
aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
this.highlight(aObject);
} catch (e) {
dump('Error getting bounds: ' + e);
return;
}
};
VisualPresenter.prototype.tabSelected = function(aDocObj) {
let vcPos = aDocObj ?
aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor.position :
null;
this.pivotChanged(vcPos);
};
VisualPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
if (aPageState == "newdoc")
this.pivotChanged(null);
};
// Internals
VisualPresenter.prototype.hide = function hide() {
this.highlightBox.style.display = 'none';
};
VisualPresenter.prototype.highlight = function(aObject) {
let vp = (Services.appinfo.OS == 'Android') ?
this.chromeWin.BrowserApp.selectedTab.getViewport() :
{ zoom: 1.0, offsetY: 0 };
let bounds = this.getBounds(aObject, vp.zoom);
// First hide it to avoid flickering when changing the style.
this.highlightBox.style.display = 'none';
this.highlightBox.style.top = bounds.top + 'px';
this.highlightBox.style.left = bounds.left + 'px';
this.highlightBox.style.width = bounds.width + 'px';
this.highlightBox.style.height = bounds.height + 'px';
this.highlightBox.style.display = 'block';
};
VisualPresenter.prototype.getBounds = function(aObject, aZoom, aStart, aEnd) {
let objX = {}, objY = {}, objW = {}, objH = {};
if (aEnd >= 0 && aStart >= 0 && aEnd != aStart) {
// TODO: Get bounds for text ranges. Leaving this blank until we have
// proper text navigation in the virtual cursor.
}
aObject.getBounds(objX, objY, objW, objH);
// Can't specify relative coords in nsIAccessible.getBounds, so we do it.
let docX = {}, docY = {};
let docRoot = aObject.rootDocument.QueryInterface(Ci.nsIAccessible);
docRoot.getBounds(docX, docY, {}, {});
let rv = {
left: Math.round((objX.value - docX.value - this.BORDER_PADDING) * aZoom),
top: Math.round((objY.value - docY.value - this.BORDER_PADDING) * aZoom),
width: Math.round((objW.value + (this.BORDER_PADDING * 2)) * aZoom),
height: Math.round((objH.value + (this.BORDER_PADDING * 2)) * aZoom)
};
return rv;
}; };
/** /**
* Android presenter. Fires Android a11y events. * Android presenter. Fires Android a11y events.
*/ */
const ANDROID_TYPE_VIEW_CLICKED = 0x01;
const ANDROID_TYPE_VIEW_LONG_CLICKED = 0x02;
const ANDROID_TYPE_VIEW_SELECTED = 0x04;
const ANDROID_TYPE_VIEW_FOCUSED = 0x08;
const ANDROID_TYPE_VIEW_TEXT_CHANGED = 0x10;
const ANDROID_TYPE_WINDOW_STATE_CHANGED = 0x20;
function AndroidPresenter() {} function AndroidPresenter() {}
AndroidPresenter.prototype = new Presenter(); AndroidPresenter.prototype = {
__proto__: Presenter.prototype,
// Android AccessibilityEvent type constants.
ANDROID_VIEW_CLICKED: 0x01,
ANDROID_VIEW_LONG_CLICKED: 0x02,
ANDROID_VIEW_SELECTED: 0x04,
ANDROID_VIEW_FOCUSED: 0x08,
ANDROID_VIEW_TEXT_CHANGED: 0x10,
ANDROID_WINDOW_STATE_CHANGED: 0x20,
pivotChanged: function AndroidPresenter_pivotChanged(aObject, aNewContext) {
let output = [];
for (let i in aNewContext)
output.push.apply(output,
UtteranceGenerator.genForObject(aNewContext[i]));
AndroidPresenter.prototype.pivotChanged = function(aObject, aNewContext) {
let output = [];
for (let i in aNewContext)
output.push.apply(output, output.push.apply(output,
UtteranceGenerator.genForObject(aNewContext[i])); UtteranceGenerator.genForObject(aObject, true));
output.push.apply(output, this.sendMessageToJava({
UtteranceGenerator.genForObject(aObject, true)); gecko: {
type: 'Accessibility:Event',
eventType: this.ANDROID_VIEW_FOCUSED,
text: output
}
});
},
this.sendMessageToJava({ actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
gecko: { this.sendMessageToJava({
type: 'Accessibility:Event', gecko: {
eventType: ANDROID_TYPE_VIEW_FOCUSED, type: 'Accessibility:Event',
text: output eventType: this.ANDROID_VIEW_CLICKED,
text: UtteranceGenerator.genForAction(aObject, aActionName)
}
});
},
tabSelected: function AndroidPresenter_tabSelected(aDocObj) {
// Send a pivot change message with the full context utterance for this doc.
let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable);
let context = [];
let parent = vcDoc.virtualCursor.position || aDocObj;
while ((parent = parent.parent)) {
context.push(parent);
if (parent == aDocObj)
break;
} }
});
};
AndroidPresenter.prototype.actionInvoked = function(aObject, aActionName) { context.reverse();
this.sendMessageToJava({
gecko: { this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context);
},
tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj,
aPageState) {
let stateUtterance = UtteranceGenerator.
genForTabStateChange(aDocObj, aPageState);
if (!stateUtterance.length)
return;
this.sendMessageToJava({
gecko: {
type: 'Accessibility:Event',
eventType: this.ANDROID_VIEW_TEXT_CHANGED,
text: stateUtterance,
addedCount: stateUtterance.join(' ').length,
removedCount: 0,
fromIndex: 0
}
});
},
textChanged: function AndroidPresenter_textChanged(aIsInserted, aStart,
aLength, aText,
aModifiedText) {
let androidEvent = {
type: 'Accessibility:Event', type: 'Accessibility:Event',
eventType: ANDROID_TYPE_VIEW_CLICKED, eventType: this.ANDROID_VIEW_TEXT_CHANGED,
text: UtteranceGenerator.genForAction(aObject, aActionName) text: [aText],
fromIndex: aStart
};
if (aIsInserted) {
androidEvent.addedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aText.substring(aStart + aLength);
} else {
androidEvent.removedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
} }
});
};
AndroidPresenter.prototype.tabSelected = function(aDocObj) { this.sendMessageToJava({gecko: androidEvent});
// Send a pivot change message with the full context utterance for this doc. },
let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable);
let context = [];
let parent = vcDoc.virtualCursor.position || aDocObj; sendMessageToJava: function AndroidPresenter_sendMessageTojava(aMessage) {
while ((parent = parent.parent)) { return Cc['@mozilla.org/android/bridge;1'].
context.push(parent); getService(Ci.nsIAndroidBridge).
if (parent == aDocObj) handleGeckoMessage(JSON.stringify(aMessage));
break;
} }
context.reverse();
this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context);
};
AndroidPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
let stateUtterance = UtteranceGenerator.
genForTabStateChange(aDocObj, aPageState);
if (!stateUtterance.length)
return;
this.sendMessageToJava({
gecko: {
type: 'Accessibility:Event',
eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED,
text: stateUtterance,
addedCount: stateUtterance.join(' ').length,
removedCount: 0,
fromIndex: 0
}
});
};
AndroidPresenter.prototype.textChanged = function(aIsInserted, aStart, aLength, aText, aModifiedText) {
let androidEvent = {
type: 'Accessibility:Event',
eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED,
text: [aText],
fromIndex: aStart
};
if (aIsInserted) {
androidEvent.addedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aText.substring(aStart + aLength);
} else {
androidEvent.removedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
}
this.sendMessageToJava({gecko: androidEvent});
};
AndroidPresenter.prototype.sendMessageToJava = function(aMessage) {
return Cc['@mozilla.org/android/bridge;1'].
getService(Ci.nsIAndroidBridge).
handleGeckoMessage(JSON.stringify(aMessage));
}; };
/** /**
@ -325,8 +335,10 @@ AndroidPresenter.prototype.sendMessageToJava = function(aMessage) {
function DummyAndroidPresenter() {} function DummyAndroidPresenter() {}
DummyAndroidPresenter.prototype = new AndroidPresenter(); DummyAndroidPresenter.prototype = {
__proto__: AndroidPresenter.prototype,
DummyAndroidPresenter.prototype.sendMessageToJava = function(aMessage) { sendMessageToJava: function DummyAndroidPresenter_sendMessageToJava(aMsg) {
dump(JSON.stringify(aMessage, null, 2) + '\n'); dump(JSON.stringify(aMsg, null, 2) + '\n');
}
}; };

View file

@ -65,10 +65,10 @@ var UtteranceGenerator = {
* @return {Array} Two string array. The first string describes the object * @return {Array} Two string array. The first string describes the object
* and its states. The second string is the object's name. Some object * and its states. The second string is the object's name. Some object
* types may have the description or name omitted, instead an empty string * types may have the description or name omitted, instead an empty string
* is returned as a placeholder. Whether the object's description or it's role * is returned as a placeholder. Whether the object's description or it's
* is included is determined by {@link verbosityRoleMap}. * role is included is determined by {@link verbosityRoleMap}.
*/ */
genForObject: function(aAccessible, aForceName) { genForObject: function genForObject(aAccessible, aForceName) {
let roleString = gAccRetrieval.getStringRole(aAccessible.role); let roleString = gAccRetrieval.getStringRole(aAccessible.role);
let func = this.objectUtteranceFunctions[roleString] || let func = this.objectUtteranceFunctions[roleString] ||
@ -91,7 +91,7 @@ var UtteranceGenerator = {
* {@link gActionMap}. * {@link gActionMap}.
* @return {Array} A one string array with the action. * @return {Array} A one string array with the action.
*/ */
genForAction: function(aObject, aActionName) { genForAction: function genForAction(aObject, aActionName) {
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])]; return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
}, },
@ -103,7 +103,7 @@ var UtteranceGenerator = {
* {@link Presenter.tabStateChanged}. * {@link Presenter.tabStateChanged}.
* @return {Array} The tab state utterace. * @return {Array} The tab state utterace.
*/ */
genForTabStateChange: function (aObject, aTabState) { genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
switch (aTabState) { switch (aTabState) {
case 'newtab': case 'newtab':
return [gStringBundle.GetStringFromName('tabNew')]; return [gStringBundle.GetStringFromName('tabNew')];
@ -177,7 +177,8 @@ var UtteranceGenerator = {
objectUtteranceFunctions: { objectUtteranceFunctions: {
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aFlags) { defaultFunc: function defaultFunc(aAccessible, aRoleStr, aFlags) {
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
let desc = (aFlags & INCLUDE_ROLE) ? this._getLocalizedRole(aRoleStr) : ''; let desc = (aFlags & INCLUDE_ROLE) ?
this._getLocalizedRole(aRoleStr) : '';
let utterance = []; let utterance = [];
@ -207,7 +208,7 @@ var UtteranceGenerator = {
return utterance; return utterance;
}, },
heading: function(aAccessible, aRoleStr, aFlags) { heading: function heading(aAccessible, aRoleStr, aFlags) {
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
let level = {}; let level = {};
aAccessible.groupPosition(level, {}, {}); aAccessible.groupPosition(level, {}, {});
@ -220,7 +221,7 @@ var UtteranceGenerator = {
return utterance; return utterance;
}, },
listitem: function(aAccessible, aRoleStr, aFlags) { listitem: function listitem(aAccessible, aRoleStr, aFlags) {
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
let localizedRole = this._getLocalizedRole(aRoleStr); let localizedRole = this._getLocalizedRole(aRoleStr);
let itemno = {}; let itemno = {};

View file

@ -18,16 +18,20 @@ var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
getService(Ci.nsIAccessibleRetrieval); getService(Ci.nsIAccessibleRetrieval);
var VirtualCursorController = { var VirtualCursorController = {
NOT_EDITABLE: 0,
SINGLE_LINE_EDITABLE: 1,
MULTI_LINE_EDITABLE: 2,
attach: function attach(aWindow) { attach: function attach(aWindow) {
this.chromeWin = aWindow; this.chromeWin = aWindow;
this.chromeWin.document.addEventListener('keypress', this.onkeypress, true); this.chromeWin.document.addEventListener('keypress', this, true);
}, },
detach: function detach() { detach: function detach() {
this.chromeWin.document.removeEventListener('keypress', this.onkeypress, true); this.chromeWin.document.removeEventListener('keypress', this, true);
}, },
getBrowserApp: function getBrowserApp() { _getBrowserApp: function _getBrowserApp() {
switch (Services.appinfo.OS) { switch (Services.appinfo.OS) {
case 'Android': case 'Android':
return this.chromeWin.BrowserApp; return this.chromeWin.BrowserApp;
@ -36,39 +40,49 @@ var VirtualCursorController = {
} }
}, },
onkeypress: function onkeypress(aEvent) { handleEvent: function handleEvent(aEvent) {
let document = VirtualCursorController.getBrowserApp(). let document = this._getBrowserApp().selectedBrowser.contentDocument;
selectedBrowser.contentDocument; let target = aEvent.target;
dump('keypress ' + aEvent.keyCode + '\n');
switch (aEvent.keyCode) { switch (aEvent.keyCode) {
case aEvent.DOM_VK_END: case aEvent.DOM_VK_END:
VirtualCursorController.moveForward(document, true); this.moveForward(document, true);
break; break;
case aEvent.DOM_VK_HOME: case aEvent.DOM_VK_HOME:
VirtualCursorController.moveBackward(document, true); this.moveBackward(document, true);
break; break;
case aEvent.DOM_VK_RIGHT: case aEvent.DOM_VK_RIGHT:
VirtualCursorController.moveForward(document, aEvent.shiftKey); if (this._isEditableText(target) &&
target.selectionEnd != target.textLength)
// Don't move forward if caret is not at end of entry.
// XXX: Fix for rtl
return;
this.moveForward(document, aEvent.shiftKey);
break; break;
case aEvent.DOM_VK_LEFT: case aEvent.DOM_VK_LEFT:
VirtualCursorController.moveBackward(document, aEvent.shiftKey); if (this._isEditableText(target) &&
target.selectionEnd != 0)
// Don't move backward if caret is not at start of entry.
// XXX: Fix for rtl
return;
this.moveBackward(document, aEvent.shiftKey);
break; break;
case aEvent.DOM_VK_UP: case aEvent.DOM_VK_UP:
if (this._isEditableText(target) == this.MULTI_LINE_EDITABLE &&
target.selectionEnd != 0)
// Don't blur content if caret is not at start of text area.
return;
if (Services.appinfo.OS == 'Android') if (Services.appinfo.OS == 'Android')
// Return focus to browser chrome, which in Android is a native widget. // Return focus to native Android browser chrome.
Cc['@mozilla.org/android/bridge;1']. Cc['@mozilla.org/android/bridge;1'].
getService(Ci.nsIAndroidBridge).handleGeckoMessage( getService(Ci.nsIAndroidBridge).handleGeckoMessage(
JSON.stringify({ gecko: { type: 'ToggleChrome:Focus' } })); JSON.stringify({ gecko: { type: 'ToggleChrome:Focus' } }));
break; break;
case aEvent.DOM_VK_RETURN: case aEvent.DOM_VK_RETURN:
// XXX: It is true that desktop does not map the keypad enter key to
// DOM_VK_ENTER. So for desktop we require a ctrl+return instead.
if (Services.appinfo.OS == 'Android' || !aEvent.ctrlKey)
return;
case aEvent.DOM_VK_ENTER: case aEvent.DOM_VK_ENTER:
VirtualCursorController.activateCurrent(document); if (this._isEditableText(target))
return;
this.activateCurrent(document);
break; break;
default: default:
return; return;
@ -78,6 +92,18 @@ var VirtualCursorController = {
aEvent.stopPropagation(); aEvent.stopPropagation();
}, },
_isEditableText: function _isEditableText(aElement) {
// XXX: Support contentEditable and design mode
if (aElement instanceof Ci.nsIDOMHTMLInputElement &&
aElement.mozIsTextField(false))
return this.SINGLE_LINE_EDITABLE;
if (aElement instanceof Ci.nsIDOMHTMLTextAreaElement)
return this.MULTI_LINE_EDITABLE;
return this.NOT_EDITABLE;
},
moveForward: function moveForward(document, last) { moveForward: function moveForward(document, last) {
let virtualCursor = this.getVirtualCursor(document); let virtualCursor = this.getVirtualCursor(document);
if (last) { if (last) {
@ -110,7 +136,7 @@ var VirtualCursorController = {
}, },
SimpleTraversalRule: { SimpleTraversalRule: {
getMatchRoles: function(aRules) { getMatchRoles: function SimpleTraversalRule_getmatchRoles(aRules) {
aRules.value = this._matchRoles; aRules.value = this._matchRoles;
return this._matchRoles.length; return this._matchRoles.length;
}, },
@ -118,7 +144,7 @@ var VirtualCursorController = {
preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT | preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE, Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE,
match: function(aAccessible) { match: function SimpleTraversalRule_match(aAccessible) {
switch (aAccessible.role) { switch (aAccessible.role) {
case Ci.nsIAccessibleRole.ROLE_COMBOBOX: case Ci.nsIAccessibleRole.ROLE_COMBOBOX:
// We don't want to ignore the subtree because this is often // We don't want to ignore the subtree because this is often

View file

@ -8,6 +8,8 @@ const FILTER_MATCH = nsIAccessibleTraversalRule.FILTER_MATCH;
const FILTER_IGNORE = nsIAccessibleTraversalRule.FILTER_IGNORE; const FILTER_IGNORE = nsIAccessibleTraversalRule.FILTER_IGNORE;
const FILTER_IGNORE_SUBTREE = nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE; const FILTER_IGNORE_SUBTREE = nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE;
const NS_ERROR_NOT_IN_TREE = 0x80780026;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Traversal rules // Traversal rules
@ -68,13 +70,13 @@ var ObjectTraversalRule =
/** /**
* A checker for virtual cursor changed events. * A checker for virtual cursor changed events.
*/ */
function virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets) function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets)
{ {
this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc); this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc);
this.check = function virtualCursorChangedChecker_check(aEvent) this.check = function VCChangedChecker_check(aEvent)
{ {
SimpleTest.info("virtualCursorChangedChecker_check"); SimpleTest.info("VCChangedChecker_check");
var event = null; var event = null;
try { try {
@ -100,7 +102,7 @@ function virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets)
"wrong end offset"); "wrong end offset");
} }
var prevPosAndOffset = virtualCursorChangedChecker. var prevPosAndOffset = VCChangedChecker.
getPreviousPosAndOffset(aDocAcc.virtualCursor); getPreviousPosAndOffset(aDocAcc.virtualCursor);
if (prevPosAndOffset) { if (prevPosAndOffset) {
@ -114,36 +116,36 @@ function virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets)
}; };
} }
virtualCursorChangedChecker.prevPosAndOffset = {}; VCChangedChecker.prevPosAndOffset = {};
virtualCursorChangedChecker.storePreviousPosAndOffset = VCChangedChecker.storePreviousPosAndOffset =
function storePreviousPosAndOffset(aPivot) function storePreviousPosAndOffset(aPivot)
{ {
virtualCursorChangedChecker.prevPosAndOffset[aPivot] = VCChangedChecker.prevPosAndOffset[aPivot] =
{position: aPivot.position, {position: aPivot.position,
startOffset: aPivot.startOffset, startOffset: aPivot.startOffset,
endOffset: aPivot.endOffset}; endOffset: aPivot.endOffset};
}; };
virtualCursorChangedChecker.getPreviousPosAndOffset = VCChangedChecker.getPreviousPosAndOffset =
function getPreviousPosAndOffset(aPivot) function getPreviousPosAndOffset(aPivot)
{ {
return virtualCursorChangedChecker.prevPosAndOffset[aPivot]; return VCChangedChecker.prevPosAndOffset[aPivot];
}; };
/** /**
* Set a text range in the pivot and wait for virtual cursor change event. * Set a text range in the pivot and wait for virtual cursor change event.
* *
* @param aDocAcc document that manages the virtual cursor * @param aDocAcc [in] document that manages the virtual cursor
* @param aTextAccessible accessible to set to virtual cursor's position * @param aTextAccessible [in] accessible to set to virtual cursor's position
* @param aTextOffsets start and end offsets of text range to set in virtual * @param aTextOffsets [in] start and end offsets of text range to set in
* cursor * virtual cursor.
*/ */
function setVirtualCursorRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets)
{ {
this.invoke = function virtualCursorChangedInvoker_invoke() this.invoke = function virtualCursorChangedInvoker_invoke()
{ {
virtualCursorChangedChecker. VCChangedChecker.
storePreviousPosAndOffset(aDocAcc.virtualCursor); storePreviousPosAndOffset(aDocAcc.virtualCursor);
SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets); SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets);
aDocAcc.virtualCursor.setTextRange(aTextAccessible, aDocAcc.virtualCursor.setTextRange(aTextAccessible,
@ -151,45 +153,44 @@ function setVirtualCursorRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets)
aTextOffsets[1]); aTextOffsets[1]);
}; };
this.getID = function setVirtualCursorRangeInvoker_getID() this.getID = function setVCRangeInvoker_getID()
{ {
return "Set offset in " + prettyName(aTextAccessible) + return "Set offset in " + prettyName(aTextAccessible) +
" to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")"; " to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")";
} };
this.eventSeq = [ this.eventSeq = [
new virtualCursorChangedChecker(aDocAcc, aTextAccessible, aTextOffsets) new VCChangedChecker(aDocAcc, aTextAccessible, aTextOffsets)
]; ];
} }
/** /**
* Move the pivot and wait for virtual cursor change event. * Move the pivot and wait for virtual cursor change event.
* *
* @param aDocAcc document that manages the virtual cursor * @param aDocAcc [in] document that manages the virtual cursor
* @param aPivotMoveMethod method to test (ie. "moveNext", "moveFirst", etc.) * @param aPivotMoveMethod [in] method to test (ie. "moveNext", "moveFirst", etc.)
* @param aRule traversal rule object * @param aRule [in] traversal rule object
* @param aIdOrNameOrAcc id, accessivle or accessible name to expect virtual * @param aIdOrNameOrAcc [in] id, accessivle or accessible name to expect
* cursor to land on after performing move method. * virtual cursor to land on after performing move method.
*/ */
function setVirtualCursorPosInvoker(aDocAcc, aPivotMoveMethod, aRule, function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc)
aIdOrNameOrAcc)
{ {
this.invoke = function virtualCursorChangedInvoker_invoke() this.invoke = function virtualCursorChangedInvoker_invoke()
{ {
virtualCursorChangedChecker. VCChangedChecker.
storePreviousPosAndOffset(aDocAcc.virtualCursor); storePreviousPosAndOffset(aDocAcc.virtualCursor);
var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule); var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule);
SimpleTest.ok((aIdOrNameOrAcc && moved) || (!aIdOrNameOrAcc && !moved), SimpleTest.ok((aIdOrNameOrAcc && moved) || (!aIdOrNameOrAcc && !moved),
"moved pivot"); "moved pivot");
}; };
this.getID = function setVirtualCursorPosInvoker_getID() this.getID = function setVCPosInvoker_getID()
{ {
return "Do " + (aIdOrNameOrAcc ? "" : "no-op ") + aPivotMoveMethod; return "Do " + (aIdOrNameOrAcc ? "" : "no-op ") + aPivotMoveMethod;
} };
if (aIdOrNameOrAcc) { if (aIdOrNameOrAcc) {
this.eventSeq = [ new virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc) ]; this.eventSeq = [ new VCChangedChecker(aDocAcc, aIdOrNameOrAcc) ];
} else { } else {
this.eventSeq = []; this.eventSeq = [];
this.unexpectedEventSeq = [ this.unexpectedEventSeq = [
@ -202,45 +203,137 @@ function setVirtualCursorPosInvoker(aDocAcc, aPivotMoveMethod, aRule,
* Add invokers to a queue to test a rule and an expected sequence of element ids * Add invokers to a queue to test a rule and an expected sequence of element ids
* or accessible names for that rule in the given document. * or accessible names for that rule in the given document.
* *
* @param aQueue event queue in which to push invoker sequence. * @param aQueue [in] event queue in which to push invoker sequence.
* @param aDocAcc the managing document of the virtual cursor we are testing * @param aDocAcc [in] the managing document of the virtual cursor we are testing
* @param aRule the traversal rule to use in the invokers * @param aRule [in] the traversal rule to use in the invokers
* @param aSequence a sequence of accessible names or elemnt ids to expect with * @param aSequence [in] a sequence of accessible names or elemnt ids to expect with
* the given rule in the given document * the given rule in the given document
*/ */
function queueTraversalSequence(aQueue, aDocAcc, aRule, aSequence) function queueTraversalSequence(aQueue, aDocAcc, aRule, aSequence)
{ {
aDocAcc.virtualCursor.position = null; aDocAcc.virtualCursor.position = null;
for (var i = 0; i < aSequence.length; i++) { for (var i = 0; i < aSequence.length; i++) {
var invoker = new setVirtualCursorPosInvoker(aDocAcc, "moveNext", var invoker =
aRule, aSequence[i]); new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
aQueue.push(invoker); aQueue.push(invoker);
} }
// No further more matches for given rule, expect no virtual cursor changes. // No further more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "moveNext", aRule, null)); aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, null));
for (var i = aSequence.length-2; i >= 0; i--) { for (var i = aSequence.length-2; i >= 0; i--) {
var invoker = new setVirtualCursorPosInvoker(aDocAcc, "movePrevious", var invoker =
aRule, aSequence[i]) new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]);
aQueue.push(invoker); aQueue.push(invoker);
} }
// No previous more matches for given rule, expect no virtual cursor changes. // No previous more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "movePrevious", aRule, null)); aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, null));
aQueue.push(new setVirtualCursorPosInvoker( aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule,
aDocAcc, "moveLast", aRule, aSequence[aSequence.length - 1])); aSequence[aSequence.length - 1]));
// No further more matches for given rule, expect no virtual cursor changes. // No further more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "moveNext", aRule, null)); aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, null));
aQueue.push(new setVirtualCursorPosInvoker( aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
aDocAcc, "moveFirst", aRule, aSequence[0]));
// No previous more matches for given rule, expect no virtual cursor changes. // No previous more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "movePrevious", aRule, null)); aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, null));
}
/**
* A checker for removing an accessible while the virtual cursor is on it.
*/
function removeVCPositionChecker(aDocAcc, aHiddenParentAcc)
{
this.__proto__ = new invokerChecker(EVENT_REORDER, aHiddenParentAcc);
this.check = function removeVCPositionChecker_check(aEvent) {
var errorResult = 0;
try {
aDocAcc.virtualCursor.moveNext(ObjectTraversalRule);
} catch (x) {
errorResult = x.result;
}
SimpleTest.is(
errorResult, NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
};
}
/**
* Put the virtual cursor's position on an object, and then remove it.
*
* @param aDocAcc [in] document that manages the virtual cursor
* @param aPosNode [in] DOM node to hide after virtual cursor's position is
* set to it.
*/
function removeVCPositionInvoker(aDocAcc, aPosNode)
{
this.accessible = getAccessible(aPosNode);
this.invoke = function removeVCPositionInvoker_invoke()
{
aDocAcc.virtualCursor.position = this.accessible;
aPosNode.parentNode.removeChild(aPosNode);
};
this.getID = function removeVCPositionInvoker_getID()
{
return "Bring virtual cursor to accessible, and remove its DOM node.";
};
this.eventSeq = [
new removeVCPositionChecker(aDocAcc, this.accessible.parent)
];
}
/**
* A checker for removing the pivot root and then calling moveFirst, and
* checking that an exception is thrown.
*/
function removeVCRootChecker(aPivot)
{
this.__proto__ = new invokerChecker(EVENT_REORDER, aPivot.root.parent);
this.check = function removeVCRootChecker_check(aEvent) {
var errorResult = 0;
try {
aPivot.moveLast(ObjectTraversalRule);
} catch (x) {
errorResult = x.result;
}
SimpleTest.is(
errorResult, NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
};
}
/**
* Create a pivot, remove its root, and perform an operation where the root is
* needed.
*
* @param aRootNode [in] DOM node of which accessible will be the root of the
* pivot. Should have more than one child.
*/
function removeVCRootInvoker(aRootNode)
{
this.pivot = gAccRetrieval.createAccessiblePivot(getAccessible(aRootNode));
this.invoke = function removeVCRootInvoker_invoke()
{
this.pivot.position = this.pivot.root.firstChild;
aRootNode.parentNode.removeChild(aRootNode);
};
this.getID = function removeVCRootInvoker_getID()
{
return "Remove root of pivot from tree.";
};
this.eventSeq = [
new removeVCRootChecker(this.pivot)
];
} }
/** /**

View file

@ -17,10 +17,11 @@
<iframe <iframe
src="data:text/html,<html><body>An <i>embedded</i> document.</body></html>"> src="data:text/html,<html><body>An <i>embedded</i> document.</body></html>">
</iframe> </iframe>
<p> <div id="hide-me">Hide me</div>
<a href="http://mozilla.org" title="Link 1 title">Link 1</a> <p id="links">
<a href="http://mozilla.org" title="Link 2 title">Link 2</a> <a href="http://mozilla.org" title="Link 1 title">Link 1</a>
<a href="http://mozilla.org" title="Link 3 title">Link 3</a> <a href="http://mozilla.org" title="Link 2 title">Link 2</a>
</p> <a href="http://mozilla.org" title="Link 3 title">Link 3</a>
</p>
</body> </body>
</html> </html>

View file

@ -60,15 +60,22 @@
'dolor', ' sit amet. Integer vitae urna leo, id ', 'dolor', ' sit amet. Integer vitae urna leo, id ',
'semper', ' nulla. ', 'Second Section Title', 'semper', ' nulla. ', 'Second Section Title',
'Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.', 'Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.',
'An ', 'embedded', ' document.', 'Link 1', 'Link 2', 'Link 3']); 'An ', 'embedded', ' document.', 'Hide me', 'Link 1', 'Link 2',
'Link 3']);
// Just a random smoke test to see if our setTextRange works. // Just a random smoke test to see if our setTextRange works.
gQueue.push( gQueue.push(
new setVirtualCursorRangeInvoker( new setVCRangeInvoker(
docAcc, docAcc,
getAccessible(doc.getElementById('paragraph-2'), nsIAccessibleText), getAccessible(doc.getElementById('paragraph-2'), nsIAccessibleText),
[2,6])); [2,6]));
gQueue.push(new removeVCPositionInvoker(
docAcc, doc.getElementById('hide-me')));
gQueue.push(new removeVCRootInvoker(
doc.getElementById('links')));
gQueue.invoke(); gQueue.invoke();
} }

View file

@ -186,8 +186,6 @@ ifdef MOZ_DEBUG
MAC_APP_NAME := $(MAC_APP_NAME)Debug MAC_APP_NAME := $(MAC_APP_NAME)Debug
endif endif
LOWER_MAC_APP_NAME = $(shell echo $(MAC_APP_NAME) | tr '[A-Z]' '[a-z]')
AB_CD = $(MOZ_UI_LOCALE) AB_CD = $(MOZ_UI_LOCALE)
AB := $(firstword $(subst -, ,$(AB_CD))) AB := $(firstword $(subst -, ,$(AB_CD)))
@ -201,6 +199,8 @@ else
APPFILES = MacOS APPFILES = MacOS
endif endif
MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/config/buildid)
libs-preqs = \ libs-preqs = \
$(call mkdir_deps,$(dist_dest)/Contents/MacOS) \ $(call mkdir_deps,$(dist_dest)/Contents/MacOS) \
$(call mkdir_deps,$(dist_dest)/Contents/Resources/$(AB).lproj) \ $(call mkdir_deps,$(dist_dest)/Contents/Resources/$(AB).lproj) \
@ -210,7 +210,7 @@ libs-preqs = \
libs repackage:: $(PROGRAM) $(libs-preqs) libs repackage:: $(PROGRAM) $(libs-preqs)
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%LOWER_MAC_APP_NAME%/$(LOWER_MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/" -e "s/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
sed -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings sed -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a $(DIST)/bin/ $(dist_dest)/Contents/$(APPFILES) rsync -a $(DIST)/bin/ $(dist_dest)/Contents/$(APPFILES)
ifdef LIBXUL_SDK ifdef LIBXUL_SDK

View file

@ -149,7 +149,7 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>firefox</string> <string>firefox</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>org.mozilla.%LOWER_MAC_APP_NAME%</string> <string>%MOZ_MACBUNDLE_ID%</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
@ -200,7 +200,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>%APP_VERSION%</string> <string>%MAC_BUNDLE_VERSION%</string>
<key>NSAppleScriptEnabled</key> <key>NSAppleScriptEnabled</key>
<true/> <true/>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

40
browser/app/macversion.py Normal file
View file

@ -0,0 +1,40 @@
#!/usr/bin/python
from optparse import OptionParser
import sys
import re
o = OptionParser()
o.add_option("--buildid", dest="buildid")
o.add_option("--version", dest="version")
(options, args) = o.parse_args()
if not options.buildid:
print >>sys.stderr, "--buildid is required"
sys.exit(1)
if not options.version:
print >>sys.stderr, "--version is required"
sys.exit(1)
# We want to build a version number that matches the format allowed for
# CFBundleVersion (nnnnn[.nn[.nn]]). We'll incorporate both the version
# number as well as the date, so that it changes at least daily (for nightly
# builds), but also so that newly-built older versions (e.g. beta build) aren't
# considered "newer" than previously-built newer versions (e.g. a trunk nightly)
buildid = open(options.buildid, 'r').read()
# extract only the major version (i.e. "14" from "14.0b1")
majorVersion = re.match(r'^(\d+)[^\d].*', options.version).group(1)
# last two digits of the year
twodigityear = buildid[2:4]
month = buildid[4:6]
if month[0] == '0':
month = month[1]
day = buildid[6:8]
if day[0] == '0':
day = day[1]
print '%s.%s.%s' % (majorVersion + twodigityear, month, day)

View file

@ -65,11 +65,6 @@
margin: 0 40px; margin: 0 40px;
} }
.text-link:-moz-focusring,
.bottom-link:-moz-focusring {
outline: 1px dotted;
}
#currentChannel { #currentChannel {
margin: 0; margin: 0;
padding: 0; padding: 0;

View file

@ -308,12 +308,30 @@
</menu> </menu>
#include browser-charsetmenu.inc #include browser-charsetmenu.inc
<menuseparator/> <menuseparator/>
#ifdef XP_MACOSX
<menuitem id="enterFullScreenItem"
accesskey="&enterFullScreenCmd.accesskey;"
label="&enterFullScreenCmd.label;"
key="key_fullScreen">
<observes element="View:FullScreen" attribute="oncommand"/>
<observes element="View:FullScreen" attribute="disabled"/>
</menuitem>
<menuitem id="exitFullScreenItem"
accesskey="&exitFullScreenCmd.accesskey;"
label="&exitFullScreenCmd.label;"
key="key_fullScreen"
hidden="true">
<observes element="View:FullScreen" attribute="oncommand"/>
<observes element="View:FullScreen" attribute="disabled"/>
</menuitem>
#else
<menuitem id="fullScreenItem" <menuitem id="fullScreenItem"
accesskey="&fullScreenCmd.accesskey;" accesskey="&fullScreenCmd.accesskey;"
label="&fullScreenCmd.label;" label="&fullScreenCmd.label;"
key="key_fullScreen" key="key_fullScreen"
type="checkbox" type="checkbox"
observes="View:FullScreen"/> observes="View:FullScreen"/>
#endif
<menuitem id="menu_showAllTabs" <menuitem id="menu_showAllTabs"
hidden="true" hidden="true"
accesskey="&showAllTabsCmd.accesskey;" accesskey="&showAllTabsCmd.accesskey;"

View file

@ -341,7 +341,8 @@
<key keycode="VK_F6" command="Browser:FocusNextFrame" modifiers="shift"/> <key keycode="VK_F6" command="Browser:FocusNextFrame" modifiers="shift"/>
<key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/> <key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/>
#else #else
<key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/> <key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,control"/>
<key id="key_fullScreen_old" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/>
<key keycode="VK_F11" command="View:FullScreen"/> <key keycode="VK_F11" command="View:FullScreen"/>
#endif #endif
<key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/> <key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/>

View file

@ -3958,6 +3958,12 @@ var FullScreen = {
// fullscreen menuitem, menubars, and the appmenu. // fullscreen menuitem, menubars, and the appmenu.
document.getElementById("View:FullScreen").setAttribute("checked", enterFS); document.getElementById("View:FullScreen").setAttribute("checked", enterFS);
#ifdef XP_MACOSX
// Make sure the menu items are adjusted.
document.getElementById("enterFullScreenItem").hidden = enterFS;
document.getElementById("exitFullScreenItem").hidden = !enterFS;
#endif
// On OS X Lion we don't want to hide toolbars when entering fullscreen, unless // On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
// we're entering DOM fullscreen, in which case we should hide the toolbars. // we're entering DOM fullscreen, in which case we should hide the toolbars.
// If we're leaving fullscreen, then we'll go through the exit code below to // If we're leaving fullscreen, then we'll go through the exit code below to

View file

@ -5,20 +5,25 @@ const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManage
const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory); const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2); const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
const kUsecPerMin = 60 * 1000000;
let tempScope = {}; let tempScope = {};
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader) Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tempScope); .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
let Sanitizer = tempScope.Sanitizer; let Sanitizer = tempScope.Sanitizer;
function test() { function test() {
waitForExplicitFinish();
setupDownloads();
setupFormHistory();
setupHistory(onHistoryReady);
}
function onHistoryReady() {
var hoursSinceMidnight = new Date().getHours(); var hoursSinceMidnight = new Date().getHours();
var minutesSinceMidnight = hoursSinceMidnight * 60 + new Date().getMinutes(); var minutesSinceMidnight = hoursSinceMidnight * 60 + new Date().getMinutes();
setupHistory();
setupFormHistory();
setupDownloads();
// Should test cookies here, but nsICookieManager/nsICookieService // Should test cookies here, but nsICookieManager/nsICookieService
// doesn't let us fake creation times. bug 463127 // doesn't let us fake creation times. bug 463127
@ -271,37 +276,46 @@ function test() {
ok(!downloadExists(5555550), "Year old download should now be deleted"); ok(!downloadExists(5555550), "Year old download should now be deleted");
finish();
} }
function setupHistory() { function setupHistory(aCallback) {
bhist.addPageWithDetails(makeURI("http://10minutes.com/"), "10 minutes ago", now_uSec - 10*60*1000000); let places = [];
bhist.addPageWithDetails(makeURI("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45*60*1000000);
bhist.addPageWithDetails(makeURI("http://1hour10minutes.com/"), "1 hour 10 minutes ago", now_uSec - 70*60*1000000); function addPlace(aURI, aTitle, aVisitDate) {
bhist.addPageWithDetails(makeURI("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90*60*1000000); places.push({
bhist.addPageWithDetails(makeURI("http://2hour10minutes.com/"), "2 hours 10 minutes ago", now_uSec - 130*60*1000000); uri: aURI,
bhist.addPageWithDetails(makeURI("http://4hour.com/"), "Less than 4 hours ago", now_uSec - 180*60*1000000); title: aTitle,
bhist.addPageWithDetails(makeURI("http://4hour10minutes.com/"), "4 hours 10 minutesago", now_uSec - 250*60*1000000); visits: [{
visitDate: aVisitDate,
transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
}]
});
}
addPlace(makeURI("http://10minutes.com/"), "10 minutes ago", now_uSec - 10 * kUsecPerMin);
addPlace(makeURI("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45 * kUsecPerMin);
addPlace(makeURI("http://1hour10minutes.com/"), "1 hour 10 minutes ago", now_uSec - 70 * kUsecPerMin);
addPlace(makeURI("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90 * kUsecPerMin);
addPlace(makeURI("http://2hour10minutes.com/"), "2 hours 10 minutes ago", now_uSec - 130 * kUsecPerMin);
addPlace(makeURI("http://4hour.com/"), "Less than 4 hours ago", now_uSec - 180 * kUsecPerMin);
addPlace(makeURI("http://4hour10minutes.com/"), "4 hours 10 minutesago", now_uSec - 250 * kUsecPerMin);
let today = new Date(); let today = new Date();
today.setHours(0); today.setHours(0);
today.setMinutes(0); today.setMinutes(0);
today.setSeconds(1); today.setSeconds(1);
bhist.addPageWithDetails(makeURI("http://today.com/"), "Today", today.valueOf() * 1000); addPlace(makeURI("http://today.com/"), "Today", today.getTime() * 1000);
let lastYear = new Date(); let lastYear = new Date();
lastYear.setFullYear(lastYear.getFullYear() - 1); lastYear.setFullYear(lastYear.getFullYear() - 1);
bhist.addPageWithDetails(makeURI("http://before-today.com/"), "Before Today", lastYear.valueOf() * 1000); addPlace(makeURI("http://before-today.com/"), "Before Today", lastYear.getTime() * 1000);
// Confirm everything worked PlacesUtils.asyncHistory.updatePlaces(places, {
ok(bhist.isVisited(makeURI("http://10minutes.com/")), "Pretend visit to 10minutes.com should exist"); handleError: function () ok(false, "Unexpected error in adding visit."),
ok(bhist.isVisited(makeURI("http://1hour.com")), "Pretend visit to 1hour.com should exist"); handleResult: function () { },
ok(bhist.isVisited(makeURI("http://1hour10minutes.com/")), "Pretend visit to 1hour10minutes.com should exist"); handleCompletion: function () aCallback()
ok(bhist.isVisited(makeURI("http://2hour.com")), "Pretend visit to 2hour.com should exist"); });
ok(bhist.isVisited(makeURI("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should exist");
ok(bhist.isVisited(makeURI("http://4hour.com")), "Pretend visit to 4hour.com should exist");
ok(bhist.isVisited(makeURI("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should exist");
ok(bhist.isVisited(makeURI("http://today.com")), "Pretend visit to today.com should exist");
ok(bhist.isVisited(makeURI("http://before-today.com")), "Pretend visit to before-today.com should exist");
} }
function setupFormHistory() { function setupFormHistory() {
@ -321,25 +335,25 @@ function setupFormHistory() {
// Artifically age the entries to the proper vintage. // Artifically age the entries to the proper vintage.
let db = formhist.DBConnection; let db = formhist.DBConnection;
let timestamp = now_uSec - 10*60*1000000; let timestamp = now_uSec - 10 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '10minutes'"); timestamp + " WHERE fieldname = '10minutes'");
timestamp = now_uSec - 45*60*1000000; timestamp = now_uSec - 45 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '1hour'"); timestamp + " WHERE fieldname = '1hour'");
timestamp = now_uSec - 70*60*1000000; timestamp = now_uSec - 70 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '1hour10minutes'"); timestamp + " WHERE fieldname = '1hour10minutes'");
timestamp = now_uSec - 90*60*1000000; timestamp = now_uSec - 90 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '2hour'"); timestamp + " WHERE fieldname = '2hour'");
timestamp = now_uSec - 130*60*1000000; timestamp = now_uSec - 130 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '2hour10minutes'"); timestamp + " WHERE fieldname = '2hour10minutes'");
timestamp = now_uSec - 180*60*1000000; timestamp = now_uSec - 180 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '4hour'"); timestamp + " WHERE fieldname = '4hour'");
timestamp = now_uSec - 250*60*1000000; timestamp = now_uSec - 250 * kUsecPerMin;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '4hour10minutes'"); timestamp + " WHERE fieldname = '4hour10minutes'");
@ -347,13 +361,13 @@ function setupFormHistory() {
today.setHours(0); today.setHours(0);
today.setMinutes(0); today.setMinutes(0);
today.setSeconds(1); today.setSeconds(1);
timestamp = today.valueOf() * 1000; timestamp = today.getTime() * 1000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = 'today'"); timestamp + " WHERE fieldname = 'today'");
let lastYear = new Date(); let lastYear = new Date();
lastYear.setFullYear(lastYear.getFullYear() - 1); lastYear.setFullYear(lastYear.getFullYear() - 1);
timestamp = lastYear.valueOf() * 1000; timestamp = lastYear.getTime() * 1000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = 'b4today'"); timestamp + " WHERE fieldname = 'b4today'");
@ -377,8 +391,8 @@ function setupDownloads() {
name: "fakefile-10-minutes", name: "fakefile-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-10-minutes", target: "fakefile-10-minutes",
startTime: now_uSec - 10*60*1000000, // 10 minutes ago, in uSec startTime: now_uSec - 10 * kUsecPerMin, // 10 minutes ago, in uSec
endTime: now_uSec - 11*60*1000000, // 1 minute later endTime: now_uSec - 11 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -404,8 +418,8 @@ function setupDownloads() {
name: "fakefile-1-hour", name: "fakefile-1-hour",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-1-hour", target: "fakefile-1-hour",
startTime: now_uSec - 45*60*1000000, // 45 minutes ago, in uSec startTime: now_uSec - 45 * kUsecPerMin, // 45 minutes ago, in uSec
endTime: now_uSec - 44*60*1000000, // 1 minute later endTime: now_uSec - 44 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -425,8 +439,8 @@ function setupDownloads() {
name: "fakefile-1-hour-10-minutes", name: "fakefile-1-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-1-hour-10-minutes", target: "fakefile-1-hour-10-minutes",
startTime: now_uSec - 70*60*1000000, // 70 minutes ago, in uSec startTime: now_uSec - 70 * kUsecPerMin, // 70 minutes ago, in uSec
endTime: now_uSec - 71*60*1000000, // 1 minute later endTime: now_uSec - 71 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -446,8 +460,8 @@ function setupDownloads() {
name: "fakefile-2-hour", name: "fakefile-2-hour",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-2-hour", target: "fakefile-2-hour",
startTime: now_uSec - 90*60*1000000, // 90 minutes ago, in uSec startTime: now_uSec - 90 * kUsecPerMin, // 90 minutes ago, in uSec
endTime: now_uSec - 89*60*1000000, // 1 minute later endTime: now_uSec - 89 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -467,8 +481,8 @@ function setupDownloads() {
name: "fakefile-2-hour-10-minutes", name: "fakefile-2-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-2-hour-10-minutes", target: "fakefile-2-hour-10-minutes",
startTime: now_uSec - 130*60*1000000, // 130 minutes ago, in uSec startTime: now_uSec - 130 * kUsecPerMin, // 130 minutes ago, in uSec
endTime: now_uSec - 131*60*1000000, // 1 minute later endTime: now_uSec - 131 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -488,8 +502,8 @@ function setupDownloads() {
name: "fakefile-4-hour", name: "fakefile-4-hour",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-4-hour", target: "fakefile-4-hour",
startTime: now_uSec - 180*60*1000000, // 180 minutes ago, in uSec startTime: now_uSec - 180 * kUsecPerMin, // 180 minutes ago, in uSec
endTime: now_uSec - 179*60*1000000, // 1 minute later endTime: now_uSec - 179 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -509,8 +523,8 @@ function setupDownloads() {
name: "fakefile-4-hour-10-minutes", name: "fakefile-4-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-4-hour-10-minutes", target: "fakefile-4-hour-10-minutes",
startTime: now_uSec - 250*60*1000000, // 250 minutes ago, in uSec startTime: now_uSec - 250 * kUsecPerMin, // 250 minutes ago, in uSec
endTime: now_uSec - 251*60*1000000, // 1 minute later endTime: now_uSec - 251 * kUsecPerMin, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -535,8 +549,8 @@ function setupDownloads() {
name: "fakefile-today", name: "fakefile-today",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-today", target: "fakefile-today",
startTime: today.valueOf() * 1000, // 12:00:30am this morning, in uSec startTime: today.getTime() * 1000, // 12:00:30am this morning, in uSec
endTime: (today.valueOf() + 1000) * 1000, // 1 second later endTime: (today.getTime() + 1000) * 1000, // 1 second later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -558,8 +572,8 @@ function setupDownloads() {
name: "fakefile-old", name: "fakefile-old",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-old", target: "fakefile-old",
startTime: lastYear.valueOf() * 1000, // 1 year ago, in uSec startTime: lastYear.getTime() * 1000, // 1 year ago, in uSec
endTime: (lastYear.valueOf() + 1000) * 1000, // 1 second later endTime: (lastYear.getTime() + 1000) * 1000, // 1 second later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };

View file

@ -60,6 +60,8 @@ const dm = Cc["@mozilla.org/download-manager;1"].
const formhist = Cc["@mozilla.org/satchel/form-history;1"]. const formhist = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2); getService(Ci.nsIFormHistory2);
const kUsecPerMin = 60 * 1000000;
// Add tests here. Each is a function that's called by doNextTest(). // Add tests here. Each is a function that's called by doNextTest().
var gAllTests = [ var gAllTests = [
@ -831,8 +833,8 @@ function addDownloadWithMinutesAgo(aMinutesAgo) {
name: name, name: name,
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169", source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: name, target: name,
startTime: now_uSec - (aMinutesAgo * 60 * 1000000), startTime: now_uSec - (aMinutesAgo * kUsecPerMin),
endTime: now_uSec - ((aMinutesAgo + 1) *60 * 1000000), endTime: now_uSec - ((aMinutesAgo + 1) * kUsecPerMin),
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED, state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0 currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
}; };
@ -872,7 +874,7 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) {
// Artifically age the entry to the proper vintage. // Artifically age the entry to the proper vintage.
let db = formhist.DBConnection; let db = formhist.DBConnection;
let timestamp = now_uSec - (aMinutesAgo * 60 * 1000000); let timestamp = now_uSec - (aMinutesAgo * kUsecPerMin);
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " + db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '" + name + "'"); timestamp + " WHERE fieldname = '" + name + "'");
@ -889,10 +891,12 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) {
*/ */
function addHistoryWithMinutesAgo(aMinutesAgo) { function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/"); let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
PlacesUtils.bhistory PlacesUtils.history.addVisit(pURI,
.addPageWithDetails(pURI, now_uSec - aMinutesAgo * kUsecPerMin,
aMinutesAgo + " minutes ago", null,
now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); Ci.nsINavHistoryService.TRANSITION_LINK,
false,
0);
is(PlacesUtils.bhistory.isVisited(pURI), true, is(PlacesUtils.bhistory.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec + "Sanity check: history visit " + pURI.spec +
" should exist after creating it"); " should exist after creating it");

View file

@ -501,10 +501,12 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) {
*/ */
function addHistoryWithMinutesAgo(aMinutesAgo) { function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/"); let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
PlacesUtils.bhistory PlacesUtils.history.addVisit(pURI,
.addPageWithDetails(pURI, now_uSec - (aMinutesAgo * 60 * 1000 * 1000),
aMinutesAgo + " minutes ago", null,
now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); Ci.nsINavHistoryService.TRANSITION_LINK,
false,
0);
is(PlacesUtils.bhistory.isVisited(pURI), true, is(PlacesUtils.bhistory.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec + "Sanity check: history visit " + pURI.spec +
" should exist after creating it"); " should exist after creating it");

View file

@ -17,7 +17,7 @@ let bhist = Cc["@mozilla.org/browser/global-history;2"]
function runTests() { function runTests() {
clearHistory(); clearHistory();
fillHistory(); yield fillHistory();
yield addNewTabPageTab(); yield addNewTabPageTab();
is(getCell(0).site.url, URL, "first site is our fake site"); is(getCell(0).site.url, URL, "first site is our fake site");
@ -29,9 +29,23 @@ function runTests() {
} }
function fillHistory() { function fillHistory() {
let uri = makeURI(URL); let visits = [];
for (let i = 59; i > 0; i--) for (let i = 59; i > 0; i--) {
bhist.addPageWithDetails(uri, "fake site", NOW - i * 60 * 1000000); visits.push({
visitDate: NOW - i * 60 * 1000000,
transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
});
}
let place = {
uri: makeURI(URL),
title: "fake site",
visits: visits
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () do_throw("Unexpected error in adding visit."),
handleResult: function () { },
handleCompletion: function () TestRunner.next()
});
} }
function clearHistory() { function clearHistory() {

View file

@ -50,13 +50,49 @@ function do_test()
const TITLE_2 = "Title 2"; const TITLE_2 = "Title 2";
do_test_pending(); do_test_pending();
waitForClearHistory(function() { waitForClearHistory(function () {
PlacesUtils.bhistory.addPageWithDetails(TEST_URI, TITLE_1, Date.now() * 1000); let place = {
uri: TEST_URI,
title: TITLE_1,
visits: [{
visitDate: Date.now() * 1000,
transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
}]
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () do_throw("Unexpected error in adding visit."),
handleResult: function () { },
handleCompletion: function () afterAddFirstVisit()
});
});
function afterAddFirstVisit()
{
do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1); do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
pb.privateBrowsingEnabled = true; pb.privateBrowsingEnabled = true;
PlacesUtils.bhistory.addPageWithDetails(TEST_URI, TITLE_2, Date.now() * 2000); let place = {
uri: TEST_URI,
title: TITLE_2,
visits: [{
visitDate: Date.now() * 2000,
transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
}]
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function (aResultCode) {
// We expect this error in Private Browsing mode.
do_check_eq(aResultCode, Cr.NS_ERROR_ILLEGAL_VALUE);
},
handleResult: function () do_throw("Unexpected success adding visit."),
handleCompletion: function () afterAddSecondVisit()
});
}
function afterAddSecondVisit()
{
do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1); do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
pb.privateBrowsingEnabled = false; pb.privateBrowsingEnabled = false;
@ -73,7 +109,7 @@ function do_test()
do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1); do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
waitForClearHistory(do_test_finished); waitForClearHistory(do_test_finished);
}); }
} }
// Support running tests on both the service itself and its wrapper // Support running tests on both the service itself and its wrapper

View file

@ -43,7 +43,9 @@
*/ */
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//// Constants //// Globals
Cu.import("resource://gre/modules/PlacesUtils.jsm");
let pb = Cc[PRIVATEBROWSING_CONTRACT_ID]. let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
getService(Ci.nsIPrivateBrowsingService); getService(Ci.nsIPrivateBrowsingService);
@ -88,9 +90,9 @@ function uri(aURIString)
function add_visit(aURI) function add_visit(aURI)
{ {
check_visited(aURI, false); check_visited(aURI, false);
let bh = Cc["@mozilla.org/browser/global-history;2"]. PlacesUtils.history.addVisit(aURI, Date.now() * 1000, null,
getService(Ci.nsIBrowserHistory); Ci.nsINavHistoryService.TRANSITION_LINK, false,
bh.addPageWithDetails(aURI, aURI.spec, Date.now() * 1000); 0);
check_visited(aURI, true); check_visited(aURI, true);
} }
@ -104,10 +106,8 @@ function add_visit(aURI)
*/ */
function check_visited(aURI, aIsVisited) function check_visited(aURI, aIsVisited)
{ {
let gh = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIGlobalHistory2);
let checker = aIsVisited ? do_check_true : do_check_false; let checker = aIsVisited ? do_check_true : do_check_false;
checker(gh.isVisited(aURI)); checker(PlacesUtils.ghistory2.isVisited(aURI));
} }
/** /**
@ -362,9 +362,7 @@ function test_history_not_cleared_with_uri_contains_domain()
check_visited(TEST_URI, true); check_visited(TEST_URI, true);
// Clear history since we left something there from this test. // Clear history since we left something there from this test.
let bh = Cc["@mozilla.org/browser/global-history;2"]. PlacesUtils.bhistory.removeAllPages();
getService(Ci.nsIBrowserHistory);
bh.removeAllPages();
} }
// Cookie Service // Cookie Service

View file

@ -0,0 +1,18 @@
# Use at least -O1 for optimization to avoid stack space
# exhaustions caused by Clang function inlining.
ac_add_options --enable-debug
ac_add_options --enable-optimize="-O1"
# ASan specific options on Linux
ac_add_options --enable-valgrind
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j4"
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View file

@ -0,0 +1,20 @@
# We still need to build with debug symbols
ac_add_options --disable-debug
ac_add_options --enable-optimize="-O2 -g"
# ASan specific options on Linux
ac_add_options --enable-valgrind
# Other options
ac_add_options --enable-codesighs
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j4"
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View file

@ -0,0 +1,18 @@
# Use at least -O1 for optimization to avoid stack space
# exhaustions caused by Clang function inlining.
ac_add_options --enable-debug
ac_add_options --enable-optimize="-O1"
# ASan specific options on Linux
ac_add_options --enable-valgrind
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j4"
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View file

@ -0,0 +1,20 @@
# We still need to build with debug symbols
ac_add_options --disable-debug
ac_add_options --enable-optimize="-O2 -g"
# ASan specific options on Linux
ac_add_options --enable-valgrind
# Other options
ac_add_options --enable-codesighs
. $topsrcdir/build/unix/mozconfig.asan
# Avoid dependency on libstdc++ 4.5
ac_add_options --enable-stdcxx-compat
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j4"
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

View file

@ -77,6 +77,12 @@ can reach it easily. -->
<!ENTITY pageInfoCmd.label "Page Info"> <!ENTITY pageInfoCmd.label "Page Info">
<!ENTITY pageInfoCmd.accesskey "I"> <!ENTITY pageInfoCmd.accesskey "I">
<!ENTITY pageInfoCmd.commandkey "i"> <!ENTITY pageInfoCmd.commandkey "i">
<!-- LOCALIZATION NOTE (enterFullScreenCmd.label, exitFullScreenCmd.label):
These should match what Safari and other Apple applications use on OS X Lion. -->
<!ENTITY enterFullScreenCmd.label "Enter Full Screen">
<!ENTITY enterFullScreenCmd.accesskey "F">
<!ENTITY exitFullScreenCmd.label "Exit Full Screen">
<!ENTITY exitFullScreenCmd.accesskey "F">
<!ENTITY fullScreenCmd.label "Full Screen"> <!ENTITY fullScreenCmd.label "Full Screen">
<!ENTITY fullScreenCmd.accesskey "F"> <!ENTITY fullScreenCmd.accesskey "F">
<!ENTITY fullScreenCmd.macCommandKey "f"> <!ENTITY fullScreenCmd.macCommandKey "f">

View file

@ -588,10 +588,8 @@ MacNativeApp.prototype = {
<string>MOZB</string>\n\ <string>MOZB</string>\n\
<key>CFBundleVersion</key>\n\ <key>CFBundleVersion</key>\n\
<string>0</string>\n\ <string>0</string>\n\
#ifdef DEBUG
<key>FirefoxBinary</key>\n\ <key>FirefoxBinary</key>\n\
<string>org.mozilla.NightlyDebug</string>\n\ #expand <string>__MOZ_MACBUNDLE_ID__</string>\n\
#endif
</dict>\n\ </dict>\n\
</plist>'; </plist>';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 672 B

View file

@ -40,6 +40,7 @@ package com.mozilla.SUTAgentAndroid;
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.InetAddress; import java.net.InetAddress;
import org.apache.http.conn.util.InetAddressUtils;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.net.SocketException; import java.net.SocketException;
import java.util.Enumeration; import java.util.Enumeration;
@ -665,7 +666,7 @@ public class SUTAgentAndroid extends Activity
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();)
{ {
InetAddress inetAddress = enumIpAddr.nextElement(); InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) if (!inetAddress.isLoopbackAddress() && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress()))
{ {
return inetAddress.getHostAddress().toString(); return inetAddress.getHostAddress().toString();
} }

View file

@ -277,5 +277,13 @@ build_one_stage({"PATH" : stage1_tool_inst_dir + "/bin:/bin:/usr/bin",
"RANLIB" : "true" }, "RANLIB" : "true" },
stage2_dir, False) stage2_dir, False)
stage2_tool_inst_dir = stage2_dir + '/inst'
stage3_dir = build_dir + '/stage3'
build_one_stage({"PATH" : stage2_tool_inst_dir + "/bin:/bin:/usr/bin",
"CC" : "gcc -fgnu89-inline",
"CXX" : "g++",
"RANLIB" : "true" },
stage3_dir, False)
build_tar_package(aux_inst_dir + "/bin/tar", build_tar_package(aux_inst_dir + "/bin/tar",
"toolchain.tar", stage2_dir, "inst") "toolchain.tar", stage3_dir, "inst")

20
build/unix/mozconfig.asan Normal file
View file

@ -0,0 +1,20 @@
# Use Clang r155417
export CC="/tools/clang-3.0/bin/clang -fgnu89-inline"
export CXX="/tools/clang-3.0/bin/clang++"
# Mandatory flags for ASan
export ASANFLAGS="-faddress-sanitizer -Dxmalloc=myxmalloc -fPIC"
export CFLAGS="$ASANFLAGS"
export CXXFLAGS="$ASANFLAGS"
export LDFLAGS="-faddress-sanitizer"
# Enable ASan specific code and build workarounds
ac_add_options --enable-address-sanitizer
# Mandatory options required for ASan builds (both on Linux and Mac)
export MOZ_DEBUG_SYMBOLS=1
ac_add_options --enable-debug-symbols
ac_add_options --disable-install-strip
ac_add_options --disable-jemalloc
ac_add_options --disable-crashreporter
ac_add_options --disable-elf-hack

View file

@ -1,12 +1,13 @@
export INCLUDE=/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/v7.0/include:/c/tools/sdks/v7.0/include/atl:/c/tools/sdks/dx10/include export INCLUDE=/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/v7.0/include:/c/tools/sdks/v7.0/include/atl:/c/tools/sdks/dx10/include
export LIBPATH=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib export LIBPATH=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib
export LIB=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib:/c/tools/sdks/v7.0/lib:/c/tools/sdks/dx10/lib export LIB=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib:/c/tools/sdks/v7.0/lib:/c/tools/sdks/dx10/lib
export PATH="/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:${PATH}"
export WIN32_REDIST_DIR=/c/tools/msvs10/VC/redist/x86/Microsoft.VC100.CRT export WIN32_REDIST_DIR=/c/tools/msvs10/VC/redist/x86/Microsoft.VC100.CRT
export MOZ_TOOLS=C:/mozilla-build/moztools
export PATH="/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:/c/mozilla-build/moztools:/c/Tools/sdks/v7.0/bin:${PATH}"
mk_add_options "export LIB=$LIB" mk_add_options "export LIB=$LIB"
mk_add_options "export LIBPATH=$LIBPATH" mk_add_options "export LIBPATH=$LIBPATH"
mk_add_options "export PATH=$PATH" mk_add_options "export PATH=$PATH"
mk_add_options "export INCLUDE=$INCLUDE" mk_add_options "export INCLUDE=$INCLUDE"
mk_add_options "export WIN32_REDIST_DIR=$WIN32_REDIST_DIR" mk_add_options "export WIN32_REDIST_DIR=$WIN32_REDIST_DIR"
mk_add_options "export MOZ_TOOLS=$MOZ_TOOLS"

View file

@ -61,6 +61,7 @@ MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
MOZ_APP_VERSION = @MOZ_APP_VERSION@ MOZ_APP_VERSION = @MOZ_APP_VERSION@
MOZ_APP_MAXVERSION = @MOZ_APP_MAXVERSION@ MOZ_APP_MAXVERSION = @MOZ_APP_MAXVERSION@
MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@ MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
MOZ_MACBUNDLE_ID = @MOZ_MACBUNDLE_ID@
MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@ MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@
MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@ MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
@ -164,6 +165,7 @@ MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
MOZ_OGG = @MOZ_OGG@ MOZ_OGG = @MOZ_OGG@
MOZ_RAW = @MOZ_RAW@ MOZ_RAW = @MOZ_RAW@
MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@ MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@
MOZ_SPEEX_RESAMPLER = @MOZ_SPEEX_RESAMPLER@
MOZ_CUBEB = @MOZ_CUBEB@ MOZ_CUBEB = @MOZ_CUBEB@
MOZ_WAVE = @MOZ_WAVE@ MOZ_WAVE = @MOZ_WAVE@
MOZ_MEDIA = @MOZ_MEDIA@ MOZ_MEDIA = @MOZ_MEDIA@

View file

@ -22,8 +22,8 @@ ifndef INCLUDED_VERSION_MK
include $(topsrcdir)/config/version.mk include $(topsrcdir)/config/version.mk
endif endif
USE_AUTOTARGETS_MK = 1
include $(topsrcdir)/config/makefiles/makeutils.mk include $(topsrcdir)/config/makefiles/makeutils.mk
include $(topsrcdir)/config/makefiles/autotargets.mk
ifdef SDK_XPIDLSRCS ifdef SDK_XPIDLSRCS
XPIDLSRCS += $(SDK_XPIDLSRCS) XPIDLSRCS += $(SDK_XPIDLSRCS)
@ -361,25 +361,25 @@ ifndef TARGETS
TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY) TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY)
endif endif
COBJS = $(CSRCS:.c=.$(OBJ_SUFFIX))
SOBJS = $(SSRCS:.S=.$(OBJ_SUFFIX))
CCOBJS = $(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(CPPSRCS)))
CPPOBJS = $(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(CPPSRCS)))
CMOBJS = $(CMSRCS:.m=.$(OBJ_SUFFIX))
CMMOBJS = $(CMMSRCS:.mm=.$(OBJ_SUFFIX))
ASOBJS = $(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
ifndef OBJS ifndef OBJS
_OBJS = \ _OBJS = $(COBJS) $(SOBJS) $(CCOBJS) $(CPPOBJS) $(CMOBJS) $(CMMOBJS) $(ASOBJS)
$(JRI_STUB_CFILES) \ OBJS = $(strip $(_OBJS))
$(addsuffix .$(OBJ_SUFFIX), $(JMC_GEN)) \
$(CSRCS:.c=.$(OBJ_SUFFIX)) \
$(SSRCS:.S=.$(OBJ_SUFFIX)) \
$(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:.cpp=.$(OBJ_SUFFIX))) \
$(CMSRCS:.m=.$(OBJ_SUFFIX)) \
$(CMMSRCS:.mm=.$(OBJ_SUFFIX)) \
$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
OBJS = $(strip $(_OBJS))
endif endif
HOST_COBJS = $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX)))
HOST_CCOBJS = $(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(HOST_CPPSRCS))))
HOST_CPPOBJS = $(addprefix host_,$(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(HOST_CPPSRCS))))
HOST_CMOBJS = $(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX)))
HOST_CMMOBJS = $(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
ifndef HOST_OBJS ifndef HOST_OBJS
_HOST_OBJS = \ _HOST_OBJS = $(HOST_COBJS) $(HOST_CCOBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
$(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX))) \
$(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(HOST_CPPSRCS:.cpp=.$(OBJ_SUFFIX)))) \
$(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX))) \
$(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
HOST_OBJS = $(strip $(_HOST_OBJS)) HOST_OBJS = $(strip $(_HOST_OBJS))
endif endif
@ -1090,32 +1090,27 @@ endif # MOZ_AUTO_DEPS
$(OBJS) $(HOST_OBJS): $(GLOBAL_DEPS) $(OBJS) $(HOST_OBJS): $(GLOBAL_DEPS)
# Rules for building native targets must come first because of the host_ prefix # Rules for building native targets must come first because of the host_ prefix
host_%.$(OBJ_SUFFIX): %.c $(HOST_COBJS): host_%.$(OBJ_SUFFIX): %.c
$(REPORT_BUILD) $(REPORT_BUILD)
$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
host_%.$(OBJ_SUFFIX): %.cpp $(HOST_CPPOBJS): host_%.$(OBJ_SUFFIX): %.cpp
$(REPORT_BUILD) $(REPORT_BUILD)
$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
host_%.$(OBJ_SUFFIX): %.cc $(HOST_CCOBJS): host_%.$(OBJ_SUFFIX): %.cc
$(REPORT_BUILD) $(REPORT_BUILD)
$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
host_%.$(OBJ_SUFFIX): %.m $(HOST_CMOBJS): host_%.$(OBJ_SUFFIX): %.m
$(REPORT_BUILD) $(REPORT_BUILD)
$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
host_%.$(OBJ_SUFFIX): %.mm $(HOST_CMMOBJS): host_%.$(OBJ_SUFFIX): %.mm
$(REPORT_BUILD) $(REPORT_BUILD)
$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
%:: %.c $(GLOBAL_DEPS) $(COBJS): %.$(OBJ_SUFFIX): %.c
$(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CC)
$(ELOG) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTOPTION)$@ $(_VPATH_SRCS)
%.$(OBJ_SUFFIX): %.c
$(REPORT_BUILD) $(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CC) @$(MAKE_DEPS_AUTO_CC)
$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS) $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS)
@ -1135,26 +1130,22 @@ qrc_%.cpp: %.qrc
ifdef ASFILES ifdef ASFILES
# The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
# a '-c' flag. # a '-c' flag.
%.$(OBJ_SUFFIX): %.$(ASM_SUFFIX) $(ASOBJS): %.$(OBJ_SUFFIX): %.$(ASM_SUFFIX)
$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS) $(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
endif endif
%.$(OBJ_SUFFIX): %.S $(SOBJS): %.$(OBJ_SUFFIX): %.S
$(AS) -o $@ $(ASFLAGS) -c $< $(AS) -o $@ $(ASFLAGS) -c $<
%:: %.cpp $(GLOBAL_DEPS)
@$(MAKE_DEPS_AUTO_CXX)
$(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS)
# #
# Please keep the next two rules in sync. # Please keep the next two rules in sync.
# #
%.$(OBJ_SUFFIX): %.cc $(CCOBJS): %.$(OBJ_SUFFIX): %.cc
$(REPORT_BUILD) $(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CXX) @$(MAKE_DEPS_AUTO_CXX)
$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
%.$(OBJ_SUFFIX): %.cpp $(CPPOBJS): %.$(OBJ_SUFFIX): %.cpp
$(REPORT_BUILD) $(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CXX) @$(MAKE_DEPS_AUTO_CXX)
ifdef STRICT_CPLUSPLUS_SUFFIX ifdef STRICT_CPLUSPLUS_SUFFIX
@ -1165,12 +1156,12 @@ else
$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
endif #STRICT_CPLUSPLUS_SUFFIX endif #STRICT_CPLUSPLUS_SUFFIX
$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm $(CMMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm
$(REPORT_BUILD) $(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CXX) @$(MAKE_DEPS_AUTO_CXX)
$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS) $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS)
$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m $(CMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m
$(REPORT_BUILD) $(REPORT_BUILD)
@$(MAKE_DEPS_AUTO_CC) @$(MAKE_DEPS_AUTO_CC)
$(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS) $(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS)
@ -1605,8 +1596,7 @@ chrome::
$(LOOP_OVER_DIRS) $(LOOP_OVER_DIRS)
$(LOOP_OVER_TOOL_DIRS) $(LOOP_OVER_TOOL_DIRS)
$(FINAL_TARGET)/chrome: $(FINAL_TARGET)/chrome: $(call mkdir_deps,$(FINAL_TARGET)/chrome)
$(NSINSTALL) -D $@
ifneq (,$(wildcard $(JAR_MANIFEST))) ifneq (,$(wildcard $(JAR_MANIFEST)))
ifndef NO_DIST_INSTALL ifndef NO_DIST_INSTALL

View file

@ -1047,6 +1047,7 @@ vpx/vpx_codec.h
vpx/vpx_decoder.h vpx/vpx_decoder.h
vpx/vp8dx.h vpx/vp8dx.h
sydneyaudio/sydney_audio.h sydneyaudio/sydney_audio.h
speex/speex_resampler.h
vorbis/codec.h vorbis/codec.h
theora/theoradec.h theora/theoradec.h
tremor/ivorbiscodec.h tremor/ivorbiscodec.h

View file

@ -4548,6 +4548,7 @@ MOZ_AUTH_EXTENSION=1
MOZ_OGG=1 MOZ_OGG=1
MOZ_RAW= MOZ_RAW=
MOZ_SYDNEYAUDIO= MOZ_SYDNEYAUDIO=
MOZ_SPEEX_RESAMPLER=1
MOZ_CUBEB= MOZ_CUBEB=
MOZ_VORBIS= MOZ_VORBIS=
MOZ_TREMOR= MOZ_TREMOR=
@ -5795,6 +5796,10 @@ if test -n "$MOZ_SYDNEYAUDIO"; then
AC_DEFINE(MOZ_SYDNEYAUDIO) AC_DEFINE(MOZ_SYDNEYAUDIO)
fi fi
if test -n "$MOZ_SPEEX_RESAMPLER"; then
AC_DEFINE(MOZ_SPEEX_RESAMPLER)
fi
if test -n "$MOZ_CUBEB"; then if test -n "$MOZ_CUBEB"; then
case "$target" in case "$target" in
*-mingw*) *-mingw*)
@ -8508,6 +8513,16 @@ else
fi fi
AC_SUBST(MOZ_MACBUNDLE_NAME) AC_SUBST(MOZ_MACBUNDLE_NAME)
dnl Mac bundle identifier (based on MOZ_APP_DISPLAYNAME)
MOZ_MACBUNDLE_ID=`echo $MOZ_APP_DISPLAYNAME | tr '[A-Z]' '[a-z]'`
MOZ_MACBUNDLE_ID=${MOZ_DISTRIBUTION_ID}.${MOZ_MACBUNDLE_ID}
if test "$MOZ_DEBUG"; then
MOZ_MACBUNDLE_ID=${MOZ_MACBUNDLE_ID}debug
fi
AC_DEFINE_UNQUOTED(MOZ_MACBUNDLE_ID,$MOZ_MACBUNDLE_ID)
AC_SUBST(MOZ_MACBUNDLE_ID)
# The following variables are available to branding and application # The following variables are available to branding and application
# configuration ($BRANDING/configure.sh and $APPLICATION/confvars.sh): # configuration ($BRANDING/configure.sh and $APPLICATION/confvars.sh):
# - MOZ_APP_VENDOR: Used for application.ini's "Vendor" field, which also # - MOZ_APP_VENDOR: Used for application.ini's "Vendor" field, which also
@ -8715,6 +8730,7 @@ AC_SUBST(MOZ_APP_EXTRA_LIBS)
AC_SUBST(MOZ_MEDIA) AC_SUBST(MOZ_MEDIA)
AC_SUBST(MOZ_SYDNEYAUDIO) AC_SUBST(MOZ_SYDNEYAUDIO)
AC_SUBST(MOZ_SPEEX_RESAMPLER)
AC_SUBST(MOZ_CUBEB) AC_SUBST(MOZ_CUBEB)
AC_SUBST(MOZ_WAVE) AC_SUBST(MOZ_WAVE)
AC_SUBST(MOZ_VORBIS) AC_SUBST(MOZ_VORBIS)

View file

@ -70,7 +70,7 @@ nsDOMMultipartFile::GetSize(PRUint64* aLength)
length += l; length += l;
} }
NS_ENSURE_TRUE(length.valid(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(length.isValid(), NS_ERROR_FAILURE);
mLength = length.value(); mLength = length.value();
} }

View file

@ -39,9 +39,8 @@
#define nsDOMBlobBuilder_h #define nsDOMBlobBuilder_h
#include "nsDOMFile.h" #include "nsDOMFile.h"
#include "CheckedInt.h"
#include "mozilla/StandardInteger.h" #include "mozilla/CheckedInt.h"
using namespace mozilla; using namespace mozilla;
@ -128,10 +127,10 @@ protected:
// Start at 1 or we'll loop forever. // Start at 1 or we'll loop forever.
CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1); CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1);
while (bufferLen.valid() && bufferLen.value() < mDataLen + aSize) while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize)
bufferLen *= 2; bufferLen *= 2;
if (!bufferLen.valid()) if (!bufferLen.isValid())
return false; return false;
// PR_ memory functions are still fallible // PR_ memory functions are still fallible

View file

@ -61,8 +61,8 @@
#include "nsIUUIDGenerator.h" #include "nsIUUIDGenerator.h"
#include "nsBlobProtocolHandler.h" #include "nsBlobProtocolHandler.h"
#include "nsStringStream.h" #include "nsStringStream.h"
#include "CheckedInt.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "plbase64.h" #include "plbase64.h"
@ -227,7 +227,7 @@ ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
newEndOffset = aSize; newEndOffset = aSize;
} }
if (!newStartOffset.valid() || !newEndOffset.valid() || if (!newStartOffset.isValid() || !newEndOffset.isValid() ||
newStartOffset.value() >= newEndOffset.value()) { newStartOffset.value() >= newEndOffset.value()) {
aStart = aEnd = 0; aStart = aEnd = 0;
} }

View file

@ -2133,11 +2133,8 @@ nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
nsIScrollableFrame* sf = GetScrollFrame(); nsIScrollableFrame* sf = GetScrollFrame();
if (sf) { if (sf) {
nsPoint pt = sf->GetScrollPosition(); nsPoint pt = sf->GetScrollPosition();
pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop); sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); aScrollTop));
// Don't allow pt.y + halfPixel since that would round up to the next CSS pixel.
nsRect range(pt.x, pt.y - halfPixel, 0, halfPixel*2 - 1);
sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
} }
return NS_OK; return NS_OK;
} }
@ -2166,11 +2163,8 @@ nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
nsIScrollableFrame* sf = GetScrollFrame(); nsIScrollableFrame* sf = GetScrollFrame();
if (sf) { if (sf) {
nsPoint pt = sf->GetScrollPosition(); nsPoint pt = sf->GetScrollPosition();
pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft); sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft,
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); nsPresContext::AppUnitsToIntCSSPixels(pt.y)));
// Don't allow pt.x + halfPixel since that would round up to the next CSS pixel.
nsRect range(pt.x - halfPixel, pt.y, halfPixel*2 - 1, 0);
sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
} }
return NS_OK; return NS_OK;
} }

View file

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=80: */
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
* *
@ -109,6 +110,7 @@
#include "nsIDOMFormData.h" #include "nsIDOMFormData.h"
#include "nsWrapperCacheInlines.h" #include "nsWrapperCacheInlines.h"
#include "nsStreamListenerWrapper.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -3046,9 +3048,6 @@ nsXMLHttpRequest::Send(JSContext *aCx, nsIVariant* aVariant, const Nullable<Requ
if (mState & XML_HTTP_REQUEST_MULTIPART) { if (mState & XML_HTTP_REQUEST_MULTIPART) {
Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 1); Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 1);
listener = new nsMultipartProxyListener(listener); listener = new nsMultipartProxyListener(listener);
if (!listener) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else { } else {
Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 0); Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 0);
} }
@ -3062,9 +3061,18 @@ nsXMLHttpRequest::Send(JSContext *aCx, nsIVariant* aVariant, const Nullable<Requ
// a same-origin request right now, since it could be redirected. // a same-origin request right now, since it could be redirected.
listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel, listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel,
withCredentials, true, &rv); withCredentials, true, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
else {
// Because of bug 682305, we can't let listener be the XHR object itself
// because JS wouldn't be able to use it. So if we haven't otherwise
// created a listener around 'this', do so now.
listener = new nsStreamListenerWrapper(listener);
}
NS_ASSERTION(listener != this,
"Using an object as a listener that can't be exposed to JS");
// Bypass the network cache in cases where it makes no sense: // Bypass the network cache in cases where it makes no sense:
// 1) Multipart responses are very large and would likely be doomed by the // 1) Multipart responses are very large and would likely be doomed by the

View file

@ -75,6 +75,7 @@ _CHROME_FILES = \
test_bug650784.html \ test_bug650784.html \
test_bug752226-3.xul \ test_bug752226-3.xul \
test_bug752226-4.xul \ test_bug752226-4.xul \
test_bug682305.html \
$(NULL) $(NULL)
libs:: $(_TEST_FILES) libs:: $(_TEST_FILES)

View file

@ -0,0 +1,159 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=682305
-->
<head>
<title>XMLHttpRequest send and channel implemented in JS</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=682305">Mozilla Bug 682305</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
/*
* Register a custom nsIProtocolHandler service
* in order to be able to implement *and use* an
* nsIChannel component written in Javascript.
*/
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var SimpleURI = Cc["@mozilla.org/network/simple-uri;1"];
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var PROTOCOL_SCHEME = "jsproto";
function CustomChannel(uri) {
this.URI = this.originalURI = uri;
}
CustomChannel.prototype = {
URI: null,
originalURI: null,
contentCharset: "utf-8",
contentLength: 0,
contentType: "text/plain",
owner: Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
securityInfo: null,
notificationCallbacks: null,
loadFlags: 0,
loadGroup: null,
name: null,
status: Cr.NS_OK,
asyncOpen: function(listener, context) {
let stream = this.open();
try {
listener.onStartRequest(this, context);
} catch(e) {}
try {
listener.onDataAvailable(this, context, stream, 0, stream.available());
} catch(e) {}
try {
listener.onStopRequest(this, context, Cr.NS_OK);
} catch(e) {}
},
open: function() {
let data = "bar";
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(data, data.length);
return stream;
},
isPending: function() {
return false;
},
cancel: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
suspend: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
resume: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
};
function CustomProtocol() {}
CustomProtocol.prototype = {
get scheme() {
return PROTOCOL_SCHEME;
},
get protocolFlags() {
return (Ci.nsIProtocolHandler.URI_NORELATIVE |
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD);
},
get defaultPort() {
return -1;
},
allowPort: function allowPort() {
return false;
},
newURI: function newURI(spec, charset, baseURI) {
var uri = SimpleURI.createInstance(Ci.nsIURI)
uri.spec = spec;
return uri.QueryInterface(Ci.nsIURI);
},
newChannel: function newChannel(URI) {
return new CustomChannel(URI);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsISupportsWeakReference,
Ci.nsIProtocolHandler])
};
var gFactory = {
register: function() {
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
var classID = Components.ID("{ed064287-1e76-49ba-a28d-dc74394a8334}");
var description = PROTOCOL_SCHEME + ": protocol";
var contractID = "@mozilla.org/network/protocol;1?name=" + PROTOCOL_SCHEME;
var factory = XPCOMUtils._getFactory(CustomProtocol);
registrar.registerFactory(classID, description, contractID, factory);
this.unregister = function() {
registrar.unregisterFactory(classID, factory);
delete this.unregister;
};
}
};
// Register the custom procotol handler
gFactory.register();
// Then, checks if XHR works with it
var xhr = new XMLHttpRequest();
xhr.open("GET", PROTOCOL_SCHEME + ":foo", true);
xhr.onload = function () {
is(xhr.responseText, "bar", "protocol doesn't work");
gFactory.unregister();
SimpleTest.finish();
}
try {
xhr.send(null);
} catch(e) {
ok(false, e);
}
</script>
</pre>
</body>
</html>

View file

@ -40,7 +40,7 @@
#include "prtypes.h" #include "prtypes.h"
#include "CheckedInt.h" #include "mozilla/CheckedInt.h"
class nsHTMLCanvasElement; class nsHTMLCanvasElement;
class nsIPrincipal; class nsIPrincipal;
@ -63,9 +63,9 @@ inline bool CheckSaneSubrectSize(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h,
CheckedInt32 checked_ymost = CheckedInt32(y) + h; CheckedInt32 checked_ymost = CheckedInt32(y) + h;
return w >= 0 && h >= 0 && x >= 0 && y >= 0 && return w >= 0 && h >= 0 && x >= 0 && y >= 0 &&
checked_xmost.valid() && checked_xmost.isValid() &&
checked_xmost.value() <= realWidth && checked_xmost.value() <= realWidth &&
checked_ymost.valid() && checked_ymost.isValid() &&
checked_ymost.value() <= realHeight; checked_ymost.value() <= realHeight;
} }

View file

@ -40,7 +40,7 @@
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsIDOMCanvasRenderingContext2D.h" #include "nsIDOMCanvasRenderingContext2D.h"
#include "CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "nsMathUtils.h" #include "nsMathUtils.h"
#include "CustomQS_Canvas.h" #include "CustomQS_Canvas.h"
@ -169,7 +169,7 @@ CreateImageData(JSContext* cx, JSObject* obj, uint32_t w, uint32_t h, jsval* vp)
h = 1; h = 1;
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(w) * h * 4; CheckedInt<uint32_t> len = CheckedInt<uint32_t>(w) * h * 4;
if (!len.valid()) { if (!len.isValid()) {
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR); return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
} }

View file

@ -425,7 +425,7 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
// If incrementing the generation would cause overflow, // If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use // don't allow it. Allowing this would allow us to use
// resource handles created from older context generations. // resource handles created from older context generations.
if (!(mGeneration+1).valid()) if (!(mGeneration + 1).isValid())
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
gl::ContextFormat format(gl::ContextFormat::BasicRGBA32); gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);

View file

@ -64,9 +64,9 @@
#include "GLContextProvider.h" #include "GLContextProvider.h"
#include "Layers.h" #include "Layers.h"
#include "CheckedInt.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ImageData.h" #include "mozilla/dom/ImageData.h"
#ifdef XP_MACOSX #ifdef XP_MACOSX
@ -481,7 +481,7 @@ public:
private: private:
WebGLMonotonicHandle NextMonotonicHandle() { WebGLMonotonicHandle NextMonotonicHandle() {
++mCurrentMonotonicHandle; ++mCurrentMonotonicHandle;
if (!mCurrentMonotonicHandle.valid()) if (!mCurrentMonotonicHandle.isValid())
NS_RUNTIMEABORT("ran out of monotonic ids!"); NS_RUNTIMEABORT("ran out of monotonic ids!");
return mCurrentMonotonicHandle.value(); return mCurrentMonotonicHandle.value();
} }
@ -1748,7 +1748,7 @@ public:
bool HasImageInfoAt(size_t level, size_t face) const { bool HasImageInfoAt(size_t level, size_t face) const {
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face; CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
return checked_index.valid() && return checked_index.isValid() &&
checked_index.value() < mImageInfos.Length() && checked_index.value() < mImageInfos.Length() &&
ImageInfoAt(level, face).mIsDefined; ImageInfoAt(level, face).mIsDefined;
} }
@ -2328,7 +2328,7 @@ public:
bool NextGeneration() bool NextGeneration()
{ {
if (!(mGeneration+1).valid()) if (!(mGeneration + 1).isValid())
return false; // must exit without changing mGeneration return false; // must exit without changing mGeneration
++mGeneration; ++mGeneration;
return true; return true;

View file

@ -687,7 +687,7 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->mLength; CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->mLength;
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length"); return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@ -726,7 +726,7 @@ WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
return ErrorInvalidOperation("BufferSubData: no buffer bound!"); return ErrorInvalidOperation("BufferSubData: no buffer bound!");
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.mLength; CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.mLength;
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length"); return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@ -941,7 +941,7 @@ WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
CheckedUint32 checked_neededByteLength = CheckedUint32 checked_neededByteLength =
GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment); GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info); return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
PRUint32 bytesNeeded = checked_neededByteLength.value(); PRUint32 bytesNeeded = checked_neededByteLength.value();
@ -1562,7 +1562,7 @@ WebGLContext::DoFakeVertexAttrib0(WebGLuint vertexCount)
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(WebGLfloat); CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(WebGLfloat);
if (!checked_dataSize.valid()) { if (!checked_dataSize.isValid()) {
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation " ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount); "with %d vertices. Try reducing the number of vertices.", vertexCount);
return false; return false;
@ -1779,7 +1779,7 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count; CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count;
if (!checked_firstPlusCount.valid()) if (!checked_firstPlusCount.isValid())
return ErrorInvalidOperation("drawArrays: overflow in first+count"); return ErrorInvalidOperation("drawArrays: overflow in first+count");
if (checked_firstPlusCount.value() > maxAllowedCount) if (checked_firstPlusCount.value() > maxAllowedCount)
@ -1847,7 +1847,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE"); return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE");
} }
if (!checked_byteCount.valid()) if (!checked_byteCount.isValid())
return ErrorInvalidValue("DrawElements: overflow in byteCount"); return ErrorInvalidValue("DrawElements: overflow in byteCount");
// If there is no current program, this is silently ignored. // If there is no current program, this is silently ignored.
@ -1863,7 +1863,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedUint32 checked_neededByteCount = checked_byteCount + byteOffset; CheckedUint32 checked_neededByteCount = checked_byteCount + byteOffset;
if (!checked_neededByteCount.valid()) if (!checked_neededByteCount.isValid())
return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount"); return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount");
if (checked_neededByteCount.value() > mBoundElementArrayBuffer->ByteLength()) if (checked_neededByteCount.value() > mBoundElementArrayBuffer->ByteLength())
@ -1880,7 +1880,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedInt32 checked_maxIndexPlusOne = CheckedInt32(maxIndex) + 1; CheckedInt32 checked_maxIndexPlusOne = CheckedInt32(maxIndex) + 1;
if (!checked_maxIndexPlusOne.valid() || if (!checked_maxIndexPlusOne.isValid() ||
checked_maxIndexPlusOne.value() > maxAllowedCount) checked_maxIndexPlusOne.value() > maxAllowedCount)
{ {
// the index array contains invalid indices for the current drawing state, but they // the index array contains invalid indices for the current drawing state, but they
@ -1893,7 +1893,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedInt32 checked_maxIndexInSubArrayPlusOne = CheckedInt32(maxIndexInSubArray) + 1; CheckedInt32 checked_maxIndexInSubArrayPlusOne = CheckedInt32(maxIndexInSubArray) + 1;
if (!checked_maxIndexInSubArrayPlusOne.valid() || if (!checked_maxIndexInSubArrayPlusOne.isValid() ||
checked_maxIndexInSubArrayPlusOne.value() > maxAllowedCount) checked_maxIndexInSubArrayPlusOne.value() > maxAllowedCount)
{ {
return ErrorInvalidOperation( return ErrorInvalidOperation(
@ -3883,7 +3883,7 @@ WebGLContext::ReadPixels(WebGLint x, WebGLint y, WebGLsizei width,
CheckedUint32 checked_alignedRowSize = CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment); RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size"); return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
if (checked_neededByteLength.value() > dataByteLen) if (checked_neededByteLength.value() > dataByteLen)
@ -5601,7 +5601,7 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
CheckedUint32 checked_alignedRowSize = CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment); RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size"); return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_neededByteLength.value(); PRUint32 bytesNeeded = checked_neededByteLength.value();
@ -5842,7 +5842,7 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
CheckedUint32 checked_alignedRowSize = CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment); RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.valid()) if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size"); return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_neededByteLength.value(); PRUint32 bytesNeeded = checked_neededByteLength.value();

View file

@ -40,8 +40,7 @@
#include "WebGLContext.h" #include "WebGLContext.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
@ -143,8 +142,8 @@ WebGLContext::ValidateBuffers(PRInt32 *maxAllowedCount, const char *info)
CheckedInt32 checked_sizeOfLastElement CheckedInt32 checked_sizeOfLastElement
= CheckedInt32(vd.componentSize()) * vd.size; = CheckedInt32(vd.componentSize()) * vd.size;
if (!checked_byteLength.valid() || if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.valid()) !checked_sizeOfLastElement.isValid())
{ {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i); ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false; return false;
@ -156,7 +155,7 @@ WebGLContext::ValidateBuffers(PRInt32 *maxAllowedCount, const char *info)
CheckedInt32 checked_maxAllowedCount CheckedInt32 checked_maxAllowedCount
= ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1; = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.valid()) { if (!checked_maxAllowedCount.isValid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i); ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false; return false;
} }
@ -401,7 +400,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
{ {
CheckedUint32 calculated_byteLength = 0; CheckedUint32 calculated_byteLength = 0;
CheckedUint32 checked_byteLength = byteLength; CheckedUint32 checked_byteLength = byteLength;
if (!checked_byteLength.valid()) { if (!checked_byteLength.isValid()) {
ErrorInvalidValue("%s: data length out of bounds", info); ErrorInvalidValue("%s: data length out of bounds", info);
return false; return false;
} }
@ -411,7 +410,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
{ {
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8; calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) { if (!calculated_byteLength.isValid() || !(checked_byteLength == calculated_byteLength)) {
ErrorInvalidValue("%s: data size does not match dimensions", info); ErrorInvalidValue("%s: data size does not match dimensions", info);
return false; return false;
} }
@ -421,7 +420,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
{ {
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16; calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) { if (!calculated_byteLength.isValid() || !(checked_byteLength == calculated_byteLength)) {
ErrorInvalidValue("%s: data size does not match dimensions", info); ErrorInvalidValue("%s: data size does not match dimensions", info);
return false; return false;
} }

View file

@ -108,7 +108,6 @@
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "nsStyleUtil.h" #include "nsStyleUtil.h"
#include "CanvasImageCache.h" #include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm> #include <algorithm>
@ -116,6 +115,7 @@
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h" #include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h" #include "mozilla/dom/PBrowserParent.h"
@ -3926,14 +3926,14 @@ nsCanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
MOZ_ASSERT(aWidth && aHeight); MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4; CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.valid()) { if (!len.isValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
} }
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth; CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight; CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.valid() || !bottomMost.valid()) { if (!rightMost.isValid() || !bottomMost.isValid()) {
return NS_ERROR_DOM_SYNTAX_ERR; return NS_ERROR_DOM_SYNTAX_ERR;
} }
@ -4066,7 +4066,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth; CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
if (!checkedDirtyX.valid()) if (!checkedDirtyX.isValid())
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyX = checkedDirtyX.value(); dirtyX = checkedDirtyX.value();
@ -4078,7 +4078,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight; CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
if (!checkedDirtyY.valid()) if (!checkedDirtyY.isValid())
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyY = checkedDirtyY.value(); dirtyY = checkedDirtyY.value();

View file

@ -104,7 +104,6 @@
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "nsStyleUtil.h" #include "nsStyleUtil.h"
#include "CanvasImageCache.h" #include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm> #include <algorithm>
@ -112,6 +111,7 @@
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h" #include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h" #include "mozilla/dom/PBrowserParent.h"
@ -4095,14 +4095,14 @@ nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx,
MOZ_ASSERT(aWidth && aHeight); MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4; CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.valid()) { if (!len.isValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
} }
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth; CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight; CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.valid() || !bottomMost.valid()) { if (!rightMost.isValid() || !bottomMost.isValid()) {
return NS_ERROR_DOM_SYNTAX_ERR; return NS_ERROR_DOM_SYNTAX_ERR;
} }
@ -4233,7 +4233,7 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRU
CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth; CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
if (!checkedDirtyX.valid()) if (!checkedDirtyX.isValid())
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyX = checkedDirtyX.value(); dirtyX = checkedDirtyX.value();
@ -4245,7 +4245,7 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRU
CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight; CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
if (!checkedDirtyY.valid()) if (!checkedDirtyY.isValid())
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyY = checkedDirtyY.value(); dirtyY = checkedDirtyY.value();

View file

@ -38,10 +38,10 @@
#include "nsHTMLCanvasElement.h" #include "nsHTMLCanvasElement.h"
#include "mozilla/Base64.h" #include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "prmem.h" #include "prmem.h"
#include "nsDOMFile.h" #include "nsDOMFile.h"
#include "CheckedInt.h"
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h" #include "nsIXPConnect.h"

View file

@ -3310,17 +3310,15 @@ nsHTMLInputElement::AllowDrop()
void void
nsHTMLInputElement::AddedToRadioGroup() nsHTMLInputElement::AddedToRadioGroup()
{ {
// Make sure not to notify if we're still being created by the parser // If the element is neither in a form nor a document, there is no group so we
bool notify = !mParserCreating; // should just stop here.
if (!mForm && !IsInDoc()) {
//
// If the input element is not in a form and
// not in a document, we just need to return.
//
if (!mForm && !(IsInDoc() && GetParent())) {
return; return;
} }
// Make sure not to notify if we're still being created by the parser
bool notify = !mParserCreating;
// //
// If the input element is checked, and we add it to the group, it will // If the input element is checked, and we add it to the group, it will
// deselect whatever is currently selected in that group // deselect whatever is currently selected in that group

View file

@ -98,6 +98,9 @@
#include "nsDOMMediaStream.h" #include "nsDOMMediaStream.h"
#include "nsIScriptError.h" #include "nsIScriptError.h"
#include "nsCSSParser.h"
#include "nsIMediaList.h"
#ifdef MOZ_OGG #ifdef MOZ_OGG
#include "nsOggDecoder.h" #include "nsOggDecoder.h"
#endif #endif
@ -850,6 +853,12 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
"Should delay load event (if in document) during load"); "Should delay load event (if in document) during load");
NS_ASSERTION(mIsLoadingFromSourceChildren, NS_ASSERTION(mIsLoadingFromSourceChildren,
"Must remember we're loading from source children"); "Must remember we're loading from source children");
nsIDocument* parentDoc = OwnerDoc()->GetParentDocument();
if (parentDoc) {
parentDoc->FlushPendingNotifications(Flush_Layout);
}
while (true) { while (true) {
nsIContent* child = GetNextSource(); nsIContent* child = GetNextSource();
if (!child) { if (!child) {
@ -876,11 +885,25 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
GetCanPlay(type) == CANPLAY_NO) { GetCanPlay(type) == CANPLAY_NO) {
DispatchAsyncSourceError(child); DispatchAsyncSourceError(child);
const PRUnichar* params[] = { type.get(), src.get() }; const PRUnichar* params[] = { type.get(), src.get() };
ReportLoadError("MediaLoadUnsupportedType", params, ArrayLength(params)); ReportLoadError("MediaLoadUnsupportedTypeAttribute", params, ArrayLength(params));
continue; continue;
} }
LOG(PR_LOG_DEBUG, ("%p Trying load from <source>=%s type=%s", this, nsAutoString media;
NS_ConvertUTF16toUTF8(src).get(), NS_ConvertUTF16toUTF8(type).get())); if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::media, media) && !media.IsEmpty()) {
nsCSSParser cssParser;
nsRefPtr<nsMediaList> mediaList(new nsMediaList());
cssParser.ParseMediaList(media, NULL, 0, mediaList, false);
nsIPresShell* presShell = OwnerDoc()->GetShell();
if (presShell && !mediaList->Matches(presShell->GetPresContext(), NULL)) {
DispatchAsyncSourceError(child);
const PRUnichar* params[] = { media.get(), src.get() };
ReportLoadError("MediaLoadSourceMediaNotMatched", params, ArrayLength(params));
continue;
}
}
LOG(PR_LOG_DEBUG, ("%p Trying load from <source>=%s type=%s media=%s", this,
NS_ConvertUTF16toUTF8(src).get(), NS_ConvertUTF16toUTF8(type).get(),
NS_ConvertUTF16toUTF8(media).get()));
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
NewURIFromString(src, getter_AddRefs(uri)); NewURIFromString(src, getter_AddRefs(uri));

View file

@ -114,6 +114,7 @@ NS_IMPL_ELEMENT_CLONE(nsHTMLSourceElement)
NS_IMPL_URI_ATTR(nsHTMLSourceElement, Src, src) NS_IMPL_URI_ATTR(nsHTMLSourceElement, Src, src)
NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Type, type) NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Type, type)
NS_IMPL_STRING_ATTR(nsHTMLSourceElement, Media, media)
nsresult nsresult
nsHTMLSourceElement::BindToTree(nsIDocument *aDocument, nsHTMLSourceElement::BindToTree(nsIDocument *aDocument,

View file

@ -243,32 +243,88 @@ nsMathMLElement::GetAttributeMappingFunction() const
return &MapMathMLAttributesInto; return &MapMathMLAttributesInto;
} }
// ================ /* static */ bool
// Utilities for parsing and retrieving numeric values nsMathMLElement::ParseNamedSpaceValue(const nsString& aString,
nsCSSValue& aCSSValue,
PRUint32 aFlags)
{
PRInt32 i = 0;
// See if it is one of the 'namedspace' (ranging -7/18em, -6/18, ... 7/18em)
if (aString.EqualsLiteral("veryverythinmathspace")) {
i = 1;
} else if (aString.EqualsLiteral("verythinmathspace")) {
i = 2;
} else if (aString.EqualsLiteral("thinmathspace")) {
i = 3;
} else if (aString.EqualsLiteral("mediummathspace")) {
i = 4;
} else if (aString.EqualsLiteral("thickmathspace")) {
i = 5;
} else if (aString.EqualsLiteral("verythickmathspace")) {
i = 6;
} else if (aString.EqualsLiteral("veryverythickmathspace")) {
i = 7;
} else if (aFlags & PARSE_ALLOW_NEGATIVE) {
if (aString.EqualsLiteral("negativeveryverythinmathspace")) {
i = -1;
} else if (aString.EqualsLiteral("negativeverythinmathspace")) {
i = -2;
} else if (aString.EqualsLiteral("negativethinmathspace")) {
i = -3;
} else if (aString.EqualsLiteral("negativemediummathspace")) {
i = -4;
} else if (aString.EqualsLiteral("negativethickmathspace")) {
i = -5;
} else if (aString.EqualsLiteral("negativeverythickmathspace")) {
i = -6;
} else if (aString.EqualsLiteral("negativeveryverythickmathspace")) {
i = -7;
}
}
if (0 != i) {
aCSSValue.SetFloatValue(float(i)/float(18), eCSSUnit_EM);
return true;
}
/* return false;
The REC says: }
An explicit plus sign ('+') is not allowed as part of a numeric value
except when it is specifically listed in the syntax (as a quoted '+'
or "+"),
Units allowed
ID Description
em ems (font-relative unit traditionally used for horizontal lengths)
ex exs (font-relative unit traditionally used for vertical lengths)
px pixels, or pixel size of a "typical computer display"
in inches (1 inch = 2.54 centimeters)
cm centimeters
mm millimeters
pt points (1 point = 1/72 inch)
pc picas (1 pica = 12 points)
% percentage of default value
Implementation here:
The numeric value is valid only if it is of the form [-] nnn.nnn
[h/v-unit]
*/
// The REC says:
//
// "Most presentation elements have attributes that accept values representing
// lengths to be used for size, spacing or similar properties. The syntax of a
// length is specified as
//
// number | number unit | namedspace
//
// There should be no space between the number and the unit of a length."
//
// "A trailing '%' represents a percent of the default value. The default
// value, or how it is obtained, is listed in the table of attributes for each
// element. [...] A number without a unit is intepreted as a multiple of the
// default value."
//
// "The possible units in MathML are:
//
// Unit Description
// em an em (font-relative unit traditionally used for horizontal lengths)
// ex an ex (font-relative unit traditionally used for vertical lengths)
// px pixels, or size of a pixel in the current display
// in inches (1 inch = 2.54 centimeters)
// cm centimeters
// mm millimeters
// pt points (1 point = 1/72 inch)
// pc picas (1 pica = 12 points)
// % percentage of default value"
//
// The numbers are defined that way:
// - unsigned-number: "a string of decimal digits with up to one decimal point
// (U+002E), representing a non-negative terminating decimal number (a type of
// rational number)"
// - number: "an optional prefix of '-' (U+002D), followed by an unsigned
// number, representing a terminating decimal number (a type of rational
// number)"
//
/* static */ bool /* static */ bool
nsMathMLElement::ParseNumericValue(const nsString& aString, nsMathMLElement::ParseNumericValue(const nsString& aString,
nsCSSValue& aCSSValue, nsCSSValue& aCSSValue,
@ -281,6 +337,10 @@ nsMathMLElement::ParseNumericValue(const nsString& aString,
if (!stringLength) if (!stringLength)
return false; return false;
if (ParseNamedSpaceValue(aString, aCSSValue, aFlags)) {
return true;
}
nsAutoString number, unit; nsAutoString number, unit;
// see if the negative sign is there // see if the negative sign is there
@ -289,10 +349,6 @@ nsMathMLElement::ParseNumericValue(const nsString& aString,
if (c == '-') { if (c == '-') {
number.Append(c); number.Append(c);
i++; i++;
// skip any space after the negative sign
if (i < stringLength && nsCRT::IsAsciiSpace(str[i]))
i++;
} }
// Gather up characters that make up the number // Gather up characters that make up the number
@ -358,6 +414,14 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aData) nsRuleData* aData)
{ {
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) { if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
// scriptsizemultiplier
//
// "Specifies the multiplier to be used to adjust font size due to changes
// in scriptlevel.
//
// values: number
// default: 0.71
//
const nsAttrValue* value = const nsAttrValue* value =
aAttributes->GetAttr(nsGkAtoms::scriptsizemultiplier_); aAttributes->GetAttr(nsGkAtoms::scriptsizemultiplier_);
nsCSSValue* scriptSizeMultiplier = nsCSSValue* scriptSizeMultiplier =
@ -377,6 +441,18 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
} }
} }
// scriptminsize
//
// "Specifies the minimum font size allowed due to changes in scriptlevel.
// Note that this does not limit the font size due to changes to mathsize."
//
// values: length
// default: 8pt
//
// We don't allow negative values.
// XXXfredw Should we allow unitless values? (bug 411227)
// XXXfredw Does a relative unit give a multiple of the default value?
//
value = aAttributes->GetAttr(nsGkAtoms::scriptminsize_); value = aAttributes->GetAttr(nsGkAtoms::scriptminsize_);
nsCSSValue* scriptMinSize = aData->ValueForScriptMinSize(); nsCSSValue* scriptMinSize = aData->ValueForScriptMinSize();
if (value && value->Type() == nsAttrValue::eString && if (value && value->Type() == nsAttrValue::eString &&
@ -384,6 +460,17 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
ParseNumericValue(value->GetStringValue(), *scriptMinSize, 0); ParseNumericValue(value->GetStringValue(), *scriptMinSize, 0);
} }
// scriptlevel
//
// "Changes the scriptlevel in effect for the children. When the value is
// given without a sign, it sets scriptlevel to the specified value; when a
// sign is given, it increments ("+") or decrements ("-") the current
// value. (Note that large decrements can result in negative values of
// scriptlevel, but these values are considered legal.)"
//
// values: ( "+" | "-" )? unsigned-integer
// default: inherited
//
value = aAttributes->GetAttr(nsGkAtoms::scriptlevel_); value = aAttributes->GetAttr(nsGkAtoms::scriptlevel_);
nsCSSValue* scriptLevel = aData->ValueForScriptLevel(); nsCSSValue* scriptLevel = aData->ValueForScriptLevel();
if (value && value->Type() == nsAttrValue::eString && if (value && value->Type() == nsAttrValue::eString &&
@ -408,6 +495,28 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
} }
} }
// mathsize
//
// "Specifies the size to display the token content. The values 'small' and
// 'big' choose a size smaller or larger than the current font size, but
// leave the exact proportions unspecified; 'normal' is allowed for
// completeness, but since it is equivalent to '100%' or '1em', it has no
// effect."
//
// values: "small" | "normal" | "big" | length
// default: inherited
//
// fontsize
//
// "Specified the size for the token. Deprecated in favor of mathsize."
//
// values: length
// default: inherited
//
// In both cases, we don't allow negative values.
// XXXfredw Should we allow unitless values? (bug 411227)
// XXXfredw Does a relative unit give a multiple of the default value?
//
bool parseSizeKeywords = true; bool parseSizeKeywords = true;
value = aAttributes->GetAttr(nsGkAtoms::mathsize_); value = aAttributes->GetAttr(nsGkAtoms::mathsize_);
if (!value) { if (!value) {
@ -435,6 +544,14 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
} }
} }
// fontfamily
//
// "Should be the name of a font that may be available to a MathML renderer,
// or a CSS font specification; See Section 6.5 Using CSS with MathML and
// CSS for more information. Deprecated in favor of mathvariant."
//
// values: string
//
value = aAttributes->GetAttr(nsGkAtoms::fontfamily_); value = aAttributes->GetAttr(nsGkAtoms::fontfamily_);
nsCSSValue* fontFamily = aData->ValueForFontFamily(); nsCSSValue* fontFamily = aData->ValueForFontFamily();
if (value && value->Type() == nsAttrValue::eString && if (value && value->Type() == nsAttrValue::eString &&
@ -443,6 +560,24 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
} }
} }
// mathbackground
//
// "Specifies the background color to be used to fill in the bounding box of
// the element and its children. The default, 'transparent', lets the
// background color, if any, used in the current rendering context to show
// through."
//
// values: color | "transparent"
// default: "transparent"
//
// background
//
// "Specified the background color to be used to fill in the bounding box of
// the element and its children. Deprecated in favor of mathbackground."
//
// values: color | "transparent"
// default: "transparent"
//
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)) { if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)) {
const nsAttrValue* value = const nsAttrValue* value =
aAttributes->GetAttr(nsGkAtoms::mathbackground_); aAttributes->GetAttr(nsGkAtoms::mathbackground_);
@ -458,6 +593,23 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
} }
} }
// mathcolor
//
// "Specifies the foreground color to use when drawing the components of this
// element, such as the content for token elements or any lines, surds, or
// other decorations. It also establishes the default mathcolor used for
// child elements when used on a layout element."
//
// values: color
// default: inherited
//
// color
//
// "Specified the color for the token. Deprecated in favor of mathcolor."
//
// values: color
// default: inherited
//
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) { if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::mathcolor_); const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::mathcolor_);
if (!value) { if (!value) {

View file

@ -89,6 +89,10 @@ public:
PARSE_ALLOW_UNITLESS = 0x01, // unitless 0 will be turned into 0px PARSE_ALLOW_UNITLESS = 0x01, // unitless 0 will be turned into 0px
PARSE_ALLOW_NEGATIVE = 0x02 PARSE_ALLOW_NEGATIVE = 0x02
}; };
static bool ParseNamedSpaceValue(const nsString& aString,
nsCSSValue& aCSSValue,
PRUint32 aFlags);
static bool ParseNumericValue(const nsString& aString, static bool ParseNumericValue(const nsString& aString,
nsCSSValue& aCSSValue, nsCSSValue& aCSSValue,
PRUint32 aFlags); PRUint32 aFlags);

View file

@ -40,13 +40,12 @@
#define VideoUtils_h #define VideoUtils_h
#include "mozilla/ReentrantMonitor.h" #include "mozilla/ReentrantMonitor.h"
#include "mozilla/CheckedInt.h"
#include "nsRect.h" #include "nsRect.h"
#include "nsIThreadManager.h" #include "nsIThreadManager.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "CheckedInt.h"
using mozilla::CheckedInt64; using mozilla::CheckedInt64;
using mozilla::CheckedUint64; using mozilla::CheckedUint64;
using mozilla::CheckedInt32; using mozilla::CheckedInt32;

View file

@ -446,23 +446,18 @@ void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
return; return;
} }
// Only inform the element of MetadataLoaded if not doing a load() in order
// to fulfill a seek, otherwise we'll get multiple metadataloaded events.
bool notifyElement = true;
{ {
ReentrantMonitorAutoEnter mon(mReentrantMonitor); ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1; mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
// Duration has changed so we should recompute playback rate // Duration has changed so we should recompute playback rate
UpdatePlaybackRate(); UpdatePlaybackRate();
notifyElement = mNextState != PLAY_STATE_SEEKING;
} }
if (mDuration == -1) { if (mDuration == -1) {
SetInfinite(true); SetInfinite(true);
} }
if (mElement && notifyElement) { if (mElement) {
// Make sure the element and the frame (if any) are told about // Make sure the element and the frame (if any) are told about
// our new size. // our new size.
Invalidate(); Invalidate();
@ -482,7 +477,7 @@ void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
ReentrantMonitorAutoEnter mon(mReentrantMonitor); ReentrantMonitorAutoEnter mon(mReentrantMonitor);
bool resourceIsLoaded = !mResourceLoaded && mResource && bool resourceIsLoaded = !mResourceLoaded && mResource &&
mResource->IsDataCachedToEndOfResource(mDecoderPosition); mResource->IsDataCachedToEndOfResource(mDecoderPosition);
if (mElement && notifyElement) { if (mElement) {
mElement->FirstFrameLoaded(resourceIsLoaded); mElement->FirstFrameLoaded(resourceIsLoaded);
} }
@ -567,11 +562,13 @@ void nsBuiltinDecoder::DecodeError()
bool nsBuiltinDecoder::IsSeeking() const bool nsBuiltinDecoder::IsSeeking() const
{ {
return mPlayState == PLAY_STATE_SEEKING || mNextState == PLAY_STATE_SEEKING; NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
return mPlayState == PLAY_STATE_SEEKING;
} }
bool nsBuiltinDecoder::IsEnded() const bool nsBuiltinDecoder::IsEnded() const
{ {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN; return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
} }
@ -580,6 +577,7 @@ void nsBuiltinDecoder::PlaybackEnded()
if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING) if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING)
return; return;
printf("nsBuiltinDecoder::PlaybackEnded mPlayState=%d\n", mPlayState);
PlaybackPositionChanged(); PlaybackPositionChanged();
ChangeState(PLAY_STATE_ENDED); ChangeState(PLAY_STATE_ENDED);
@ -794,6 +792,7 @@ void nsBuiltinDecoder::SeekingStopped()
seekWasAborted = true; seekWasAborted = true;
} else { } else {
UnpinForSeek(); UnpinForSeek();
printf("nsBuiltinDecoder::SeekingStopped, next state=%d\n", mNextState);
ChangeState(mNextState); ChangeState(mNextState);
} }
} }
@ -827,6 +826,7 @@ void nsBuiltinDecoder::SeekingStoppedAtEnd()
seekWasAborted = true; seekWasAborted = true;
} else { } else {
UnpinForSeek(); UnpinForSeek();
printf("nsBuiltinDecoder::SeekingStoppedAtEnd, next state=PLAY_STATE_ENDED\n");
fireEnded = true; fireEnded = true;
ChangeState(PLAY_STATE_ENDED); ChangeState(PLAY_STATE_ENDED);
} }
@ -909,6 +909,9 @@ void nsBuiltinDecoder::PlaybackPositionChanged()
// current time after the seek has started but before it has // current time after the seek has started but before it has
// completed. // completed.
mCurrentTime = mDecoderStateMachine->GetCurrentTime(); mCurrentTime = mDecoderStateMachine->GetCurrentTime();
} else {
printf("Suppressed timeupdate during seeking: currentTime=%f, new time=%f\n",
mCurrentTime, mDecoderStateMachine->GetCurrentTime());
} }
mDecoderStateMachine->ClearPositionChangeFlag(); mDecoderStateMachine->ClearPositionChangeFlag();
} }

View file

@ -470,8 +470,8 @@ public:
// Call on the main thread only. // Call on the main thread only.
virtual void NetworkError(); virtual void NetworkError();
// Call from any thread safely. Return true if we are currently // Return true if we are currently seeking in the media resource.
// seeking in the media resource. // Call on the main thread only.
virtual bool IsSeeking() const; virtual bool IsSeeking() const;
// Return true if the decoder has reached the end of playback. // Return true if the decoder has reached the end of playback.
@ -742,16 +742,20 @@ public:
// Data about MediaStreams that are being fed by this decoder. // Data about MediaStreams that are being fed by this decoder.
nsTArray<OutputMediaStream> mOutputStreams; nsTArray<OutputMediaStream> mOutputStreams;
// Set to one of the valid play states. It is protected by the // Set to one of the valid play states.
// monitor mReentrantMonitor. This monitor must be acquired when reading or // This can only be changed on the main thread while holding the decoder
// writing the state. Any change to the state on the main thread // monitor. Thus, it can be safely read while holding the decoder monitor
// must call NotifyAll on the monitor so the decode thread can wake up. // OR on the main thread.
// Any change to the state on the main thread must call NotifyAll on the
// monitor so the decode thread can wake up.
PlayState mPlayState; PlayState mPlayState;
// The state to change to after a seek or load operation. It must only // The state to change to after a seek or load operation.
// be changed from the main thread. The decoder monitor must be acquired // This can only be changed on the main thread while holding the decoder
// when writing to the state, or when reading from a non-main thread. // monitor. Thus, it can be safely read while holding the decoder monitor
// OR on the main thread.
// Any change to the state must call NotifyAll on the monitor. // Any change to the state must call NotifyAll on the monitor.
// This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING.
PlayState mNextState; PlayState mNextState;
// True when we have fully loaded the resource and reported that // True when we have fully loaded the resource and reported that

View file

@ -164,8 +164,8 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
// the frame we've been supplied without indexing out of bounds. // the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width); CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height); CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.valid() || xLimit.value() > aBuffer.mPlanes[0].mStride || if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
!yLimit.valid() || yLimit.value() > aBuffer.mPlanes[0].mHeight) !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
{ {
// The specified picture dimensions can't be contained inside the video // The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail. // frame, we'll stomp memory if we try to copy it. Fail.
@ -346,7 +346,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
break; break;
CheckedInt64 startFrame = UsecsToFrames(audio->mTime, mInfo.mAudioRate); CheckedInt64 startFrame = UsecsToFrames(audio->mTime, mInfo.mAudioRate);
CheckedInt64 targetFrame = UsecsToFrames(aTarget, mInfo.mAudioRate); CheckedInt64 targetFrame = UsecsToFrames(aTarget, mInfo.mAudioRate);
if (!startFrame.valid() || !targetFrame.valid()) { if (!startFrame.isValid() || !targetFrame.isValid()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (startFrame.value() + audio->mFrames <= targetFrame.value()) { if (startFrame.value() + audio->mFrames <= targetFrame.value()) {
@ -390,7 +390,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
audio->mAudioData.get() + (framesToPrune * channels), audio->mAudioData.get() + (framesToPrune * channels),
frames * channels * sizeof(AudioDataValue)); frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudioRate); CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudioRate);
if (!duration.valid()) { if (!duration.isValid()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsAutoPtr<AudioData> data(new AudioData(audio->mOffset, nsAutoPtr<AudioData> data(new AudioData(audio->mOffset,

View file

@ -547,7 +547,7 @@ void nsBuiltinDecoderStateMachine::SendOutputStreamAudio(AudioData* aAudio,
CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate, CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate,
aStream->mAudioFramesWrittenBaseTime + mStartTime) + aStream->mAudioFramesWritten; aStream->mAudioFramesWrittenBaseTime + mStartTime) + aStream->mAudioFramesWritten;
CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime); CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime);
if (!audioWrittenOffset.valid() || !frameOffset.valid()) if (!audioWrittenOffset.isValid() || !frameOffset.isValid())
return; return;
if (audioWrittenOffset.value() < frameOffset.value()) { if (audioWrittenOffset.value() < frameOffset.value()) {
// Write silence to catch up // Write silence to catch up
@ -1115,7 +1115,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
// samples. // samples.
CheckedInt64 sampleTime = UsecsToFrames(s->mTime, rate); CheckedInt64 sampleTime = UsecsToFrames(s->mTime, rate);
CheckedInt64 missingFrames = sampleTime - playedFrames; CheckedInt64 missingFrames = sampleTime - playedFrames;
if (!missingFrames.valid() || !sampleTime.valid()) { if (!missingFrames.isValid() || !sampleTime.isValid()) {
NS_WARNING("Int overflow adding in AudioLoop()"); NS_WARNING("Int overflow adding in AudioLoop()");
break; break;
} }
@ -1139,7 +1139,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
{ {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
CheckedInt64 playedUsecs = FramesToUsecs(audioDuration, rate) + audioStartTime; CheckedInt64 playedUsecs = FramesToUsecs(audioDuration, rate) + audioStartTime;
if (!playedUsecs.valid()) { if (!playedUsecs.isValid()) {
NS_WARNING("Int overflow calculating audio end time"); NS_WARNING("Int overflow calculating audio end time");
break; break;
} }
@ -2198,6 +2198,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0; PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0;
PRInt64 clockTime = NS_MAX(mEndTime, NS_MAX(videoTime, GetAudioClock())); PRInt64 clockTime = NS_MAX(mEndTime, NS_MAX(videoTime, GetAudioClock()));
UpdatePlaybackPosition(clockTime); UpdatePlaybackPosition(clockTime);
printf("nsBuiltinDecoderStateMachine::RunStateMachine queuing nsBuiltinDecoder::PlaybackEnded\n");
nsCOMPtr<nsIRunnable> event = nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::PlaybackEnded); NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::PlaybackEnded);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);

View file

@ -353,10 +353,10 @@ PRInt64 nsTheoraState::Time(th_info* aInfo, PRInt64 aGranulepos)
ogg_int64_t pframe = aGranulepos - (iframe << shift); ogg_int64_t pframe = aGranulepos - (iframe << shift);
PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1); PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1);
CheckedInt64 t = ((CheckedInt64(frameno) + 1) * USECS_PER_S) * aInfo->fps_denominator; CheckedInt64 t = ((CheckedInt64(frameno) + 1) * USECS_PER_S) * aInfo->fps_denominator;
if (!t.valid()) if (!t.isValid())
return -1; return -1;
t /= aInfo->fps_numerator; t /= aInfo->fps_numerator;
return t.valid() ? t.value() : -1; return t.isValid() ? t.value() : -1;
} }
PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) { PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
@ -364,7 +364,7 @@ PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
return -1; return -1;
} }
CheckedInt64 t = (CheckedInt64(th_granule_frame(mCtx, granulepos)) * USECS_PER_S) * mInfo.fps_denominator; CheckedInt64 t = (CheckedInt64(th_granule_frame(mCtx, granulepos)) * USECS_PER_S) * mInfo.fps_denominator;
if (!t.valid()) if (!t.isValid())
return -1; return -1;
return t.value() / mInfo.fps_numerator; return t.value() / mInfo.fps_numerator;
} }
@ -622,7 +622,7 @@ PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos)
return -1; return -1;
} }
CheckedInt64 t = CheckedInt64(aGranulepos) * USECS_PER_S; CheckedInt64 t = CheckedInt64(aGranulepos) * USECS_PER_S;
if (!t.valid()) if (!t.isValid())
t = 0; t = 0;
return t.value() / aInfo->rate; return t.value() / aInfo->rate;
} }
@ -884,7 +884,7 @@ PRInt64 nsOpusState::Time(PRInt64 granulepos)
// Ogg Opus always runs at a granule rate of 48 kHz. // Ogg Opus always runs at a granule rate of 48 kHz.
CheckedInt64 t = CheckedInt64(granulepos - mPreSkip) * USECS_PER_S; CheckedInt64 t = CheckedInt64(granulepos - mPreSkip) * USECS_PER_S;
return t.valid() ? t.value() / mRate : -1; return t.isValid() ? t.value() / mRate : -1;
} }
bool nsOpusState::IsHeader(ogg_packet* aPacket) bool nsOpusState::IsHeader(ogg_packet* aPacket)
@ -1048,7 +1048,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Extract the start time. // Extract the start time.
CheckedInt64 t = CheckedInt64(LEInt64(p + INDEX_FIRST_NUMER_OFFSET)) * USECS_PER_S; CheckedInt64 t = CheckedInt64(LEInt64(p + INDEX_FIRST_NUMER_OFFSET)) * USECS_PER_S;
if (!t.valid()) { if (!t.isValid()) {
return (mActive = false); return (mActive = false);
} else { } else {
startTime = t.value() / timeDenom; startTime = t.value() / timeDenom;
@ -1056,7 +1056,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Extract the end time. // Extract the end time.
t = LEInt64(p + INDEX_LAST_NUMER_OFFSET) * USECS_PER_S; t = LEInt64(p + INDEX_LAST_NUMER_OFFSET) * USECS_PER_S;
if (!t.valid()) { if (!t.isValid()) {
return (mActive = false); return (mActive = false);
} else { } else {
endTime = t.value() / timeDenom; endTime = t.value() / timeDenom;
@ -1065,7 +1065,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Check the numKeyPoints value read, ensure we're not going to run out of // Check the numKeyPoints value read, ensure we're not going to run out of
// memory while trying to decode the index packet. // memory while trying to decode the index packet.
CheckedInt64 minPacketSize = (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET; CheckedInt64 minPacketSize = (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET;
if (!minPacketSize.valid()) if (!minPacketSize.isValid())
{ {
return (mActive = false); return (mActive = false);
} }
@ -1103,7 +1103,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
p = ReadVariableLengthInt(p, limit, delta); p = ReadVariableLengthInt(p, limit, delta);
offset += delta; offset += delta;
if (p == limit || if (p == limit ||
!offset.valid() || !offset.isValid() ||
offset.value() > mLength || offset.value() > mLength ||
offset.value() < 0) offset.value() < 0)
{ {
@ -1111,14 +1111,14 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
} }
p = ReadVariableLengthInt(p, limit, delta); p = ReadVariableLengthInt(p, limit, delta);
time += delta; time += delta;
if (!time.valid() || if (!time.isValid() ||
time.value() > endTime || time.value() > endTime ||
time.value() < startTime) time.value() < startTime)
{ {
return (mActive = false); return (mActive = false);
} }
CheckedInt64 timeUsecs = time * USECS_PER_S; CheckedInt64 timeUsecs = time * USECS_PER_S;
if (!timeUsecs.valid()) if (!timeUsecs.isValid())
return mActive = false; return mActive = false;
timeUsecs /= timeDenom; timeUsecs /= timeDenom;
keyPoints->Add(offset.value(), timeUsecs.value()); keyPoints->Add(offset.value(), timeUsecs.value());
@ -1228,8 +1228,8 @@ nsresult nsSkeletonState::GetDuration(const nsTArray<PRUint32>& aTracks,
} }
NS_ASSERTION(endTime > startTime, "Duration must be positive"); NS_ASSERTION(endTime > startTime, "Duration must be positive");
CheckedInt64 duration = CheckedInt64(endTime) - startTime; CheckedInt64 duration = CheckedInt64(endTime) - startTime;
aDuration = duration.valid() ? duration.value() : 0; aDuration = duration.isValid() ? duration.value() : 0;
return duration.valid() ? NS_OK : NS_ERROR_FAILURE; return duration.isValid() ? NS_OK : NS_ERROR_FAILURE;
} }
bool nsSkeletonState::DecodeHeader(ogg_packet* aPacket) bool nsSkeletonState::DecodeHeader(ogg_packet* aPacket)

View file

@ -87,7 +87,7 @@ nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo)
CheckedUint32 dummy = CheckedUint32(static_cast<PRUint32>(mMetadata.frameWidth)) * CheckedUint32 dummy = CheckedUint32(static_cast<PRUint32>(mMetadata.frameWidth)) *
static_cast<PRUint32>(mMetadata.frameHeight); static_cast<PRUint32>(mMetadata.frameHeight);
NS_ENSURE_TRUE(dummy.valid(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(dummy.isValid(), NS_ERROR_FAILURE);
if (mMetadata.aspectDenominator == 0 || if (mMetadata.aspectDenominator == 0 ||
mMetadata.framerateDenominator == 0) mMetadata.framerateDenominator == 0)
@ -268,7 +268,7 @@ nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime,
CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize; CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize;
offset += sizeof(nsRawVideoHeader); offset += sizeof(nsRawVideoHeader);
NS_ENSURE_TRUE(offset.valid(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(offset.isValid(), NS_ERROR_FAILURE);
nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value()); nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value());
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

View file

@ -161,6 +161,7 @@ _TEST_FILES = \
use_large_cache.js \ use_large_cache.js \
test_audiowrite.html \ test_audiowrite.html \
test_mozHasAudio.html \ test_mozHasAudio.html \
test_source_media.html \
$(NULL) $(NULL)
# Don't run in suite # Don't run in suite

View file

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Media test: media attribute for the source element.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="../../html/content/test/reflect.js"></script>
</head>
<body>
<pre id="test">
<script type="text/javascript">
var testCount = 0;
function notifyFinished() {
testCount++;
if (testCount == 2) {
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
reflectString({
element: document.createElement("source"),
attribute: "media",
});
var media = getPlayableVideo(gSmallTests);
if (media == null) {
todo(false, "No media supported.");
SimpleTest.finish();
} else {
var v = document.createElement('video');
v.innerHTML = "<source src=\"" + media.name + "?fail\" media=\"not all\">" +
"<source src=\""+ media.name + "?pass\" media=\"all\">";
var v2 = document.createElement("video");
v2.innerHTML = "<source src=\""+ media.name +"?pass\">" +
"<source src=\""+ media.name + "?fail\" media=\"all\">";
document.body.appendChild(v);
document.body.appendChild(v2);
v.addEventListener("loadedmetadata", function(e) {
ok(/pass/.test(e.target.currentSrc),
"The source has been chosen according to the media attribute.");
notifyFinished();
});
v2.addEventListener("loadedmetadata", function(e) {
ok(/pass/.test(e.target.currentSrc),
"If no media attribute is specified, it defaults to \'all\'.")
notifyFinished();
});
}
</script>
</pre>
</body>
</html>

View file

@ -209,10 +209,8 @@ void nsWebMBufferedParser::Append(const unsigned char* aBuffer, PRUint32 aLength
mCurrentOffset += aLength; mCurrentOffset += aLength;
} }
void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered, bool nsWebMBufferedState::CalculateBufferedForRange(PRInt64 aStartOffset, PRInt64 aEndOffset,
PRInt64 aStartOffset, PRInt64 aEndOffset, PRUint64* aStartTime, PRUint64* aEndTime)
PRUint64 aTimecodeScale,
PRInt64 aStartTimeOffsetNS)
{ {
ReentrantMonitorAutoEnter mon(mReentrantMonitor); ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -220,7 +218,7 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
PRUint32 start; PRUint32 start;
mTimeMapping.GreatestIndexLtEq(aStartOffset, start); mTimeMapping.GreatestIndexLtEq(aStartOffset, start);
if (start == mTimeMapping.Length()) { if (start == mTimeMapping.Length()) {
return; return false;
} }
// Find the first nsWebMTimeDataOffset at or before aEndOffset. // Find the first nsWebMTimeDataOffset at or before aEndOffset.
@ -233,7 +231,7 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
// Range is empty. // Range is empty.
if (end <= start) { if (end <= start) {
return; return false;
} }
NS_ASSERTION(mTimeMapping[start].mOffset >= aStartOffset && NS_ASSERTION(mTimeMapping[start].mOffset >= aStartOffset &&
@ -252,9 +250,9 @@ void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered,
// from the ranges' start and end timestamps, so that those timestamps are // from the ranges' start and end timestamps, so that those timestamps are
// normalized in the range [0,duration]. // normalized in the range [0,duration].
double startTime = (mTimeMapping[start].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; *aStartTime = mTimeMapping[start].mTimecode;
double endTime = (mTimeMapping[end].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; *aEndTime = mTimeMapping[end].mTimecode;
aBuffered->Add(startTime, endTime); return true;
} }
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset)

View file

@ -225,10 +225,8 @@ public:
} }
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset); void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
void CalculateBufferedForRange(nsTimeRanges* aBuffered, bool CalculateBufferedForRange(PRInt64 aStartOffset, PRInt64 aEndOffset,
PRInt64 aStartOffset, PRInt64 aEndOffset, PRUint64* aStartTime, PRUint64* aEndTime);
PRUint64 aTimecodeScale,
PRInt64 aStartTimeOffsetNS);
private: private:
// Synchronizes access to the mTimeMapping array. // Synchronizes access to the mTimeMapping array.

View file

@ -448,12 +448,12 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
// from after the gap. // from after the gap.
CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, rate); CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, rate);
CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, rate); CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, rate);
if (!tstamp_frames.valid() || !decoded_frames.valid()) { if (!tstamp_frames.isValid() || !decoded_frames.isValid()) {
NS_WARNING("Int overflow converting WebM times to frames"); NS_WARNING("Int overflow converting WebM times to frames");
return false; return false;
} }
decoded_frames += mAudioFrames; decoded_frames += mAudioFrames;
if (!decoded_frames.valid()) { if (!decoded_frames.isValid()) {
NS_WARNING("Int overflow adding decoded_frames"); NS_WARNING("Int overflow adding decoded_frames");
return false; return false;
} }
@ -461,7 +461,7 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
#ifdef DEBUG #ifdef DEBUG
CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), rate); CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), rate);
LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio stream\n", LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio stream\n",
usecs.valid() ? usecs.value(): -1, usecs.isValid() ? usecs.value() : -1,
tstamp_frames.value() - decoded_frames.value())); tstamp_frames.value() - decoded_frames.value()));
#endif #endif
mPacketCount++; mPacketCount++;
@ -501,18 +501,18 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
} }
CheckedInt64 duration = FramesToUsecs(frames, rate); CheckedInt64 duration = FramesToUsecs(frames, rate);
if (!duration.valid()) { if (!duration.isValid()) {
NS_WARNING("Int overflow converting WebM audio duration"); NS_WARNING("Int overflow converting WebM audio duration");
return false; return false;
} }
CheckedInt64 total_duration = FramesToUsecs(total_frames, rate); CheckedInt64 total_duration = FramesToUsecs(total_frames, rate);
if (!total_duration.valid()) { if (!total_duration.isValid()) {
NS_WARNING("Int overflow converting WebM audio total_duration"); NS_WARNING("Int overflow converting WebM audio total_duration");
return false; return false;
} }
CheckedInt64 time = total_duration + tstamp_usecs; CheckedInt64 time = total_duration + tstamp_usecs;
if (!time.valid()) { if (!time.isValid()) {
NS_WARNING("Int overflow adding total_duration and tstamp_usecs"); NS_WARNING("Int overflow adding total_duration and tstamp_usecs");
nestegg_free_packet(aPacket); nestegg_free_packet(aPacket);
return false; return false;
@ -791,24 +791,45 @@ nsresult nsWebMReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
} }
// Special case completely cached files. This also handles local files. // Special case completely cached files. This also handles local files.
if (resource->IsDataCachedToEndOfResource(0)) { bool isFullyCached = resource->IsDataCachedToEndOfResource(0);
if (isFullyCached) {
uint64_t duration = 0; uint64_t duration = 0;
if (nestegg_duration(mContext, &duration) == 0) { if (nestegg_duration(mContext, &duration) == 0) {
aBuffered->Add(0, duration / NS_PER_S); aBuffered->Add(0, duration / NS_PER_S);
} }
} else { }
PRUint32 bufferedLength = 0;
aBuffered->GetLength(&bufferedLength);
// Either we the file is not fully cached, or we couldn't find a duration in
// the WebM bitstream.
if (!isFullyCached || !bufferedLength) {
MediaResource* resource = mDecoder->GetResource(); MediaResource* resource = mDecoder->GetResource();
nsTArray<MediaByteRange> ranges; nsTArray<MediaByteRange> ranges;
nsresult res = resource->GetCachedRanges(ranges); nsresult res = resource->GetCachedRanges(ranges);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
PRInt64 startTimeOffsetNS = aStartTime * NS_PER_USEC;
for (PRUint32 index = 0; index < ranges.Length(); index++) { for (PRUint32 index = 0; index < ranges.Length(); index++) {
mBufferedState->CalculateBufferedForRange(aBuffered, PRUint64 start, end;
ranges[index].mStart, bool rv = mBufferedState->CalculateBufferedForRange(ranges[index].mStart,
ranges[index].mEnd, ranges[index].mEnd,
timecodeScale, &start, &end);
startTimeOffsetNS); if (rv) {
double startTime = start * timecodeScale / NS_PER_S - aStartTime;
double endTime = end * timecodeScale / NS_PER_S - aStartTime;
// If this range extends to the end of the file, the true end time
// is the file's duration.
if (resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
uint64_t duration = 0;
if (nestegg_duration(mContext, &duration) == 0) {
endTime = duration / NS_PER_S;
}
}
aBuffered->Add(startTime, endTime);
}
} }
} }

View file

@ -67,17 +67,17 @@ BrowserElementParent.prototype = {
} }
}, },
_observeInProcessBrowserFrameShown: function(frameLoader, data) { _observeInProcessBrowserFrameShown: function(frameLoader) {
debug("In-process browser frame shown " + frameLoader); debug("In-process browser frame shown " + frameLoader);
this._setUpMessageManagerListeners(frameLoader, data); this._setUpMessageManagerListeners(frameLoader);
}, },
_observeRemoteBrowserFrameShown: function(frameLoader, data) { _observeRemoteBrowserFrameShown: function(frameLoader) {
debug("Remote browser frame shown " + frameLoader); debug("Remote browser frame shown " + frameLoader);
this._setUpMessageManagerListeners(frameLoader, data); this._setUpMessageManagerListeners(frameLoader);
}, },
_setUpMessageManagerListeners: function(frameLoader, data) { _setUpMessageManagerListeners: function(frameLoader) {
let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement; let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
if (!frameElement) { if (!frameElement) {
debug("No frame element?"); debug("No frame element?");
@ -150,10 +150,10 @@ BrowserElementParent.prototype = {
} }
break; break;
case 'remote-browser-frame-shown': case 'remote-browser-frame-shown':
this._observeRemoteBrowserFrameShown(subject, data); this._observeRemoteBrowserFrameShown(subject);
break; break;
case 'in-process-browser-frame-shown': case 'in-process-browser-frame-shown':
this._observeInProcessBrowserFrameShown(subject, data); this._observeInProcessBrowserFrameShown(subject);
break; break;
case 'content-document-global-created': case 'content-document-global-created':
this._observeContentGlobalCreated(subject); this._observeContentGlobalCreated(subject);

View file

@ -5877,7 +5877,7 @@ DefineIDBInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
return NS_OK; return NS_OK;
} }
class nsDOMConstructor : public nsIDOMDOMConstructor class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor
{ {
protected: protected:
nsDOMConstructor(const PRUnichar* aName, nsDOMConstructor(const PRUnichar* aName,

View file

@ -5328,12 +5328,7 @@ nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
if (aYScroll > maxpx) { if (aYScroll > maxpx) {
aYScroll = maxpx; aYScroll = maxpx;
} }
nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aXScroll), sf->ScrollToCSSPixels(nsIntPoint(aXScroll, aYScroll));
nsPresContext::CSSPixelsToAppUnits(aYScroll));
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
// Don't allow pt.x/y + halfPixel since that would round up to the next CSS pixel.
nsRect range(pt.x - halfPixel, pt.y - halfPixel, halfPixel*2 - 1, halfPixel*2 - 1);
sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
} }
return NS_OK; return NS_OK;

View file

@ -138,18 +138,25 @@ inline bool
IsArrayLike(JSContext* cx, JSObject* obj) IsArrayLike(JSContext* cx, JSObject* obj)
{ {
MOZ_ASSERT(obj); MOZ_ASSERT(obj);
// For simplicity, check for security wrappers up front // For simplicity, check for security wrappers up front. In case we
// have a security wrapper, don't forget to enter the compartment of
// the underlying object after unwrapping.
JSAutoEnterCompartment ac;
if (js::IsWrapper(obj)) { if (js::IsWrapper(obj)) {
obj = XPCWrapper::Unwrap(cx, obj, false); obj = XPCWrapper::Unwrap(cx, obj, false);
if (!obj) { if (!obj) {
// Let's say it's not // Let's say it's not
return false; return false;
} }
if (!ac.enter(cx, obj)) {
return false;
}
} }
// XXXbz need to detect platform objects (including listbinding // XXXbz need to detect platform objects (including listbinding
// ones) with indexGetters here! // ones) with indexGetters here!
return JS_IsArrayObject(cx, obj); return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj, cx);
} }
inline bool inline bool
@ -582,6 +589,84 @@ ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
JSBool JSBool
ThrowingConstructorWorkers(JSContext* cx, unsigned argc, JS::Value* vp); ThrowingConstructorWorkers(JSContext* cx, unsigned argc, JS::Value* vp);
template<class T>
class NonNull
{
public:
NonNull()
#ifdef DEBUG
: inited(false)
#endif
{}
operator T&() {
MOZ_ASSERT(inited);
MOZ_ASSERT(ptr, "NonNull<T> was set to null");
return *ptr;
}
void operator=(T* t) {
ptr = t;
MOZ_ASSERT(ptr);
#ifdef DEBUG
inited = true;
#endif
}
T** Slot() {
#ifdef DEBUG
inited = true;
#endif
return &ptr;
}
protected:
T* ptr;
#ifdef DEBUG
bool inited;
#endif
};
template<class T>
class OwningNonNull
{
public:
OwningNonNull()
#ifdef DEBUG
: inited(false)
#endif
{}
operator T&() {
MOZ_ASSERT(inited);
MOZ_ASSERT(ptr, "OwningNonNull<T> was set to null");
return *ptr;
}
void operator=(T* t) {
init(t);
}
void operator=(const already_AddRefed<T>& t) {
init(t);
}
protected:
template<typename U>
void init(U t) {
ptr = t;
MOZ_ASSERT(ptr);
#ifdef DEBUG
inited = true;
#endif
}
nsRefPtr<T> ptr;
#ifdef DEBUG
bool inited;
#endif
};
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View file

@ -1115,12 +1115,12 @@ class CastableObjectUnwrapper():
def __str__(self): def __str__(self):
return string.Template( return string.Template(
""" { """{
nsresult rv = UnwrapObject<${protoID}>(cx, ${source}, &${target}); nsresult rv = UnwrapObject<${protoID}>(cx, ${source}, ${target});
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
${codeOnFailure} ${codeOnFailure}
} }
}""").substitute(self.substitution) }""").substitute(self.substitution)
class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper): class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
""" """
@ -1150,128 +1150,300 @@ class CallbackObjectUnwrapper:
def __str__(self): def __str__(self):
if self.descriptor.workers: if self.descriptor.workers:
return string.Template(""" return string.Template(
${target} = ${source};""").substitute(self.substitution) "${target} = ${source};"
).substitute(self.substitution)
return string.Template(""" return string.Template(
nsresult rv; """nsresult rv;
XPCCallContext ccx(JS_CALLER, cx); XPCCallContext ccx(JS_CALLER, cx);
if (!ccx.IsValid()) { if (!ccx.IsValid()) {
rv = NS_ERROR_XPC_BAD_CONVERT_JS; rv = NS_ERROR_XPC_BAD_CONVERT_JS;
${codeOnFailure} ${codeOnFailure}
} }
const nsIID& iid = NS_GET_IID(${nativeType}); const nsIID& iid = NS_GET_IID(${nativeType});
nsRefPtr<nsXPCWrappedJS> wrappedJS; nsRefPtr<nsXPCWrappedJS> wrappedJS;
rv = nsXPCWrappedJS::GetNewOrUsed(ccx, ${source}, iid, rv = nsXPCWrappedJS::GetNewOrUsed(ccx, ${source}, iid,
NULL, getter_AddRefs(wrappedJS)); NULL, getter_AddRefs(wrappedJS));
if (NS_FAILED(rv) || !wrappedJS) { if (NS_FAILED(rv) || !wrappedJS) {
${codeOnFailure} ${codeOnFailure}
} }
${target} = do_QueryObject(wrappedJS.get()); // Use a temp nsCOMPtr for the null-check, because ${target} might be
if (!${target}) { // OwningNonNull, not an nsCOMPtr.
${codeOnFailure} nsCOMPtr<${nativeType}> tmp = do_QueryObject(wrappedJS.get());
}""").substitute(self.substitution) if (!tmp) {
${codeOnFailure}
}
${target} = tmp.forget();""").substitute(self.substitution)
def getArgumentConversionTemplate(type, descriptor): def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
if type.isSequence() or type.isArray(): isDefinitelyObject=False,
raise TypeError("Can't handle sequence or array arguments yet") isSequenceMember=False):
"""
Get a template for converting a JS value to a native object based on the
given type and descriptor. If failureCode is given, then we're actually
testing whether we can convert the argument to the desired type. That
means that failures to convert due to the JS value being the wrong type of
value need to use failureCode instead of throwing exceptions. Failures to
convert that are due to JS exceptions (from toString or valueOf methods) or
out of memory conditions need to throw exceptions no matter what
failureCode is.
if descriptor is not None: If isDefinitelyObject is True, that means we know the value
assert(type.isInterface()) isObject() and we have no need to recheck that.
The return value from this function is a tuple consisting of three things:
1) A string representing the conversion code. This will have template
substitution performed on it as follows:
${val} replaced by an expression for the JS::Value in question
${valPtr} is a pointer to the JS::Value in question
${holderName} replaced by the holder's name, if any
${declName} replaced by the declaration's name
2) A CGThing representing the native C++ type we're converting to
(declType). This is allowed to be None if the conversion code is
supposed to be used as-is.
3) A CGThing representing the type of a "holder" (holderType) which will
hold a possible reference to the C++ thing whose type we returned in #1,
or None if no such holder is needed.
${declName} must be in scope before the generated code is entered.
If holderType is not None then ${holderName} must be in scope
before the generated code is entered.
"""
# A helper function for wrapping up the template body for
# possibly-nullable objecty stuff
def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
codeToSetNull, isWorker):
if not isDefinitelyObject:
# Handle the non-object cases by wrapping up the whole
# thing in an if cascade.
templateBody = (
"if (${val}.isObject()) {\n" +
CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable():
templateBody += (
"} else if (${val}.isNullOrUndefined()) {\n"
" %s;\n" % codeToSetNull)
templateBody += (
"} else {\n"
" return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
"}" % toStringBool(not isWorker))
return templateBody
if type.isArray():
raise TypeError("Can't handle array arguments yet")
if type.isSequence():
if isSequenceMember:
raise TypeError("Can't handle sequences of sequences")
if failureCode is not None:
raise TypeError("Can't handle sequences when failureCode is not None")
nullable = type.nullable();
if nullable:
type = type.inner;
elementType = type.inner;
# We don't know anything about the object-ness of the things
# we wrap, so don't pass through isDefinitelyObject
(elementTemplate, elementDeclType,
elementHolderType) = getJSToNativeConversionTemplate(
elementType, descriptorProvider, isSequenceMember=True)
if elementHolderType is not None:
raise TypeError("Shouldn't need holders for sequences")
# Have to make sure to use a fallible array, because it's trivial for
# page JS to create things with very large lengths.
typeName = CGWrapper(elementDeclType, pre="nsTArray< ", post=" >")
if nullable:
typeName = CGWrapper(typeName, pre="Nullable< ", post=" >")
templateBody = ("""JSObject* seq = &${val}.toObject();\n
if (!IsArrayLike(cx, seq)) {
return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
}
uint32_t length;
// JS_GetArrayLength actually works on all objects
if (!JS_GetArrayLength(cx, seq, &length)) {
return false;
}
// Jump through a hoop to do a fallible allocation but later end up with
// an infallible array.
FallibleTArray< %s > arr;
if (!arr.SetCapacity(length)) {
return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY);
}
for (uint32_t i = 0; i < length; ++i) {
jsval temp;
if (!JS_GetElement(cx, seq, i, &temp)) {
return false;
}
""" % (toStringBool(descriptorProvider.workers),
elementDeclType.define(),
toStringBool(descriptorProvider.workers)))
templateBody += CGIndenter(CGGeneric(
string.Template(elementTemplate).substitute(
{
"val" : "temp",
"declName" : "*arr.AppendElement()"
}
))).define()
templateBody += """
}
// And the other half of the hoop-jump"""
if nullable:
templateBody += """
${declName}.SetValue().SwapElements(arr);
"""
else:
templateBody += """
${declName}.SwapElements(arr);
"""
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
type, "${declName}.SetNull()",
descriptorProvider.workers)
return (templateBody, typeName, None)
if type.isInterface() and not type.isArrayBuffer():
descriptor = descriptorProvider.getDescriptor(
type.unroll().inner.identifier.name)
# This is an interface that we implement as a concrete class # This is an interface that we implement as a concrete class
# or an XPCOM interface. # or an XPCOM interface.
# Allow null pointers for nullable types and old-binding classes
argIsPointer = type.nullable() or type.unroll().inner.isExternal() argIsPointer = type.nullable() or type.unroll().inner.isExternal()
# Sequences and non-worker callbacks have to hold a strong ref to the
# thing being passed down.
forceOwningType = (descriptor.interface.isCallback() and
not descriptor.workers) or isSequenceMember
typeName = descriptor.nativeType
typePtr = typeName + "*"
# Compute a few things:
# - declType is the type we want to return as the first element of our
# tuple.
# - holderType is the type we want to return as the third element
# of our tuple.
# - declInit is the initializer expression for our decl, if any.
# - target is where a pointer to the object is being stored
# Set up some sensible defaults for these things insofar as we can.
holderType = None
if argIsPointer: if argIsPointer:
nameSuffix = "" if forceOwningType:
declType = "nsRefPtr<" + typeName + ">"
else:
declType = typePtr
target = "&${declName}"
else: else:
nameSuffix = "_ptr" if forceOwningType:
declType = "OwningNonNull<" + typeName + ">"
else:
declType = "NonNull<" + typeName + ">"
target = "${declName}.Slot()"
# If we're going to QI, we want an nsCOMPtr. But note that XPConnect templateBody = ""
# unwrapping may or may not QI, and we don't know whether it will. So
# we use a raw pointer for the isExternal() case, and if a ref is needed
# it'll be handled by the xpc_qsSelfRef we put on the stack later.
if descriptor.castable or type.unroll().inner.isExternal() or descriptor.workers:
declType = " ${typeName}*"
else:
declType = " nsCOMPtr<${typeName}>"
template = declType + " ${name}%s;\n" % nameSuffix
# We have to be very careful here to put anything that might need to
# hold references across the C++ call in |template| and not
# |templateBody|, since things in |templateBody| will go out of scope
# before the call happens.
templateBody = " if (${argVal}.isObject()) {"
if descriptor.castable: if descriptor.castable:
templateBody += str(FailureFatalCastableObjectUnwrapper( if failureCode is not None:
descriptor, templateBody += str(CastableObjectUnwrapper(
"&${argVal}.toObject()", descriptor,
"${name}"+nameSuffix)).replace("\n", "\n ") + "\n" "&${val}.toObject()",
target,
failureCode))
else:
templateBody += str(FailureFatalCastableObjectUnwrapper(
descriptor,
"&${val}.toObject()",
target))
elif descriptor.interface.isCallback(): elif descriptor.interface.isCallback():
templateBody += str(CallbackObjectUnwrapper( templateBody += str(CallbackObjectUnwrapper(
descriptor, descriptor,
"&${argVal}.toObject()", "&${val}.toObject()",
"${name}"+nameSuffix)) + "\n" "${declName}",
codeOnFailure=failureCode))
elif descriptor.workers: elif descriptor.workers:
templateBody += """ templateBody += "${declName} = &${val}.toObject();"
${name}%s = &${argVal}.toObject();
MOZ_ASSERT(${name}%s);
""" % (nameSuffix, nameSuffix)
else: else:
template += " xpc_qsSelfRef tmpRef_${name};\n" # Either external, or new-binding non-castable. We always have a
template += " jsval tmpVal_${name} = ${argVal};\n" # holder for these, because we don't actually know whether we have
templateBody += """ # to addref when unwrapping or not. So we just pass an
${typeName}* tmp; # getter_AddRefs(nsCOMPtr) to XPConnect and if we'll need a release
if (NS_FAILED(xpc_qsUnwrapArg<${typeName}>(cx, ${argVal}, &tmp, &tmpRef_${name}.ptr, # it'll put a non-null pointer in there.
&tmpVal_${name}))) { if forceOwningType:
return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); # Don't return a holderType in this case; our declName
} # will just own stuff.
MOZ_ASSERT(tmp); templateBody += "nsCOMPtr<" + typeName + "> ${holderName};"
${name}%s = tmp; else:
""" % (toStringBool(not descriptor.workers), nameSuffix) holderType = "nsCOMPtr<" + typeName + ">"
if type.nullable():
templateBody += ( templateBody += (
" } else if (${argVal}.isNullOrUndefined()) {\n" "jsval tmpVal = ${val};\n" +
" ${name}%s = NULL;\n" % nameSuffix) typePtr + " tmp;\n"
"if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, getter_AddRefs(${holderName}), &tmpVal))) {\n")
if failureCode is not None:
templateBody += " " + failureCode + "\n"
else:
templateBody += (
" return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
% toStringBool(not descriptor.workers))
templateBody += ("}\n"
"MOZ_ASSERT(tmp);\n")
templateBody += ( if not isDefinitelyObject:
" } else {\n" # Our tmpVal will go out of scope, so we can't rely on it
" return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n" # for rooting
" }\n" % toStringBool(not descriptor.workers)) templateBody += (
"if (tmpVal != ${val} && !${holderName}) {\n"
" // We have to have a strong ref, because we got this off\n"
" // some random object that might get GCed\n"
" ${holderName} = tmp;\n"
"}\n")
template += templateBody # And store our tmp, before it goes out of scope.
templateBody += "${declName} = tmp;"
if not argIsPointer: templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
template += " ${typeName} &${name} = *${name}_ptr;\n" type, "${declName} = NULL",
descriptor.workers)
return template declType = CGGeneric(declType)
if holderType is not None:
holderType = CGGeneric(holderType)
return (templateBody, declType, holderType)
if type.isArrayBuffer(): if type.isArrayBuffer():
if isSequenceMember:
raise TypeError("Can't handle sequences of arraybuffers")
declType = "JSObject*"
template = ( template = (
" JSObject* ${name};\n" "if (${val}.isObject() && JS_IsArrayBufferObject(&${val}.toObject(), cx)) {\n"
" if (${argVal}.isObject() && JS_IsArrayBufferObject(&${argVal}.toObject(), cx)) {\n" " ${declName} = &${val}.toObject();\n"
" ${name} = &${argVal}.toObject();\n" "}")
" }")
if type.nullable(): if type.nullable():
template += ( template += (
" else if (${argVal}.isNullOrUndefined()) {\n" " else if (${val}.isNullOrUndefined()) {\n"
" ${name} = NULL;\n" " ${declName} = NULL;\n"
" }") "}")
template += ( template += (
# XXXbz We don't know whether we're on workers, so play it safe # XXXbz We don't know whether we're on workers, so play it safe
" else {\n" " else {\n"
" return Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n" " return Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
" }") "}")
return template return (template, CGGeneric(declType), None)
if type.isInterface():
raise TypeError("Interface type with no descriptor: " + type)
if type.isString(): if type.isString():
if isSequenceMember:
raise TypeError("Can't handle sequences of strings")
# XXXbz Need to figure out string behavior based on extended args? Also, how to # XXXbz Need to figure out string behavior based on extended args? Also, how to
# detect them? # detect them?
@ -1285,12 +1457,12 @@ def getArgumentConversionTemplate(type, descriptor):
undefinedBehavior = "eStringify" undefinedBehavior = "eStringify"
return ( return (
" const xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr},\n" "const xpc_qsDOMString ${declName}(cx, ${val}, ${valPtr},\n"
" xpc_qsDOMString::%s,\n" " xpc_qsDOMString::%s,\n"
" xpc_qsDOMString::%s);\n" " xpc_qsDOMString::%s);\n"
" if (!${name}.IsValid()) {\n" "if (!${declName}.IsValid()) {\n"
" return false;\n" " return false;\n"
" }\n" % (nullBehavior, undefinedBehavior)) "}" % (nullBehavior, undefinedBehavior), None, None)
if type.isEnum(): if type.isEnum():
if type.nullable(): if type.nullable():
@ -1298,46 +1470,74 @@ def getArgumentConversionTemplate(type, descriptor):
"yet") "yet")
enum = type.inner.identifier.name enum = type.inner.identifier.name
return ( return (
" %(enumtype)s ${name};\n" "{\n"
" {\n" " bool ok;\n"
" bool ok;\n" " ${declName} = static_cast<%(enumtype)s>(FindEnumStringIndex(cx, ${val}, %(values)s, &ok));\n"
" ${name} = static_cast<%(enumtype)s>(FindEnumStringIndex(cx, ${argVal}, %(values)s, &ok));\n" " if (!ok) {\n"
" if (!ok) {\n" " return false;\n"
" return false;\n" " }\n"
" }\n" "}" % { "enumtype" : enum,
" }" % { "enumtype" : enum, "values" : enum + "Values::strings" },
"values" : enum + "Values::strings" }) CGGeneric(enum), None)
if type.isCallback(): if type.isCallback():
if isSequenceMember:
raise TypeError("Can't handle sequences of callbacks")
# XXXbz we're going to assume that callback types are always # XXXbz we're going to assume that callback types are always
# nullable and always have [TreatNonCallableAsNull] for now. # nullable and always have [TreatNonCallableAsNull] for now.
return ( return (
" JSObject* ${name};\n" "if (${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())) {\n"
" if (${argVal}.isObject() && JS_ObjectIsCallable(cx, &${argVal}.toObject())) {\n" " ${declName} = &${val}.toObject();\n"
" ${name} = &${argVal}.toObject();\n" "} else {\n"
" } else {\n" " ${declName} = NULL;\n"
" ${name} = NULL;\n" "}", CGGeneric("JSObject*"), None)
" }\n")
if type.isAny(): if type.isAny():
return " JS::Value ${name} = ${argVal};\n" if isSequenceMember:
raise TypeError("Can't handle sequences of 'any'")
return ("${declName} = ${val};", CGGeneric("JS::Value"), None)
if not type.isPrimitive(): if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % type) raise TypeError("Need conversion for argument type '%s'" % type)
# XXXbz need to add support for [EnforceRange] and [Clamp] # XXXbz need to add support for [EnforceRange] and [Clamp]
typeName = builtinNames[type.tag()]
if type.nullable(): if type.nullable():
return (" Nullable<${typeName}> ${name};\n" return ("if (${val}.isNullOrUndefined()) {\n"
" if (${argVal}.isNullOrUndefined()) {\n" " ${declName}.SetNull();\n"
" ${name}.SetNull();\n" "} else if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName}.SetValue())) {\n"
" } else if (!ValueToPrimitive<${typeName}>(cx, ${argVal}, &${name}.SetValue())) {\n" " return false;\n"
" return false;\n" "}", CGGeneric("Nullable<" + typeName + ">"), None)
" }\n")
else: else:
return (" ${typeName} ${name};\n" return ("if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName})) {\n"
" if (!ValueToPrimitive<${typeName}>(cx, ${argVal}, &${name})) {\n" " return false;\n"
" return false;\n" "}", CGGeneric(typeName), None)
" }\n")
def instantiateJSToNativeConversionTemplate(templateTuple, replacements):
"""
Take a tuple as returned by getJSToNativeConversionTemplate and a set of
replacements as required by the strings in such a tuple, and generate code
to convert into stack C++ types.
"""
(templateBody, declType, holderType) = templateTuple
result = CGList([], "\n")
if holderType is not None:
result.append(
CGList([holderType, CGGeneric(" "),
CGGeneric(replacements["holderName"]),
CGGeneric(";")]))
if declType is not None:
result.append(
CGList([declType, CGGeneric(" "),
CGGeneric(replacements["declName"]),
CGGeneric(";")]))
result.append(CGGeneric(
string.Template(templateBody).substitute(replacements)
))
# Add an empty CGGeneric to get an extra newline after the argument
# conversion.
result.append(CGGeneric(""))
return result;
def convertConstIDLValueToJSVal(value): def convertConstIDLValueToJSVal(value):
if isinstance(value, IDLNullValue): if isinstance(value, IDLNullValue):
@ -1363,7 +1563,6 @@ def convertIDLDefaultValueToJSVal(value):
assert False # Not implemented! assert False # Not implemented!
return convertConstIDLValueToJSVal(value) return convertConstIDLValueToJSVal(value)
unindenter = re.compile("^ ", re.MULTILINE)
class CGArgumentConverter(CGThing): class CGArgumentConverter(CGThing):
""" """
A class that takes an IDL argument object, its index in the A class that takes an IDL argument object, its index in the
@ -1375,44 +1574,38 @@ class CGArgumentConverter(CGThing):
self.argument = argument self.argument = argument
# XXXbz should optional jsval args get JSVAL_VOID? What about # XXXbz should optional jsval args get JSVAL_VOID? What about
# others? # others?
self.replacementVariables = { replacer = {
"index" : index, "index" : index,
"argc" : argc, "argc" : argc,
"argv" : argv, "argv" : argv,
"defaultValue" : "JSVAL_VOID", "defaultValue" : "JSVAL_VOID"
"name" : "arg%d" % index }
self.replacementVariables = {
"declName" : "arg%d" % index,
"holderName" : ("arg%d" % index) + "_holder"
} }
if argument.optional: if argument.optional:
if argument.defaultValue: if argument.defaultValue:
self.replacementVariables["defaultValue"] = convertIDLDefaultValueToJSVal(argument.defaultValue) replacer["defaultValue"] = convertIDLDefaultValueToJSVal(argument.defaultValue)
self.replacementVariables["argVal"] = string.Template( self.replacementVariables["val"] = string.Template(
"(${index} < ${argc} ? ${argv}[${index}] : ${defaultValue})" "(${index} < ${argc} ? ${argv}[${index}] : ${defaultValue})"
).substitute(self.replacementVariables) ).substitute(replacer)
self.replacementVariables["argPtr"] = string.Template( self.replacementVariables["valPtr"] = string.Template(
"(${index} < ${argc} ? &${argv}[${index}] : NULL)" "(${index} < ${argc} ? &${argv}[${index}] : NULL)"
).substitute(self.replacementVariables) ).substitute(replacer)
else: else:
self.replacementVariables["argVal"] = string.Template( self.replacementVariables["val"] = string.Template(
"${argv}[${index}]" "${argv}[${index}]"
).substitute(self.replacementVariables) ).substitute(replacer)
self.replacementVariables["argPtr"] = ( self.replacementVariables["valPtr"] = (
"&" + self.replacementVariables["argVal"]) "&" + self.replacementVariables["val"])
self.descriptor = None self.descriptorProvider = descriptorProvider
if argument.type.isPrimitive():
self.replacementVariables["typeName"] = builtinNames[argument.type.tag()]
elif argument.type.isInterface() and not argument.type.isArrayBuffer():
descriptor = descriptorProvider.getDescriptor(
argument.type.unroll().inner.identifier.name)
self.descriptor = descriptor
self.replacementVariables["typeName"] = descriptor.nativeType
def define(self): def define(self):
return string.Template( return instantiateJSToNativeConversionTemplate(
re.sub(unindenter, getJSToNativeConversionTemplate(self.argument.type,
"", self.descriptorProvider),
getArgumentConversionTemplate(self.argument.type, self.replacementVariables).define()
self.descriptor))
).substitute(self.replacementVariables)
def getWrapTemplateForType(type, descriptorProvider, result, successCode): def getWrapTemplateForType(type, descriptorProvider, result, successCode):
""" """
@ -1460,8 +1653,45 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode):
if type is None or type.isVoid(): if type is None or type.isVoid():
return setValue("JSVAL_VOID") return setValue("JSVAL_VOID")
if type.isSequence() or type.isArray(): if type.isArray():
raise TypeError("Can't handle sequence or array return values yet") raise TypeError("Can't handle array return values yet")
if type.isSequence():
if type.nullable():
# Nullable sequences are Nullable< nsTArray<T> >
return """
if (%s.IsNull()) {
%s
}
%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(),
getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode))
# Now do non-nullable sequences. We use setting the element
# in the array as our succcess code because when we succeed in
# wrapping that's what we should do.
innerTemplate = wrapForType(
type.inner, descriptorProvider,
{
'result' : "%s[i]" % result,
'successCode': ("if (!JS_SetElement(cx, returnArray, i, &tmp)) {\n"
" return false;\n"
"}"),
'jsvalRef': "tmp",
'jsvalPtr': "&tmp"
}
)
innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define()
return ("""
uint32_t length = %s.Length();
JSObject *returnArray = JS_NewArrayObject(cx, length, NULL);
if (!returnArray) {
return false;
}
jsval tmp;
for (uint32_t i = 0; i < length; ++i) {
%s
}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)")
if type.isInterface() and not type.isArrayBuffer(): if type.isInterface() and not type.isArrayBuffer():
descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name) descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
@ -1582,6 +1812,51 @@ def wrapForType(type, descriptorProvider, templateValues):
defaultValues = {'obj': 'obj'} defaultValues = {'obj': 'obj'}
return string.Template(wrap).substitute(defaultValues, **templateValues) return string.Template(wrap).substitute(defaultValues, **templateValues)
def getRetvalDeclarationForType(returnType, descriptorProvider,
resultAlreadyAddRefed):
if returnType is None or returnType.isVoid():
# Nothing to declare
result = None
elif returnType.isPrimitive() and returnType.tag() in builtinNames:
result = CGGeneric(builtinNames[returnType.tag()])
if returnType.nullable():
result = CGWrapper(result, pre="Nullable<", post=">")
elif returnType.isString():
result = CGGeneric("nsString")
elif returnType.isEnum():
if returnType.nullable():
raise TypeError("We don't support nullable enum return values")
result = CGGeneric(returnType.inner.identifier.name)
elif returnType.isInterface() and not returnType.isArrayBuffer():
result = CGGeneric(descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType)
if resultAlreadyAddRefed:
result = CGWrapper(result, pre="nsRefPtr<", post=">")
else:
result = CGWrapper(result, post="*")
elif returnType.isCallback():
# XXXbz we're going to assume that callback types are always
# nullable for now.
result = CGGeneric("JSObject*")
elif returnType.tag() is IDLType.Tags.any:
result = CGGeneric("JS::Value")
elif returnType.isSequence():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
# Assume no need to addref for now
result = CGWrapper(getRetvalDeclarationForType(returnType.inner,
descriptorProvider,
False),
pre="nsTArray< ", post=" >")
if nullable:
result = CGWrapper(result, pre="Nullable< ", post=" >")
else:
raise TypeError("Don't know how to declare return value for %s" %
returnType)
return result
class CGCallGenerator(CGThing): class CGCallGenerator(CGThing):
""" """
A class to generate an actual call to a C++ object. Assumes that the C++ A class to generate an actual call to a C++ object. Assumes that the C++
@ -1594,42 +1869,16 @@ class CGCallGenerator(CGThing):
isFallible = errorReport is not None isFallible = errorReport is not None
args = CGList([CGGeneric("arg" + str(i)) for i in range(argCount)], ", ") args = CGList([CGGeneric("arg" + str(i)) for i in range(argCount)], ", ")
resultOutParam = returnType is not None and returnType.isString() resultOutParam = (returnType is not None and
(returnType.isString() or returnType.isSequence()))
# Return values that go in outparams go here # Return values that go in outparams go here
if resultOutParam: if resultOutParam:
args.append(CGGeneric("result")) args.append(CGGeneric("result"))
if isFallible: if isFallible:
args.append(CGGeneric("rv")) args.append(CGGeneric("rv"))
if returnType is None or returnType.isVoid(): result = getRetvalDeclarationForType(returnType, descriptorProvider,
# Nothing to declare resultAlreadyAddRefed)
result = None
elif returnType.isPrimitive() and returnType.tag() in builtinNames:
result = CGGeneric(builtinNames[returnType.tag()])
if returnType.nullable():
result = CGWrapper(result, pre="Nullable<", post=">")
elif returnType.isString():
result = CGGeneric("nsString")
elif returnType.isEnum():
if returnType.nullable():
raise TypeError("We don't support nullable enum return values")
result = CGGeneric(returnType.inner.identifier.name)
elif returnType.isInterface() and not returnType.isArrayBuffer():
result = CGGeneric(descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType)
if resultAlreadyAddRefed:
result = CGWrapper(result, pre="nsRefPtr<", post=">")
else:
result = CGWrapper(result, post="*")
elif returnType.isCallback():
# XXXbz we're going to assume that callback types are always
# nullable for now.
result = CGGeneric("JSObject*")
elif returnType.tag() is IDLType.Tags.any:
result = CGGeneric("JS::Value")
else:
raise TypeError("Don't know how to declare return value for %s" %
returnType)
# Build up our actual call # Build up our actual call
self.cgRoot = CGList([], "\n") self.cgRoot = CGList([], "\n")
@ -1958,63 +2207,24 @@ class CGMethodCall(CGThing):
caseBody.append(CGIndenter(CGGeneric("do {"))); caseBody.append(CGIndenter(CGGeneric("do {")));
type = sig[1][distinguishingIndex].type type = sig[1][distinguishingIndex].type
# XXXbz this duplicates some argument-unwrapping code! testCode = instantiateJSToNativeConversionTemplate(
interfaceDesc = descriptor.getDescriptor( getJSToNativeConversionTemplate(type, descriptor,
type.unroll().inner.identifier.name) failureCode="break;",
argIsPointer = (type.nullable() or isDefinitelyObject=True),
type.unroll().inner.isExternal())
if argIsPointer:
nameSuffix = ""
else:
nameSuffix = "_ptr"
if (interfaceDesc.castable or
type.unroll().inner.isExternal() or
interfaceDesc.workers):
declType = " ${typeName}*"
else:
declType = " nsCOMPtr<${typeName}>"
template = declType + " ${name}%s;\n" % nameSuffix
if interfaceDesc.castable:
template += str(CastableObjectUnwrapper(
interfaceDesc,
"&${argVal}.toObject()",
"${name}"+nameSuffix,
"break;")) + "\n"
elif interfaceDesc.workers:
template += """
${name}%s = &${argVal}.toObject();
MOZ_ASSERT(${name}%s);
""" % (nameSuffix, nameSuffix)
else:
template += " xpc_qsSelfRef tmpRef_${name};\n"
template += " jsval tmpVal_${name} = ${argVal};\n"
template += """
${typeName}* tmp;
if (NS_FAILED(xpc_qsUnwrapArg<${typeName}>(cx, ${argVal}, &tmp, &tmpRef_${name}.ptr,
&tmpVal_${name}))) {
break;
}
MOZ_ASSERT(tmp);
${name}%s = tmp;
""" % nameSuffix
if not argIsPointer:
template += " ${typeName} &${name} = *${name}_ptr;\n"
testCode = string.Template(template).substitute(
{ {
"typeName": interfaceDesc.nativeType, "declName" : "arg%d" % distinguishingIndex,
"name" : "arg%d" % distinguishingIndex, "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
"argVal" : distinguishingArg "val" : distinguishingArg
} })
)
caseBody.append(CGIndenter(CGGeneric(testCode))); # Indent by 4, since we need to indent further than our "do" statement
caseBody.append(CGIndenter(testCode, 4));
# If we got this far, we know we unwrapped to the right # If we got this far, we know we unwrapped to the right
# interface, so just do the call. Start conversion with # interface, so just do the call. Start conversion with
# distinguishingIndex + 1, since we already converted # distinguishingIndex + 1, since we already converted
# distinguishingIndex. # distinguishingIndex.
caseBody.append(CGIndenter(CGIndenter( caseBody.append(CGIndenter(
getPerSignatureCall(sig, distinguishingIndex + 1)))) getPerSignatureCall(sig, distinguishingIndex + 1), 4))
caseBody.append(CGIndenter(CGGeneric("} while (0);"))) caseBody.append(CGIndenter(CGGeneric("} while (0);")))
caseBody.append(CGGeneric("}")) caseBody.append(CGGeneric("}"))
@ -2022,7 +2232,7 @@ class CGMethodCall(CGThing):
# XXXbz Now we're supposed to check for distinguishingArg being # XXXbz Now we're supposed to check for distinguishingArg being
# an array or a platform object that supports indexed # an array or a platform object that supports indexed
# properties... skip that last for now. It's a bit of a pain. # properties... skip that last for now. It's a bit of a pain.
pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject()" % pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" %
(distinguishingArg, distinguishingArg), (distinguishingArg, distinguishingArg),
lambda s: lambda s:
(s[1][distinguishingIndex].type.isArray() or (s[1][distinguishingIndex].type.isArray() or
@ -2168,8 +2378,9 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args) CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
def definition_body(self): def definition_body(self):
unwrapThis = CGGeneric( unwrapThis = CGIndenter(CGGeneric(
str(FailureFatalCastableObjectUnwrapper(self.descriptor, "obj", "self"))) str(FailureFatalCastableObjectUnwrapper(self.descriptor,
"obj", "&self"))))
return CGList([ self.getThis(), unwrapThis, return CGList([ self.getThis(), unwrapThis,
self.generate_code() ], "\n").define() self.generate_code() ], "\n").define()

View file

@ -47,6 +47,10 @@ public:
private: private:
nsresult mResult; nsresult mResult;
// Not to be implemented, to make sure people always pass this by
// reference, not by value.
ErrorResult(const ErrorResult&) MOZ_DELETE;
}; };
} // namespace mozilla } // namespace mozilla

View file

@ -52,6 +52,11 @@ public:
return mValue; return mValue;
} }
T& Value() {
MOZ_ASSERT(!mIsNull);
return mValue;
}
bool IsNull() const { bool IsNull() const {
return mIsNull; return mIsNull;
} }

View file

@ -814,10 +814,10 @@ class IDLSequenceType(IDLType):
return False return False
def isPrimitive(self): def isPrimitive(self):
return self.inner.isPrimitive() return False;
def isString(self): def isString(self):
return self.inner.isString() return False;
def isVoid(self): def isVoid(self):
return False return False

View file

@ -104,16 +104,16 @@ class ToggleBtTask : public nsRunnable
} }
// return 1 if it's enabled, 0 if it's disabled, and -1 on error // return 1 if it's enabled, 0 if it's disabled, and -1 on error
int isEnabled = sBluedroidFunctions.bt_is_enabled(); int isEnabled = IsBluetoothEnabled();
if ((isEnabled == 1 && mEnabled) || (isEnabled == 0 && !mEnabled)) { if ((isEnabled == 1 && mEnabled) || (isEnabled == 0 && !mEnabled)) {
result = true; result = true;
} else if (isEnabled < 0) { } else if (isEnabled < 0) {
result = false; result = false;
} else if (mEnabled) { } else if (mEnabled) {
result = (sBluedroidFunctions.bt_enable() == 0) ? true : false; result = (EnableBluetooth() == 0) ? true : false;
} else { } else {
result = (sBluedroidFunctions.bt_disable() == 0) ? true : false; result = (DisableBluetooth() == 0) ? true : false;
} }
#else #else
result = true; result = true;

View file

@ -14,6 +14,21 @@ namespace mozilla {
namespace dom { namespace dom {
namespace bluetooth { namespace bluetooth {
static struct BluedroidFunctions {
bool initialized;
bool tried_initialization;
BluedroidFunctions() :
initialized(false),
tried_initialization(false)
{
}
int (* bt_enable)();
int (* bt_disable)();
int (* bt_is_enabled)();
} sBluedroidFunctions;
bool EnsureBluetoothInit() { bool EnsureBluetoothInit() {
if (sBluedroidFunctions.tried_initialization) if (sBluedroidFunctions.tried_initialization)
{ {
@ -49,6 +64,22 @@ bool EnsureBluetoothInit() {
return true; return true;
} }
int IsBluetoothEnabled()
{
return sBluedroidFunctions.bt_is_enabled();
}
int EnableBluetooth()
{
return sBluedroidFunctions.bt_enable();
}
int DisableBluetooth()
{
return sBluedroidFunctions.bt_disable();
}
} }
} }
} }

View file

@ -11,22 +11,11 @@ namespace mozilla {
namespace dom { namespace dom {
namespace bluetooth { namespace bluetooth {
static struct BluedroidFunctions {
bool initialized;
bool tried_initialization;
BluedroidFunctions() :
initialized(false),
tried_initialization(false)
{
}
int (* bt_enable)();
int (* bt_disable)();
int (* bt_is_enabled)();
} sBluedroidFunctions;
bool EnsureBluetoothInit(); bool EnsureBluetoothInit();
int IsBluetoothEnabled();
int EnableBluetooth();
int DisableBluetooth();
} }
} }
} }

View file

@ -52,9 +52,9 @@ class nsIThread;
BEGIN_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE
class CheckPermissionsHelper : public nsIRunnable, class CheckPermissionsHelper MOZ_FINAL : public nsIRunnable,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsIObserver public nsIObserver
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

View file

@ -55,9 +55,9 @@ class nsPIDOMWindow;
BEGIN_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE
class CheckQuotaHelper : public nsIRunnable, class CheckQuotaHelper MOZ_FINAL : public nsIRunnable,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsIObserver public nsIObserver
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

View file

@ -63,7 +63,7 @@ class ContinueObjectStoreHelper;
class ContinueIndexHelper; class ContinueIndexHelper;
class ContinueIndexObjectHelper; class ContinueIndexObjectHelper;
class IDBCursor : public nsIIDBCursorWithValue class IDBCursor MOZ_FINAL : public nsIIDBCursorWithValue
{ {
friend class ContinueHelper; friend class ContinueHelper;
friend class ContinueObjectStoreHelper; friend class ContinueObjectStoreHelper;

View file

@ -57,7 +57,7 @@ struct DatabaseInfo;
class IDBDatabase; class IDBDatabase;
struct ObjectStoreInfo; struct ObjectStoreInfo;
class IDBFactory : public nsIIDBFactory class IDBFactory MOZ_FINAL : public nsIIDBFactory
{ {
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray; typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;

View file

@ -55,7 +55,7 @@ class AsyncConnectionHelper;
class IDBObjectStore; class IDBObjectStore;
struct IndexInfo; struct IndexInfo;
class IDBIndex : public nsIIDBIndex class IDBIndex MOZ_FINAL : public nsIIDBIndex
{ {
public: public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View file

@ -51,7 +51,7 @@ class mozIStorageStatement;
BEGIN_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE
class IDBKeyRange : public nsIIDBKeyRange class IDBKeyRange MOZ_FINAL : public nsIIDBKeyRange
{ {
public: public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View file

@ -63,7 +63,7 @@ struct IndexUpdateInfo;
struct StructuredCloneReadInfo; struct StructuredCloneReadInfo;
struct StructuredCloneWriteInfo; struct StructuredCloneWriteInfo;
class IDBObjectStore : public nsIIDBObjectStore class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
{ {
public: public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View file

@ -219,7 +219,7 @@ private:
nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos; nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos;
}; };
class CommitHelper : public nsIRunnable class CommitHelper MOZ_FINAL : public nsIRunnable
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -263,7 +263,7 @@ private:
bool mAborted; bool mAborted;
}; };
class UpdateRefcountFunction : public mozIStorageFunction class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

View file

@ -125,7 +125,7 @@ GetBaseFilename(const nsAString& aFilename,
return true; return true;
} }
class QuotaCallback : public mozIStorageQuotaCallback class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

View file

@ -69,8 +69,8 @@ class AsyncConnectionHelper;
class CheckQuotaHelper; class CheckQuotaHelper;
class IndexedDatabaseManager : public nsIIndexedDatabaseManager, class IndexedDatabaseManager MOZ_FINAL : public nsIIndexedDatabaseManager,
public nsIObserver public nsIObserver
{ {
friend class IDBDatabase; friend class IDBDatabase;
@ -243,7 +243,7 @@ private:
// directory that contains them before dispatching itself back to the main // directory that contains them before dispatching itself back to the main
// thread. When back on the main thread the runnable will notify the // thread. When back on the main thread the runnable will notify the
// IndexedDatabaseManager that the job has been completed. // IndexedDatabaseManager that the job has been completed.
class OriginClearRunnable : public nsIRunnable class OriginClearRunnable MOZ_FINAL : public nsIRunnable
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -272,7 +272,7 @@ private:
// before dispatching itself back to the main thread. When on the main thread // before dispatching itself back to the main thread. When on the main thread
// the runnable will call the callback and then notify the // the runnable will call the callback and then notify the
// IndexedDatabaseManager that the job has been completed. // IndexedDatabaseManager that the job has been completed.
class AsyncUsageRunnable : public nsIRunnable class AsyncUsageRunnable MOZ_FINAL : public nsIRunnable
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -326,7 +326,7 @@ private:
// A callback runnable used by the TransactionPool when it's safe to proceed // A callback runnable used by the TransactionPool when it's safe to proceed
// with a SetVersion/DeleteDatabase/etc. // with a SetVersion/DeleteDatabase/etc.
class WaitForTransactionsToFinishRunnable : public nsIRunnable class WaitForTransactionsToFinishRunnable MOZ_FINAL : public nsIRunnable
{ {
public: public:
WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp) WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp)
@ -345,7 +345,7 @@ private:
SynchronizedOp* mOp; SynchronizedOp* mOp;
}; };
class AsyncDeleteFileRunnable : public nsIRunnable class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

View file

@ -853,7 +853,7 @@ UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
return NS_OK; return NS_OK;
} }
class CompressDataBlobsFunction : public mozIStorageFunction class CompressDataBlobsFunction MOZ_FINAL : public mozIStorageFunction
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -1095,7 +1095,7 @@ UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
return NS_OK; return NS_OK;
} }
class EncodeKeysFunction : public mozIStorageFunction class EncodeKeysFunction MOZ_FINAL : public mozIStorageFunction
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS

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