This commit is contained in:
Wes Kocher 2013-09-18 16:48:24 -07:00
Родитель ed2f5b0505 cd77eb0805
Коммит bf4520a53b
206 изменённых файлов: 3684 добавлений и 1468 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -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.
*/

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}
}
},

Просмотреть файл

@ -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 = [

Просмотреть файл

@ -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>

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -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);

Просмотреть файл

@ -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=$*

Просмотреть файл

@ -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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 \

Просмотреть файл

@ -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>

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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],

Просмотреть файл

@ -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.
*/

Просмотреть файл

@ -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/.

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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()),

Просмотреть файл

@ -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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

@ -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();
});

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

@ -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',
]

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -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

Просмотреть файл

@ -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']

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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();

Просмотреть файл

@ -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();

Просмотреть файл

@ -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>';

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

@ -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:

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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)

Просмотреть файл

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

Просмотреть файл

@ -1,9 +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$(topsrcdir)/dom/base
INCLUDES += -I$(topsrcdir)/content/base/src

Просмотреть файл

@ -18,3 +18,7 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
"/content/base/src",
"/dom/base",
]

Просмотреть файл

@ -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$(srcdir)/../base \
-I$(topsrcdir)/content/events/src

Просмотреть файл

@ -22,3 +22,6 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'/content/base/src',
]

Просмотреть файл

@ -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) \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/netwerk/base/src \
$(NULL)

Просмотреть файл

@ -22,3 +22,7 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
"/dom/base",
"/netwerk/base/src",
]

Просмотреть файл

@ -1,9 +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/base \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src

Просмотреть файл

@ -19,3 +19,8 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
"/content/base/src",
"/content/events/src",
"/dom/base",
]

Просмотреть файл

@ -5,7 +5,7 @@
var success = 0;
try {
parent[name].success = 1;
SpecialPowers.unwrap(SpecialPowers.wrap(parent)[name]).success = 1;
} catch (e) {
parent.postMessage(e, "http://mochi.test:8888");
}

Просмотреть файл

@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=850517
function go() {
var ifrA = $('a');
var ifrB = $('b');
var sb = new SpecialPowers.Cu.Sandbox('http://www.example.com');
var sb = new SpecialPowers.Cu.Sandbox(SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal());
sb.win = window;
sb.childA = ifrA.contentWindow;
sb.childB = ifrB.contentWindow;
@ -26,8 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=850517
SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb);
ifrA.removeAttribute('name');
is(typeof window.theoneandonly, 'undefined', "Revocation works");
SpecialPowers.Cu.evalInSandbox('try { win.theoneandonly; ok(false, "Should have thrown"); } ' +
'catch (e) {ok(!!/denied/.exec(e) && !!/theoneandonly/.exec(e), "Revocation works via Xray");};', sb);
SpecialPowers.Cu.evalInSandbox('is(typeof win.theoneandonly, "undefined", "Revocation works via Xray");', sb);
ifrB.setAttribute('name', 'theoneandonly');
is(window.theoneandonly.frameElement, ifrB, "Another mule kicking in the same old stall");
SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childB, "Another mule via Xray");', sb);

Просмотреть файл

@ -50,6 +50,8 @@
function receiveSubDomain(evt)
{
var topframe =
SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.topDomainFrame);
if (evt.origin !== "http://mochi.test:8888")
{
fail("wrong top-domain origin: " + evt.origin);
@ -62,12 +64,13 @@
}
document.domain = "example.com";
window.parent.topDomainFrame.postMessage("domain-switch",
"http://example.com");
topframe.postMessage("domain-switch", "http://example.com");
}
function receiveTopDomain(evt)
{
var subframe =
SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.subDomainFrame);
if (evt.origin !== "http://test1.example.com")
{
fail("wrong subdomain origin: " + evt.origin);
@ -78,14 +81,14 @@
fail("wrong subdomain message: " + evt.origin);
return;
}
if (evt.source !== window.parent.subDomainFrame)
if (evt.source !== subframe)
{
fail("wrong source on message from subdomain");
return;
}
document.domain = "example.com";
window.parent.subDomainFrame.testSiblingPostMessage();
subframe.testSiblingPostMessage();
}
function testSiblingPostMessage()

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

@ -12,6 +12,13 @@
* and create derivative works of this document.
*/
enum SelectionMode {
"select",
"start",
"end",
"preserve",
};
interface nsIControllers;
interface HTMLInputElement : HTMLElement {
@ -114,8 +121,11 @@ interface HTMLInputElement : HTMLElement {
attribute long selectionEnd;
[Throws]
attribute DOMString selectionDirection;
// Bug 850364 void setRangeText(DOMString replacement);
// Bug 850364 setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode);
[Throws]
void setRangeText(DOMString replacement);
[Throws]
void setRangeText(DOMString replacement, unsigned long start,
unsigned long end, optional SelectionMode selectionMode = "preserve");
// also has obsolete members
};

Просмотреть файл

@ -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/.
LOCAL_INCLUDES = \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/system \
-I$(topsrcdir)/xpcom/build \
$(NULL)

Просмотреть файл

@ -58,3 +58,10 @@ LIBXUL_LIBRARY = True
MSVC_ENABLE_PGO = True
LOCAL_INCLUDES += [
'../base',
'../system',
'/content/base/src',
'/content/events/src',
'/xpcom/build',
]

Просмотреть файл

@ -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/.
LOCAL_INCLUDES += \
-I$(topsrcdir)/editor/libeditor/text \
-I$(topsrcdir)/editor/txmgr/src \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/layout/style \
-I$(topsrcdir)/extensions/spellcheck/src \
$(NULL)

Просмотреть файл

@ -39,3 +39,11 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../text',
'/content/base/src',
'/content/events/src',
'/editor/txmgr/src',
'/extensions/spellcheck/src',
'/layout/style',
]

Просмотреть файл

@ -1,19 +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$(topsrcdir)/editor/libeditor/base \
-I$(topsrcdir)/editor/libeditor/text \
-I$(topsrcdir)/editor/txmgr/src \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/layout/style \
$(NULL)
LOCAL_INCLUDES += \
-I$(topsrcdir)/layout/generic \
-I$(topsrcdir)/layout/tables \
-I$(topsrcdir)/layout/xul/base/src \
$(null)

Просмотреть файл

@ -34,3 +34,13 @@ FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../base',
'../text',
'/content/base/src',
'/editor/txmgr/src',
'/layout/generic',
'/layout/style',
'/layout/tables',
'/layout/xul/base/src',
]

Просмотреть файл

@ -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$(topsrcdir)/editor/libeditor/base \
-I$(topsrcdir)/editor/txmgr/src \
-I$(topsrcdir)/content/base/src \
$(NULL)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше