Merge m-c to b-i

This commit is contained in:
Phil Ringnalda 2013-09-18 23:31:20 -07:00
commit e5c7226e34
262 changed files with 4569 additions and 2113 deletions

View File

@ -300,47 +300,114 @@ nsAccessiblePivot::MoveNextByText(TextBoundaryType aBoundary, bool* aResult)
*aResult = false;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
HyperTextAccessible* text = mPosition->AsHyperText();
Accessible* oldPosition = mPosition;
while (!text) {
oldPosition = mPosition;
mPosition = mPosition->Parent();
text = mPosition->AsHyperText();
}
int32_t tempStart = mStartOffset, tempEnd = mEndOffset;
Accessible* tempPosition = mPosition;
Accessible* root = GetActiveRoot();
while (true) {
Accessible* curPosition = tempPosition;
HyperTextAccessible* text;
// Find the nearest text node using a preorder traversal starting from
// the current node.
if (!(text = tempPosition->AsHyperText())) {
text = SearchForText(tempPosition, false);
if (!text)
return NS_OK;
if (text != curPosition)
tempStart = tempEnd = -1;
tempPosition = text;
}
if (mEndOffset == -1)
mEndOffset = text != oldPosition ? text->GetChildOffset(oldPosition) : 0;
// If the search led to the parent of the node we started on (e.g. when
// starting on a text leaf), start the text movement from the end of that
// node, otherwise we just default to 0.
if (tempEnd == -1)
tempEnd = text == curPosition->Parent() ?
text->GetChildOffset(curPosition) : 0;
if (mEndOffset == text->CharacterCount())
// If there's no more text on the current node, try to find the next text
// node; if there isn't one, bail out.
if (tempEnd == text->CharacterCount()) {
if (tempPosition == root)
return NS_OK;
// If we're currently sitting on a link, try move to either the next
// sibling or the parent, whichever is closer to the current end
// offset. Otherwise, do a forward search for the next node to land on
// (we don't do this in the first case because we don't want to go to the
// subtree).
Accessible* sibling = tempPosition->NextSibling();
if (tempPosition->IsLink()) {
if (sibling && sibling->IsLink()) {
tempStart = tempEnd = -1;
tempPosition = sibling;
} else {
tempStart = tempPosition->StartOffset();
tempEnd = tempPosition->EndOffset();
tempPosition = tempPosition->Parent();
}
} else {
tempPosition = SearchForText(tempPosition, false);
if (!tempPosition)
return NS_OK;
tempStart = tempEnd = -1;
}
continue;
}
AccessibleTextBoundary startBoundary, endBoundary;
switch (aBoundary) {
case CHAR_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_CHAR;
endBoundary = nsIAccessibleText::BOUNDARY_CHAR;
break;
case WORD_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_WORD_START;
endBoundary = nsIAccessibleText::BOUNDARY_WORD_END;
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsAutoString unusedText;
int32_t newStart = 0, newEnd = 0, currentEnd = tempEnd;
text->GetTextAtOffset(tempEnd, endBoundary, &newStart, &tempEnd, unusedText);
text->GetTextBeforeOffset(tempEnd, startBoundary, &newStart, &newEnd,
unusedText);
int32_t potentialStart = newEnd == tempEnd ? newStart : newEnd;
tempStart = potentialStart > tempStart ? potentialStart : currentEnd;
// The offset range we've obtained might have embedded characters in it,
// limit the range to the start of the first occurrence of an embedded
// character.
Accessible* childAtOffset = nullptr;
for (int32_t i = tempStart; i < tempEnd; i++) {
childAtOffset = text->GetChildAtOffset(i);
if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset)) {
tempEnd = i;
break;
}
}
// If there's an embedded character at the very start of the range, we
// instead want to traverse into it. So restart the movement with
// the child as the starting point.
if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset) &&
tempStart == childAtOffset->StartOffset()) {
tempPosition = childAtOffset;
tempStart = tempEnd = -1;
continue;
}
*aResult = true;
Accessible* startPosition = mPosition;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
mPosition = tempPosition;
mStartOffset = tempStart;
mEndOffset = tempEnd;
NotifyOfPivotChange(startPosition, oldStart, oldEnd,
nsIAccessiblePivot::REASON_TEXT);
return NS_OK;
AccessibleTextBoundary startBoundary, endBoundary;
switch (aBoundary) {
case CHAR_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_CHAR;
endBoundary = nsIAccessibleText::BOUNDARY_CHAR;
break;
case WORD_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_WORD_START;
endBoundary = nsIAccessibleText::BOUNDARY_WORD_END;
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsAutoString unusedText;
int32_t newStart = 0, newEnd = 0;
text->GetTextAtOffset(mEndOffset, endBoundary, &newStart, &mEndOffset, unusedText);
text->GetTextBeforeOffset(mEndOffset, startBoundary, &newStart, &newEnd,
unusedText);
mStartOffset = newEnd == mEndOffset ? newStart : newEnd;
*aResult = true;
NotifyOfPivotChange(mPosition, oldStart, oldEnd,
nsIAccessiblePivot::REASON_TEXT);
return NS_OK;
}
NS_IMETHODIMP
@ -350,52 +417,127 @@ nsAccessiblePivot::MovePreviousByText(TextBoundaryType aBoundary, bool* aResult)
*aResult = false;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
HyperTextAccessible* text = mPosition->AsHyperText();
Accessible* oldPosition = mPosition;
while (!text) {
oldPosition = mPosition;
mPosition = mPosition->Parent();
text = mPosition->AsHyperText();
}
int32_t tempStart = mStartOffset, tempEnd = mEndOffset;
Accessible* tempPosition = mPosition;
Accessible* root = GetActiveRoot();
while (true) {
Accessible* curPosition = tempPosition;
HyperTextAccessible* text;
// Find the nearest text node using a reverse preorder traversal starting
// from the current node.
if (!(text = tempPosition->AsHyperText())) {
text = SearchForText(tempPosition, true);
if (!text)
return NS_OK;
if (text != curPosition)
tempStart = tempEnd = -1;
tempPosition = text;
}
if (mStartOffset == -1)
mStartOffset = text != oldPosition ? text->GetChildOffset(oldPosition) : 0;
// If the search led to the parent of the node we started on (e.g. when
// starting on a text leaf), start the text movement from the end of that
// node, otherwise we just default to 0.
if (tempStart == -1) {
if (tempPosition != curPosition)
tempStart = text == curPosition->Parent() ?
text->GetChildOffset(curPosition) : text->CharacterCount();
else
tempStart = 0;
}
if (mStartOffset == 0)
// If there's no more text on the current node, try to find the previous
// text node; if there isn't one, bail out.
if (tempStart == 0) {
if (tempPosition == root)
return NS_OK;
// If we're currently sitting on a link, try move to either the previous
// sibling or the parent, whichever is closer to the current end
// offset. Otherwise, do a forward search for the next node to land on
// (we don't do this in the first case because we don't want to go to the
// subtree).
Accessible* sibling = tempPosition->PrevSibling();
if (tempPosition->IsLink()) {
if (sibling && sibling->IsLink()) {
HyperTextAccessible* siblingText = sibling->AsHyperText();
tempStart = tempEnd = siblingText ?
siblingText->CharacterCount() : -1;
tempPosition = sibling;
} else {
tempStart = tempPosition->StartOffset();
tempEnd = tempPosition->EndOffset();
tempPosition = tempPosition->Parent();
}
} else {
HyperTextAccessible* tempText = SearchForText(tempPosition, true);
if (!tempText)
return NS_OK;
tempPosition = tempText;
tempStart = tempEnd = tempText->CharacterCount();
}
continue;
}
AccessibleTextBoundary startBoundary, endBoundary;
switch (aBoundary) {
case CHAR_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_CHAR;
endBoundary = nsIAccessibleText::BOUNDARY_CHAR;
break;
case WORD_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_WORD_START;
endBoundary = nsIAccessibleText::BOUNDARY_WORD_END;
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsAutoString unusedText;
int32_t newStart = 0, newEnd = 0, currentStart = tempStart, potentialEnd = 0;
text->GetTextBeforeOffset(tempStart, startBoundary, &newStart, &newEnd,
unusedText);
if (newStart < tempStart)
tempStart = newEnd >= currentStart ? newStart : newEnd;
else // XXX: In certain odd cases newStart is equal to tempStart
text->GetTextBeforeOffset(tempStart - 1, startBoundary, &newStart,
&tempStart, unusedText);
text->GetTextAtOffset(tempStart, endBoundary, &newStart, &potentialEnd,
unusedText);
tempEnd = potentialEnd < tempEnd ? potentialEnd : currentStart;
// The offset range we've obtained might have embedded characters in it,
// limit the range to the start of the last occurrence of an embedded
// character.
Accessible* childAtOffset = nullptr;
for (int32_t i = tempEnd - 1; i >= tempStart; i--) {
childAtOffset = text->GetChildAtOffset(i);
if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset)) {
tempStart = childAtOffset->EndOffset();
break;
}
}
// If there's an embedded character at the very end of the range, we
// instead want to traverse into it. So restart the movement with
// the child as the starting point.
if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset) &&
tempEnd == childAtOffset->EndOffset()) {
tempPosition = childAtOffset;
tempStart = tempEnd = childAtOffset->AsHyperText()->CharacterCount();
continue;
}
*aResult = true;
Accessible* startPosition = mPosition;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
mPosition = tempPosition;
mStartOffset = tempStart;
mEndOffset = tempEnd;
NotifyOfPivotChange(startPosition, oldStart, oldEnd,
nsIAccessiblePivot::REASON_TEXT);
return NS_OK;
AccessibleTextBoundary startBoundary, endBoundary;
switch (aBoundary) {
case CHAR_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_CHAR;
endBoundary = nsIAccessibleText::BOUNDARY_CHAR;
break;
case WORD_BOUNDARY:
startBoundary = nsIAccessibleText::BOUNDARY_WORD_START;
endBoundary = nsIAccessibleText::BOUNDARY_WORD_END;
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsAutoString unusedText;
int32_t newStart = 0, newEnd = 0;
text->GetTextBeforeOffset(mStartOffset, startBoundary, &newStart, &newEnd,
unusedText);
if (newStart < mStartOffset)
mStartOffset = newEnd == mStartOffset ? newStart : newEnd;
else // XXX: In certain odd cases newStart is equal to mStartOffset
text->GetTextBeforeOffset(mStartOffset - 1, startBoundary, &newStart,
&mStartOffset, unusedText);
text->GetTextAtOffset(mStartOffset, endBoundary, &newStart, &mEndOffset,
unusedText);
*aResult = true;
NotifyOfPivotChange(mPosition, oldStart, oldEnd,
nsIAccessiblePivot::REASON_TEXT);
return NS_OK;
}
NS_IMETHODIMP
@ -636,6 +778,48 @@ nsAccessiblePivot::SearchForward(Accessible* aAccessible,
return nullptr;
}
HyperTextAccessible*
nsAccessiblePivot::SearchForText(Accessible* aAccessible, bool aBackward)
{
Accessible* root = GetActiveRoot();
Accessible* accessible = aAccessible;
while (true) {
Accessible* child = nullptr;
while ((child = (aBackward ? accessible->LastChild() :
accessible->FirstChild()))) {
accessible = child;
if (child->IsHyperText())
return child->AsHyperText();
}
Accessible* sibling = nullptr;
Accessible* temp = accessible;
do {
if (temp == root)
break;
if (temp != aAccessible && temp->IsHyperText())
return temp->AsHyperText();
sibling = aBackward ? temp->PrevSibling() : temp->NextSibling();
if (sibling)
break;
} while ((temp = temp->Parent()));
if (!sibling)
break;
accessible = sibling;
if (accessible->IsHyperText())
return accessible->AsHyperText();
}
return nullptr;
}
bool
nsAccessiblePivot::NotifyOfPivotChange(Accessible* aOldPosition,
int32_t aOldStart, int32_t aOldEnd,

View File

@ -72,6 +72,12 @@ private:
bool aSearchCurrent,
nsresult* aResult);
/*
* Search in preorder for the first text accessible.
*/
mozilla::a11y::HyperTextAccessible* SearchForText(Accessible* aAccessible,
bool aBackward);
/*
* Get the effective root for this pivot, either the true root or modal root.
*/

View File

@ -593,14 +593,8 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
// addTextOffset, to put us after the embedded object char. We'll only treat the offset as
// before the embedded object char if we end at the very beginning of the child.
addTextOffset = addTextOffset > 0;
}
else {
// Start offset, inclusive
// Make sure the offset lands on the embedded object character in order to indicate
// the true inner offset is inside the subtree for that link
addTextOffset =
(nsAccUtils::TextLength(descendantAcc) == addTextOffset) ? 1 : 0;
}
} else
addTextOffset = 0;
descendantAcc = parentAcc;
}

View File

@ -19,6 +19,8 @@ const ACCESSFU_DISABLE = 0;
const ACCESSFU_ENABLE = 1;
const ACCESSFU_AUTO = 2;
const SCREENREADER_SETTING = 'accessibility.screenreader';
this.AccessFu = {
/**
* Initialize chrome-layer accessibility functionality.
@ -35,8 +37,15 @@ this.AccessFu = {
Services.obs.addObserver(this, 'Accessibility:Settings', false);
} catch (x) {
// Not on Android
if (Utils.MozBuildApp === 'b2g') {
aWindow.addEventListener('ContentStart', this, false);
if (aWindow.navigator.mozSettings) {
let lock = aWindow.navigator.mozSettings.createLock();
let req = lock.get(SCREENREADER_SETTING);
req.addEventListener('success', () => {
this._systemPref = req.result[SCREENREADER_SETTING];
this._enableOrDisable();
});
aWindow.navigator.mozSettings.addObserver(
SCREENREADER_SETTING, this.handleEvent.bind(this));
}
}
@ -56,10 +65,9 @@ this.AccessFu = {
}
if (Utils.MozBuildApp === 'mobile/android') {
Services.obs.removeObserver(this, 'Accessibility:Settings');
} else if (Utils.MozBuildApp === 'b2g') {
Utils.win.shell.contentBrowser.contentWindow.removeEventListener(
'mozContentEvent', this);
Utils.win.removeEventListener('ContentStart', this);
} else if (Utils.win.navigator.mozSettings) {
Utils.win.navigator.mozSettings.removeObserver(
SCREENREADER_SETTING, this.handleEvent.bind(this));
}
delete this._activatePref;
Utils.uninit();
@ -308,20 +316,6 @@ this.AccessFu = {
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case 'ContentStart':
{
Utils.win.shell.contentBrowser.contentWindow.addEventListener(
'mozContentEvent', this, false, true);
break;
}
case 'mozContentEvent':
{
if (aEvent.detail.type == 'accessibility-screenreader') {
this._systemPref = aEvent.detail.enabled;
this._enableOrDisable();
}
break;
}
case 'TabOpen':
{
let mm = Utils.getMessageManager(aEvent.target);
@ -351,6 +345,15 @@ this.AccessFu = {
}
break;
}
default:
{
// A settings change, it does not have an event type
if (aEvent.settingName == SCREENREADER_SETTING) {
this._systemPref = aEvent.settingValue;
this._enableOrDisable();
}
break;
}
}
},

View File

@ -1541,10 +1541,12 @@ function moveToTextStart(aID)
/**
* Move the caret in text accessible.
*/
function moveCaretToDOMPoint(aID, aNode, aOffset, aExpectedOffset,
aFocusTargetID)
function moveCaretToDOMPoint(aID, aDOMPointNodeID, aDOMPointOffset,
aExpectedOffset, aFocusTargetID,
aCheckFunc)
{
this.target = getAccessible(aID, [nsIAccessibleText]);
this.DOMPointNode = getNode(aDOMPointNodeID);
this.focus = aFocusTargetID ? getAccessible(aFocusTargetID) : null;
this.focusNode = this.focus ? this.focus.DOMNode : null;
@ -1553,13 +1555,25 @@ function moveCaretToDOMPoint(aID, aNode, aOffset, aExpectedOffset,
if (this.focusNode)
this.focusNode.focus();
window.getSelection().getRangeAt(0).setStart(aNode, aOffset);
var selection = this.DOMPointNode.ownerDocument.defaultView.getSelection();
var selRange = selection.getRangeAt(0);
selRange.setStart(this.DOMPointNode, aDOMPointOffset);
selRange.collapse(true);
selection.removeRange(selRange);
selection.addRange(selRange);
}
this.getID = function moveCaretToDOMPoint_getID()
{
return "Set caret on " + prettyName(aID) + " at point: " +
prettyName(aNode) + " node with offset " + aOffset;
prettyName(aDOMPointNodeID) + " node with offset " + aDOMPointOffset;
}
this.finalCheck = function moveCaretToDOMPoint_finalCheck()
{
if (aCheckFunc)
aCheckFunc.call();
}
this.eventSeq = [

View File

@ -5,8 +5,25 @@
<meta charset="utf-8" />
</head>
<body>
<div id="start-block">This is the very beginning.</div>
<p id="paragraph-1">
This <b>is</b> <a href="#">the</a> test of text.
This <b>is</b> <a id="p1-link-1" href="#">the</a> test of text.
</p>
<div id="section-1">A <a id="s1-link-1" href="#">multiword link</a> is here. <a id="s1-link-2" href="#">We</a> will traverse</div>
<div id="section-2">into, out, and between the subtrees.</div>
<p id="paragraph-2">Singularity.</p>
<table>
<tr>
<td id="cell-1">Magical</td>
<td id="cell-2">unicorns</td>
</tr>
<tr>
<td id="cell-3">and wizards</td>
<td id="cell-4">really exist.</td>
</tr>
</table>
<div id="section-3">Endless fun!</div>
<p id="paragraph-3">Objects<a id="p3-link-1" href="#">adjacent</a>to <a id="p3-link-2" href="#">each</a><a id="p3-link-3" href="#">other</a> should be separate.</p>
<div id="end-block">End!</div>
</body>
</html>

View File

@ -38,7 +38,6 @@
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('paragraph-1'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,4],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [4,5],
@ -47,15 +46,170 @@
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [5,7],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [8,9],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,3],
getAccessible(doc.getElementById('p1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [10,14],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [8,9],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,3],
getAccessible(doc.getElementById('p1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [5,7],
getAccessible(doc.getElementById('paragraph-1'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('section-1'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,1],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,9],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [10,14],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [4,6],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [7,12],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,2],
getAccessible(doc.getElementById('s1-link-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [15,19],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [20,28],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,5],
getAccessible(doc.getElementById('section-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [6,10],
getAccessible(doc.getElementById('section-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,5],
getAccessible(doc.getElementById('section-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [20,28],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [15,19],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,2],
getAccessible(doc.getElementById('s1-link-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [7,12],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [4,6],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [10,14],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,9],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,1],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('s1-link-1'))));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', CHAR_BOUNDARY, [1,2],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', CHAR_BOUNDARY, [0,1],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [1,2],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [0,1],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [1,2],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [2,9],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [10,14],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [3,4],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', CHAR_BOUNDARY, [13,14],
getAccessible(doc.getElementById('s1-link-1'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('section-2'))));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', CHAR_BOUNDARY, [27,28],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', CHAR_BOUNDARY, [0,1],
getAccessible(doc.getElementById('section-2'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('paragraph-2'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,12],
getAccessible(doc.getElementById('paragraph-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('cell-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,8],
getAccessible(doc.getElementById('cell-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,3],
getAccessible(doc.getElementById('cell-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [4,11],
getAccessible(doc.getElementById('cell-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,6],
getAccessible(doc.getElementById('cell-4'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [7,13],
getAccessible(doc.getElementById('cell-4'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('section-3'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('section-3'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('section-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [7,13],
getAccessible(doc.getElementById('cell-4'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,6],
getAccessible(doc.getElementById('cell-4'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [4,11],
getAccessible(doc.getElementById('cell-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,3],
getAccessible(doc.getElementById('cell-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,8],
getAccessible(doc.getElementById('cell-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('cell-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,12],
getAccessible(doc.getElementById('paragraph-2'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('paragraph-3'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('paragraph-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,8],
getAccessible(doc.getElementById('p3-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [8,10],
getAccessible(doc.getElementById('paragraph-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,4],
getAccessible(doc.getElementById('p3-link-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,5],
getAccessible(doc.getElementById('p3-link-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [14,20],
getAccessible(doc.getElementById('paragraph-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,5],
getAccessible(doc.getElementById('p3-link-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,4],
getAccessible(doc.getElementById('p3-link-2'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [8,10],
getAccessible(doc.getElementById('paragraph-3'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,8],
getAccessible(doc.getElementById('p3-link-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,7],
getAccessible(doc.getElementById('paragraph-3'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('s1-link-2'))));
// Start with the pivot in the middle of the paragraph
gQueue.push(new setVCPosInvoker(docAcc, "moveNext", ObjectTraversalRule, " will traverse"));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [15,19],
getAccessible(doc.getElementById('section-1'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, [0,2],
getAccessible(doc.getElementById('s1-link-2'), nsIAccessibleText)));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('end-block'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,4],
getAccessible(doc.getElementById('end-block'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, null, false));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('start-block'))));
gQueue.push(new setVCTextInvoker(docAcc, 'moveNextByText', WORD_BOUNDARY, [0,4],
getAccessible(doc.getElementById('start-block'), nsIAccessibleText)));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, null, false));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, null, false));
gQueue.push(new setVCPosInvoker(docAcc, null, null,
getAccessible(doc.getElementById('start-block'))));
gQueue.push(new setVCTextInvoker(docAcc, 'movePreviousByText', WORD_BOUNDARY, null, false));
gQueue.invoke();
}

View File

@ -35,6 +35,29 @@
"Wrong caret offset for " + aID);
}
function testCaretOffsets(aList)
{
for (var i = 0; i < aList.length; i++)
testCaretOffset(aList[0][0], aList[0][1]);
}
function queueTraversalList(aList, aFocusNode)
{
for (var i = 0 ; i < aList.length; i++) {
var node = aList[i].DOMPoint[0];
var nodeOffset = aList[i].DOMPoint[1];
var textAcc = aList[i].point[0];
var textOffset = aList[i].point[1];
var textList = aList[i].pointList;
var invoker =
new moveCaretToDOMPoint(textAcc, node, nodeOffset, textOffset,
((i == 0) ? aFocusNode : null),
testCaretOffsets.bind(null, textList))
gQueue.push(invoker);
}
}
/**
* Do tests.
*/
@ -48,7 +71,7 @@
turnCaretBrowsing(true);
// test caret offsets
testCaretOffset(document, 14);
testCaretOffset(document, 16);
testCaretOffset("textbox", -1);
testCaretOffset("textarea", -1);
testCaretOffset("p", -1);
@ -59,6 +82,49 @@
gQueue.push(new setCaretOffset("textbox", 1, "textbox"));
gQueue.push(new setCaretOffset("link", 1, "link"));
gQueue.push(new setCaretOffset("heading", 1, document));
// a*b*c
var p2Doc = getNode("p2_container").contentDocument;
var traversalList = [
{ // before 'a'
DOMPoint: [ getNode("p2", p2Doc).firstChild, 0 ],
point: [ getNode("p2", p2Doc), 0 ],
pointList: [ [ p2Doc, 0 ] ]
},
{ // after 'a' (before anchor)
DOMPoint: [ getNode("p2", p2Doc).firstChild, 1 ],
point: [ getNode("p2", p2Doc), 1 ],
pointList: [ [ p2Doc, 0 ] ]
},
{ // before 'b' (inside anchor)
DOMPoint: [ getNode("p2_a", p2Doc).firstChild, 0 ],
point: [ getNode("p2_a", p2Doc), 0 ],
pointList: [
[ getNode("p2", p2Doc), 1 ],
[ p2Doc, 0 ]
]
},
{ // after 'b' (inside anchor)
DOMPoint: [ getNode("p2_a", p2Doc).firstChild, 1 ],
point: [ getNode("p2_a", p2Doc), 1 ],
pointList: [
[ getNode("p2", p2Doc), 1 ] ,
[ p2Doc, 0 ]
]
},
{ // before 'c' (after anchor)
DOMPoint: [ getNode("p2", p2Doc).lastChild, 0 ],
point: [ getNode("p2", p2Doc), 2 ],
pointList: [ [ p2Doc, 0 ] ]
},
{ // after 'c'
DOMPoint: [ getNode("p2", p2Doc).lastChild, 1 ],
point: [ getNode("p2", p2Doc), 3 ],
pointList: [ [ p2Doc, 0 ] ]
}
];
queueTraversalList(traversalList, getNode("p2", p2Doc));
gQueue.onFinish = function()
{
turnCaretBrowsing(false);
@ -77,22 +143,27 @@
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=448744"
title="caretOffset should return -1 if the system caret is not currently with in that particular object">
Mozilla Bug 448744
Bug 448744
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=524115"
title="HyperText accessible should get focus when the caret is positioned inside of it, text is changed or copied into clipboard by ATs">
Mozilla Bug 524115
Bug 524115
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=546068"
title="Position is not being updated when atk_text_set_caret_offset is used">
Mozilla Bug 546068
Bug 546068
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=672717"
title="Broken caret when moving into/out of embedded objects with right arrow">
Bug 672717
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=725581"
title="caretOffset for textarea should be -1 when textarea doesn't have a focus">
Mozilla Bug 725581
Bug 725581
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
@ -104,6 +175,8 @@
<p id="p" contentEditable="true"><span>text</span><br/>text</p>
<a id="link" href="about:">about mozilla</a>
<h5 id="heading">heading</h5>
<iframe id="p2_container"
src="data:text/html,<p id='p2' contentEditable='true'>a<a id='p2_a' href='mozilla.org'>b</a>c</p>"></iframe>
<div id="eventdump"></div>
</body>

View File

@ -135,6 +135,11 @@ pref("browser.search.suggest.enabled", true);
// tell the search service that we don't really expose the "current engine"
pref("browser.search.noCurrentEngine", true);
// Enable sparse localization by setting a few package locale overrides
pref("chrome.override_package.global", "b2g-l10n");
pref("chrome.override_package.mozapps", "b2g-l10n");
pref("chrome.override_package.passwordmgr", "b2g-l10n");
// enable xul error pages
pref("browser.xul.error_pages.enabled", true);

View File

@ -74,7 +74,6 @@ libs-%:
# Tailored target to just add the chrome processing for multi-locale builds
chrome-%:
@$(MAKE) -C ../../toolkit/locales chrome-$*
@$(MAKE) chrome AB_CD=$*
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales chrome AB_CD=$*

View File

@ -13,3 +13,61 @@
* locale/@AB_CD@/b2g-l10n/netError.dtd (%chrome/overrides/netError.dtd)
* locale/@AB_CD@/b2g-l10n/aboutCertError.dtd (%chrome/overrides/aboutCertError.dtd)
* locale/@AB_CD@/b2g-l10n/appstrings.properties (%chrome/overrides/appstrings.properties)
# overrides for toolkit l10n, also for en-US
relativesrcdir toolkit/locales:
locale/@AB_CD@/b2g-l10n/overrides/about.dtd (%chrome/global/about.dtd)
locale/@AB_CD@/b2g-l10n/overrides/aboutAbout.dtd (%chrome/global/aboutAbout.dtd)
locale/@AB_CD@/b2g-l10n/overrides/aboutRights.dtd (%chrome/global/aboutRights.dtd)
locale/@AB_CD@/b2g-l10n/overrides/commonDialogs.properties (%chrome/global/commonDialogs.properties)
locale/@AB_CD@/b2g-l10n/overrides/handling/handling.properties (%chrome/mozapps/handling/handling.properties)
locale/@AB_CD@/b2g-l10n/overrides/intl.properties (%chrome/global/intl.properties)
locale/@AB_CD@/b2g-l10n/overrides/intl.css (%chrome/global/intl.css)
locale/@AB_CD@/b2g-l10n/overrides/passwordmgr.properties (%chrome/passwordmgr/passwordmgr.properties)
locale/@AB_CD@/b2g-l10n/overrides/search/search.properties (%chrome/search/search.properties)
locale/@AB_CD@/b2g-l10n/overrides/update/updates.properties (%chrome/mozapps/update/updates.properties)
# about:support
locale/@AB_CD@/b2g-l10n/overrides/global/aboutSupport.dtd (%chrome/global/aboutSupport.dtd)
locale/@AB_CD@/b2g-l10n/overrides/global/aboutSupport.properties (%chrome/global/aboutSupport.properties)
#about:crashes
locale/@AB_CD@/b2g-l10n/overrides/crashreporter/crashes.dtd (%crashreporter/crashes.dtd)
locale/@AB_CD@/b2g-l10n/overrides/crashreporter/crashes.properties (%crashreporter/crashes.properties)
#about:mozilla
locale/@AB_CD@/b2g-l10n/overrides/global/mozilla.dtd (%chrome/global/mozilla.dtd)
#about:telemetry
locale/@AB_CD@/b2g-l10n/overrides/global/aboutTelemetry.dtd (%chrome/global/aboutTelemetry.dtd)
locale/@AB_CD@/b2g-l10n/overrides/global/aboutTelemetry.properties (%chrome/global/aboutTelemetry.properties)
% override chrome://global/locale/about.dtd chrome://b2g-l10n/locale/overrides/about.dtd
% override chrome://global/locale/aboutAbout.dtd chrome://b2g-l10n/locale/overrides/aboutAbout.dtd
% override chrome://global/locale/aboutRights.dtd chrome://b2g-l10n/locale/overrides/aboutRights.dtd
% override chrome://global/locale/commonDialogs.properties chrome://b2g-l10n/locale/overrides/commonDialogs.properties
% override chrome://mozapps/locale/handling/handling.properties chrome://b2g-l10n/locale/overrides/handling/handling.properties
% override chrome://global/locale/intl.properties chrome://b2g-l10n/locale/overrides/intl.properties
% override chrome://global/locale/intl.css chrome://b2g-l10n/locale/overrides/intl.css
% override chrome://passwordmgr/locale/passwordmgr.properties chrome://b2g-l10n/locale/overrides/passwordmgr/passwordmgr.properties
% override chrome://global/locale/search/search.properties chrome://b2g-l10n/locale/overrides/search/search.properties
% override chrome://mozapps/locale/update/updates.properties chrome://b2g-l10n/locale/overrides/update/updates.properties
% override chrome://global/locale/aboutSupport.dtd chrome://b2g-l10n/locale/overrides/global/aboutSupport.dtd
% override chrome://global/locale/aboutSupport.properties chrome://b2g-l10n/locale/overrides/global/aboutSupport.properties
% override chrome://global/locale/crashes.dtd chrome://b2g-l10n/locale/overrides/crashreporter/crashes.dtd
% override chrome://global/locale/crashes.properties chrome://b2g-l10n/locale/overrides/crashreporter/crashes.properties
% override chrome://global/locale/mozilla.dtd chrome://b2g-l10n/locale/overrides/global/mozilla.dtd
% override chrome://global/locale/aboutTelemetry.dtd chrome://b2g-l10n/locale/overrides/global/aboutTelemetry.dtd
% override chrome://global/locale/aboutTelemetry.properties chrome://b2g-l10n/locale/overrides/global/aboutTelemetry.properties
# overrides for dom l10n, also for en-US
relativesrcdir dom/locales:
locale/@AB_CD@/b2g-l10n/overrides/charsetTitles.properties (%chrome/charsetTitles.properties)
locale/@AB_CD@/b2g-l10n/overrides/global.dtd (%chrome/global.dtd)
locale/@AB_CD@/b2g-l10n/overrides/AccessFu.properties (%chrome/accessibility/AccessFu.properties)
locale/@AB_CD@/b2g-l10n/overrides/dom/dom.properties (%chrome/dom/dom.properties)
#about:plugins
locale/@AB_CD@/b2g-l10n/overrides/plugins.properties (%chrome/plugins.properties)
% override chrome://global/locale/charsetTitles.properties chrome://b2g-l10n/locale/overrides/charsetTitles.properties
% override chrome://global/locale/global.dtd chrome://b2g-l10n/locale/overrides/global.dtd
% override chrome://global/locale/AccessFu.properties chrome://b2g-l10n/locale/overrides/AccessFu.properties
% override chrome://global/locale/dom/dom.properties chrome://b2g-l10n/locale/overrides/dom/dom.properties
% override chrome://global/locale/plugins.properties chrome://b2g-l10n/locale/overrides/plugins.properties

View File

@ -1119,18 +1119,25 @@ var gBrowserInit = {
// If the user manually opens the download manager before the timeout, the
// downloads will start right away, and getting the service again won't hurt.
setTimeout(function() {
let DownloadsCommon =
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
if (DownloadsCommon.useJSTransfer) {
// Open the data link without initalizing nsIDownloadManager.
DownloadsCommon.initializeAllDataLinks();
} else {
// Initalizing nsIDownloadManager will trigger the data link.
Services.downloads;
try {
let DownloadsCommon =
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
if (DownloadsCommon.useJSTransfer) {
// Open the data link without initalizing nsIDownloadManager.
DownloadsCommon.initializeAllDataLinks();
let DownloadsTaskbar =
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {}).DownloadsTaskbar;
DownloadsTaskbar.registerIndicator(window);
} else {
// Initalizing nsIDownloadManager will trigger the data link.
Services.downloads;
let DownloadTaskbarProgress =
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
DownloadTaskbarProgress.onBrowserWindowLoad(window);
}
} catch (ex) {
Cu.reportError(ex);
}
let DownloadTaskbarProgress =
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
DownloadTaskbarProgress.onBrowserWindowLoad(window);
}, 10000);
// The object handling the downloads indicator is also initialized here in the

View File

@ -0,0 +1,180 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Handles the download progress indicator in the taskbar.
*/
"use strict";
this.EXPORTED_SYMBOLS = [
"DownloadsTaskbar",
];
////////////////////////////////////////////////////////////////////////////////
//// Globals
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function () {
if (!("@mozilla.org/windows-taskbar;1" in Cc)) {
return null;
}
let winTaskbar = Cc["@mozilla.org/windows-taskbar;1"]
.getService(Ci.nsIWinTaskbar);
return winTaskbar.available && winTaskbar;
});
XPCOMUtils.defineLazyGetter(this, "gMacTaskbarProgress", function () {
return ("@mozilla.org/widget/macdocksupport;1" in Cc) &&
Cc["@mozilla.org/widget/macdocksupport;1"]
.getService(Ci.nsITaskbarProgress);
});
////////////////////////////////////////////////////////////////////////////////
//// DownloadsTaskbar
/**
* Handles the download progress indicator in the taskbar.
*/
this.DownloadsTaskbar = {
/**
* Underlying DownloadSummary providing the aggregate download information, or
* null if the indicator has never been initialized.
*/
_summary: null,
/**
* nsITaskbarProgress object to which download information is dispatched.
* This can be null if the indicator has never been initialized or if the
* indicator is currently hidden on Windows.
*/
_taskbarProgress: null,
/**
* This method is called after a new browser window is opened, and ensures
* that the download progress indicator is displayed in the taskbar.
*
* On Windows, the indicator is attached to the first browser window that
* calls this method. When the window is closed, the indicator is moved to
* another browser window, if available, in no particular order. When there
* are no browser windows visible, the indicator is hidden.
*
* On Mac OS X, the indicator is initialized globally when this method is
* called for the first time. Subsequent calls have no effect.
*
* @param aBrowserWindow
* nsIDOMWindow object of the newly opened browser window to which the
* indicator may be attached.
*/
registerIndicator: function (aBrowserWindow)
{
if (!this._taskbarProgress) {
if (gMacTaskbarProgress) {
// On Mac OS X, we have to register the global indicator only once.
this._taskbarProgress = gMacTaskbarProgress;
// Free the XPCOM reference on shutdown, to prevent detecting a leak.
Services.obs.addObserver(() => {
this._taskbarProgress = null;
gMacTaskbarProgress = null;
}, "quit-application-granted", false);
} else if (gWinTaskbar) {
// On Windows, the indicator is currently hidden because we have no
// previous browser window, thus we should attach the indicator now.
this._attachIndicator(aBrowserWindow);
} else {
// The taskbar indicator is not available on this platform.
return;
}
}
// Ensure that the DownloadSummary object will be created asynchronously.
if (!this._summary) {
Downloads.getSummary(Downloads.ALL).then(summary => {
// In case the method is re-entered, we simply ignore redundant
// invocations of the callback, instead of keeping separate state.
if (this._summary) {
return;
}
this._summary = summary;
return this._summary.addView(this);
}).then(null, Cu.reportError);
}
},
/**
* On Windows, attaches the taskbar indicator to the specified browser window.
*/
_attachIndicator: function (aWindow)
{
// Activate the indicator on the specified window.
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow).docShell;
this._taskbarProgress = gWinTaskbar.getTaskbarProgress(docShell);
// If the DownloadSummary object has already been created, we should update
// the state of the new indicator, otherwise it will be updated as soon as
// the DownloadSummary view is registered.
if (this._summary) {
this.onSummaryChanged();
}
aWindow.addEventListener("unload", () => {
// Locate another browser window, excluding the one being closed.
let browserWindow = RecentWindow.getMostRecentBrowserWindow();
if (browserWindow) {
// Move the progress indicator to the other browser window.
this._attachIndicator(browserWindow);
} else {
// The last browser window has been closed. We remove the reference to
// the taskbar progress object so that the indicator will be registered
// again on the next browser window that is opened.
this._taskbarProgress = null;
}
}, false);
},
//////////////////////////////////////////////////////////////////////////////
//// DownloadSummary view
onSummaryChanged: function ()
{
// If the last browser window has been closed, we have no indicator anymore.
if (!this._taskbarProgress) {
return;
}
if (this._summary.allHaveStopped || this._summary.progressTotalBytes == 0) {
this._taskbarProgress.setProgressState(
Ci.nsITaskbarProgress.STATE_NO_PROGRESS, 0, 0);
} else {
// For a brief moment before completion, some download components may
// report more transferred bytes than the total number of bytes. Thus,
// ensure that we never break the expectations of the progress indicator.
let progressCurrentBytes = Math.min(this._summary.progressTotalBytes,
this._summary.progressCurrentBytes);
this._taskbarProgress.setProgressState(
Ci.nsITaskbarProgress.STATE_NORMAL,
progressCurrentBytes,
this._summary.progressTotalBytes);
}
},
};

View File

@ -13,5 +13,6 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'DownloadsCommon.jsm',
'DownloadsLogger.jsm',
'DownloadsTaskbar.jsm',
]

View File

@ -215,34 +215,27 @@
accesskey="&newWindowsAsTabs.accesskey;"
preference="browser.link.open_newwindow"
onsyncfrompreference="return gMainPane.readLinkTarget();"
onsynctopreference="return gMainPane.writeLinkTarget();"
class="indent"/>
onsynctopreference="return gMainPane.writeLinkTarget();"/>
<checkbox id="warnCloseMultiple" label="&warnCloseMultipleTabs.label;"
accesskey="&warnCloseMultipleTabs.accesskey;"
preference="browser.tabs.warnOnClose"
class="indent"/>
preference="browser.tabs.warnOnClose"/>
<checkbox id="warnOpenMany" label="&warnOpenManyTabs.label;"
accesskey="&warnOpenManyTabs.accesskey;"
preference="browser.tabs.warnOnOpen"
class="indent"/>
preference="browser.tabs.warnOnOpen"/>
<checkbox id="restoreOnDemand" label="&restoreTabsOnDemand.label;"
accesskey="&restoreTabsOnDemand.accesskey;"
preference="browser.sessionstore.restore_on_demand"
class="indent"/>
preference="browser.sessionstore.restore_on_demand"/>
<checkbox id="switchToNewTabs" label="&switchToNewTabs.label;"
accesskey="&switchToNewTabs.accesskey;"
preference="browser.tabs.loadInBackground"
class="indent"/>
preference="browser.tabs.loadInBackground"/>
#ifdef XP_WIN
<checkbox id="showTabsInTaskbar" label="&showTabsInTaskbar.label;"
accesskey="&showTabsInTaskbar.accesskey;"
preference="browser.taskbar.previews.enable"
class="indent"/>
preference="browser.taskbar.previews.enable"/>
#endif
</groupbox>

View File

@ -22,6 +22,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_breakpoints-pane.js \
browser_dbg_chrome-debugging.js \
browser_dbg_clean-exit.js \
browser_dbg_clean-exit-window.js \
browser_dbg_cmd-blackbox.js \
browser_dbg_cmd-break.js \
browser_dbg_cmd-dbg.js \

View File

@ -0,0 +1,90 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that closing a window with the debugger in a paused state exits cleanly.
*/
let gDebuggee, gPanel, gDebugger, gWindow;
const TAB_URL = EXAMPLE_URL + "doc_inline-debugger-statement.html";
function test() {
addWindow(TAB_URL)
.then(win => initDebugger(TAB_URL, win))
.then(([aTab, aDebuggee, aPanel, aWindow]) => {
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gWindow = aWindow;
return testCleanExit(gWindow);
})
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
}
function testCleanExit(aWindow) {
let deferred = promise.defer();
gWindow = aWindow;
ok(!!gWindow, "Second window created.");
gWindow.focus();
let topWindow = Services.wm.getMostRecentWindow("navigator:browser");
is(topWindow, gWindow,
"The second window is on top.");
let isActive = promise.defer();
let isLoaded = promise.defer();
promise.all([isActive.promise, isLoaded.promise]).then(() => {
gWindow.BrowserChromeTest.runWhenReady(() => {
waitForSourceAndCaretAndScopes(gPanel, ".html", 16).then(() => {
is(gDebugger.gThreadClient.paused, true,
"Should be paused after the debugger statement.");
gWindow.close();
deferred.resolve();
finish();
});
gDebuggee.runDebuggerStatement();
});
});
let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
if (focusManager.activeWindow != gWindow) {
gWindow.addEventListener("activate", function onActivate(aEvent) {
if (aEvent.target != gWindow) {
return;
}
gWindow.removeEventListener("activate", onActivate, true);
isActive.resolve();
}, true);
} else {
isActive.resolve();
}
let contentLocation = gWindow.content.location.href;
if (contentLocation != TAB_URL) {
gWindow.document.addEventListener("load", function onLoad(aEvent) {
if (aEvent.target.documentURI != TAB_URL) {
return;
}
gWindow.document.removeEventListener("load", onLoad, true);
isLoaded.resolve();
}, true);
} else {
isLoaded.resolve();
}
return deferred.promise;
}
registerCleanupFunction(function() {
gWindow = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -416,18 +416,18 @@ function backspaceText(aElement, aTimes) {
}
}
function getTab(aTarget) {
function getTab(aTarget, aWindow) {
if (aTarget instanceof XULElement) {
return promise.resolve(aTarget);
} else {
return addTab(aTarget);
return addTab(aTarget, aWindow);
}
}
function initDebugger(aTarget, aWindow) {
info("Initializing a debugger panel.");
return getTab(aTarget).then(aTab => {
return getTab(aTarget, aWindow).then(aTab => {
info("Debugee tab added successfully: " + aTarget);
let deferred = promise.defer();
@ -445,7 +445,7 @@ function initDebugger(aTarget, aWindow) {
info("Debugger client resumed successfully.");
prepareDebugger(debuggerPanel);
deferred.resolve([aTab, debuggee, debuggerPanel]);
deferred.resolve([aTab, debuggee, debuggerPanel, aWindow]);
});
});

View File

@ -180,12 +180,6 @@ function ResponsiveUI(aWindow, aTab)
this.buildUI();
this.checkMenus();
this.docShell = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
this.docShell.deviceSizeIsPageSize = true;
try {
if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
this.rotate();
@ -258,8 +252,6 @@ ResponsiveUI.prototype = {
this.browser.removeEventListener("load", this.bound_onPageLoad, true);
this.browser.removeEventListener("unload", this.bound_onPageUnload, true);
this.docShell.deviceSizeIsPageSize = false;
if (this._floatingScrollbars)
switchToNativeScrollbars(this.tab);
@ -296,7 +288,6 @@ ResponsiveUI.prototype = {
this.container.removeAttribute("responsivemode");
this.stack.removeAttribute("responsivemode");
delete this.docShell;
delete this.tab.__responsiveUI;
if (this.touchEventHandler)
this.touchEventHandler.stop();

View File

@ -9,7 +9,6 @@ MOCHITEST_BROWSER_FILES := \
browser_responsive_cmd.js \
browser_responsivecomputedview.js \
browser_responsiveui_touch.js \
browser_responsive_devicewidth.js \
touch.html \
head.js \
$(NULL)

View File

@ -1,61 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let instance;
let mgr = ResponsiveUI.ResponsiveUIManager;
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
}, true);
content.location = "data:text/html,mop";
function startTest() {
mgr.once("on", function() {executeSoon(onUIOpen)});
document.getElementById("Tools:ResponsiveUI").doCommand();
}
function onUIOpen() {
instance = gBrowser.selectedTab.__responsiveUI;
instance.stack.setAttribute("notransition", "true");
ok(instance, "instance of the module is attached to the tab.");
let mql = content.matchMedia("(max-device-width:100px)")
ok(!mql.matches, "media query doesn't match.");
mql.addListener(onMediaChange);
instance.setSize(90, 500);
}
function onMediaChange(mql) {
mql.removeListener(onMediaChange);
ok(mql.matches, "media query matches.");
ok(window.screen.width != content.screen.width, "screen.width is not the size of the screen.");
is(content.screen.width, 90, "screen.width is the width of the page.");
is(content.screen.height, 500, "screen.height is the height of the page.");
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
mql.addListener(onMediaChange2);
docShell.deviceSizeIsPageSize = false;
}
function onMediaChange2(mql) {
mql.removeListener(onMediaChange);
ok(!mql.matches, "media query has been re-evaluated.");
ok(window.screen.width == content.screen.width, "screen.width is not the size of the screen.");
instance.stack.removeAttribute("notransition");
document.getElementById("Tools:ResponsiveUI").doCommand();
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -668,16 +668,13 @@ PropertyView.prototype = {
/**
* Returns the className that should be assigned to the propertyView.
*
* @return string
*/
get propertyHeaderClassName()
{
if (this.visible) {
this.tree._darkStripe = !this.tree._darkStripe;
let darkValue = this.tree._darkStripe ?
"property-view theme-bg-darker" : "property-view";
return darkValue;
let isDark = this.tree._darkStripe = !this.tree._darkStripe;
return isDark ? "property-view theme-bg-darker" : "property-view";
}
return "property-view-hidden";
},
@ -690,49 +687,66 @@ PropertyView.prototype = {
get propertyContentClassName()
{
if (this.visible) {
let darkValue = this.tree._darkStripe ?
"property-content theme-bg-darker" : "property-content";
return darkValue;
let isDark = this.tree._darkStripe;
return isDark ? "property-content theme-bg-darker" : "property-content";
}
return "property-content-hidden";
},
/**
* Build the markup for on computed style
* @return Element
*/
buildMain: function PropertyView_buildMain()
{
let doc = this.tree.styleDocument;
let onToggle = this.onStyleToggle.bind(this);
// Build the container element
this.element = doc.createElementNS(HTML_NS, "div");
this.element.setAttribute("class", this.propertyHeaderClassName);
this.matchedExpander = doc.createElementNS(HTML_NS, "div");
this.matchedExpander.className = "expander theme-twisty";
this.matchedExpander.setAttribute("tabindex", "0");
this.matchedExpander.addEventListener("click",
this.matchedExpanderClick.bind(this), false);
this.matchedExpander.addEventListener("keydown", function(aEvent) {
// Make it keyboard navigable
this.element.setAttribute("tabindex", "0");
this.element.addEventListener("keydown", function(aEvent) {
let keyEvent = Ci.nsIDOMKeyEvent;
if (aEvent.keyCode == keyEvent.DOM_VK_F1) {
this.mdnLinkClick();
}
if (aEvent.keyCode == keyEvent.DOM_VK_RETURN ||
aEvent.keyCode == keyEvent.DOM_VK_SPACE) {
this.matchedExpanderClick(aEvent);
onToggle(aEvent);
}
}.bind(this), false);
// Build the twisty expand/collapse
this.matchedExpander = doc.createElementNS(HTML_NS, "div");
this.matchedExpander.className = "expander theme-twisty";
this.matchedExpander.addEventListener("click", onToggle, false);
this.element.appendChild(this.matchedExpander);
// Build the style name element
this.nameNode = doc.createElementNS(HTML_NS, "div");
this.element.appendChild(this.nameNode);
this.nameNode.setAttribute("class", "property-name theme-fg-color5");
// Reset its tabindex attribute otherwise, if an ellipsis is applied
// it will be reachable via TABing
this.nameNode.setAttribute("tabindex", "");
this.nameNode.textContent = this.nameNode.title = this.name;
this.nameNode.addEventListener("click", function(aEvent) {
this.matchedExpander.focus();
}.bind(this), false);
// Make it hand over the focus to the container
this.nameNode.addEventListener("click", () => this.element.focus(), false);
this.element.appendChild(this.nameNode);
// Build the style value element
this.valueNode = doc.createElementNS(HTML_NS, "div");
this.element.appendChild(this.valueNode);
this.valueNode.setAttribute("class", "property-value theme-fg-color1");
// Reset its tabindex attribute otherwise, if an ellipsis is applied
// it will be reachable via TABing
this.valueNode.setAttribute("tabindex", "");
this.valueNode.setAttribute("dir", "ltr");
this.valueNode.textContent = this.valueNode.title = this.value;
// Make it hand over the focus to the container
this.valueNode.addEventListener("click", () => this.element.focus(), false);
this.element.appendChild(this.valueNode);
return this.element;
},
@ -836,7 +850,7 @@ PropertyView.prototype = {
* @param {Event} aEvent Used to determine the class name of the targets click
* event.
*/
matchedExpanderClick: function PropertyView_matchedExpanderClick(aEvent)
onStyleToggle: function PropertyView_onStyleToggle(aEvent)
{
this.matchedExpanded = !this.matchedExpanded;
this.refreshMatchedSelectors();

View File

@ -36,6 +36,7 @@ MOCHITEST_BROWSER_FILES = \
browser_bug894376_css_value_completion_existing_property_value_pair.js \
browser_ruleview_bug_902966_revert_value_on_ESC.js \
browser_ruleview_pseudoelement.js \
browser_computedview_bug835808_keyboard_nav.js \
head.js \
$(NULL)

View File

@ -0,0 +1,94 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the style inspector works properly
let doc, computedView, inspector;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad(evt) {
gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,computed view context menu test";
}
function createDocument()
{
doc.body.innerHTML = '<style type="text/css"> ' +
'span { font-variant: small-caps; color: #000000; } ' +
'.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
'<h1>Some header text</h1>\n' +
'<p id="salutation" style="font-size: 12pt">hi.</p>\n' +
'<p id="body" style="font-size: 12pt">I am a test-case. This text exists ' +
'solely to provide some things to <span style="color: yellow">' +
'highlight</span> and <span style="font-weight: bold">count</span> ' +
'style list-items in the box at right. If you are reading this, ' +
'you should go do something else instead. Maybe read a book. Or better ' +
'yet, write some test-cases for another bit of code. ' +
'<span style="font-style: italic">some text</span></p>\n' +
'<p id="closing">more text</p>\n' +
'<p>even more text</p>' +
'</div>';
doc.title = "Computed view keyboard navigation test";
openComputedView(startTests);
}
function startTests(aInspector, aComputedView)
{
computedView = aComputedView;
inspector = aInspector;
testTabThrougStyles();
}
function endTests()
{
computedView = inspector = doc = null;
gBrowser.removeCurrentTab();
finish();
}
function testTabThrougStyles()
{
let span = doc.querySelector("span");
inspector.once("computed-view-refreshed", () => {
// Selecting the first computed style in the list
let firstStyle = computedView.styleDocument.querySelector(".property-view");
ok(firstStyle, "First computed style found in panel");
firstStyle.focus();
// Tab to select the 2nd style, press return
EventUtils.synthesizeKey("VK_TAB", {});
EventUtils.synthesizeKey("VK_RETURN", {});
inspector.once("computed-view-property-expanded", () => {
// Verify the 2nd style has been expanded
let secondStyleSelectors = computedView.styleDocument.querySelectorAll(
".property-content .matchedselectors")[1];
ok(secondStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
// Tab back up and test the same thing, with space
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
EventUtils.synthesizeKey("VK_SPACE", {});
inspector.once("computed-view-property-expanded", () => {
// Verify the 1st style has been expanded too
let firstStyleSelectors = computedView.styleDocument.querySelectorAll(
".property-content .matchedselectors")[0];
ok(firstStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
endTests();
});
});
});
inspector.selection.setNode(span);
}

View File

@ -45,6 +45,7 @@ body {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
outline: 0;
}
.property-value {
@ -58,6 +59,7 @@ body {
background-size: 5px 8px;
background-position: 2px center;
padding-left: 10px;
outline: 0;
}
.other-property-value {

View File

@ -63,6 +63,7 @@ body {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
outline: 0;
}
.property-value {
@ -76,6 +77,7 @@ body {
background-size: 5px 8px;
background-position: 2px center;
padding-left: 10px;
outline: 0;
}
.other-property-value {

View File

@ -63,6 +63,7 @@ body {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
outline: 0;
}
.property-value {
@ -76,6 +77,7 @@ body {
background-size: 5px 8px;
background-position: 2px center;
padding-left: 10px;
outline: 0;
}
.other-property-value {

View File

@ -683,16 +683,15 @@ class Automation(object):
def killAndGetStackNoScreenshot(self, processPID, utilityPath, debuggerInfo):
"""Kill the process, preferrably in a way that gets us a stack trace."""
if self.CRASHREPORTER and not debuggerInfo:
if self.UNIXISH:
if not self.IS_WIN32:
# ABRT will get picked up by Breakpad's signal handler
os.kill(processPID, signal.SIGABRT)
return
elif self.IS_WIN32:
else:
# We should have a "crashinject" program in our utility path
crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(processPID)]).wait() == 0:
return
#TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
self.log.info("Can't trigger Breakpad, just killing process")
self.killPid(processPID)

View File

@ -7,7 +7,6 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/Date.h"
#include "mozilla/dom/HTMLInputElementBinding.h"
#include "nsAsyncDOMEvent.h"
#include "nsAttrValueInlines.h"
@ -4504,6 +4503,11 @@ HTMLInputElement::SetSelectionRange(int32_t aSelectionStart,
if (!aRv.Failed()) {
aRv = textControlFrame->ScrollSelectionIntoView();
}
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
static_cast<nsIDOMHTMLInputElement*>(this),
NS_LITERAL_STRING("select"), true,
false);
}
}
}
@ -4521,6 +4525,113 @@ HTMLInputElement::SetSelectionRange(int32_t aSelectionStart,
return rv.ErrorCode();
}
void
HTMLInputElement::SetRangeText(const nsAString& aReplacement, ErrorResult& aRv)
{
if (!SupportsSetRangeText()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
int32_t start, end;
aRv = GetSelectionRange(&start, &end);
if (aRv.Failed()) {
nsTextEditorState* state = GetEditorState();
if (state && state->IsSelectionCached()) {
start = state->GetSelectionProperties().mStart;
end = state->GetSelectionProperties().mEnd;
aRv = NS_OK;
}
}
SetRangeText(aReplacement, start, end, mozilla::dom::SelectionMode::Preserve,
aRv, start, end);
}
void
HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
uint32_t aEnd, const SelectionMode& aSelectMode,
ErrorResult& aRv, int32_t aSelectionStart,
int32_t aSelectionEnd)
{
if (!SupportsSetRangeText()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
if (aStart > aEnd) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
nsAutoString value;
GetValueInternal(value);
uint32_t inputValueLength = value.Length();
if (aStart > inputValueLength) {
aStart = inputValueLength;
}
if (aEnd > inputValueLength) {
aEnd = inputValueLength;
}
if (aSelectionStart == -1 && aSelectionEnd == -1) {
aRv = GetSelectionRange(&aSelectionStart, &aSelectionEnd);
if (aRv.Failed()) {
nsTextEditorState* state = GetEditorState();
if (state && state->IsSelectionCached()) {
aSelectionStart = state->GetSelectionProperties().mStart;
aSelectionEnd = state->GetSelectionProperties().mEnd;
aRv = NS_OK;
}
}
}
if (aStart < aEnd) {
value.Replace(aStart, aEnd - aStart, aReplacement);
SetValueInternal(value, false, false);
}
uint32_t newEnd = aStart + aReplacement.Length();
int32_t delta = aReplacement.Length() - (aEnd - aStart);
switch (aSelectMode) {
case mozilla::dom::SelectionMode::Select:
{
aSelectionStart = aStart;
aSelectionEnd = newEnd;
}
break;
case mozilla::dom::SelectionMode::Start:
{
aSelectionStart = aSelectionEnd = aStart;
}
break;
case mozilla::dom::SelectionMode::End:
{
aSelectionStart = aSelectionEnd = newEnd;
}
break;
case mozilla::dom::SelectionMode::Preserve:
{
if ((uint32_t)aSelectionStart > aEnd)
aSelectionStart += delta;
else if ((uint32_t)aSelectionStart > aStart)
aSelectionStart = aStart;
if ((uint32_t)aSelectionEnd > aEnd)
aSelectionEnd += delta;
else if ((uint32_t)aSelectionEnd > aStart)
aSelectionEnd = newEnd;
}
break;
}
Optional<nsAString> direction;
SetSelectionRange(aSelectionStart, aSelectionEnd, direction, aRv);
}
int32_t
HTMLInputElement::GetSelectionStart(ErrorResult& aRv)
{

View File

@ -17,6 +17,7 @@
#include "nsCOMPtr.h"
#include "nsIConstraintValidation.h"
#include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
#include "mozilla/dom/HTMLInputElementBinding.h"
#include "nsIFilePicker.h"
#include "nsIContentPrefService2.h"
#include "mozilla/Decimal.h"
@ -641,6 +642,13 @@ public:
const Optional< nsAString >& direction,
ErrorResult& aRv);
void SetRangeText(const nsAString& aReplacement, ErrorResult& aRv);
void SetRangeText(const nsAString& aReplacement, uint32_t aStart,
uint32_t aEnd, const SelectionMode& aSelectMode,
ErrorResult& aRv, int32_t aSelectionStart = -1,
int32_t aSelectionEnd = -1);
// XPCOM GetAlign() is OK
void SetAlign(const nsAString& aValue, ErrorResult& aRv)
{
@ -1239,6 +1247,15 @@ private:
return MayFireChangeOnBlur(mType);
}
/**
* Returns true if setRangeText can be called on element
*/
bool SupportsSetRangeText() const {
return mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_SEARCH ||
mType == NS_FORM_INPUT_URL || mType == NS_FORM_INPUT_TEL ||
mType == NS_FORM_INPUT_PASSWORD;
}
static bool MayFireChangeOnBlur(uint8_t aType) {
return IsSingleLineTextControl(false, aType) ||
aType == NS_FORM_INPUT_RANGE;

View File

@ -5,6 +5,7 @@
MOCHITEST_FILES = \
save_restore_radio_groups.sjs \
test_save_restore_radio_groups.html \
test_set_range_text.html \
test_change_event.html \
test_mozistextfield.html \
test_input_attributes_reflection.html \

View File

@ -0,0 +1,183 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=850364
-->
<head>
<title>Test for Bug 850364</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=850364">Mozilla Bug 850364</a>
<p id="display"></p>
<div id="content">
<!-- "SetRangeText() supported types"-->
<input type="text" id="input_text"></input>
<input type="search" id="input_search"></input>
<input type="url" id="input_url"></input>
<input type="tel" id="input_tel"></input>
<input type="password" id="input_password"></input>
<!-- "SetRangeText() non-supported types" -->
<input type="button" id="input_button"></input>
<input type="submit" id="input_submit"></input>
<input type="image" id="input_image"></input>
<input type="reset" id="input_reset"></input>
<input type="radio" id="input_radio"></input>
<input type="checkbox" id="input_checkbox"></input>
<input type="range" id="input_range"></input>
<input type="file" id="input_file"></input>
<input type="email" id="input_email"></input>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 850364 **/
var SupportedTypes = ["text", "search", "url", "tel", "password"];
var NonSupportedTypes = ["button", "submit", "image", "reset", "radio",
"checkbox", "range", "file", "email"];
SimpleTest.waitForExplicitFinish();
function TestInputs() {
var opThrows, elem, i, msg;
//Non-supported types should throw
for (i = 0; i < NonSupportedTypes.length; ++i) {
opThrows = false;
msg = "input_" + NonSupportedTypes[i];
elem = document.getElementById(msg);
elem.focus();
try {
elem.setRangeText("abc");
} catch (ex) {
opThrows = true;
}
ok(opThrows, msg + " should throw NotSupportedError");
}
//Supported types should not throw
for (i = 0; i < SupportedTypes.length; ++i) {
opThrows = false;
msg = "input_" + SupportedTypes[i];
elem = document.getElementById(msg);
elem.focus();
try {
elem.setRangeText("abc");
} catch (ex) {
opThrows = true;
}
is(opThrows, false, msg + " should not throw NotSupportedError");
elem.addEventListener("select", function (aEvent) {
ok(true, "select event should be fired for "+ msg);
}, false);
elem.addEventListener("input", function (aEvent) {
ok(false, "input event should NOT be fired for " + msg);
}, false);
//test setRange(replacement)
elem.value = "0123456789ABCDEF";
elem.setSelectionRange(1, 6);
elem.setRangeText("xyz");
is(elem.value, "0xyz6789ABCDEF", msg + ".value == \"0xyz6789ABCDEF\"");
is(elem.selectionStart, 1, msg + ".selectionStart == 1");
is(elem.selectionEnd, 4, msg + ".selectionEnd == 4");
elem.setRangeText("mnk");
is(elem.value, "0mnk6789ABCDEF", msg + ".value == \"0mnk6789ABCDEF\"");
//test SetRange(replacement, start, end, mode) with start > end
try {
elem.setRangeText("abc", 20, 4);
} catch (ex) {
opThrows = (ex.name == "IndexSizeError" && ex.code == DOMException.INDEX_SIZE_ERR);
}
is(opThrows, true, msg + " should throw IndexSizeError");
//test SelectionMode 'select'
elem.value = "0123456789ABCDEF";
elem.setRangeText("xyz", 4, 9, "select");
is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"select\"");
is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"select\"");
elem.setRangeText("pqm", 6, 25, "select");
is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"select\"");
is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"select\"");
//test SelectionMode 'start'
elem.value = "0123456789ABCDEF";
elem.setRangeText("xyz", 4, 9, "start");
is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"start\"");
is(elem.selectionEnd, 4, msg + ".selectionEnd == 4, with \"start\"");
elem.setRangeText("pqm", 6, 25, "start");
is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"start\"");
is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"start\"");
//test SelectionMode 'end'
elem.value = "0123456789ABCDEF";
elem.setRangeText("xyz", 4, 9, "end");
is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
is(elem.selectionStart, 7, msg + ".selectionStart == 7, with \"end\"");
is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"end\"");
elem.setRangeText("pqm", 6, 25, "end");
is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
is(elem.selectionStart, 9, msg + ".selectionStart == 9, with \"end\"");
is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"end\"");
//test SelectionMode 'preserve' (default)
//subcase: selection{Start|End} > end
elem.value = "0123456789";
elem.setSelectionRange(6, 9);
elem.setRangeText("Z", 1, 2, "preserve");
is(elem.value, "0Z23456789", msg + ".value == \"0Z23456789\"");
is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"preserve\"");
is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"preserve\"");
//subcase: selection{Start|End} < end
elem.value = "0123456789";
elem.setSelectionRange(4, 5);
elem.setRangeText("QRST", 2, 9, "preserve");
is(elem.value, "01QRST9", msg + ".value == \"01QRST9\"");
is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"preserve\"");
is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"preserve\"");
//subcase: selectionStart > end, selectionEnd < end
elem.value = "0123456789";
elem.setSelectionRange(8, 4);
elem.setRangeText("QRST", 1, 5);
is(elem.value, "0QRST56789", msg + ".value == \"0QRST56789\"");
is(elem.selectionStart, 1, msg + ".selectionStart == 1, with \"default\"");
is(elem.selectionEnd, 5, msg + ".selectionEnd == 5, with \"default\"");
//subcase: selectionStart < end, selectionEnd > end
elem.value = "0123456789";
elem.setSelectionRange(4, 9);
elem.setRangeText("QRST", 2, 6);
is(elem.value, "01QRST6789", msg + ".value == \"01QRST6789\"");
is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"default\"");
is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"default\"");
}
SimpleTest.finish();
}
addLoadEvent(TestInputs);
</script>
</pre>
</body>
</html>

View File

@ -1,16 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += \
-I$(srcdir)/../../../base/src \
-I$(srcdir)/../../../events/src \
-I$(srcdir)/../../content/src \
-I$(topsrcdir)/layout/style \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/caps/include \
-I$(topsrcdir)/xpcom/ds \
$(NULL)

View File

@ -33,3 +33,12 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'../../content/src',
'/caps/include',
'/content/base/src',
'/content/events/src',
'/dom/base',
'/layout/style',
'/xpcom/ds',
]

View File

@ -125,6 +125,19 @@ BufferComplexMultiply(const float* aInput,
}
}
float
AudioBufferPeakValue(const float *aInput, uint32_t aSize)
{
float max = 0.0f;
for (uint32_t i = 0; i < aSize; i++) {
float mag = fabs(aInput[i]);
if (mag > max) {
max = mag;
}
}
return max;
}
void
AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
const float aScale[WEBAUDIO_BLOCK_SIZE],

View File

@ -134,6 +134,11 @@ void BufferComplexMultiply(const float* aInput,
float* aOutput,
uint32_t aSize);
/**
* Vector maximum element magnitude ( max(abs(aInput)) ).
*/
float AudioBufferPeakValue(const float* aInput, uint32_t aSize);
/**
* In place gain. aScale == 1.0f should be optimized.
*/

View File

@ -1,3 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

View File

@ -1,10 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir)/../../base/src \
-I$(srcdir)/../../html/content/src \
$(NULL)

View File

@ -25,3 +25,7 @@ LIBRARY_NAME = 'gkconmediaplugins_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'/content/base/src',
'/content/html/content/src',
]

View File

@ -1,11 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir)/../../base/src \
-I$(srcdir)/../../html/content/src \
$(NULL)

View File

@ -23,3 +23,7 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'/content/base/src',
'/content/html/content/src',
]

View File

@ -396,8 +396,11 @@ AudioContext::CreatePeriodicWave(const Float32Array& aRealData,
}
nsRefPtr<PeriodicWave> periodicWave =
new PeriodicWave(this, aRealData.Data(), aRealData.Length(),
aImagData.Data(), aImagData.Length());
new PeriodicWave(this, aRealData.Data(), aImagData.Data(),
aImagData.Length(), aRv);
if (aRv.Failed()) {
return nullptr;
}
return periodicWave.forget();
}

View File

@ -39,11 +39,14 @@ public:
CreateInterpolatedBlock(const FFTBlock& block0,
const FFTBlock& block1, double interp);
// Transform FFTSize() points of aData and store the result internally.
void PerformFFT(const float* aData)
{
EnsureFFT();
kiss_fftr(mFFT, aData, mOutputBuffer.Elements());
}
// Inverse-transform internal data and store the resulting FFTSize()
// points in aData.
void PerformInverseFFT(float* aData)
{
EnsureIFFT();
@ -52,6 +55,27 @@ public:
aData[i] /= mFFTSize;
}
}
// Inverse-transform the FFTSize()/2+1 points of data in each
// of aRealDataIn and aImagDataIn and store the resulting
// FFTSize() points in aRealDataOut.
void PerformInverseFFT(float* aRealDataIn,
float *aImagDataIn,
float *aRealDataOut)
{
EnsureIFFT();
const uint32_t inputSize = mFFTSize / 2 + 1;
nsTArray<kiss_fft_cpx> inputBuffer;
inputBuffer.SetLength(inputSize);
for (uint32_t i = 0; i < inputSize; ++i) {
inputBuffer[i].r = aRealDataIn[i];
inputBuffer[i].i = aImagDataIn[i];
}
kiss_fftri(mIFFT, inputBuffer.Elements(), aRealDataOut);
for (uint32_t i = 0; i < mFFTSize; ++i) {
aRealDataOut[i] /= mFFTSize;
}
}
void Multiply(const FFTBlock& aFrame)
{
BufferComplexMultiply(reinterpret_cast<const float*>(mOutputBuffer.Elements()),

View File

@ -9,6 +9,7 @@
#include "AudioNodeStream.h"
#include "AudioDestinationNode.h"
#include "WebAudioUtils.h"
#include "blink/PeriodicWave.h"
namespace mozilla {
namespace dom {
@ -36,6 +37,39 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode)
static const float sLeak = 0.995f;
class DCBlocker
{
public:
// These are sane defauts when the initial mPhase is zero
DCBlocker(float aLastInput = 0.0f,
float aLastOutput = 0.0f,
float aPole = 0.995)
:mLastInput(aLastInput),
mLastOutput(aLastOutput),
mPole(aPole)
{
MOZ_ASSERT(aPole > 0);
}
inline float Process(float aInput)
{
float out;
out = mLastOutput * mPole + aInput - mLastInput;
mLastOutput = out;
mLastInput = aInput;
return out;
}
private:
float mLastInput;
float mLastOutput;
float mPole;
};
class OscillatorNodeEngine : public AudioNodeEngine
{
public:
@ -50,6 +84,17 @@ public:
, mDetune(0.f)
, mType(OscillatorType::Sine)
, mPhase(0.)
, mFinalFrequency(0.0)
, mNumberOfHarmonics(0)
, mSignalPeriod(0.0)
, mAmplitudeAtZero(0.0)
, mPhaseIncrement(0.0)
, mSquare(0.0)
, mTriangle(0.0)
, mSaw(0.0)
, mPhaseWrap(0.0)
, mRecomputeFrequency(true)
, mCustomLength(0)
{
}
@ -70,6 +115,7 @@ public:
const AudioParamTimeline& aValue,
TrackRate aSampleRate) MOZ_OVERRIDE
{
mRecomputeFrequency = true;
switch (aIndex) {
case FREQUENCY:
MOZ_ASSERT(mSource && mDestination);
@ -85,6 +131,7 @@ public:
NS_ERROR("Bad OscillatorNodeEngine TimelineParameter");
}
}
virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
{
switch (aIndex) {
@ -94,29 +141,127 @@ public:
NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
}
}
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
{
switch (aIndex) {
case TYPE: mType = static_cast<OscillatorType>(aParam); break;
default:
NS_ERROR("Bad OscillatorNodeEngine Int32Parameter");
case TYPE:
// Set the new type.
mType = static_cast<OscillatorType>(aParam);
if (mType != OscillatorType::Custom) {
// Forget any previous custom data.
mCustomLength = 0;
mCustom = nullptr;
mPeriodicWave = nullptr;
}
// Update BLIT integrators with the new initial conditions.
switch (mType) {
case OscillatorType::Sine:
mPhase = 0.0;
break;
case OscillatorType::Square:
mPhase = 0.0;
// Initial integration condition is -0.5, because our
// square has 50% duty cycle.
mSquare = -0.5;
break;
case OscillatorType::Triangle:
// Initial mPhase and related integration condition so the
// triangle is in the middle of the first upward slope.
// XXX actually do the maths and put the right number here.
mPhase = (float)(M_PI / 2);
mSquare = 0.5;
mTriangle = 0.0;
break;
case OscillatorType::Sawtooth:
// Initial mPhase so the oscillator starts at the
// middle of the ramp, per spec.
mPhase = (float)(M_PI / 2);
// mSaw = 0 when mPhase = pi/2.
mSaw = 0.0;
break;
case OscillatorType::Custom:
// Custom waveforms don't use BLIT.
break;
default:
NS_ERROR("Bad OscillatorNodeEngine type parameter.");
}
// End type switch.
break;
case PERIODICWAVE:
MOZ_ASSERT(aParam >= 0, "negative custom array length");
mCustomLength = static_cast<uint32_t>(aParam);
break;
default:
NS_ERROR("Bad OscillatorNodeEngine Int32Parameter.");
}
// End index switch.
}
virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
{
MOZ_ASSERT(mCustomLength, "Custom buffer sent before length");
mCustom = aBuffer;
MOZ_ASSERT(mCustom->GetChannels() == 2,
"PeriodicWave should have sent two channels");
mPeriodicWave = WebCore::PeriodicWave::create(mSource->SampleRate(),
mCustom->GetData(0), mCustom->GetData(1), mCustomLength);
}
void IncrementPhase()
{
mPhase += mPhaseIncrement;
if (mPhase > mPhaseWrap) {
mPhase -= mPhaseWrap;
}
}
double ComputeFrequency(TrackTicks ticks, size_t count)
// Square and triangle are using a bipolar band-limited impulse train, saw is
// using a normal band-limited impulse train.
bool UsesBipolarBLIT() {
return mType == OscillatorType::Square || mType == OscillatorType::Triangle;
}
void UpdateFrequencyIfNeeded(TrackTicks ticks, size_t count)
{
double frequency, detune;
if (mFrequency.HasSimpleValue()) {
bool simpleFrequency = mFrequency.HasSimpleValue();
bool simpleDetune = mDetune.HasSimpleValue();
// Shortcut if frequency-related AudioParam are not automated, and we
// already have computed the frequency information and related parameters.
if (simpleFrequency && simpleDetune && !mRecomputeFrequency) {
return;
}
if (simpleFrequency) {
frequency = mFrequency.GetValue();
} else {
frequency = mFrequency.GetValueAtTime(ticks, count);
}
if (mDetune.HasSimpleValue()) {
if (simpleDetune) {
detune = mDetune.GetValue();
} else {
detune = mDetune.GetValueAtTime(ticks, count);
}
return frequency * pow(2., detune / 1200.);
mFinalFrequency = frequency * pow(2., detune / 1200.);
mRecomputeFrequency = false;
// When using bipolar BLIT, we divide the signal period by two, because we
// are using two BLIT out of phase.
mSignalPeriod = UsesBipolarBLIT() ? 0.5 * mSource->SampleRate() / mFinalFrequency
: mSource->SampleRate() / mFinalFrequency;
// Wrap the phase accordingly:
mPhaseWrap = UsesBipolarBLIT() || mType == OscillatorType::Sine ? 2 * M_PI
: M_PI;
// Even number of harmonics for bipolar blit, odd otherwise.
mNumberOfHarmonics = UsesBipolarBLIT() ? 2 * floor(0.5 * mSignalPeriod)
: 2 * floor(0.5 * mSignalPeriod) + 1;
mPhaseIncrement = mType == OscillatorType::Sine ? 2 * M_PI / mSignalPeriod
: M_PI / mSignalPeriod;
mAmplitudeAtZero = mNumberOfHarmonics / mSignalPeriod;
}
void FillBounds(float* output, TrackTicks ticks,
@ -141,95 +286,138 @@ public:
}
}
void ComputeSine(AudioChunk *aOutput)
float BipolarBLIT()
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
float blit;
float denom = sin(mPhase);
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 2.*M_PI / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
output[i] = sin(phase);
}
mPhase = phase;
while (mPhase > 2.0*M_PI) {
// Rescale to avoid precision reductions on long runs.
mPhase -= 2.0*M_PI;
}
}
void ComputeSquare(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
output[i] = phase < 0.5 ? 1.0 : -1.0;
}
mPhase = phase;
}
void ComputeSawtooth(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
output[i] = phase < 0.5 ? 2.0*phase : 2.0*(phase - 1.0);
}
mPhase = phase;
}
void ComputeTriangle(AudioChunk *aOutput)
{
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
TrackTicks ticks = mSource->GetCurrentPosition();
uint32_t start, end;
FillBounds(output, ticks, start, end);
double rate = 1.0 / mSource->SampleRate();
double phase = mPhase;
for (uint32_t i = start; i < end; ++i) {
phase += ComputeFrequency(ticks, i) * rate;
if (phase > 1.0) {
phase -= 1.0;
}
if (phase < 0.25) {
output[i] = 4.0*phase;
} else if (phase < 0.75) {
output[i] = 1.0 - 4.0*(phase - 0.25);
if (fabs(denom) < std::numeric_limits<float>::epsilon()) {
if (mPhase < 0.1f || mPhase > 2 * M_PI - 0.1f) {
blit = mAmplitudeAtZero;
} else {
output[i] = 4.0*(phase - 0.75) - 1.0;
blit = -mAmplitudeAtZero;
}
} else {
blit = sin(mNumberOfHarmonics * mPhase);
blit /= mSignalPeriod * denom;
}
return blit;
}
float UnipolarBLIT()
{
float blit;
float denom = sin(mPhase);
if (fabs(denom) <= std::numeric_limits<float>::epsilon()) {
blit = mAmplitudeAtZero;
} else {
blit = sin(mNumberOfHarmonics * mPhase);
blit /= mSignalPeriod * denom;
}
return blit;
}
void ComputeSine(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
aOutput[i] = sin(mPhase);
IncrementPhase();
}
}
void ComputeSquare(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// Integration to get us a square. It turns out we can have a
// pure integrator here.
mSquare += BipolarBLIT();
aOutput[i] = mSquare;
// maybe we want to apply a gain, the wg has not decided yet
aOutput[i] *= 1.5;
IncrementPhase();
}
}
void ComputeSawtooth(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
float dcoffset;
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// DC offset so the Saw does not ramp up to infinity when integrating.
dcoffset = mFinalFrequency / mSource->SampleRate();
// Integrate and offset so we get mAmplitudeAtZero sawtooth. We have a
// very low frequency component somewhere here, but I'm not sure where.
mSaw += UnipolarBLIT() - dcoffset;
// reverse the saw so we are spec compliant
aOutput[i] = -mSaw * 1.5;
IncrementPhase();
}
}
void ComputeTriangle(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
{
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
// Integrate to get a square
mSquare += BipolarBLIT();
// Leaky integrate to get a triangle. We get too much dc offset if we don't
// leaky integrate here.
// C6 = k0 / period
// (period is samplingrate / frequency, k0 = (PI/2)/(2*PI)) = 0.25
float C6 = 0.25 / (mSource->SampleRate() / mFinalFrequency);
mTriangle = mTriangle * sLeak + mSquare + C6;
// DC Block, and scale back to [-1.0; 1.0]
aOutput[i] = mDCBlocker.Process(mTriangle) / (mSignalPeriod/2) * 1.5;
IncrementPhase();
}
}
void ComputeCustom(float* aOutput,
TrackTicks ticks,
uint32_t aStart,
uint32_t aEnd)
{
MOZ_ASSERT(mPeriodicWave, "No custom waveform data");
uint32_t periodicWaveSize = mPeriodicWave->periodicWaveSize();
float* higherWaveData = nullptr;
float* lowerWaveData = nullptr;
float tableInterpolationFactor;
float rate = 1.0 / mSource->SampleRate();
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateFrequencyIfNeeded(ticks, i);
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
lowerWaveData,
higherWaveData,
tableInterpolationFactor);
// mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
mPhase += periodicWaveSize * mFinalFrequency * rate;
if (mPhase >= periodicWaveSize) {
mPhase -= periodicWaveSize;
}
// Bilinear interpolation between adjacent samples in each table.
uint32_t j1 = floor(mPhase);
uint32_t j2 = j1 + 1;
if (j2 >= periodicWaveSize) {
j2 -= periodicWaveSize;
}
float sampleInterpolationFactor = mPhase - j1;
float lower = sampleInterpolationFactor * lowerWaveData[j1] +
(1 - sampleInterpolationFactor) * lowerWaveData[j2];
float higher = sampleInterpolationFactor * higherWaveData[j1] +
(1 - sampleInterpolationFactor) * higherWaveData[j2];
aOutput[i] = tableInterpolationFactor * lower +
(1 - tableInterpolationFactor) * higher;
}
mPhase = phase;
}
void ComputeSilence(AudioChunk *aOutput)
@ -261,25 +449,38 @@ public:
*aFinished = true;
return;
}
AllocateAudioBlock(1, aOutput);
float* output = static_cast<float*>(
const_cast<void*>(aOutput->mChannelData[0]));
uint32_t start, end;
FillBounds(output, ticks, start, end);
// Synthesize the correct waveform.
switch (mType) {
switch(mType) {
case OscillatorType::Sine:
ComputeSine(aOutput);
ComputeSine(output, ticks, start, end);
break;
case OscillatorType::Square:
ComputeSquare(aOutput);
break;
case OscillatorType::Sawtooth:
ComputeSawtooth(aOutput);
ComputeSquare(output, ticks, start, end);
break;
case OscillatorType::Triangle:
ComputeTriangle(aOutput);
ComputeTriangle(output, ticks, start, end);
break;
case OscillatorType::Sawtooth:
ComputeSawtooth(output, ticks, start, end);
break;
case OscillatorType::Custom:
ComputeCustom(output, ticks, start, end);
break;
default:
ComputeSilence(aOutput);
}
};
}
DCBlocker mDCBlocker;
AudioNodeStream* mSource;
AudioNodeStream* mDestination;
TrackTicks mStart;
@ -287,7 +488,20 @@ public:
AudioParamTimeline mFrequency;
AudioParamTimeline mDetune;
OscillatorType mType;
double mPhase;
float mPhase;
float mFinalFrequency;
uint32_t mNumberOfHarmonics;
float mSignalPeriod;
float mAmplitudeAtZero;
float mPhaseIncrement;
float mSquare;
float mTriangle;
float mSaw;
float mPhaseWrap;
bool mRecomputeFrequency;
nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
uint32_t mCustomLength;
nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
};
OscillatorNode::OscillatorNode(AudioContext* aContext)
@ -338,10 +552,25 @@ OscillatorNode::SendDetuneToStream(AudioNode* aNode)
void
OscillatorNode::SendTypeToStream()
{
SendInt32ParameterToStream(OscillatorNodeEngine::TYPE, static_cast<int32_t>(mType));
if (mType == OscillatorType::Custom) {
// TODO: Send the custom wave table somehow
// The engine assumes we'll send the custom data before updating the type.
SendPeriodicWaveToStream();
}
SendInt32ParameterToStream(OscillatorNodeEngine::TYPE, static_cast<int32_t>(mType));
}
void OscillatorNode::SendPeriodicWaveToStream()
{
NS_ASSERTION(mType == OscillatorType::Custom,
"Sending custom waveform to engine thread with non-custom type");
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
MOZ_ASSERT(ns, "Missing node stream.");
MOZ_ASSERT(mPeriodicWave, "Send called without PeriodicWave object.");
SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE,
mPeriodicWave->DataLength());
nsRefPtr<ThreadSharedFloatArrayBufferList> data =
mPeriodicWave->GetThreadSharedBuffer();
ns->SetBuffer(data.forget());
}
void

View File

@ -77,9 +77,10 @@ public:
// Shut up the compiler warning
break;
}
if (aType == OscillatorType::Custom) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
// ::Custom can only be set by setPeriodicWave().
// https://github.com/WebAudio/web-audio-api/issues/105 for exception.
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mType = aType;
@ -108,6 +109,7 @@ public:
void SetPeriodicWave(PeriodicWave& aPeriodicWave)
{
mPeriodicWave = &aPeriodicWave;
// SendTypeToStream will call SendPeriodicWaveToStream for us.
mType = OscillatorType::Custom;
SendTypeToStream();
}
@ -120,6 +122,7 @@ private:
static void SendFrequencyToStream(AudioNode* aNode);
static void SendDetuneToStream(AudioNode* aNode);
void SendTypeToStream();
void SendPeriodicWaveToStream();
private:
OscillatorType mType;

View File

@ -18,13 +18,30 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PeriodicWave, Release)
PeriodicWave::PeriodicWave(AudioContext* aContext,
const float* aRealData,
uint32_t aRealDataLength,
const float* aImagData,
uint32_t aImagDataLength)
const uint32_t aLength,
ErrorResult& aRv)
: mContext(aContext)
{
MOZ_ASSERT(aContext);
SetIsDOMBinding();
// Caller should have checked this and thrown.
MOZ_ASSERT(aLength > 0);
MOZ_ASSERT(aLength <= 4096);
mLength = aLength;
// Copy coefficient data. The two arrays share an allocation.
mCoefficients = new ThreadSharedFloatArrayBufferList(2);
float* buffer = static_cast<float*>(malloc(aLength*sizeof(float)*2));
if (buffer == nullptr) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(buffer, aRealData, aLength);
mCoefficients->SetData(0, buffer, buffer);
PodCopy(buffer+aLength, aImagData, aLength);
mCoefficients->SetData(1, nullptr, buffer+aLength);
}
JSObject*
@ -33,6 +50,6 @@ PeriodicWave::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
return PeriodicWaveBinding::Wrap(aCx, aScope, this);
}
}
}
} // namespace dom
} // namespace mozilla

View File

@ -12,6 +12,7 @@
#include "mozilla/Attributes.h"
#include "EnableWebAudioCheck.h"
#include "AudioContext.h"
#include "AudioNodeEngine.h"
#include "nsAutoPtr.h"
namespace mozilla {
@ -24,9 +25,9 @@ class PeriodicWave MOZ_FINAL : public nsWrapperCache,
public:
PeriodicWave(AudioContext* aContext,
const float* aRealData,
uint32_t aRealDataLength,
const float* aImagData,
uint32_t aImagDataLength);
const uint32_t aLength,
ErrorResult& aRv);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PeriodicWave)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PeriodicWave)
@ -39,12 +40,23 @@ public:
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
uint32_t DataLength() const
{
return mLength;
}
ThreadSharedFloatArrayBufferList* GetThreadSharedBuffer() const
{
return mCoefficients;
}
private:
nsRefPtr<AudioContext> mContext;
nsRefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;
uint32_t mLength;
};
}
}
#endif

View File

@ -0,0 +1,297 @@
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "PeriodicWave.h"
#include <algorithm>
#include <cmath>
#include "mozilla/FFTBlock.h"
const unsigned PeriodicWaveSize = 4096; // This must be a power of two.
const unsigned NumberOfRanges = 36; // There should be 3 * log2(PeriodicWaveSize) 1/3 octave ranges.
const float CentsPerRange = 1200 / 3; // 1/3 Octave.
using namespace mozilla;
using mozilla::dom::OscillatorType;
namespace WebCore {
PeriodicWave* PeriodicWave::create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents)
{
bool isGood = real && imag && numberOfComponents > 0 &&
numberOfComponents <= PeriodicWaveSize;
MOZ_ASSERT(isGood);
if (isGood) {
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->createBandLimitedTables(real, imag, numberOfComponents);
return periodicWave;
}
return 0;
}
PeriodicWave* PeriodicWave::createSine(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sine);
return periodicWave;
}
PeriodicWave* PeriodicWave::createSquare(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Square);
return periodicWave;
}
PeriodicWave* PeriodicWave::createSawtooth(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
return periodicWave;
}
PeriodicWave* PeriodicWave::createTriangle(float sampleRate)
{
PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
periodicWave->generateBasicWaveform(OscillatorType::Triangle);
return periodicWave;
}
PeriodicWave::PeriodicWave(float sampleRate)
: m_sampleRate(sampleRate)
, m_periodicWaveSize(PeriodicWaveSize)
, m_numberOfRanges(NumberOfRanges)
, m_centsPerRange(CentsPerRange)
{
float nyquist = 0.5 * m_sampleRate;
m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials();
m_rateScale = m_periodicWaveSize / m_sampleRate;
}
void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData, float& tableInterpolationFactor)
{
// Negative frequencies are allowed, in which case we alias
// to the positive frequency.
fundamentalFrequency = fabsf(fundamentalFrequency);
// Calculate the pitch range.
float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / m_lowestFundamentalFrequency : 0.5;
float centsAboveLowestFrequency = logf(ratio)/logf(2.0f) * 1200;
// Add one to round-up to the next range just in time to truncate
// partials before aliasing occurs.
float pitchRange = 1 + centsAboveLowestFrequency / m_centsPerRange;
pitchRange = std::max(pitchRange, 0.0f);
pitchRange = std::min(pitchRange, static_cast<float>(m_numberOfRanges - 1));
// The words "lower" and "higher" refer to the table data having
// the lower and higher numbers of partials. It's a little confusing
// since the range index gets larger the more partials we cull out.
// So the lower table data will have a larger range index.
unsigned rangeIndex1 = static_cast<unsigned>(pitchRange);
unsigned rangeIndex2 = rangeIndex1 < m_numberOfRanges - 1 ? rangeIndex1 + 1 : rangeIndex1;
lowerWaveData = m_bandLimitedTables[rangeIndex2]->Elements();
higherWaveData = m_bandLimitedTables[rangeIndex1]->Elements();
// Ranges from 0 -> 1 to interpolate between lower -> higher.
tableInterpolationFactor = pitchRange - rangeIndex1;
}
unsigned PeriodicWave::maxNumberOfPartials() const
{
return m_periodicWaveSize / 2;
}
unsigned PeriodicWave::numberOfPartialsForRange(unsigned rangeIndex) const
{
// Number of cents below nyquist where we cull partials.
float centsToCull = rangeIndex * m_centsPerRange;
// A value from 0 -> 1 representing what fraction of the partials to keep.
float cullingScale = pow(2, -centsToCull / 1200);
// The very top range will have all the partials culled.
unsigned numberOfPartials = cullingScale * maxNumberOfPartials();
return numberOfPartials;
}
// Convert into time-domain wave buffers.
// One table is created for each range for non-aliasing playback
// at different playback rates. Thus, higher ranges have more
// high-frequency partials culled out.
void PeriodicWave::createBandLimitedTables(const float* realData, const float* imagData, unsigned numberOfComponents)
{
float normalizationScale = 1;
unsigned fftSize = m_periodicWaveSize;
unsigned halfSize = fftSize / 2 + 1;
unsigned i;
numberOfComponents = std::min(numberOfComponents, halfSize);
m_bandLimitedTables.SetCapacity(m_numberOfRanges);
for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) {
// This FFTBlock is used to cull partials (represented by frequency bins).
FFTBlock frame(fftSize);
float* realP = new float[halfSize];
float* imagP = new float[halfSize];
// Copy from loaded frequency data and scale.
float scale = fftSize;
AudioBufferCopyWithScale(realData, scale, realP, numberOfComponents);
AudioBufferCopyWithScale(imagData, scale, imagP, numberOfComponents);
// If fewer components were provided than 1/2 FFT size,
// then clear the remaining bins.
for (i = numberOfComponents; i < halfSize; ++i) {
realP[i] = 0;
imagP[i] = 0;
}
// Generate complex conjugate because of the way the
// inverse FFT is defined.
float minusOne = -1;
AudioBufferInPlaceScale(imagP, 1, minusOne, halfSize);
// Find the starting bin where we should start culling.
// We need to clear out the highest frequencies to band-limit
// the waveform.
unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex);
// Cull the aliasing partials for this pitch range.
for (i = numberOfPartials + 1; i < halfSize; ++i) {
realP[i] = 0;
imagP[i] = 0;
}
// Clear nyquist if necessary.
if (numberOfPartials < halfSize)
realP[halfSize-1] = 0;
// Clear any DC-offset.
realP[0] = 0;
// Clear values which have no effect.
imagP[0] = 0;
imagP[halfSize-1] = 0;
// Create the band-limited table.
AudioFloatArray* table = new AudioFloatArray(m_periodicWaveSize);
m_bandLimitedTables.AppendElement(table);
// Apply an inverse FFT to generate the time-domain table data.
float* data = m_bandLimitedTables[rangeIndex]->Elements();
frame.PerformInverseFFT(realP, imagP, data);
// For the first range (which has the highest power), calculate
// its peak value then compute normalization scale.
if (!rangeIndex) {
float maxValue;
maxValue = AudioBufferPeakValue(data, m_periodicWaveSize);
if (maxValue)
normalizationScale = 1.0f / maxValue;
}
// Apply normalization scale.
AudioBufferInPlaceScale(data, 1, normalizationScale, m_periodicWaveSize);
}
}
void PeriodicWave::generateBasicWaveform(OscillatorType shape)
{
const float piFloat = M_PI;
unsigned fftSize = periodicWaveSize();
unsigned halfSize = fftSize / 2 + 1;
AudioFloatArray real(halfSize);
AudioFloatArray imag(halfSize);
float* realP = real.Elements();
float* imagP = imag.Elements();
// Clear DC and Nyquist.
realP[0] = 0;
imagP[0] = 0;
realP[halfSize-1] = 0;
imagP[halfSize-1] = 0;
for (unsigned n = 1; n < halfSize; ++n) {
float omega = 2 * piFloat * n;
float invOmega = 1 / omega;
// Fourier coefficients according to standard definition.
float a; // Coefficient for cos().
float b; // Coefficient for sin().
// Calculate Fourier coefficients depending on the shape.
// Note that the overall scaling (magnitude) of the waveforms
// is normalized in createBandLimitedTables().
switch (shape) {
case OscillatorType::Sine:
// Standard sine wave function.
a = 0;
b = (n == 1) ? 1 : 0;
break;
case OscillatorType::Square:
// Square-shaped waveform with the first half its maximum value
// and the second half its minimum value.
a = 0;
b = invOmega * ((n & 1) ? 2 : 0);
break;
case OscillatorType::Sawtooth:
// Sawtooth-shaped waveform with the first half ramping from
// zero to maximum and the second half from minimum to zero.
a = 0;
b = -invOmega * cos(0.5 * omega);
break;
case OscillatorType::Triangle:
// Triangle-shaped waveform going from its maximum value to
// its minimum value then back to the maximum value.
a = (4 - 4 * cos(0.5 * omega)) / (n * n * piFloat * piFloat);
b = 0;
break;
default:
NS_NOTREACHED("invalid oscillator type");
a = 0;
b = 0;
break;
}
realP[n] = a;
imagP[n] = b;
}
createBandLimitedTables(realP, imagP, halfSize);
}
} // namespace WebCore

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PeriodicWave_h
#define PeriodicWave_h
#include "mozilla/dom/OscillatorNodeBinding.h"
#include <nsAutoPtr.h>
#include <nsTArray.h>
namespace WebCore {
typedef nsTArray<float> AudioFloatArray;
class PeriodicWave {
public:
static PeriodicWave* createSine(float sampleRate);
static PeriodicWave* createSquare(float sampleRate);
static PeriodicWave* createSawtooth(float sampleRate);
static PeriodicWave* createTriangle(float sampleRate);
// Creates an arbitrary periodic wave given the frequency components
// (Fourier coefficients).
static PeriodicWave* create(float sampleRate,
const float* real,
const float* imag,
size_t numberOfComponents);
// Returns pointers to the lower and higher wave data for the pitch range
// containing the given fundamental frequency. These two tables are in
// adjacent "pitch" ranges where the higher table will have the maximum
// number of partials which won't alias when played back at this
// fundamental frequency. The lower wave is the next range containing fewer
// partials than the higher wave. Interpolation between these two tables
// can be made according to tableInterpolationFactor. Where values
// from 0 -> 1 interpolate between lower -> higher.
void waveDataForFundamentalFrequency(float, float* &lowerWaveData, float* &higherWaveData, float& tableInterpolationFactor);
// Returns the scalar multiplier to the oscillator frequency to calculate
// wave buffer phase increment.
float rateScale() const { return m_rateScale; }
unsigned periodicWaveSize() const { return m_periodicWaveSize; }
float sampleRate() const { return m_sampleRate; }
private:
explicit PeriodicWave(float sampleRate);
void generateBasicWaveform(mozilla::dom::OscillatorType);
float m_sampleRate;
unsigned m_periodicWaveSize;
unsigned m_numberOfRanges;
float m_centsPerRange;
// The lowest frequency (in Hertz) where playback will include all of the
// partials. Playing back lower than this frequency will gradually lose
// more high-frequency information.
// This frequency is quite low (~10Hz @ // 44.1KHz)
float m_lowestFundamentalFrequency;
float m_rateScale;
unsigned numberOfRanges() const { return m_numberOfRanges; }
// Maximum possible number of partials (before culling).
unsigned maxNumberOfPartials() const;
unsigned numberOfPartialsForRange(unsigned rangeIndex) const;
// Creates tables based on numberOfComponents Fourier coefficients.
void createBandLimitedTables(const float* real, const float* imag, unsigned numberOfComponents);
nsTArray<nsAutoPtr<AudioFloatArray> > m_bandLimitedTables;
};
} // namespace WebCore
#endif // PeriodicWave_h

View File

@ -17,6 +17,7 @@ CPP_SOURCES += [
'HRTFElevation.cpp',
'HRTFKernel.cpp',
'HRTFPanner.cpp',
'PeriodicWave.cpp',
'Reverb.cpp',
'ReverbAccumulationBuffer.cpp',
'ReverbConvolver.cpp',

View File

@ -22,10 +22,10 @@ addLoadEvent(function() {
is(osc.type, "sine", "Correct default type");
expectException(function() {
osc.type = "custom";
}, DOMException.NOT_SUPPORTED_ERR);
}, DOMException.INVALID_STATE_ERR);
expectException(function() {
osc.type = osc.CUSTOM;
}, DOMException.NOT_SUPPORTED_ERR);
}, DOMException.INVALID_STATE_ERR);
is(osc.type, "sine", "Cannot set the type to custom");
is(osc.frequency.value, 440, "Correct default frequency value");
is(osc.detune.value, 0, "Correct default detine value");
@ -43,6 +43,12 @@ addLoadEvent(function() {
osc.type = types[i];
}
// Verify setPeriodicWave()
var real = new Float32Array([1.0, 0.5, 0.25, 0.125]);
var imag = new Float32Array([1.0, 0.7, -1.0, 0.5]);
osc.setPeriodicWave(context.createPeriodicWave(real, imag));
is(osc.type, "custom", "Failed to set custom waveform");
SimpleTest.finish();
});

View File

@ -1,10 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
LOCAL_INCLUDES += \
-I$(srcdir)/../base/src \
-I$(srcdir)/../../layout/style \
-I$(srcdir)/../events/src \
$(NULL)

View File

@ -67,3 +67,8 @@ LIBXUL_LIBRARY = True
LIBRARY_NAME = 'gkconsmil_s'
LOCAL_INCLUDES += [
'../base/src',
'../events/src',
'/layout/style',
]

View File

@ -1,17 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir) \
-I$(srcdir)/../../../xml/document/src \
-I$(srcdir)/../../../html/document/src \
-I$(srcdir)/../../../../layout/style \
-I$(srcdir)/../../../base/src \
-I$(srcdir)/../../../events/src \
-I$(topsrcdir)/xpcom/ds \
-I$(topsrcdir)/content/svg/content/src \
$(NULL)

View File

@ -20,3 +20,12 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'/content/base/src',
'/content/events/src',
'/content/html/document/src',
'/content/svg/content/src',
'/content/xml/document/src',
'/layout/style',
'/xpcom/ds',
]

View File

@ -1,18 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = \
-I$(srcdir)/../../base/src \
-I$(srcdir)/../../html/document/src \
-I$(srcdir)/../../xml/document/src \
-I$(srcdir)/../../xul/content/src \
-I$(srcdir)/../../xul/document/src \
-I$(srcdir)/../../events/src \
-I$(srcdir)/../../../layout/style \
-I$(srcdir)/../../../dom/base \
-I$(topsrcdir)/xpcom/ds \
$(NULL)

View File

@ -44,3 +44,14 @@ MSVC_ENABLE_PGO = True
LIBRARY_NAME = 'gkconxbl_s'
LOCAL_INCLUDES += [
'/content/base/src',
'/content/events/src',
'/content/html/document/src',
'/content/xml/document/src',
'/content/xul/content/src',
'/content/xul/document/src',
'/dom/base',
'/layout/style',
'/xpcom/ds',
]

View File

@ -1,18 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = \
-I$(srcdir) \
-I$(srcdir)/../../../html/document/src \
-I$(srcdir)/../../../../layout/style \
-I$(srcdir)/../../../base/src \
-I$(srcdir)/../../../xul/content/src \
-I$(srcdir)/../../../events/src \
-I$(srcdir)/../../../../dom/base \
-I$(srcdir)/../../../../caps/include \
-I$(topsrcdir)/xpcom/ds \
$(NULL)

View File

@ -25,3 +25,13 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'/caps/include',
'/content/base/src',
'/content/events/src',
'/content/html/document/src',
'/content/xul/content/src',
'/dom/base',
'/layout/style',
'/xpcom/ds',
]

View File

@ -1,13 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir)/../../public \
-I$(srcdir) \
-I$(srcdir)/../xml \
-I$(srcdir)/../xpath \
-I$(srcdir)/../xslt \
$(NULL)

View File

@ -20,3 +20,9 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../../public',
'../xml',
'../xpath',
'../xslt',
]

View File

@ -1,13 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir)/../base \
-I$(srcdir) \
-I$(srcdir)/../xpath \
-I$(srcdir)/../xslt \
-I$(srcdir)/../../../base/src \
$(NULL)

View File

@ -17,3 +17,9 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../base',
'../xpath',
'../xslt',
'/content/base/src',
]

View File

@ -1,12 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir)/../base \
-I$(srcdir)/../xml \
-I$(srcdir) \
-I$(srcdir)/../xslt \
$(NULL)

View File

@ -57,3 +57,8 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../base',
'../xml',
'../xslt',
]

View File

@ -1,18 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# For nsDependentJSString
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/base \
$(NULL)
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(srcdir) \
-I$(srcdir)/../base \
-I$(srcdir)/../xml \
-I$(srcdir)/../xpath \
-I$(srcdir)/../../../base/src \
$(NULL)

View File

@ -50,3 +50,12 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
# For nsDependentJSString
LOCAL_INCLUDES += ["/dom/base"]
LOCAL_INCLUDES += [
'../base',
'../xml',
'../xpath',
'/content/base/src',
]

View File

@ -1,21 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = \
-I$(srcdir)/../../document/src \
-I$(srcdir)/../../templates/src \
-I$(srcdir)/../../../xml/content/src \
-I$(srcdir)/../../../base/src \
-I$(srcdir)/../../../xml/document/src \
-I$(srcdir)/../../../../layout/generic \
-I$(srcdir)/../../../../layout/style \
-I$(srcdir)/../../../../layout/xul/base/src \
-I$(srcdir)/../../../html/content/src \
-I$(srcdir)/../../../events/src \
-I$(srcdir)/../../../xbl/src \
-I$(topsrcdir)/xpcom/ds \
$(NULL)

View File

@ -19,3 +19,17 @@ if CONFIG['MOZ_XUL']:
FAIL_ON_WARNINGS = True
LOCAL_INCLUDES += [
'../../document/src',
'../../templates/src',
'/content/base/src',
'/content/events/src',
'/content/html/content/src',
'/content/xbl/src',
'/content/xml/content/src',
'/content/xml/document/src',
'/layout/generic',
'/layout/style',
'/layout/xul/base/src',
'/xpcom/ds',
]

View File

@ -1,20 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = -I$(srcdir)/../../../base/src \
-I$(srcdir)/../../content/src \
-I$(srcdir)/../../templates/src \
-I$(srcdir)/../../../../layout/base \
-I$(srcdir)/../../../../layout/generic \
-I$(srcdir)/../../../../layout/style \
-I$(srcdir)/../../../../layout/xul/base/src \
-I$(srcdir)/../../../xml/document/src \
-I$(srcdir)/../../../xbl/src \
-I$(srcdir)/../../../events/src \
-I$(topsrcdir)/xpcom/ds \
-I$(topsrcdir)/dom/base \
$(NULL)

View File

@ -27,3 +27,17 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'/content/base/src',
'/content/events/src',
'/content/xbl/src',
'/content/xml/document/src',
'/content/xul/content/src',
'/content/xul/templates/src',
'/dom/base',
'/layout/base',
'/layout/generic',
'/layout/style',
'/layout/xul/base/src',
'/xpcom/ds',
]

View File

@ -1,12 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = -I$(srcdir)/../../../base/src \
-I$(srcdir)/../../content/src \
-I$(srcdir)/../../../../dom/base \
-I$(srcdir)/../../../../layout/xul/tree/ \
$(NULL)

View File

@ -41,3 +41,9 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'../../content/src',
'/content/base/src',
'/dom/base',
'/layout/xul/tree/',
]

View File

@ -750,7 +750,6 @@ nsDocShell::nsDocShell():
mIsAppTab(false),
mUseGlobalHistory(false),
mInPrivateBrowsing(false),
mDeviceSizeIsPageSize(false),
mFiredUnloadEvent(false),
mEODForCurrentDocument(false),
mURIResultedInDocument(false),
@ -3933,27 +3932,6 @@ nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
{
if (mDeviceSizeIsPageSize != aValue) {
mDeviceSizeIsPageSize = aValue;
nsRefPtr<nsPresContext> presContext;
GetPresContext(getter_AddRefs(presContext));
if (presContext) {
presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
{
*aValue = mDeviceSizeIsPageSize;
return NS_OK;
}
void
nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
{

View File

@ -809,7 +809,6 @@ protected:
bool mIsAppTab;
bool mUseGlobalHistory;
bool mInPrivateBrowsing;
bool mDeviceSizeIsPageSize;
// This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation

View File

@ -916,12 +916,4 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
boolean isCommandEnabled(in string command);
void doCommand(in string command);
/**
* If deviceSizeIsPageSize is set to true, device-width/height media queries
* will be calculated from the page size, not the device size.
*
* Used by the Responsive Design View.
*/
[infallible] attribute boolean deviceSizeIsPageSize;
};

View File

@ -1,28 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORT_LIBRARY = 1
SHARED_LIBRARY_LIBS= \
../base/$(LIB_PREFIX)basedocshell_s.$(LIB_SUFFIX) \
$(DEPTH)/uriloader/base/$(LIB_PREFIX)uriloaderbase_s.$(LIB_SUFFIX) \
$(DEPTH)/uriloader/exthandler/$(LIB_PREFIX)exthandler_s.$(LIB_SUFFIX) \
$(DEPTH)/uriloader/prefetch/$(LIB_PREFIX)prefetch_s.$(LIB_SUFFIX) \
../shistory/src/$(LIB_PREFIX)shistory_s.$(LIB_SUFFIX) \
$(NULL)
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = \
-I$(srcdir) \
-I$(srcdir)/../base \
-I$(srcdir)/../shistory/src \
-I$(topsrcdir)/uriloader/base \
-I$(topsrcdir)/uriloader/prefetch \
-I$(topsrcdir)/uriloader/exthandler \
$(NULL)
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
LOCAL_INCLUDES += -I$(topsrcdir)/uriloader/exthandler/mac
endif

View File

@ -18,3 +18,13 @@ LIBRARY_NAME = 'docshell'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../base',
'../shistory/src/',
'/uriloader/base',
'/uriloader/exthandler',
'/uriloader/prefetch',
]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
LOCAL_INCLUDES += ['/uriloader/exthandler/mac']

View File

@ -1,8 +0,0 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += -I$(srcdir)/../../base

View File

@ -25,3 +25,6 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'/docshell/base',
]

View File

@ -93,6 +93,10 @@ function isInaccessible(wnd, message) {
}
}
function getSubframe(win, i) {
return SpecialPowers.unwrap(SpecialPowers.wrap(win)[i]);
}
///////////////////////////////////////////////////////////////////////////
// Functions that require UniversalXPConnect privilege
///////////////////////////////////////////////////////////////////////////

View File

@ -9,17 +9,18 @@
iframe { width: 90%; height: 50px; }
</style>
<script>
window.onload = function () {
navigateByLocation(window0.frames[0]);
navigateByLocation(getSubframe(window0, 0));
navigateByOpen("window1_child0");
navigateByForm("window2_child0");
navigateByHyperlink("window3_child0");
xpcWaitForFinishedFrames(function() {
isInaccessible(window0.frames[0], "Should not be able to navigate off-domain frame by setting location.");
isInaccessible(window1.frames[0], "Should not be able to navigate off-domain frame by calling window.open.");
isInaccessible(window2.frames[0], "Should not be able to navigate off-domain frame by submitting form.");
isInaccessible(window3.frames[0], "Should not be able to navigate off-domain frame by targeted hyperlink.");
isInaccessible(getSubframe(window0, 0), "Should not be able to navigate off-domain frame by setting location.");
isInaccessible(getSubframe(window1, 0), "Should not be able to navigate off-domain frame by calling window.open.");
isInaccessible(getSubframe(window2, 0), "Should not be able to navigate off-domain frame by submitting form.");
isInaccessible(getSubframe(window3, 0), "Should not be able to navigate off-domain frame by targeted hyperlink.");
window0.close();
window1.close();

View File

@ -14,16 +14,16 @@ if (!navigator.platform.startsWith("Win")) {
}
window.onload = function () {
navigateByLocation(frames[0].frames[0]);
navigateByLocation(getSubframe(getSubframe(frames, 0), 0));
navigateByOpen("child1_child0");
navigateByForm("child2_child0");
navigateByHyperlink("child3_child0");
xpcWaitForFinishedFrames(function() {
isNavigated(frames[0].frames[0], "Should be able to navigate off-domain grandchild by setting location.");
isNavigated(frames[1].frames[0], "Should be able to navigate off-domain grandchild by calling window.open.");
isNavigated(frames[2].frames[0], "Should be able to navigate off-domain grandchild by submitting form.");
isNavigated(frames[3].frames[0], "Should be able to navigate off-domain grandchild by targeted hyperlink.");
isNavigated(getSubframe(getSubframe(frames, 0), 0), "Should be able to navigate off-domain grandchild by setting location.");
isNavigated(getSubframe(getSubframe(frames, 1), 0), "Should be able to navigate off-domain grandchild by calling window.open.");
isNavigated(getSubframe(getSubframe(frames, 2), 0), "Should be able to navigate off-domain grandchild by submitting form.");
isNavigated(getSubframe(getSubframe(frames, 3), 0), "Should be able to navigate off-domain grandchild by targeted hyperlink.");
xpcCleanupWindows();
SimpleTest.finish();

View File

@ -11,7 +11,7 @@
<script>
window.onload = function () {
document.getElementById('active').innerHTML =
'<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#parent.frames[0],location"></iframe>' +
'<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#SpecialPowers.unwrap(SpecialPowers.wrap(parent).frames[0]),location"></iframe>' +
'<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child1,open"></iframe>' +
'<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child2,form"></iframe>' +
'<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child3,hyperlink"></iframe>';

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -34,3 +34,6 @@ LIBXUL_LIBRARY = True
LIBRARY_NAME = 'dom_activities_s'
LOCAL_INCLUDES += [
'/dom/base',
]

View File

@ -385,19 +385,6 @@ nsScreen::SlowMozUnlockOrientation()
return NS_OK;
}
bool
nsScreen::IsDeviceSizePageSize()
{
nsPIDOMWindow* owner = GetOwner();
if (owner) {
nsIDocShell* docShell = owner->GetDocShell();
if (docShell) {
return docShell->GetDeviceSizeIsPageSize();
}
}
return false;
}
/* virtual */
JSObject*
nsScreen::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)

View File

@ -51,15 +51,6 @@ public:
int32_t GetWidth(ErrorResult& aRv)
{
nsRect rect;
if (IsDeviceSizePageSize()) {
nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
if (owner) {
int32_t innerWidth = 0;
aRv = owner->GetInnerWidth(&innerWidth);
return innerWidth;
}
}
aRv = GetRect(rect);
return rect.width;
}
@ -67,15 +58,6 @@ public:
int32_t GetHeight(ErrorResult& aRv)
{
nsRect rect;
if (IsDeviceSizePageSize()) {
nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
if (owner) {
int32_t innerHeight = 0;
aRv = owner->GetInnerHeight(&innerHeight);
return innerHeight;
}
}
aRv = GetRect(rect);
return rect.height;
}
@ -155,8 +137,6 @@ private:
LockPermission GetLockOrientationPermission() const;
bool IsDeviceSizePageSize();
nsRefPtr<FullScreenEventListener> mEventListener;
};

View File

@ -3505,7 +3505,12 @@ for (uint32_t i = 0; i < length; ++i) {
raise NoSuchDescriptorError("Can't handle member callbacks in "
"workers; need to sort out rooting"
"issues")
declType = CGGeneric("JS::Rooted<JSObject*>")
if isOptional:
# We have a specialization of Optional that will use a
# Rooted for the storage here.
declType = CGGeneric("JS::Handle<JSObject*>")
else:
declType = CGGeneric("JS::Rooted<JSObject*>")
conversion = " ${declName} = &${val}.toObject();\n"
declArgs = "cx"
else:

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -61,3 +61,6 @@ LIBXUL_LIBRARY = True
LIBRARY_NAME = 'domfile_s'
LOCAL_INCLUDES += [
'../base',
]

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,5 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/dom/dom-config.mk

View File

@ -1,8 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/workers \
-I$(topsrcdir)/dom/base \
$(NULL)

View File

@ -25,3 +25,7 @@ LIBXUL_LIBRARY = True
LIBRARY_NAME = 'dompromise_s'
LOCAL_INCLUDES += [
'../base',
'../workers',
]

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