зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c
This commit is contained in:
Коммит
bf4520a53b
|
@ -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)
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче