This commit is contained in:
Ryan VanderMeulen 2014-02-04 14:44:51 -05:00
Родитель 6ce92b7a6a f448244211
Коммит baf68d3bd6
239 изменённых файлов: 3324 добавлений и 2628 удалений

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

@ -99,3 +99,8 @@ ad0ae007aa9e03cd74e9005cd6652e544139b3b5 FIREFOX_AURORA_25_BASE
05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
ba2cc1eda988a1614d8986ae145d28e1268409b9 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
ba2cc1eda988a1614d8986ae145d28e1268409b9 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
0000000000000000000000000000000000000000 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
0000000000000000000000000000000000000000 FIREFOX_AURORA_29_BASE-m
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE

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

@ -231,18 +231,12 @@ HyperTextAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
endChild->AppendTextTo(aText, 0, endOffset - endChildOffset);
}
Accessible*
HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
int32_t aNodeOffset,
int32_t* aHyperTextOffset,
bool aIsEndOffset) const
int32_t
HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
bool aIsEndOffset) const
{
if (!aHyperTextOffset)
return nullptr;
*aHyperTextOffset = 0;
if (!aNode)
return nullptr;
return 0;
uint32_t addTextOffset = 0;
nsINode* findNode = nullptr;
@ -254,10 +248,11 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
// For text nodes, aNodeOffset comes in as a character offset
// Text offset will be added at the end, if we find the offset in this hypertext
// We want the "skipped" offset into the text (rendered text without the extra whitespace)
nsIFrame *frame = aNode->AsContent()->GetPrimaryFrame();
NS_ENSURE_TRUE(frame, nullptr);
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
NS_ENSURE_TRUE(frame, 0);
nsresult rv = ContentToRenderedOffset(frame, aNodeOffset, &addTextOffset);
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_SUCCESS(rv, 0);
// Get the child node and
findNode = aNode;
@ -276,8 +271,7 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
if (aNode == GetNode()) {
// Case #1: this accessible has no children and thus has empty text,
// we can only be at hypertext offset 0.
*aHyperTextOffset = 0;
return nullptr;
return 0;
}
// Case #2: there are no children, we're at this node.
@ -295,7 +289,7 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
// Get accessible for this findNode, or if that node isn't accessible, use the
// accessible for the next DOM node which has one (based on forward depth first search)
Accessible* descendantAcc = nullptr;
Accessible* descendant = nullptr;
if (findNode) {
nsCOMPtr<nsIContent> findContent(do_QueryInterface(findNode));
if (findContent && findContent->IsHTML() &&
@ -305,18 +299,17 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
nsGkAtoms::_true,
eIgnoreCase)) {
// This <br> is the hacky "bogus node" used when there is no text in a control
*aHyperTextOffset = 0;
return nullptr;
return 0;
}
descendantAcc = GetFirstAvailableAccessible(findNode);
descendant = GetFirstAvailableAccessible(findNode);
}
// From the descendant, go up and get the immediate child of this hypertext
Accessible* childAccAtOffset = nullptr;
while (descendantAcc) {
Accessible* parentAcc = descendantAcc->Parent();
if (parentAcc == this) {
childAccAtOffset = descendantAcc;
Accessible* childAtOffset = nullptr;
while (descendant) {
Accessible* parent = descendant->Parent();
if (parent == this) {
childAtOffset = descendant;
break;
}
@ -328,42 +321,17 @@ HyperTextAccessible::DOMPointToHypertextOffset(nsINode* aNode,
// is not at 0 offset then the returned offset should be after an embedded
// character the original point belongs to.
if (aIsEndOffset)
addTextOffset = (addTextOffset > 0 || descendantAcc->IndexInParent() > 0) ? 1 : 0;
addTextOffset = (addTextOffset > 0 || descendant->IndexInParent() > 0) ? 1 : 0;
else
addTextOffset = 0;
descendantAcc = parentAcc;
descendant = parent;
}
// Loop through, adding offsets until we reach childAccessible
// If childAccessible is null we will end up adding up the entire length of
// the hypertext, which is good -- it just means our offset node
// came after the last accessible child's node
uint32_t childCount = ChildCount();
uint32_t childIdx = 0;
Accessible* childAcc = nullptr;
for (; childIdx < childCount; childIdx++) {
childAcc = mChildren[childIdx];
if (childAcc == childAccAtOffset)
break;
*aHyperTextOffset += nsAccUtils::TextLength(childAcc);
}
if (childIdx < childCount) {
*aHyperTextOffset += addTextOffset;
NS_ASSERTION(childAcc == childAccAtOffset,
"These should be equal whenever we exit loop and childAcc != nullptr");
if (childIdx < childCount - 1 ||
addTextOffset < nsAccUtils::TextLength(childAccAtOffset)) {
// If not at end of last text node, we will return the accessible we were in
return childAccAtOffset;
}
}
return nullptr;
// If the given DOM point cannot be mapped into offset relative this hypertext
// offset then return length as fallback value.
return childAtOffset ?
GetChildOffset(childAtOffset) + addTextOffset : CharacterCount();
}
bool
@ -490,17 +458,14 @@ HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
if (!pos.mResultContent)
return -1;
// Turn the resulting node and offset into a hyperTextOffset
// If finalAccessible is nullptr, then DOMPointToHypertextOffset() searched
// through the hypertext children without finding the node/offset position.
int32_t hyperTextOffset = 0;
Accessible* finalAccessible =
DOMPointToHypertextOffset(pos.mResultContent, pos.mContentOffset,
&hyperTextOffset, aDirection == eDirNext);
// Turn the resulting DOM point into an offset.
int32_t hyperTextOffset = DOMPointToOffset(pos.mResultContent,
pos.mContentOffset,
aDirection == eDirNext);
// If we reached the end during search, this means we didn't find the DOM point
// and we're actually at the start of the paragraph
if (!finalAccessible && aDirection == eDirPrevious)
if (hyperTextOffset == CharacterCount() && aDirection == eDirPrevious)
return 0;
return hyperTextOffset;
@ -1173,9 +1138,7 @@ HyperTextAccessible::CaretOffset() const
return -1;
}
int32_t caretOffset = -1;
DOMPointToHypertextOffset(focusNode, focusOffset, &caretOffset);
return caretOffset;
return DOMPointToOffset(focusNode, focusOffset);
}
int32_t
@ -1384,13 +1347,8 @@ HyperTextAccessible::SelectionBoundsAt(int32_t aSelectionNum,
endOffset = tempOffset;
}
Accessible* startAccessible =
DOMPointToHypertextOffset(startNode, startOffset, aStartOffset);
if (!startAccessible) {
*aStartOffset = 0; // Could not find start point within this hypertext, so starts before
}
DOMPointToHypertextOffset(endNode, endOffset, aEndOffset, true);
*aStartOffset = DOMPointToOffset(startNode, startOffset);
*aEndOffset = DOMPointToOffset(endNode, endOffset, true);
return true;
}
@ -1781,7 +1739,7 @@ nsresult
HyperTextAccessible::RangeBoundToHypertextOffset(nsRange* aRange,
bool aIsStartBound,
bool aIsStartHTOffset,
int32_t* aHTOffset)
int32_t* aOffset)
{
nsINode* node = nullptr;
int32_t nodeOffset = 0;
@ -1794,12 +1752,7 @@ HyperTextAccessible::RangeBoundToHypertextOffset(nsRange* aRange,
nodeOffset = aRange->EndOffset();
}
Accessible* startAcc =
DOMPointToHypertextOffset(node, nodeOffset, aHTOffset);
if (aIsStartHTOffset && !startAcc)
*aHTOffset = 0;
*aOffset = DOMPointToOffset(node, nodeOffset);
return NS_OK;
}

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

@ -99,34 +99,26 @@ public:
// HyperTextAccessible: DOM point to text offset conversions.
/**
* Turn a DOM Node and offset into a character offset into this hypertext.
* Will look for closest match when the DOM node does not have an accessible
* object associated with it. Will return an offset for the end of
* the string if the node is not found.
*
* @param aNode - the node to look for
* @param aNodeOffset - the offset to look for
* if -1 just look directly for the node
* if >=0 and aNode is text, this represents a char offset
* if >=0 and aNode is not text, this represents a child node offset
* @param aResultOffset - the character offset into the current
* HyperTextAccessible
* @param aIsEndOffset - if true, then then this offset is not inclusive. The character
* indicated by the offset returned is at [offset - 1]. This means
* if the passed-in offset is really in a descendant, then the offset returned
* will come just after the relevant embedded object characer.
* If false, then the offset is inclusive. The character indicated
* by the offset returned is at [offset]. If the passed-in offset in inside a
* descendant, then the returned offset will be on the relevant embedded object char.
*
* @return the accessible child which contained the offset, if
* it is within the current HyperTextAccessible,
* otherwise nullptr
*/
Accessible* DOMPointToHypertextOffset(nsINode *aNode,
int32_t aNodeOffset,
int32_t* aHypertextOffset,
bool aIsEndOffset = false) const;
* Turn a DOM point (node and offset) into a character offset of this
* hypertext. Will look for closest match when the DOM node does not have
* an accessible object associated with it. Will return an offset for the end
* of the string if the node is not found.
*
* @param aNode [in] the node to look for
* @param aNodeOffset [in] the offset to look for
* if -1 just look directly for the node
* if >=0 and aNode is text, this represents a char offset
* if >=0 and aNode is not text, this represents a child node offset
* @param aIsEndOffset [in] if true, then then this offset is not inclusive. The character
* indicated by the offset returned is at [offset - 1]. This means
* if the passed-in offset is really in a descendant, then the offset returned
* will come just after the relevant embedded object characer.
* If false, then the offset is inclusive. The character indicated
* by the offset returned is at [offset]. If the passed-in offset in inside a
* descendant, then the returned offset will be on the relevant embedded object char.
*/
int32_t DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
bool aIsEndOffset = false) const;
/**
* Convert start and end hypertext offsets into DOM range.
@ -480,7 +472,7 @@ protected:
* Return hyper text offset for the specified bound of the given DOM range.
* If the bound is outside of the hyper text then offset value is either
* 0 or number of characters of hyper text, it depends on type of requested
* offset. The method is a wrapper for DOMPointToHypertextOffset.
* offset. The method is a wrapper for DOMPointToOffset.
*
* @param aRange [in] the given range
* @param aIsStartBound [in] specifies whether the required range bound is

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

@ -132,8 +132,12 @@ var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
case Roles.LINK:
case Roles.HEADER:
case Roles.HEADING:
return hasZeroOrSingleChildDescendants() ?
(Filters.MATCH | Filters.IGNORE_SUBTREE) : (Filters.IGNORE);
if ((aAccessible.childCount > 0 || aAccessible.name) &&
hasZeroOrSingleChildDescendants()) {
return Filters.MATCH | Filters.IGNORE_SUBTREE;
} else {
return Filters.IGNORE;
}
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
@ -217,7 +221,10 @@ this.TraversalRules = {
}),
Heading: new BaseTraversalRule(
[Roles.HEADING]),
[Roles.HEADING],
function Heading_match(aAccessible) {
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
}),
ListItem: new BaseTraversalRule(
[Roles.LISTITEM,

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

@ -82,6 +82,7 @@
<a id="anchor-2">Sentences</a>
<a id="link-3" href="http://www.example.com">Link the third</a>
<hr id="separator-1">
<h6 id="heading-6"></h6>
<table id="table-1">
<tr>
<td>3</td>

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

@ -95,6 +95,30 @@
queueTraversalSequence(gQueue, docAcc, TraversalRules.Table, null,
['table-1', 'table-2']);
queueTraversalSequence(gQueue, docAcc, TraversalRules.Simple, null,
['heading-1', 'Name:', 'input-1-1', 'label-1-2',
'button-1-1', 'Radios are old: ', 'radio-1-1',
'Radios are new: ', 'radio-1-2', 'Password:',
'input-1-3', 'Unlucky number:', 'input-1-4',
'button-1-2', 'Check me: ', 'checkbox-1-1',
'select-1-1', 'Value 1', 'Value 2', 'Value 3',
'Check me too: ', 'checkbox-1-2', 'But not me: ',
'Or me! ', 'Value 1', 'Value 2', 'Value 3',
'Electronic mailing address:', 'input-1-5',
'button-1-3', 'heading-2', 'heading-3',
'button-2-1', 'button-2-2', 'button-2-3',
'button-2-4', 'Programming Language',
'A esoteric weapon wielded by only the most ' +
'formidable warriors, for its unrelenting strict' +
' power is unfathomable.',
'Lists of Programming Languages', 'Lisp ',
'Scheme', 'Racket', 'Clojure', 'JavaScript', 'heading-5',
'image-2', 'image-3', 'Not actually an image',
'link-1', 'anchor-1', 'link-2', 'anchor-2', 'link-3',
'3', '1', '4', '1', 'Just an innocuous separator',
'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
'Dirt', 'Messy Stuff']);
gQueue.invoke();
}

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

@ -265,7 +265,9 @@ function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets, aI
this.getID = function setVCPosInvoker_getID()
{
return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod;
return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod + " in " +
prettyName(aIdOrNameOrAcc) + ", " + boundaryToString(aBoundary) +
", [" + aTextOffsets + "]";
};
if (expectMove) {
@ -379,7 +381,9 @@ function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence)
// Add modal root (if any)
aQueue.push(new setModalRootInvoker(aDocAcc, aModalRoot, 0));
for (var i = 0; i < aSequence.length; i++) {
aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
for (var i = 1; i < aSequence.length; i++) {
var invoker =
new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
aQueue.push(invoker);

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

@ -13,6 +13,7 @@
</script>
<script type="application/javascript" src="../common.js"></script>
<script type="application/javascript" src="../text.js"></script>
<script type="application/javascript" src="../browser.js"></script>
<script type="application/javascript" src="../events.js"></script>
<script type="application/javascript" src="../role.js"></script>

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

@ -6,7 +6,7 @@
const { Cc, Ci } = require('chrome');
const { isPrivate } = require('sdk/private-browsing');
const { isWindowPBSupported } = require('sdk/private-browsing/utils');
const { onFocus, getMostRecentWindow, getWindowTitle,
const { onFocus, getMostRecentWindow, getWindowTitle, getInnerId,
getFrames, windows, open: openWindow, isWindowPrivate } = require('sdk/window/utils');
const { open, close, focus, promise } = require('sdk/window/helpers');
const { browserWindows } = require("sdk/windows");
@ -25,31 +25,28 @@ function makeEmptyBrowserWindow(options) {
chrome: true,
private: !!options.private
}
});
}).then(focus);
}
exports.testWindowTrackerIgnoresPrivateWindows = function(assert, done) {
var myNonPrivateWindow, myPrivateWindow;
var finished = false;
var privateWindow;
var myNonPrivateWindowId, myPrivateWindowId;
var privateWindowClosed = false;
var privateWindowOpened = false;
var trackedWindowIds = [];
let wt = winUtils.WindowTracker({
onTrack: function(window) {
if (window === myPrivateWindow) {
assert.equal(isPrivate(window), isWindowPBSupported);
privateWindowOpened = true;
}
let id = getInnerId(window);
trackedWindowIds.push(id);
},
onUntrack: function(window) {
if (window === myPrivateWindow && isWindowPBSupported) {
let id = getInnerId(window);
if (id === myPrivateWindowId) {
privateWindowClosed = true;
}
if (window === myNonPrivateWindow) {
assert.equal(privateWindowClosed, isWindowPBSupported);
assert.ok(privateWindowOpened);
if (id === myNonPrivateWindowId) {
assert.equal(privateWindowClosed, true, 'private window was untracked');
wt.unload();
done();
}
@ -57,27 +54,23 @@ exports.testWindowTrackerIgnoresPrivateWindows = function(assert, done) {
});
// make a new private window
myPrivateWindow = openWindow(BROWSER, {
features: {
private: true
}
});
promise(myPrivateWindow, 'load').then(function(window) {
makeEmptyBrowserWindow({ private: true }).then(function(window) {
myPrivateWindowId = getInnerId(window);
assert.ok(trackedWindowIds.indexOf(myPrivateWindowId) >= 0, 'private window was tracked');
assert.equal(isPrivate(window), isWindowPBSupported, 'private window isPrivate');
assert.equal(isWindowPrivate(window), isWindowPBSupported);
assert.ok(getFrames(window).length > 1, 'there are frames for private window');
assert.equal(getWindowTitle(window), window.document.title,
'getWindowTitle works');
close(myPrivateWindow).then(function() {
close(window).then(function() {
assert.pass('private window was closed');
makeEmptyBrowserWindow().then(function(window) {
myNonPrivateWindow = window;
assert.notDeepEqual(myPrivateWindow, myNonPrivateWindow);
assert.pass('opened new window');
close(myNonPrivateWindow).then(function() {
assert.pass('non private window was closed');
})
myNonPrivateWindowId = getInnerId(window);
assert.notEqual(myPrivateWindowId, myNonPrivateWindowId, 'non private window was opened');
close(window);
});
});
});
@ -95,7 +88,7 @@ exports.testSettingActiveWindowDoesNotIgnorePrivateWindow = function(assert, don
// make a new private window
makeEmptyBrowserWindow({
private: true
}).then(focus).then(function(window) {
}).then(function(window) {
let continueAfterFocus = function(window) onFocus(window).then(nextTest);
// PWPB case
@ -172,7 +165,7 @@ exports.testActiveWindowDoesNotIgnorePrivateWindow = function(assert, done) {
// make a new private window
makeEmptyBrowserWindow({
private: true
}).then(focus).then(function(window) {
}).then(function(window) {
// PWPB case
if (isWindowPBSupported) {
assert.equal(isPrivate(winUtils.activeWindow), true,
@ -212,7 +205,7 @@ exports.testWindowIteratorIgnoresPrivateWindows = function(assert, done) {
// make a new private window
makeEmptyBrowserWindow({
private: true
}).then(focus).then(function(window) {
}).then(function(window) {
assert.equal(isWindowPrivate(window), isWindowPBSupported);
assert.ok(toArray(winUtils.windowIterator()).indexOf(window) > -1,
"window is in windowIterator()");

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

@ -128,12 +128,14 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let url = aSource.url;
let label = SourceUtils.getSourceLabel(url.split(" -> ").pop());
let group = SourceUtils.getSourceGroup(url.split(" -> ").pop());
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(url));
let contents = document.createElement("label");
contents.className = "plain dbg-source-item";
contents.setAttribute("value", label);
contents.setAttribute("crop", "start");
contents.setAttribute("flex", "1");
contents.setAttribute("tooltiptext", unicodeUrl);
// Append a source item to this container.
this.push([contents, url], {

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

@ -45,6 +45,13 @@ function testSourcesDisplay() {
is(gSources.itemCount, 2,
"Found the expected number of sources.");
is(gSources.items[0].target.querySelector(".dbg-source-item").getAttribute("tooltiptext"),
EXAMPLE_URL + "code_script-switching-01.js",
"The correct tooltip text is displayed for the first source.");
is(gSources.items[1].target.querySelector(".dbg-source-item").getAttribute("tooltiptext"),
EXAMPLE_URL + "code_script-switching-02.js",
"The correct tooltip text is displayed for the second source.");
ok(gSources.containsValue(EXAMPLE_URL + gLabel1),
"First source url is incorrect.");
ok(gSources.containsValue(EXAMPLE_URL + gLabel2),

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

@ -338,8 +338,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this._summary = $("#requests-menu-network-summary-label");
this._summary.setAttribute("value", L10N.getStr("networkMenu.empty"));
this.sortContents(this._byTiming);
this.allowFocusOnRightClick = true;
this.widget.maintainSelectionVisible = false;
this.maintainSelectionVisible = true;
this.widget.autoscrollWithAppendedItems = true;
this.widget.addEventListener("select", this._onSelect, false);
@ -471,27 +472,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
}
},
/**
* Create a new custom request form populated with the data from
* the currently selected request.
*/
cloneSelectedRequest: function() {
let selected = this.selectedItem.attachment;
// Create the element node for the network request item.
let menuView = this._createMenuView(selected.method, selected.url);
// Append a network request item to this container.
let newItem = this.push([menuView], {
attachment: Object.create(selected, {
isCustom: { value: true }
})
});
// Immediately switch to new request pane.
this.selectedItem = newItem;
},
/**
* Opens selected item in a new tab.
*/
@ -521,16 +501,37 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
});
},
/**
* Create a new custom request form populated with the data from
* the currently selected request.
*/
cloneSelectedRequest: function() {
let selected = this.selectedItem.attachment;
// Create the element node for the network request item.
let menuView = this._createMenuView(selected.method, selected.url);
// Append a network request item to this container.
let newItem = this.push([menuView], {
attachment: Object.create(selected, {
isCustom: { value: true }
})
});
// Immediately switch to new request pane.
this.selectedItem = newItem;
},
/**
* Send a new HTTP request using the data in the custom request form.
*/
sendCustomRequest: function() {
let selected = this.selectedItem.attachment;
let data = Object.create(selected);
let data = Object.create(selected, {
headers: { value: selected.requestHeaders.headers }
});
if (selected.requestHeaders) {
data.headers = selected.requestHeaders.headers;
}
if (selected.requestPostData) {
data.body = selected.requestPostData.postData.text;
}
@ -548,9 +549,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
*/
closeCustomRequest: function() {
this.remove(this.selectedItem);
NetMonitorView.Sidebar.toggle(false);
},
},
/**
* Filters all network requests in this container by a specified type.
@ -2126,26 +2126,41 @@ NetworkDetailsView.prototype = {
// Handle json, which we tentatively identify by checking the MIME type
// for "json" after any word boundary. This works for the standard
// "application/json", and also for custom types like "x-bigcorp-json".
// This should be marginally more reliable than just looking for "json".
if (/\bjson/.test(mimeType)) {
let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback.
let sanitizedJSON = aString.replace(jsonpRegex, "");
let callbackPadding = aString.match(jsonpRegex);
// Additionally, we also directly parse the response text content to
// verify whether it's json or not, to handle responses incorrectly
// labeled as text/plain instead.
let jsonMimeType, jsonObject, jsonObjectParseError;
try {
// Test the mime type *and* parse the string, because "JSONP" responses
// (json with callback) aren't actually valid json.
jsonMimeType = /\bjson/.test(mimeType);
jsonObject = JSON.parse(aString);
} catch (e) {
jsonObjectParseError = e;
}
if (jsonMimeType || jsonObject) {
// Extract the actual json substring in case this might be a "JSONP".
// This regex basically parses a function call and captures the
// function name and arguments in two separate groups.
let jsonpRegex = /^\s*([\w$]+)\s*\(\s*([^]*)\s*\)\s*;?\s*$/;
let [_, callbackPadding, jsonpString] = aString.match(jsonpRegex) || [];
// Make sure this is a valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
try {
var jsonObject = JSON.parse(sanitizedJSON);
} catch (e) {
var parsingError = e;
if (callbackPadding && jsonpString) {
try {
jsonObject = JSON.parse(jsonpString);
} catch (e) {
jsonObjectParseError = e;
}
}
// Valid JSON.
// Valid JSON or JSONP.
if (jsonObject) {
$("#response-content-json-box").hidden = false;
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
? L10N.getFormatStr("jsonpScopeName", callbackPadding)
: L10N.getStr("jsonScopeName");
return this._json.controller.setSingleVariable({
@ -2157,8 +2172,8 @@ NetworkDetailsView.prototype = {
else {
$("#response-content-textarea-box").hidden = false;
let infoHeader = $("#response-content-info-header");
infoHeader.setAttribute("value", parsingError);
infoHeader.setAttribute("tooltiptext", parsingError);
infoHeader.setAttribute("value", jsonObjectParseError);
infoHeader.setAttribute("tooltiptext", jsonObjectParseError);
infoHeader.hidden = false;
return NetMonitorView.editor("#response-content-textarea").then(aEditor => {
aEditor.setMode(Editor.modes.js);
@ -2328,13 +2343,9 @@ PerformanceStatisticsView.prototype = {
id: "#primed-cache-chart",
title: "charts.cacheEnabled",
data: this._sanitizeChartDataSource(aItems),
sorted: true,
totals: {
size: L10N.getStr("charts.totalSize"),
time: L10N.getStr("charts.totalTime2"),
cached: L10N.getStr("charts.totalCached"),
count: L10N.getStr("charts.totalCount")
}
strings: this._commonChartStrings,
totals: this._commonChartTotals,
sorted: true
});
window.emit(EVENTS.PRIMED_CACHE_CHART_DISPLAYED);
},
@ -2350,26 +2361,54 @@ PerformanceStatisticsView.prototype = {
id: "#empty-cache-chart",
title: "charts.cacheDisabled",
data: this._sanitizeChartDataSource(aItems, true),
sorted: true,
totals: {
size: L10N.getStr("charts.totalSize"),
time: L10N.getStr("charts.totalTime2"),
cached: L10N.getStr("charts.totalCached"),
count: L10N.getStr("charts.totalCount")
}
strings: this._commonChartStrings,
totals: this._commonChartTotals,
sorted: true
});
window.emit(EVENTS.EMPTY_CACHE_CHART_DISPLAYED);
},
/**
* Common stringifier predicates used for items and totals in both the
* "primed" and "empty" cache charts.
*/
_commonChartStrings: {
size: value => {
let string = L10N.numberWithDecimals(value / 1024, CONTENT_SIZE_DECIMALS);
return L10N.getFormatStr("charts.sizeKB", string);
},
time: value => {
let string = L10N.numberWithDecimals(value / 1000, REQUEST_TIME_DECIMALS);
return L10N.getFormatStr("charts.totalS", string);
}
},
_commonChartTotals: {
size: total => {
let string = L10N.numberWithDecimals(total / 1024, CONTENT_SIZE_DECIMALS);
return L10N.getFormatStr("charts.totalSize", string);
},
time: total => {
let seconds = total / 1000;
let string = L10N.numberWithDecimals(seconds, REQUEST_TIME_DECIMALS);
return PluralForm.get(seconds, L10N.getStr("charts.totalSeconds")).replace("#1", string);
},
cached: total => {
return L10N.getFormatStr("charts.totalCached", total);
},
count: total => {
return L10N.getFormatStr("charts.totalCount", total);
}
},
/**
* Adds a specific chart to this container.
*
* @param object
* An object containing all or some the following properties:
* - id: either "#primed-cache-chart" or "#empty-cache-chart"
* - title/data/sorted/totals: @see Chart.jsm for details
* - title/data/strings/totals/sorted: @see Chart.jsm for details
*/
_createChart: function({ id, title, data, sorted, totals }) {
_createChart: function({ id, title, data, strings, totals, sorted }) {
let container = $(id);
// Nuke all existing charts of the specified type.
@ -2382,8 +2421,9 @@ PerformanceStatisticsView.prototype = {
diameter: NETWORK_ANALYSIS_PIE_CHART_DIAMETER,
title: L10N.getStr(title),
data: data,
sorted: sorted,
totals: totals
strings: strings,
totals: totals,
sorted: sorted
});
chart.on("click", (_, item) => {
@ -2448,13 +2488,6 @@ PerformanceStatisticsView.prototype = {
data[type].count++;
}
for (let chartItem of data) {
let size = L10N.numberWithDecimals(chartItem.size / 1024, CONTENT_SIZE_DECIMALS);
let time = L10N.numberWithDecimals(chartItem.time / 1000, REQUEST_TIME_DECIMALS);
chartItem.size = L10N.getFormatStr("charts.sizeKB", size);
chartItem.time = L10N.getFormatStr("charts.totalS", time);
}
return data.filter(e => e.count > 0);
},
};

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

@ -215,6 +215,11 @@
data-key="flash"
label="&netmonitorUI.footer.filterFlash;">
</button>
<button id="requests-menu-filter-other-button"
class="requests-menu-filter-button requests-menu-footer-button"
data-key="other"
label="&netmonitorUI.footer.filterOther;">
</button>
<spacer id="requests-menu-spacer"
class="requests-menu-footer-spacer"
flex="100"/>

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

@ -10,6 +10,7 @@ support-files =
html_json-custom-mime-test-page.html
html_json-long-test-page.html
html_json-malformed-test-page.html
html_json-text-mime-test-page.html
html_jsonp-test-page.html
html_navigate-test-page.html
html_post-data-test-page.html
@ -46,6 +47,7 @@ support-files =
[browser_net_json-long.js]
[browser_net_json-malformed.js]
[browser_net_json_custom_mime.js]
[browser_net_json_text_mime.js]
[browser_net_jsonp.js]
[browser_net_large-response.js]
[browser_net_open_request_in_tab.js]

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

@ -9,24 +9,27 @@ function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, Chart } = aMonitor.panelWin;
let { document, L10N, Chart } = aMonitor.panelWin;
let container = document.createElement("box");
let table = Chart.Table(document, {
title: "Table title",
data: [{
label1: 1,
label2: "11.1foo"
label2: 11.1
}, {
label1: 2,
label2: "12.2bar"
label2: 12.2
}, {
label1: 3,
label2: "13.3baz"
label2: 13.3
}],
strings: {
label2: (value, index) => value + ["foo", "bar", "baz"][index]
},
totals: {
label1: "Hello %S",
label2: "World %S"
label1: value => "Hello " + L10N.numberWithDecimals(value, 2),
label2: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

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

@ -17,8 +17,8 @@ function test() {
title: "Table title",
data: null,
totals: {
label1: "Hello %S",
label2: "World %S"
label1: value => "Hello " + L10N.numberWithDecimals(value, 2),
label2: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

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

@ -9,24 +9,27 @@ function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, Chart } = aMonitor.panelWin;
let { document, L10N, Chart } = aMonitor.panelWin;
let container = document.createElement("box");
let chart = Chart.PieTable(document, {
title: "Table title",
data: [{
size: 1,
label: "11.1foo"
label: 11.1
}, {
size: 2,
label: "12.2bar"
label: 12.2
}, {
size: 3,
label: "13.3baz"
label: 13.3
}],
strings: {
label2: (value, index) => value + ["foo", "bar", "baz"][index]
},
totals: {
size: "Hello %S",
label: "World %S"
size: value => "Hello " + L10N.numberWithDecimals(value, 2),
label: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

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

@ -0,0 +1,81 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if JSON responses with unusal/custom MIME types are handled correctly.
*/
function test() {
initNetMonitor(JSON_TEXT_MIME_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=json-text-mime", {
status: 200,
statusText: "OK",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED)
.then(testResponseTab)
.then(() => teardown(aMonitor))
.then(finish);
function testResponseTab() {
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), false,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), true,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
"There should be 1 json scope displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-property").length, 2,
"There should be 2 json properties displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
"greeting", "The first json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
"\"Hello third-party JSON!\"", "The first json property value was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
"__proto__", "The second json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
"Object", "The second json property value was incorrect.");
}
});
aDebuggee.performRequests();
});
}

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

@ -10,11 +10,12 @@ function test() {
info("Starting test... ");
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
NetworkDetails._json.lazyEmpty = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
waitForNetworkEvents(aMonitor, 2).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp&jsonp=$_0123Fun", {
status: 200,
@ -24,19 +25,37 @@ function test() {
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
"GET", CONTENT_TYPE_SJS + "?fmt=jsonp2&jsonp=$_4567Sad", {
status: 200,
statusText: "OK",
type: "json",
fullMimeType: "text/json; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.05),
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
Task.spawn(function() {
let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED)
.then(testResponseTab)
.then(() => teardown(aMonitor))
.then(finish);
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
function testResponseTab() {
yield waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED);
testResponseTab("$_0123Fun", "\"Hello JSONP!\"");
RequestsMenu.selectedIndex = 1;
yield waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED);
testResponseTab("$_4567Sad", "\"Hello weird JSONP!\"");
yield teardown(aMonitor);
finish();
});
function testResponseTab(aFunction, aGreeting) {
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
@ -66,13 +85,13 @@ function test() {
let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(jsonScope.querySelector(".name").getAttribute("value"),
L10N.getFormatStr("jsonpScopeName", "$_0123Fun"),
L10N.getFormatStr("jsonpScopeName", aFunction),
"The json scope doesn't have the correct title.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
"greeting", "The first json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
"\"Hello JSONP!\"", "The first json property value was incorrect.");
aGreeting, "The first json property value was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
"__proto__", "The second json property name was incorrect.");

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

@ -26,6 +26,7 @@ const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
const JSON_CUSTOM_MIME_URL = EXAMPLE_URL + "html_json-custom-mime-test-page.html";
const JSON_TEXT_MIME_URL = EXAMPLE_URL + "html_json-text-mime-test-page.html";
const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";

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

@ -0,0 +1,35 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>JSON text test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=json-text-mime", function() {
// Done.
});
}
</script>
</body>
</html>

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

@ -26,7 +26,9 @@
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=jsonp&jsonp=$_0123Fun", function() {
// Done.
get("sjs_content-type-test-server.sjs?fmt=jsonp2&jsonp=$_4567Sad", function() {
// Done.
});
});
}
</script>

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

@ -95,6 +95,15 @@ function handleRequest(request, response) {
response.finish();
break;
}
case "jsonp2": {
let fun = params.filter((s) => s.contains("jsonp="))[0].split("=")[1];
response.setStatusLine(request.httpVersion, status, "OK");
response.setHeader("Content-Type", "text/json; charset=utf-8", false);
maybeMakeCached();
response.write(" " + fun + " ( { \"greeting\": \"Hello weird JSONP!\" } ) ; ");
response.finish();
break;
}
case "json-long": {
let str = "{ \"greeting\": \"Hello long string JSON!\" },";
response.setStatusLine(request.httpVersion, status, "OK");
@ -112,6 +121,14 @@ function handleRequest(request, response) {
response.finish();
break;
}
case "json-text-mime": {
response.setStatusLine(request.httpVersion, status, "OK");
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
maybeMakeCached();
response.write("{ \"greeting\": \"Hello third-party JSON!\" }");
response.finish();
break;
}
case "json-custom-mime": {
response.setStatusLine(request.httpVersion, status, "OK");
response.setHeader("Content-Type", "text/x-bigcorp-json; charset=utf-8", false);

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

@ -96,18 +96,19 @@ function PieTableChart(node, pie, table) {
* - data: an array of items used to display each slice in the pie
* and each row in the table;
* @see `createPieChart` and `createTableChart` for details.
* - strings: @see `createTableChart` for details.
* - totals: @see `createTableChart` for details.
* - sorted: a flag specifying if the `data` should be sorted
* ascending by `size`.
* - totals: @see `createTableChart` for details.
* @return PieTableChart
* A pie+table chart proxy instance, which emits the following events:
* - "mouseenter", when the mouse enters a slice or a row
* - "mouseleave", when the mouse leaves a slice or a row
* - "click", when the mouse enters a slice or a row
*/
function createPieTableChart(document, { sorted, title, diameter, data, totals }) {
function createPieTableChart(document, { title, diameter, data, strings, totals, sorted }) {
if (sorted) {
data = data.slice().sort((a, b) => +(parseFloat(a.size) < parseFloat(b.size)));
data = data.slice().sort((a, b) => +(a.size < b.size));
}
let pie = Chart.Pie(document, {
@ -118,6 +119,7 @@ function createPieTableChart(document, { sorted, title, diameter, data, totals }
let table = Chart.Table(document, {
title: title,
data: data,
strings: strings,
totals: totals
});
@ -202,7 +204,7 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
let isPlaceholder = false;
// Filter out very small sizes, as they'll just render invisible slices.
data = data ? data.filter(e => parseFloat(e.size) > EPSILON) : null;
data = data ? data.filter(e => e.size > EPSILON) : null;
// If there's no data available, display an empty placeholder.
if (!data || !data.length) {
@ -222,10 +224,10 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
let proxy = new PieChart(container);
let total = data.reduce((acc, e) => acc + parseFloat(e.size), 0);
let angles = data.map(e => parseFloat(e.size) / total * (TAU - EPSILON));
let largest = data.reduce((a, b) => parseFloat(a.size) > parseFloat(b.size) ? a : b);
let smallest = data.reduce((a, b) => parseFloat(a.size) < parseFloat(b.size) ? a : b);
let total = data.reduce((acc, e) => acc + e.size, 0);
let angles = data.map(e => e.size / total * (TAU - EPSILON));
let largest = data.reduce((a, b) => a.size > b.size ? a : b);
let smallest = data.reduce((a, b) => a.size < b.size ? a : b);
let textDistance = radius / NAMED_SLICE_TEXT_DISTANCE_RATIO;
let translateDistance = radius / HOVERED_SLICE_TRANSLATE_DISTANCE_RATIO;
@ -307,19 +309,25 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
* should be objects representing columns, for which the
* properties' values will be displayed in each cell of a row.
* e.g: [{
* size: 1,
* label2: "1foo",
* label3: "2yolo"
* label1: 1,
* label2: 3,
* label3: "foo"
* }, {
* size: 2,
* label2: "3bar",
* label3: "4swag"
* label1: 4,
* label2: 6,
* label3: "bar
* }];
* - strings: an object specifying for which rows in the `data` array
* their cell values should be stringified and localized
* based on a predicate function;
* e.g: {
* label1: value => l10n.getFormatStr("...", value)
* }
* - totals: an object specifying for which rows in the `data` array
* the sum of their cells is to be displayed in the chart;
* e.g: {
* label1: "Total size: %S",
* label3: "Total lolz: %S"
* label1: total => l10n.getFormatStr("...", total), // 5
* label2: total => l10n.getFormatStr("...", total), // 9
* }
* @return TableChart
* A table chart proxy instance, which emits the following events:
@ -327,7 +335,9 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
* - "mouseleave", when the mouse leaves a row
* - "click", when the mouse clicks a row
*/
function createTableChart(document, { data, totals, title }) {
function createTableChart(document, { title, data, strings, totals }) {
strings = strings || {};
totals = totals || {};
let isPlaceholder = false;
// If there's no data available, display an empty placeholder.
@ -365,10 +375,12 @@ function createTableChart(document, { data, totals, title }) {
rowNode.appendChild(boxNode);
for (let [key, value] in Iterator(rowInfo)) {
let index = data.indexOf(rowInfo);
let stringified = strings[key] ? strings[key](value, index) : value;
let labelNode = document.createElement("label");
labelNode.className = "plain table-chart-row-label";
labelNode.setAttribute("name", key);
labelNode.setAttribute("value", value);
labelNode.setAttribute("value", stringified);
rowNode.appendChild(labelNode);
}
@ -380,13 +392,13 @@ function createTableChart(document, { data, totals, title }) {
let totalsNode = document.createElement("vbox");
totalsNode.className = "table-chart-totals";
for (let [key, value] in Iterator(totals || {})) {
let total = data.reduce((acc, e) => acc + parseFloat(e[key]), 0);
let formatted = !isNaN(total) ? L10N.numberWithDecimals(total, 2) : 0;
for (let [key, value] in Iterator(totals)) {
let total = data.reduce((acc, e) => acc + e[key], 0);
let stringified = totals[key] ? totals[key](total || 0) : total;
let labelNode = document.createElement("label");
labelNode.className = "plain table-chart-summary-label";
labelNode.setAttribute("name", key);
labelNode.setAttribute("value", value.replace("%S", formatted));
labelNode.setAttribute("value", stringified);
totalsNode.appendChild(labelNode);
}

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

@ -423,7 +423,6 @@ function SideMenuGroup(aWidget, aName, aOptions={}) {
let target = this._target = this.document.createElement("vbox");
target.className = "side-menu-widget-group";
target.setAttribute("name", aName);
target.setAttribute("tooltiptext", aName);
let list = this._list = this.document.createElement("vbox");
list.className = "side-menu-widget-group-list";

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

@ -166,9 +166,11 @@ charts.cacheDisabled=Empty cache
# in the performance analysis view for total requests size, in kilobytes.
charts.totalSize=Size: %S KB
# LOCALIZATION NOTE (charts.totalTime2): This is the label displayed
# in the performance analysis view for total requests time, in seconds.
charts.totalTime2=Time: %S seconds
# LOCALIZATION NOTE (charts.totalSeconds): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# This is the label displayed in the performance analysis view for the
# total requests time, in seconds.
charts.totalSeconds=Time: #1 second;Time: #1 seconds
# LOCALIZATION NOTE (charts.totalCached): This is the label displayed
# in the performance analysis view for total cached responses.

Двоичные данные
browser/themes/linux/devtools/inspect-button.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.3 KiB

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

@ -3,15 +3,6 @@
* 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/. */
#inspector-inspect-toolbutton {
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#inspector-inspect-toolbutton[checked=true] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-searchbox {
transition-property: max-width, -moz-padding-end, -moz-padding-start;
transition-duration: 250ms;

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 275 B

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

@ -23,11 +23,6 @@ browser.jar:
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
@ -73,7 +68,13 @@ browser.jar:
skin/classic/browser/webRTC-shareDevice-16.png
skin/classic/browser/webRTC-shareDevice-64.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@ -190,7 +191,10 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
skin/classic/browser/devtools/option-icon.png (../shared/devtools/images/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (../shared/devtools/images/itemToggle.png)
skin/classic/browser/devtools/itemToggle-light.png (../shared/devtools/images/itemToggle-light.png)
@ -200,7 +204,6 @@ browser.jar:
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
skin/classic/browser/devtools/noise.png (devtools/noise.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)

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

@ -1024,11 +1024,19 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(0px, 320px, 64px, 256px);
}
#bookmarks-menu-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(64px, 320px, 128px, 256px);
}
#history-panelmenu[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #history-panelmenu {
-moz-image-region: rect(0px, 448px, 64px, 384px);
}
#history-panelmenu[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(64px, 448px, 128px, 384px);
}
#downloads-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #downloads-button {
-moz-image-region: rect(0px, 512px, 64px, 448px);
@ -1069,6 +1077,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(0, 960px, 64px, 896px);
}
#characterencoding-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(64px, 960px, 128px, 896px);
}
#new-window-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #new-window-button {
-moz-image-region: rect(0px, 1024px, 64px, 960px);
@ -1109,6 +1121,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(0px, 1472px, 64px, 1408px);
}
#developer-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(64px, 1472px, 128px, 1408px);
}
#preferences-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #preferences-button {
-moz-image-region: rect(0px, 1536px, 64px, 1472px);

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

@ -5,6 +5,12 @@
%include ../../shared/customizableui/panelUIOverlay.inc.css
@media (min-resolution: 2dppx) {
toolbarbutton.panel-multiview-anchor {
background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
background-size: 16px;
}
#PanelUI-customize {
list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
}

Двоичные данные
browser/themes/osx/devtools/inspect-button.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.3 KiB

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

@ -6,15 +6,6 @@
%include ../shared.inc
%filter substitution
#inspector-inspect-toolbutton {
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#inspector-inspect-toolbutton[checked=true] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-toolbar {
padding-top: 4px;
padding-bottom: 4px;

Двоичные данные
browser/themes/osx/devtools/magnifying-glass.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 275 B

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

@ -23,13 +23,6 @@ browser.jar:
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
@ -120,6 +113,15 @@ browser.jar:
skin/classic/browser/webRTC-shareDevice-64@2x.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/webRTC-sharingDevice-16@2x.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png (../shared/customizableui/subView-arrow-back-inverted@2x.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
@ -298,7 +300,10 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
skin/classic/browser/devtools/option-icon.png (../shared/devtools/images/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (../shared/devtools/images/itemToggle.png)
skin/classic/browser/devtools/itemToggle-light.png (../shared/devtools/images/itemToggle-light.png)
@ -308,7 +313,6 @@ browser.jar:
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
skin/classic/browser/devtools/noise.png (devtools/noise.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)

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

@ -523,12 +523,22 @@ panelview toolbarseparator,
height: 16px;
}
#PanelUI-footer.panel-multiview-anchor,
#PanelUI-footer.panel-multiview-anchor > #PanelUI-help,
#PanelUI-footer > #PanelUI-footer-inner.panel-multiview-anchor,
toolbarbutton.panel-multiview-anchor {
background-color: Highlight;
background-image: linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
background-repeat: repeat-x;
}
toolbarbutton.panel-multiview-anchor {
background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
background-position: right 5px center;
background-repeat: no-repeat;
}
#PanelUI-footer > #PanelUI-footer-inner.panel-multiview-anchor,
toolbarbutton.panel-multiview-anchor,
toolbarbutton.panel-multiview-anchor > .toolbarbutton-menubutton-button {
color: HighlightText;
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 307 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 667 B

Двоичные данные
browser/themes/shared/devtools/images/magnifying-glass-light.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 186 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 421 B

Двоичные данные
browser/themes/shared/devtools/images/magnifying-glass.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 192 B

Двоичные данные
browser/themes/shared/devtools/images/magnifying-glass@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 449 B

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

@ -217,12 +217,30 @@
padding-bottom: 3px;
-moz-padding-start: 22px;
-moz-padding-end: 12px;
background-image: url(magnifying-glass.png);
background-position: 8px center;
background-size: 11px 11px;
background-repeat: no-repeat;
font-size: inherit;
}
.theme-dark .devtools-searchinput {
background-image: url(magnifying-glass.png);
}
.theme-light .devtools-searchinput {
background-image: url(magnifying-glass-light.png);
}
@media (min-resolution: 2dppx) {
.theme-dark .devtools-searchinput {
background-image: url(magnifying-glass@2x.png);
}
.theme-light .devtools-searchinput {
background-image: url(magnifying-glass-light@2x.png);
}
}
.devtools-searchinput:-moz-locale-dir(rtl) {
background-position: calc(100% - 8px) center;
}

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

@ -15,11 +15,19 @@ toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {
-moz-image-region: rect(0px, 160px, 32px, 128px);
}
#bookmarks-menu-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(32px, 160px, 64px, 128px);
}
#history-panelmenu[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #history-panelmenu {
-moz-image-region: rect(0px, 224px, 32px, 192px);
}
#history-panelmenu[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(32px, 224px, 64px, 192px);
}
#downloads-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #downloads-button {
-moz-image-region: rect(0px, 256px, 32px, 224px);
@ -60,6 +68,10 @@ toolbarpaletteitem[place="palette"] > #characterencoding-button {
-moz-image-region: rect(0px, 480px, 32px, 448px);
}
#characterencoding-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(32px, 480px, 64px, 448px);
}
#new-window-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #new-window-button {
-moz-image-region: rect(0px, 512px, 32px, 480px);
@ -100,6 +112,10 @@ toolbarpaletteitem[place="palette"] > #developer-button {
-moz-image-region: rect(0px, 736px, 32px, 704px);
}
#developer-button[cui-areatype="menu-panel"].panel-multiview-anchor {
-moz-image-region: rect(32px, 736px, 64px, 704px);
}
#preferences-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #preferences-button {
-moz-image-region: rect(0px, 768px, 32px, 736px);

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.3 KiB

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

@ -3,15 +3,6 @@
* 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/. */
#inspector-inspect-toolbutton {
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#inspector-inspect-toolbutton[checked=true] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-searchbox {
transition-property: max-width, -moz-padding-end, -moz-padding-start;
transition-duration: 250ms;

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

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

@ -25,12 +25,6 @@ browser.jar:
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
@ -92,7 +86,14 @@ browser.jar:
skin/classic/browser/webRTC-shareDevice-16.png
skin/classic/browser/webRTC-shareDevice-64.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
* skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@ -219,17 +220,19 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
skin/classic/browser/devtools/option-icon.png (../shared/devtools/images/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (../shared/devtools/images/itemToggle.png)
skin/classic/browser/devtools/itemToggle-light.png (../shared/devtools/images/itemToggle-light.png)
skin/classic/browser/devtools/itemArrow-dark-rtl.png (../shared/devtools/images/itemArrow-dark-rtl.png)
skin/classic/browser/devtools/itemArrow-dark-ltr.png (../shared/devtools/images/itemArrow-dark-ltr.png)
skin/classic/browser/devtools/itemArrow-rtl.png (../shared/devtools/images/itemArrow-rtl.svg)
skin/classic/browser/devtools/itemArrow-ltr.png (../shared/devtools/images/itemArrow-ltr.svg)
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
skin/classic/browser/devtools/noise.png (devtools/noise.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
@ -335,12 +338,6 @@ browser.jar:
* skin/classic/aero/browser/browser.css (browser-aero.css)
* skin/classic/aero/browser/browser-lightweightTheme.css
skin/classic/aero/browser/click-to-play-warning-stripes.png
skin/classic/aero/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/aero/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/aero/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
* skin/classic/aero/browser/engineManager.css
skin/classic/aero/browser/fullscreen-darknoise.png
skin/classic/aero/browser/Geolocation-16.png
@ -401,7 +398,14 @@ browser.jar:
skin/classic/aero/browser/webRTC-shareDevice-16.png
skin/classic/aero/browser/webRTC-shareDevice-64.png
skin/classic/aero/browser/webRTC-sharingDevice-16.png
skin/classic/aero/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/aero/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/aero/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
* skin/classic/aero/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/aero/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
* skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
skin/classic/aero/browser/downloads/buttons.png (downloads/buttons-aero.png)
skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@ -429,6 +433,7 @@ browser.jar:
skin/classic/aero/browser/places/bookmarksMenu.png (places/bookmarksMenu-aero.png)
skin/classic/aero/browser/places/bookmarksToolbar.png (places/bookmarksToolbar-aero.png)
skin/classic/aero/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel-aero.png)
skin/classic/aero/browser/places/bookmarks-notification-finish.png (places/bookmarks-notification-finish.png)
skin/classic/aero/browser/places/calendar.png (places/calendar-aero.png)
skin/classic/aero/browser/places/toolbarDropMarker.png (places/toolbarDropMarker-aero.png)
skin/classic/aero/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
@ -527,7 +532,10 @@ browser.jar:
* skin/classic/aero/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/aero/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/aero/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/aero/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/aero/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/aero/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/aero/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
skin/classic/aero/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
skin/classic/aero/browser/devtools/option-icon.png (../shared/devtools/images/option-icon.png)
skin/classic/aero/browser/devtools/itemToggle.png (../shared/devtools/images/itemToggle.png)
skin/classic/aero/browser/devtools/itemToggle-light.png (../shared/devtools/images/itemToggle-light.png)
@ -537,7 +545,6 @@ browser.jar:
skin/classic/aero/browser/devtools/itemArrow-ltr.png (../shared/devtools/images/itemArrow-ltr.svg)
skin/classic/aero/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
skin/classic/aero/browser/devtools/noise.png (devtools/noise.png)
skin/classic/aero/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/aero/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/aero/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
skin/classic/aero/browser/devtools/layoutview.css (devtools/layoutview.css)

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

@ -3675,7 +3675,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.15.4, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.15.5, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSS"; then

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

@ -6915,6 +6915,14 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
// app that does not use it.
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
if (docShell && docShell->GetIsApp()) {
nsString uri;
GetDocumentURI(uri);
if (!uri.EqualsLiteral("about:blank")) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM"), this,
nsContentUtils::eDOM_PROPERTIES,
"ImplicitMetaViewportTagFallback");
}
mViewportType = DisplayWidthHeightNoZoom;
return nsViewportInfo(aDisplaySize, /* allowZoom */ false);
}

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

@ -3,5 +3,6 @@ conformance/misc/type-conversion-test.html
conformance/more/conformance/quickCheckAPI-B2.html
conformance/more/conformance/quickCheckAPI-B3.html
conformance/more/conformance/quickCheckAPI-B4.html
conformance/more/conformance/quickCheckAPI-C.html
conformance/reading/read-pixels-test.html
conformance/textures/texture-mips.html

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

@ -23,7 +23,7 @@ function checkCache(url, inMemory, shouldExist, cb)
this.onCacheEntryAvailable = function oCEA(entry, isNew, appCache, status) {
if (shouldExist) {
ok(entry, "Entry not found");
is(this.inMemory, !entry.persistToDisk, "Entry is " + (inMemory ? "" : " not ") + " in memory as expected");
is(this.inMemory, !entry.persistent, "Entry is " + (inMemory ? "" : " not ") + " in memory as expected");
is(status, Components.results.NS_OK, "Entry not found");
} else {
ok(!entry, "Entry found");

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

@ -430,3 +430,4 @@ support-files =
[test_video_wakelock.html]
[test_input_files_not_nsIFile.html]
[test_ignoreuserfocus.html]
[test_fragment_form_pointer.html]

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

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=946585
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 946585</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=946585">Mozilla Bug 946585</a>
<p id="display"></p>
<div id="content" style="display: none">
<form><div id="formdiv"></div></form>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 946585 **/
var formDiv = document.getElementById("formdiv");
formDiv.innerHTML = '<form>';
is(formDiv.firstChild, null, "InnerHTML should not produce form element because the div has a form pointer.");
</script>
</body>
</html>

335
content/media/MediaData.cpp Normal file
Просмотреть файл

@ -0,0 +1,335 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "MediaData.h"
#include "MediaInfo.h"
#ifdef MOZ_OMX_DECODER
#include "GrallocImages.h"
#endif
#include "VideoUtils.h"
#include "ImageContainer.h"
namespace mozilla {
using namespace mozilla::gfx;
using layers::ImageContainer;
using layers::PlanarYCbCrImage;
using layers::PlanarYCbCrData;
void
AudioData::EnsureAudioBuffer()
{
if (mAudioBuffer)
return;
mAudioBuffer = SharedBuffer::Create(mFrames*mChannels*sizeof(AudioDataValue));
AudioDataValue* data = static_cast<AudioDataValue*>(mAudioBuffer->Data());
for (uint32_t i = 0; i < mFrames; ++i) {
for (uint32_t j = 0; j < mChannels; ++j) {
data[j*mFrames + i] = mAudioData[i*mChannels + j];
}
}
}
static bool
ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
{
return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPlane.mStride > 0;
}
#if 0
static bool
IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
const VideoData::YCbCrBuffer::Plane& aCbPlane,
const VideoData::YCbCrBuffer::Plane& aCrPlane)
{
return
aYPlane.mWidth % 2 == 0 &&
aYPlane.mHeight % 2 == 0 &&
aYPlane.mWidth / 2 == aCbPlane.mWidth &&
aYPlane.mHeight / 2 == aCbPlane.mHeight &&
aCbPlane.mWidth == aCrPlane.mWidth &&
aCbPlane.mHeight == aCrPlane.mHeight;
}
#endif
VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
: MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
mTimecode(aTimecode),
mDuplicate(true),
mKeyframe(false)
{
MOZ_COUNT_CTOR(VideoData);
NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
}
VideoData::VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
bool aKeyframe,
int64_t aTimecode,
nsIntSize aDisplay)
: MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
mDisplay(aDisplay),
mTimecode(aTimecode),
mDuplicate(false),
mKeyframe(aKeyframe)
{
MOZ_COUNT_CTOR(VideoData);
NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
}
VideoData::~VideoData()
{
MOZ_COUNT_DTOR(VideoData);
}
/* static */
VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
int64_t aDuration)
{
VideoData* v = new VideoData(aOther->mOffset,
aOther->mTime,
aDuration,
aOther->mKeyframe,
aOther->mTimecode,
aOther->mDisplay);
v->mImage = aOther->mImage;
return v;
}
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
if (!aImage && !aContainer) {
// Create a dummy VideoData with no image. This gives us something to
// send to media streams if necessary.
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
return v.forget();
}
// The following situation should never happen unless there is a bug
// in the decoder
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
NS_ERROR("C planes with different sizes");
return nullptr;
}
// The following situations could be triggered by invalid input
if (aPicture.width <= 0 || aPicture.height <= 0) {
NS_WARNING("Empty picture rect");
return nullptr;
}
if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
!ValidatePlane(aBuffer.mPlanes[2])) {
NS_WARNING("Invalid plane size");
return nullptr;
}
// Ensure the picture size specified in the headers can be extracted out of
// the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
{
// The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail.
NS_WARNING("Overflowing picture rect");
return nullptr;
}
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
if (!aImage) {
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
// format.
#if 0
if (IsYV12Format(Y, Cb, Cr)) {
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
}
#endif
if (!v->mImage) {
v->mImage = aContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
}
} else {
v->mImage = aImage;
}
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
"Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
PlanarYCbCrData data;
data.mYChannel = Y.mData + Y.mOffset;
data.mYSize = IntSize(Y.mWidth, Y.mHeight);
data.mYStride = Y.mStride;
data.mYSkip = Y.mSkip;
data.mCbChannel = Cb.mData + Cb.mOffset;
data.mCrChannel = Cr.mData + Cr.mOffset;
data.mCbCrSize = IntSize(Cb.mWidth, Cb.mHeight);
data.mCbCrStride = Cb.mStride;
data.mCbSkip = Cb.mSkip;
data.mCrSkip = Cr.mSkip;
data.mPicX = aPicture.x;
data.mPicY = aPicture.y;
data.mPicSize = aPicture.Size().ToIntSize();
data.mStereoMode = aInfo.mStereoMode;
videoImage->SetDelayedConversion(true);
if (!aImage) {
videoImage->SetData(data);
} else {
videoImage->SetDataNoCopy(data);
}
return v.forget();
}
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
return Create(aInfo, aContainer, nullptr, aOffset, aTime, aDuration, aBuffer,
aKeyframe, aTimecode, aPicture);
}
VideoData* VideoData::Create(VideoInfo& aInfo,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
return Create(aInfo, nullptr, aImage, aOffset, aTime, aDuration, aBuffer,
aKeyframe, aTimecode, aPicture);
}
VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const nsRefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
v->mImage = aImage;
return v.forget();
}
#ifdef MOZ_OMX_DECODER
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
mozilla::layers::GraphicBufferLocked* aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
if (!aContainer) {
// Create a dummy VideoData with no image. This gives us something to
// send to media streams if necessary.
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
return v.forget();
}
// The following situations could be triggered by invalid input
if (aPicture.width <= 0 || aPicture.height <= 0) {
NS_WARNING("Empty picture rect");
return nullptr;
}
// Ensure the picture size specified in the headers can be extracted out of
// the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.isValid() || !yLimit.isValid())
{
// The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail.
NS_WARNING("Overflowing picture rect");
return nullptr;
}
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
"Wrong format?");
typedef mozilla::layers::GrallocImage GrallocImage;
GrallocImage* videoImage = static_cast<GrallocImage*>(v->mImage.get());
GrallocImage::GrallocData data;
data.mPicSize = aPicture.Size().ToIntSize();
data.mGraphicBuffer = aBuffer;
videoImage->SetData(data);
return v.forget();
}
#endif // MOZ_OMX_DECODER
} // namespace mozilla

249
content/media/MediaData.h Normal file
Просмотреть файл

@ -0,0 +1,249 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#if !defined(MediaData_h)
#define MediaData_h
#include "nsSize.h"
#include "nsRect.h"
#include "AudioSampleFormat.h"
#include "nsIMemoryReporter.h"
#include "SharedBuffer.h"
namespace mozilla {
namespace layers {
class Image;
class ImageContainer;
}
// Container that holds media samples.
class MediaData {
public:
enum Type {
AUDIO_SAMPLES = 0,
VIDEO_FRAME = 1
};
MediaData(Type aType,
int64_t aOffset,
int64_t aTimestamp,
int64_t aDuration)
: mType(aType)
, mOffset(aOffset)
, mTime(aTimestamp)
, mDuration(aDuration)
{}
virtual ~MediaData() {}
// Type of contained data.
const Type mType;
// Approximate byte offset where this data was demuxed from its media.
const int64_t mOffset;
// Start time of sample, in microseconds.
const int64_t mTime;
// Duration of sample, in microseconds.
const int64_t mDuration;
int64_t GetEndTime() const { return mTime + mDuration; }
};
// Holds chunk a decoded audio frames.
class AudioData : public MediaData {
public:
AudioData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
uint32_t aFrames,
AudioDataValue* aData,
uint32_t aChannels)
: MediaData(AUDIO_SAMPLES, aOffset, aTime, aDuration)
, mFrames(aFrames)
, mChannels(aChannels)
, mAudioData(aData)
{
MOZ_COUNT_CTOR(AudioData);
}
~AudioData()
{
MOZ_COUNT_DTOR(AudioData);
}
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t size = aMallocSizeOf(this) + aMallocSizeOf(mAudioData);
if (mAudioBuffer) {
size += mAudioBuffer->SizeOfIncludingThis(aMallocSizeOf);
}
return size;
}
// If mAudioBuffer is null, creates it from mAudioData.
void EnsureAudioBuffer();
const uint32_t mFrames;
const uint32_t mChannels;
// At least one of mAudioBuffer/mAudioData must be non-null.
// mChannels channels, each with mFrames frames
nsRefPtr<SharedBuffer> mAudioBuffer;
// mFrames frames, each with mChannels values
nsAutoArrayPtr<AudioDataValue> mAudioData;
};
namespace layers {
class GraphicBufferLocked;
}
class VideoInfo;
// Holds a decoded video frame, in YCbCr format. These are queued in the reader.
class VideoData : public MediaData {
public:
typedef layers::ImageContainer ImageContainer;
typedef layers::Image Image;
// YCbCr data obtained from decoding the video. The index's are:
// 0 = Y
// 1 = Cb
// 2 = Cr
struct YCbCrBuffer {
struct Plane {
uint8_t* mData;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mStride;
uint32_t mOffset;
uint32_t mSkip;
};
Plane mPlanes[3];
};
// Constructs a VideoData object. If aImage is nullptr, creates a new Image
// holding a copy of the YCbCr data passed in aBuffer. If aImage is not
// nullptr, it's stored as the underlying video image and aBuffer is assumed
// to point to memory within aImage so no copy is made. aTimecode is a codec
// specific number representing the timestamp of the frame of video data.
// Returns nsnull if an error occurs. This may indicate that memory couldn't
// be allocated to create the VideoData object, or it may indicate some
// problem with the input data (e.g. negative stride).
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Variant that always makes a copy of aBuffer
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Variant to create a VideoData instance given an existing aImage
static VideoData* Create(VideoInfo& aInfo,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
layers::GraphicBufferLocked* aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
static VideoData* CreateFromImage(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const nsRefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Creates a new VideoData identical to aOther, but with a different
// specified duration. All data from aOther is copied into the new
// VideoData. The new VideoData's mImage field holds a reference to
// aOther's mImage, i.e. the Image is not copied. This function is useful
// in reader backends that can't determine the duration of a VideoData
// until the next frame is decoded, i.e. it's a way to change the const
// duration field on a VideoData.
static VideoData* ShallowCopyUpdateDuration(VideoData* aOther,
int64_t aDuration);
// Constructs a duplicate VideoData object. This intrinsically tells the
// player that it does not need to update the displayed frame when this
// frame is played; this frame is identical to the previous.
static VideoData* CreateDuplicate(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
int64_t aTimecode)
{
return new VideoData(aOffset, aTime, aDuration, aTimecode);
}
~VideoData();
// Dimensions at which to display the video frame. The picture region
// will be scaled to this size. This is should be the picture region's
// dimensions scaled with respect to its aspect ratio.
const nsIntSize mDisplay;
// Codec specific internal time code. For Ogg based codecs this is the
// granulepos.
const int64_t mTimecode;
// This frame's image.
nsRefPtr<Image> mImage;
// When true, denotes that this frame is identical to the frame that
// came before; it's a duplicate. mBuffer will be empty.
const bool mDuplicate;
const bool mKeyframe;
public:
VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
int64_t aTimecode);
VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
bool aKeyframe,
int64_t aTimecode,
nsIntSize aDisplay);
};
} // namespace mozilla
#endif // MediaData_h

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

@ -1,13 +1,10 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "MediaDecoderReader.h"
#ifdef MOZ_OMX_DECODER
#include "GrallocImages.h"
#endif
#include "AbstractMediaDecoder.h"
#include "VideoUtils.h"
#include "ImageContainer.h"
@ -18,20 +15,6 @@
namespace mozilla {
using namespace mozilla::gfx;
using layers::ImageContainer;
using layers::PlanarYCbCrImage;
using layers::PlanarYCbCrData;
// Verify these values are sane. Once we've checked the frame sizes, we then
// can do less integer overflow checking.
static_assert(MAX_VIDEO_WIDTH < PlanarYCbCrImage::MAX_DIMENSION,
"MAX_VIDEO_WIDTH is too large");
static_assert(MAX_VIDEO_HEIGHT < PlanarYCbCrImage::MAX_DIMENSION,
"MAX_VIDEO_HEIGHT is too large");
static_assert(PlanarYCbCrImage::MAX_DIMENSION < UINT32_MAX / PlanarYCbCrImage::MAX_DIMENSION,
"MAX_DIMENSION*MAX_DIMENSION doesn't fit in 32 bits");
// Un-comment to enable logging of seek bisections.
//#define SEEK_LOGGING
@ -48,344 +31,6 @@ extern PRLogModuleInfo* gMediaDecoderLog;
#define SEEK_LOG(type, msg)
#endif
void
AudioData::EnsureAudioBuffer()
{
if (mAudioBuffer)
return;
mAudioBuffer = SharedBuffer::Create(mFrames*mChannels*sizeof(AudioDataValue));
AudioDataValue* data = static_cast<AudioDataValue*>(mAudioBuffer->Data());
for (uint32_t i = 0; i < mFrames; ++i) {
for (uint32_t j = 0; j < mChannels; ++j) {
data[j*mFrames + i] = mAudioData[i*mChannels + j];
}
}
}
static bool
ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
{
return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPlane.mStride > 0;
}
#if 0
static bool
IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
const VideoData::YCbCrBuffer::Plane& aCbPlane,
const VideoData::YCbCrBuffer::Plane& aCrPlane)
{
return
aYPlane.mWidth % 2 == 0 &&
aYPlane.mHeight % 2 == 0 &&
aYPlane.mWidth / 2 == aCbPlane.mWidth &&
aYPlane.mHeight / 2 == aCbPlane.mHeight &&
aCbPlane.mWidth == aCrPlane.mWidth &&
aCbPlane.mHeight == aCrPlane.mHeight;
}
#endif
bool
VideoInfo::ValidateVideoRegion(const nsIntSize& aFrame,
const nsIntRect& aPicture,
const nsIntSize& aDisplay)
{
return
aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aFrame.width * aFrame.height != 0 &&
aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPicture.width * aPicture.height != 0 &&
aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aDisplay.width * aDisplay.height != 0;
}
VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
: MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
mTimecode(aTimecode),
mDuplicate(true),
mKeyframe(false)
{
MOZ_COUNT_CTOR(VideoData);
NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
}
VideoData::VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
bool aKeyframe,
int64_t aTimecode,
nsIntSize aDisplay)
: MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
mDisplay(aDisplay),
mTimecode(aTimecode),
mDuplicate(false),
mKeyframe(aKeyframe)
{
MOZ_COUNT_CTOR(VideoData);
NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
}
VideoData::~VideoData()
{
MOZ_COUNT_DTOR(VideoData);
}
/* static */
VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
int64_t aDuration)
{
VideoData* v = new VideoData(aOther->mOffset,
aOther->mTime,
aDuration,
aOther->mKeyframe,
aOther->mTimecode,
aOther->mDisplay);
v->mImage = aOther->mImage;
return v;
}
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
if (!aImage && !aContainer) {
// Create a dummy VideoData with no image. This gives us something to
// send to media streams if necessary.
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
return v.forget();
}
// The following situation should never happen unless there is a bug
// in the decoder
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
NS_ERROR("C planes with different sizes");
return nullptr;
}
// The following situations could be triggered by invalid input
if (aPicture.width <= 0 || aPicture.height <= 0) {
NS_WARNING("Empty picture rect");
return nullptr;
}
if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
!ValidatePlane(aBuffer.mPlanes[2])) {
NS_WARNING("Invalid plane size");
return nullptr;
}
// Ensure the picture size specified in the headers can be extracted out of
// the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
{
// The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail.
NS_WARNING("Overflowing picture rect");
return nullptr;
}
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
if (!aImage) {
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
// format.
#if 0
if (IsYV12Format(Y, Cb, Cr)) {
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
}
#endif
if (!v->mImage) {
v->mImage = aContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
}
} else {
v->mImage = aImage;
}
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
"Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
PlanarYCbCrData data;
data.mYChannel = Y.mData + Y.mOffset;
data.mYSize = IntSize(Y.mWidth, Y.mHeight);
data.mYStride = Y.mStride;
data.mYSkip = Y.mSkip;
data.mCbChannel = Cb.mData + Cb.mOffset;
data.mCrChannel = Cr.mData + Cr.mOffset;
data.mCbCrSize = IntSize(Cb.mWidth, Cb.mHeight);
data.mCbCrStride = Cb.mStride;
data.mCbSkip = Cb.mSkip;
data.mCrSkip = Cr.mSkip;
data.mPicX = aPicture.x;
data.mPicY = aPicture.y;
data.mPicSize = aPicture.Size().ToIntSize();
data.mStereoMode = aInfo.mStereoMode;
videoImage->SetDelayedConversion(true);
if (!aImage) {
videoImage->SetData(data);
} else {
videoImage->SetDataNoCopy(data);
}
return v.forget();
}
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
return Create(aInfo, aContainer, nullptr, aOffset, aTime, aDuration, aBuffer,
aKeyframe, aTimecode, aPicture);
}
VideoData* VideoData::Create(VideoInfo& aInfo,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
return Create(aInfo, nullptr, aImage, aOffset, aTime, aDuration, aBuffer,
aKeyframe, aTimecode, aPicture);
}
VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const nsRefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
v->mImage = aImage;
return v.forget();
}
#ifdef MOZ_OMX_DECODER
VideoData* VideoData::Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
mozilla::layers::GraphicBufferLocked* aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture)
{
if (!aContainer) {
// Create a dummy VideoData with no image. This gives us something to
// send to media streams if necessary.
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
return v.forget();
}
// The following situations could be triggered by invalid input
if (aPicture.width <= 0 || aPicture.height <= 0) {
NS_WARNING("Empty picture rect");
return nullptr;
}
// Ensure the picture size specified in the headers can be extracted out of
// the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.isValid() || !yLimit.isValid())
{
// The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail.
NS_WARNING("Overflowing picture rect");
return nullptr;
}
nsAutoPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay));
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
"Wrong format?");
typedef mozilla::layers::GrallocImage GrallocImage;
GrallocImage* videoImage = static_cast<GrallocImage*>(v->mImage.get());
GrallocImage::GrallocData data;
data.mPicSize = aPicture.Size().ToIntSize();
data.mGraphicBuffer = aBuffer;
videoImage->SetData(data);
return v.forget();
}
#endif // MOZ_OMX_DECODER
void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
const VideoData* v = static_cast<const VideoData*>(anObject);
if (!v->mImage) {

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

@ -1,471 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#if !defined(MediaDecoderReader_h_)
#define MediaDecoderReader_h_
#include <nsDeque.h>
#include "nsSize.h"
#include "mozilla/ReentrantMonitor.h"
#include "SharedBuffer.h"
#include "AudioSampleFormat.h"
#include "AbstractMediaDecoder.h"
#include "ImageTypes.h"
#include "nsIMemoryReporter.h"
struct nsIntRect;
#include "MediaInfo.h"
#include "MediaData.h"
#include "MediaQueue.h"
namespace mozilla {
namespace layers {
class Image;
class ImageContainer;
}
namespace dom {
class TimeRanges;
}
// Stores info relevant to presenting media frames.
class VideoInfo {
public:
VideoInfo()
: mDisplay(0,0),
mStereoMode(StereoMode::MONO),
mHasVideo(false)
{}
// Returns true if it's safe to use aPicture as the picture to be
// extracted inside a frame of size aFrame, and scaled up to and displayed
// at a size of aDisplay. You should validate the frame, picture, and
// display regions before using them to display video frames.
static bool ValidateVideoRegion(const nsIntSize& aFrame,
const nsIntRect& aPicture,
const nsIntSize& aDisplay);
// Size in pixels at which the video is rendered. This is after it has
// been scaled by its aspect ratio.
nsIntSize mDisplay;
// Indicates the frame layout for single track stereo videos.
StereoMode mStereoMode;
// True if we have an active video bitstream.
bool mHasVideo;
};
class AudioInfo {
public:
AudioInfo()
: mRate(44100),
mChannels(2),
mHasAudio(false)
{}
// Sample rate.
uint32_t mRate;
// Number of audio channels.
uint32_t mChannels;
// True if we have an active audio bitstream.
bool mHasAudio;
};
class MediaInfo {
public:
bool HasVideo() const
{
return mVideo.mHasVideo;
}
bool HasAudio() const
{
return mAudio.mHasAudio;
}
bool HasValidMedia() const
{
return HasVideo() || HasAudio();
}
VideoInfo mVideo;
AudioInfo mAudio;
};
// Container that holds media samples.
class MediaData {
public:
enum Type {
AUDIO_SAMPLES = 0,
VIDEO_FRAME = 1
};
MediaData(Type aType,
int64_t aOffset,
int64_t aTimestamp,
int64_t aDuration)
: mType(aType),
mOffset(aOffset),
mTime(aTimestamp),
mDuration(aDuration)
{}
virtual ~MediaData() {}
// Type of contained data.
const Type mType;
// Approximate byte offset where this data was demuxed from its media.
const int64_t mOffset;
// Start time of sample, in microseconds.
const int64_t mTime;
// Duration of sample, in microseconds.
const int64_t mDuration;
int64_t GetEndTime() const { return mTime + mDuration; }
};
// Holds chunk a decoded audio frames.
class AudioData : public MediaData {
public:
AudioData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
uint32_t aFrames,
AudioDataValue* aData,
uint32_t aChannels)
: MediaData(AUDIO_SAMPLES, aOffset, aTime, aDuration),
mFrames(aFrames),
mChannels(aChannels),
mAudioData(aData)
{
MOZ_COUNT_CTOR(AudioData);
}
~AudioData()
{
MOZ_COUNT_DTOR(AudioData);
}
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t size = aMallocSizeOf(this) + aMallocSizeOf(mAudioData);
if (mAudioBuffer) {
size += mAudioBuffer->SizeOfIncludingThis(aMallocSizeOf);
}
return size;
}
// If mAudioBuffer is null, creates it from mAudioData.
void EnsureAudioBuffer();
const uint32_t mFrames;
const uint32_t mChannels;
// At least one of mAudioBuffer/mAudioData must be non-null.
// mChannels channels, each with mFrames frames
nsRefPtr<SharedBuffer> mAudioBuffer;
// mFrames frames, each with mChannels values
nsAutoArrayPtr<AudioDataValue> mAudioData;
};
namespace layers {
class GraphicBufferLocked;
}
// Holds a decoded video frame, in YCbCr format. These are queued in the reader.
class VideoData : public MediaData {
public:
typedef layers::ImageContainer ImageContainer;
typedef layers::Image Image;
// YCbCr data obtained from decoding the video. The index's are:
// 0 = Y
// 1 = Cb
// 2 = Cr
struct YCbCrBuffer {
struct Plane {
uint8_t* mData;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mStride;
uint32_t mOffset;
uint32_t mSkip;
};
Plane mPlanes[3];
};
// Constructs a VideoData object. If aImage is nullptr, creates a new Image
// holding a copy of the YCbCr data passed in aBuffer. If aImage is not
// nullptr, it's stored as the underlying video image and aBuffer is assumed
// to point to memory within aImage so no copy is made. aTimecode is a codec
// specific number representing the timestamp of the frame of video data.
// Returns nsnull if an error occurs. This may indicate that memory couldn't
// be allocated to create the VideoData object, or it may indicate some
// problem with the input data (e.g. negative stride).
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Variant that always makes a copy of aBuffer
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Variant to create a VideoData instance given an existing aImage
static VideoData* Create(VideoInfo& aInfo,
Image* aImage,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const YCbCrBuffer &aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
static VideoData* Create(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
layers::GraphicBufferLocked* aBuffer,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
static VideoData* CreateFromImage(VideoInfo& aInfo,
ImageContainer* aContainer,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const nsRefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
nsIntRect aPicture);
// Creates a new VideoData identical to aOther, but with a different
// specified duration. All data from aOther is copied into the new
// VideoData. The new VideoData's mImage field holds a reference to
// aOther's mImage, i.e. the Image is not copied. This function is useful
// in reader backends that can't determine the duration of a VideoData
// until the next frame is decoded, i.e. it's a way to change the const
// duration field on a VideoData.
static VideoData* ShallowCopyUpdateDuration(VideoData* aOther,
int64_t aDuration);
// Constructs a duplicate VideoData object. This intrinsically tells the
// player that it does not need to update the displayed frame when this
// frame is played; this frame is identical to the previous.
static VideoData* CreateDuplicate(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
int64_t aTimecode)
{
return new VideoData(aOffset, aTime, aDuration, aTimecode);
}
~VideoData();
// Dimensions at which to display the video frame. The picture region
// will be scaled to this size. This is should be the picture region's
// dimensions scaled with respect to its aspect ratio.
const nsIntSize mDisplay;
// Codec specific internal time code. For Ogg based codecs this is the
// granulepos.
const int64_t mTimecode;
// This frame's image.
nsRefPtr<Image> mImage;
// When true, denotes that this frame is identical to the frame that
// came before; it's a duplicate. mBuffer will be empty.
const bool mDuplicate;
const bool mKeyframe;
public:
VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
int64_t aTimecode);
VideoData(int64_t aOffset,
int64_t aTime,
int64_t aDuration,
bool aKeyframe,
int64_t aTimecode,
nsIntSize aDisplay);
};
// Thread and type safe wrapper around nsDeque.
template <class T>
class MediaQueueDeallocator : public nsDequeFunctor {
virtual void* operator() (void* anObject) {
delete static_cast<T*>(anObject);
return nullptr;
}
};
template <class T> class MediaQueue : private nsDeque {
public:
MediaQueue()
: nsDeque(new MediaQueueDeallocator<T>()),
mReentrantMonitor("mediaqueue"),
mEndOfStream(false)
{}
~MediaQueue() {
Reset();
}
inline int32_t GetSize() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return nsDeque::GetSize();
}
inline void Push(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Push(aItem);
}
inline void PushFront(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::PushFront(aItem);
}
inline T* Pop() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::Pop());
}
inline T* PopFront() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::PopFront());
}
inline T* Peek() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::Peek());
}
inline T* PeekFront() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::PeekFront());
}
inline void Empty() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Empty();
}
inline void Erase() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Erase();
}
void Reset() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (GetSize() > 0) {
T* x = PopFront();
delete x;
}
mEndOfStream = false;
}
bool AtEndOfStream() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return GetSize() == 0 && mEndOfStream;
}
// Returns true if the media queue has had its last item added to it.
// This happens when the media stream has been completely decoded. Note this
// does not mean that the corresponding stream has finished playback.
bool IsFinished() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mEndOfStream;
}
// Informs the media queue that it won't be receiving any more items.
void Finish() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mEndOfStream = true;
}
// Returns the approximate number of microseconds of items in the queue.
int64_t Duration() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (GetSize() < 2) {
return 0;
}
T* last = Peek();
T* first = PeekFront();
return last->mTime - first->mTime;
}
void LockedForEach(nsDequeFunctor& aFunctor) const {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
ForEach(aFunctor);
}
// Extracts elements from the queue into aResult, in order.
// Elements whose start time is before aTime are ignored.
void GetElementsAfter(int64_t aTime, nsTArray<T*>* aResult) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!GetSize())
return;
int32_t i;
for (i = GetSize() - 1; i > 0; --i) {
T* v = static_cast<T*>(ObjectAt(i));
if (v->GetEndTime() < aTime)
break;
}
// Elements less than i have a end time before aTime. It's also possible
// that the element at i has a end time before aTime, but that's OK.
for (; i < GetSize(); ++i) {
aResult->AppendElement(static_cast<T*>(ObjectAt(i)));
}
}
uint32_t FrameCount() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
uint32_t frames = 0;
for (int32_t i = 0; i < GetSize(); ++i) {
T* v = static_cast<T*>(ObjectAt(i));
frames += v->mFrames;
}
return frames;
}
private:
mutable ReentrantMonitor mReentrantMonitor;
// True when we've decoded the last frame of data in the
// bitstream for which we're queueing frame data.
bool mEndOfStream;
};
// Encapsulates the decoding and reading of media data. Reading can only be
// done on the decode thread. Never hold the decoder monitor when
// calling into this class. Unless otherwise specified, methods and fields of

76
content/media/MediaInfo.h Normal file
Просмотреть файл

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#if !defined(MediaInfo_h)
#define MediaInfo_h
#include "nsSize.h"
#include "nsRect.h"
#include "ImageTypes.h"
namespace mozilla {
// Stores info relevant to presenting media frames.
class VideoInfo {
public:
VideoInfo()
: mDisplay(0,0)
, mStereoMode(StereoMode::MONO)
, mHasVideo(false)
{}
// Size in pixels at which the video is rendered. This is after it has
// been scaled by its aspect ratio.
nsIntSize mDisplay;
// Indicates the frame layout for single track stereo videos.
StereoMode mStereoMode;
// True if we have an active video bitstream.
bool mHasVideo;
};
class AudioInfo {
public:
AudioInfo()
: mRate(44100)
, mChannels(2)
, mHasAudio(false)
{}
// Sample rate.
uint32_t mRate;
// Number of audio channels.
uint32_t mChannels;
// True if we have an active audio bitstream.
bool mHasAudio;
};
class MediaInfo {
public:
bool HasVideo() const
{
return mVideo.mHasVideo;
}
bool HasAudio() const
{
return mAudio.mHasAudio;
}
bool HasValidMedia() const
{
return HasVideo() || HasAudio();
}
VideoInfo mVideo;
AudioInfo mAudio;
};
} // namespace mozilla
#endif // MediaInfo_h

165
content/media/MediaQueue.h Normal file
Просмотреть файл

@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaQueue_h_)
#define MediaQueue_h_
#include "nsDeque.h"
#include "nsTArray.h"
#include "mozilla/ReentrantMonitor.h"
namespace mozilla {
// Thread and type safe wrapper around nsDeque.
template <class T>
class MediaQueueDeallocator : public nsDequeFunctor {
virtual void* operator() (void* anObject) {
delete static_cast<T*>(anObject);
return nullptr;
}
};
template <class T> class MediaQueue : private nsDeque {
public:
MediaQueue()
: nsDeque(new MediaQueueDeallocator<T>()),
mReentrantMonitor("mediaqueue"),
mEndOfStream(false)
{}
~MediaQueue() {
Reset();
}
inline int32_t GetSize() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return nsDeque::GetSize();
}
inline void Push(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Push(aItem);
}
inline void PushFront(T* aItem) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::PushFront(aItem);
}
inline T* Pop() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::Pop());
}
inline T* PopFront() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::PopFront());
}
inline T* Peek() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::Peek());
}
inline T* PeekFront() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return static_cast<T*>(nsDeque::PeekFront());
}
inline void Empty() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Empty();
}
inline void Erase() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsDeque::Erase();
}
void Reset() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (GetSize() > 0) {
T* x = PopFront();
delete x;
}
mEndOfStream = false;
}
bool AtEndOfStream() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return GetSize() == 0 && mEndOfStream;
}
// Returns true if the media queue has had its last item added to it.
// This happens when the media stream has been completely decoded. Note this
// does not mean that the corresponding stream has finished playback.
bool IsFinished() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mEndOfStream;
}
// Informs the media queue that it won't be receiving any more items.
void Finish() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mEndOfStream = true;
}
// Returns the approximate number of microseconds of items in the queue.
int64_t Duration() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (GetSize() < 2) {
return 0;
}
T* last = Peek();
T* first = PeekFront();
return last->mTime - first->mTime;
}
void LockedForEach(nsDequeFunctor& aFunctor) const {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
ForEach(aFunctor);
}
// Extracts elements from the queue into aResult, in order.
// Elements whose start time is before aTime are ignored.
void GetElementsAfter(int64_t aTime, nsTArray<T*>* aResult) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!GetSize())
return;
int32_t i;
for (i = GetSize() - 1; i > 0; --i) {
T* v = static_cast<T*>(ObjectAt(i));
if (v->GetEndTime() < aTime)
break;
}
// Elements less than i have a end time before aTime. It's also possible
// that the element at i has a end time before aTime, but that's OK.
for (; i < GetSize(); ++i) {
aResult->AppendElement(static_cast<T*>(ObjectAt(i)));
}
}
uint32_t FrameCount() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
uint32_t frames = 0;
for (int32_t i = 0; i < GetSize(); ++i) {
T* v = static_cast<T*>(ObjectAt(i));
frames += v->mFrames;
}
return frames;
}
private:
mutable ReentrantMonitor mReentrantMonitor;
// True when we've decoded the last frame of data in the
// bitstream for which we're queueing frame data.
bool mEndOfStream;
};
} // namespace mozilla
#endif

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

@ -8,11 +8,14 @@
#include "nsMathUtils.h"
#include "nsSize.h"
#include "VorbisUtils.h"
#include "ImageContainer.h"
#include <stdint.h>
namespace mozilla {
using layers::PlanarYCbCrImage;
// Converts from number of audio frames to microseconds, given the specified
// audio rate.
CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
@ -156,4 +159,27 @@ IsVideoContentType(const nsCString& aContentType)
return false;
}
} // end namespace mozilla
bool
IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
const nsIntSize& aDisplay)
{
return
aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aFrame.width * aFrame.height != 0 &&
aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPicture.width * aPicture.height != 0 &&
aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aDisplay.width * aDisplay.height != 0;
}
} // end namespace mozilla

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

@ -26,6 +26,7 @@ using mozilla::CheckedInt32;
using mozilla::CheckedUint32;
struct nsIntSize;
struct nsIntRect;
// This file contains stuff we'd rather put elsewhere, but which is
// dependent on other changes which we don't want to wait for. We plan to
@ -135,7 +136,7 @@ static const int32_t MAX_VIDEO_WIDTH = 4000;
static const int32_t MAX_VIDEO_HEIGHT = 3000;
// Scales the display rect aDisplay by aspect ratio aAspectRatio.
// Note that aDisplay must be validated by VideoInfo::ValidateVideoRegion()
// Note that aDisplay must be validated by IsValidVideoRegion()
// before being used!
void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
@ -157,6 +158,13 @@ int DownmixAudioToStereo(mozilla::AudioDataValue* buffer,
bool IsVideoContentType(const nsCString& aContentType);
// Returns true if it's safe to use aPicture as the picture to be
// extracted inside a frame of size aFrame, and scaled up to and displayed
// at a size of aDisplay. You should validate the frame, picture, and
// display regions before using them to display video frames.
bool IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
const nsIntSize& aDisplay);
} // end namespace mozilla
#endif

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

@ -171,7 +171,7 @@ WMFVideoDecoder::ConfigureVideoFrameGeometry()
nsIntSize frameSize = nsIntSize(width, height);
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRegion, displaySize)) {
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
// Video track's frame sizes will overflow. Ignore the video track.
return E_FAIL;
}

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

@ -73,11 +73,14 @@ EXPORTS += [
'FileBlockCache.h',
'Latency.h',
'MediaCache.h',
'MediaData.h',
'MediaDecoder.h',
'MediaDecoderOwner.h',
'MediaDecoderReader.h',
'MediaDecoderStateMachine.h',
'MediaInfo.h',
'MediaMetadataManager.h',
'MediaQueue.h',
'MediaRecorder.h',
'MediaResource.h',
'MediaSegment.h',
@ -122,6 +125,7 @@ UNIFIED_SOURCES += [
'EncodedBufferCache.cpp',
'FileBlockCache.cpp',
'MediaCache.cpp',
'MediaData.cpp',
'MediaDecoder.cpp',
'MediaDecoderReader.cpp',
'MediaDecoderStateMachine.cpp',

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

@ -276,7 +276,7 @@ bool TheoraState::Init() {
// maximum, or zero sized.
nsIntSize frame(mInfo.frame_width, mInfo.frame_height);
nsIntRect picture(mInfo.pic_x, mInfo.pic_y, mInfo.pic_width, mInfo.pic_height);
if (!VideoInfo::ValidateVideoRegion(frame, picture, frame)) {
if (!IsValidVideoRegion(frame, picture, frame)) {
return mActive = false;
}

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

@ -288,7 +288,7 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
nsIntSize frameSize(mTheoraState->mInfo.frame_width,
mTheoraState->mInfo.frame_height);
if (VideoInfo::ValidateVideoRegion(frameSize, picture, displaySize)) {
if (IsValidVideoRegion(frameSize, picture, displaySize)) {
// Video track's frame sizes will not overflow. Activate the video track.
mInfo.mVideo.mHasVideo = true;
mInfo.mVideo.mDisplay = displaySize;

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

@ -146,7 +146,7 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
// that our video frame creation code doesn't overflow.
nsIntSize displaySize(width, height);
nsIntSize frameSize(width, height);
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRect, displaySize)) {
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
return NS_ERROR_FAILURE;
}

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

@ -73,7 +73,7 @@ nsresult MediaPluginReader::ReadMetadata(MediaInfo* aInfo,
// that our video frame creation code doesn't overflow.
nsIntSize displaySize(width, height);
nsIntSize frameSize(width, height);
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRect, displaySize)) {
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
return NS_ERROR_FAILURE;
}

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

@ -70,7 +70,7 @@ nsresult RawReader::ReadMetadata(MediaInfo* aInfo,
ScaleDisplayByAspectRatio(display, pixelAspectRatio);
mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight);
nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight);
if (!VideoInfo::ValidateVideoRegion(frameSize, mPicture, display)) {
if (!IsValidVideoRegion(frameSize, mPicture, display)) {
// Video track's frame sizes will overflow. Fail.
return NS_ERROR_FAILURE;
}

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

@ -329,7 +329,7 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
// that our video frame creation code doesn't overflow.
nsIntSize displaySize(params.display_width, params.display_height);
nsIntSize frameSize(params.width, params.height);
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRect, displaySize)) {
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
// Video track's frame sizes will overflow. Ignore the video track.
continue;
}

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

@ -314,7 +314,7 @@ WMFReader::ConfigureVideoFrameGeometry(IMFMediaType* aMediaType)
nsIntSize frameSize = nsIntSize(width, height);
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRegion, displaySize)) {
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
// Video track's frame sizes will overflow. Ignore the video track.
return E_FAIL;
}

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

@ -6781,9 +6781,15 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
// Permission will be checked in the parent process.
appCacheChannel->SetChooseApplicationCache(true);
} else {
appCacheChannel->SetChooseApplicationCache(
NS_ShouldCheckAppCache(newURI,
mInPrivateBrowsing));
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (secMan) {
nsCOMPtr<nsIPrincipal> principal;
secMan->GetDocShellCodebasePrincipal(newURI, this, getter_AddRefs(principal));
appCacheChannel->SetChooseApplicationCache(NS_ShouldCheckAppCache(principal,
mInPrivateBrowsing));
}
}
}
@ -9713,8 +9719,15 @@ nsDocShell::DoURILoad(nsIURI * aURI,
// Permission will be checked in the parent process
appCacheChannel->SetChooseApplicationCache(true);
} else {
appCacheChannel->SetChooseApplicationCache(
NS_ShouldCheckAppCache(aURI, mInPrivateBrowsing));
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (secMan) {
nsCOMPtr<nsIPrincipal> principal;
secMan->GetDocShellCodebasePrincipal(aURI, this, getter_AddRefs(principal));
appCacheChannel->SetChooseApplicationCache(
NS_ShouldCheckAppCache(principal, mInPrivateBrowsing));
}
}
}

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

@ -1575,9 +1575,8 @@ this.DOMApplicationRegistry = {
},
manifestURL: aApp.manifestURL
});
let cacheUpdate = aProfileDir
? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
: updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
let cacheUpdate = updateSvc.scheduleAppUpdate(
appcacheURI, docURI, aApp.localId, false, aProfileDir);
// We save the download details for potential further usage like
// cancelling it.

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

@ -205,6 +205,7 @@ static const DOMJSClass Class = {
nullptr, /* hasInstance */
nullptr, /* construct */
%s, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
},

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

@ -221,6 +221,10 @@ this.DOMIdentity = {
return this._serviceContexts.get(this._mmContexts.get(targetMM));
},
hasContextForMM: function(targetMM) {
return this._mmContexts.has(targetMM);
},
/*
* Delete the RPWatchContext object for a given message manager. Removes the
* mapping both from _serviceContexts and _mmContexts.
@ -344,6 +348,10 @@ this.DOMIdentity = {
},
_childProcessShutdown: function DOMIdentity__childProcessShutdown(targetMM) {
if (!this.hasContextForMM(targetMM)) {
return;
}
this.getContextForMM(targetMM).RP.childProcessShutdown(targetMM);
this.deleteContextForMM(targetMM);

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

@ -144,3 +144,4 @@ UseOfDOM3LoadMethodWarning=Use of document.load() is deprecated. To upgrade your
ShowModalDialogWarning=Use of window.showModalDialog() is deprecated. Use window.open() instead. For more help https://developer.mozilla.org/en-US/docs/Web/API/Window.open
# LOCALIZATION NOTE: Do not translate "window._content" or "window.content"
Window_ContentWarning=window._content is deprecated. Please use window.content instead.
ImplicitMetaViewportTagFallback=No meta-viewport tag found. Please explicitly specify one to prevent unexpected behavioural changes in future versions. For more help https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi.h"
#include "js/CharacterEncoding.h"
#include "js/OldDebugAPI.h"
#include "nsJSON.h"
#include "nsIXPConnect.h"
@ -524,8 +525,8 @@ nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
JS::Rooted<JS::Value> reviver(mCx, JS::NullValue()), value(mCx);
JS::StableCharPtr chars(reinterpret_cast<const jschar*>(mBufferedChars.Elements()),
mBufferedChars.Length());
JS::ConstTwoByteChars chars(reinterpret_cast<const jschar*>(mBufferedChars.Elements()),
mBufferedChars.Length());
bool ok = JS_ParseJSONWithReviver(mCx, chars.get(),
uint32_t(mBufferedChars.Length()),
reviver, &value);

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

@ -1,4 +1,6 @@
[DEFAULT]
# Timeouts on all platforms (bug 932350)
skip-if = true
support-files =
child_ip_address.html
file_crossdomainprops_inner.html

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

@ -1,6 +1,6 @@
[DEFAULT]
# Timeouts on OS X (bug 921635)
skip-if = os == "mac"
# Timeouts on all platforms (bug 932350)
skip-if = true
support-files =
DOMTestCase.js
activity-home.css

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

@ -1,6 +1,6 @@
[DEFAULT]
# Timeouts on OS X (bug 921635)
skip-if = os == "mac"
# Timeouts on all platforms (bug 932350)
skip-if = true
support-files =
DOMTestCase.js
exclusions.js

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

@ -1,6 +1,6 @@
[DEFAULT]
# Timeouts on OS X (bug 921635)
skip-if = os == "mac"
# Timeouts on all platforms (bug 932350)
skip-if = true
support-files =
DOMTestCase.js
files/anchor.html

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

@ -65,15 +65,29 @@ MacIOSurfaceTextureClientOGL::GetSize() const
return gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
}
class MacIOSurfaceTextureClientData : public TextureClientData
{
public:
MacIOSurfaceTextureClientData(MacIOSurface* aSurface)
: mSurface(aSurface)
{}
virtual void DeallocateSharedData(ISurfaceAllocator*) MOZ_OVERRIDE
{
mSurface = nullptr;
}
private:
RefPtr<MacIOSurface> mSurface;
};
TextureClientData*
MacIOSurfaceTextureClientOGL::DropTextureData()
{
// MacIOSurface has proper cross-process refcounting so we can just drop
// our reference now, and the data will stay alive (at least) until the host
// has also been torn down.
TextureClientData* data = new MacIOSurfaceTextureClientData(mSurface);
mSurface = nullptr;
MarkInvalid();
return nullptr;
return data;
}
}

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

@ -788,10 +788,9 @@ gfxRect gfx3DMatrix::ProjectRectBounds(const gfxRect& aRect) const
gfxPoint points[4];
points[0] = ProjectPoint(aRect.TopLeft());
points[1] = ProjectPoint(gfxPoint(aRect.X() + aRect.Width(), aRect.Y()));
points[2] = ProjectPoint(gfxPoint(aRect.X(), aRect.Y() + aRect.Height()));
points[3] = ProjectPoint(gfxPoint(aRect.X() + aRect.Width(),
aRect.Y() + aRect.Height()));
points[1] = ProjectPoint(aRect.TopRight());
points[2] = ProjectPoint(aRect.BottomLeft());
points[3] = ProjectPoint(aRect.BottomRight());
gfxFloat min_x, max_x;
gfxFloat min_y, max_y;
@ -809,6 +808,34 @@ gfxRect gfx3DMatrix::ProjectRectBounds(const gfxRect& aRect) const
return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y);
}
gfxRect gfx3DMatrix::UntransformBounds(const gfxRect& aRect, const gfxRect& aChildBounds) const
{
if (Is2D()) {
return Inverse().TransformBounds(aRect);
}
gfxRect bounds = TransformBounds(aChildBounds);
gfxRect rect = aRect.Intersect(bounds);
return Inverse().ProjectRectBounds(rect);
}
bool gfx3DMatrix::UntransformPoint(const gfxPoint& aPoint, const gfxRect& aChildBounds, gfxPoint* aOut) const
{
if (Is2D()) {
*aOut = Inverse().Transform(aPoint);
return true;
}
gfxRect bounds = TransformBounds(aChildBounds);
if (!bounds.Contains(aPoint)) {
return false;
}
*aOut = Inverse().ProjectPoint(aPoint);
return true;
}
gfxPoint3D gfx3DMatrix::GetNormalVector() const
{
// Define a plane in transformed space as the transformations

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

@ -250,6 +250,25 @@ public:
gfxPoint ProjectPoint(const gfxPoint& aPoint) const;
gfxRect ProjectRectBounds(const gfxRect& aRect) const;
/**
* Transforms a point by the inverse of this matrix. In the case of perspective transforms, some screen
* points have no equivalent in the untransformed plane (if they exist past the vanishing point). To
* avoid this, we need to specify the bounds of the untransformed plane to restrict the search area.
*
* @param aPoint Point to untransform.
* @param aChildBounds Bounds of the untransformed plane.
* @param aOut Untransformed point.
* @return Returns true if a point was found within a ChildBounds, false otherwise.
*/
bool UntransformPoint(const gfxPoint& aPoint, const gfxRect& aChildBounds, gfxPoint* aOut) const;
/**
* Same as UntransformPoint, but untransforms a rect and returns the bounding rect of the result.
* Returns an empty rect if the result doesn't intersect aChildBounds.
*/
gfxRect UntransformBounds(const gfxRect& aRect, const gfxRect& aChildBounds) const;
/**
* Inverts this matrix, if possible. Otherwise, the matrix is left

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

@ -28,11 +28,7 @@ SHLIB.c= $(CC) -dynamiclib -dynamic $(CFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
SHLIB.cc= $(CXX) -dynamiclib -dynamic $(CXXFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
## Compiler switches to embed a library name and version information
ifeq ($(ENABLE_RPATH),YES)
LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name $(libdir)/$(notdir $(MIDDLE_SO_TARGET))
else
LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name $(notdir $(MIDDLE_SO_TARGET))
endif
LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name @executable_path/$(notdir $(MIDDLE_SO_TARGET))
## Compiler switch to embed a runtime search path
LD_RPATH=

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

@ -52,6 +52,7 @@ svn info $1 | grep -v '^Revision: [[:digit:]]\+$' > ${icu_dir}/SVN-INFO
patch -d ${icu_dir}/../../ -p1 < ${icu_dir}/../icu-patches/bug-724533
patch -d ${icu_dir}/../../ -p1 < ${icu_dir}/../icu-patches/bug-899722-4
patch -d ${icu_dir}/../../ -p1 < ${icu_dir}/../icu-patches/bug-915735
patch -d ${icu_dir}/../../ -p1 < ${icu_dir}/../icu-patches/genrb-omitCollationRules.diff
patch -d ${icu_dir}/../../ -p1 < ${icu_dir}/../icu-patches/qualify-uinitonce-windows.diff

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

@ -123,21 +123,6 @@ class TwoByteChars : public mozilla::Range<jschar>
TwoByteChars(const jschar *aChars, size_t aLength) : Base(const_cast<jschar *>(aChars), aLength) {}
};
/*
* A non-convertible variant of TwoByteChars that does not refer to characters
* inlined inside a JSShortString or a JSInlineString. StableTwoByteChars are
* thus safe to hold across a GC.
*/
class StableTwoByteChars : public mozilla::Range<jschar>
{
typedef mozilla::Range<jschar> Base;
public:
StableTwoByteChars() : Base() {}
StableTwoByteChars(jschar *aChars, size_t aLength) : Base(aChars, aLength) {}
StableTwoByteChars(const jschar *aChars, size_t aLength) : Base(const_cast<jschar *>(aChars), aLength) {}
};
/*
* A TwoByteChars, but \0 terminated for compatibility with JSFlatString.
*/
@ -157,6 +142,25 @@ class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
using Base::operator=;
};
typedef mozilla::RangedPtr<const jschar> ConstCharPtr;
/*
* Like TwoByteChars, but the chars are const.
*/
class ConstTwoByteChars : public mozilla::RangedPtr<const jschar>
{
public:
ConstTwoByteChars(const ConstTwoByteChars &s) : ConstCharPtr(s) {}
ConstTwoByteChars(const mozilla::RangedPtr<const jschar> &s) : ConstCharPtr(s) {}
ConstTwoByteChars(const jschar *s, size_t len) : ConstCharPtr(s, len) {}
ConstTwoByteChars(const jschar *pos, const jschar *start, size_t len)
: ConstCharPtr(pos, start, len)
{}
using ConstCharPtr::operator=;
};
/*
* Convert a 2-byte character sequence to "ISO-Latin-1". This works by
* truncating each 2-byte pair in the sequence to a 1-byte pair. If the source

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

@ -25,6 +25,7 @@
*/
class JSFreeOp;
struct JSFunctionSpec;
namespace js {
@ -416,6 +417,23 @@ struct ClassSizeMeasurement
JS_CLASS_MEMBERS;
};
// Callback for the creation of constructor and prototype objects.
typedef JSObject *(*ClassObjectCreationOp)(JSContext *cx, JSProtoKey key);
// Callback for custom post-processing after class initialization via ClassSpec.
typedef bool (*FinishClassInitOp)(JSContext *cx, JS::HandleObject ctor,
JS::HandleObject proto);
struct ClassSpec
{
ClassObjectCreationOp createConstructor;
ClassObjectCreationOp createPrototype;
const JSFunctionSpec *constructorFunctions;
const JSFunctionSpec *prototypeFunctions;
FinishClassInitOp finishInit;
bool defined() const { return !!createConstructor; }
};
struct ClassExtension
{
JSObjectOp outerObject;
@ -442,6 +460,7 @@ struct ClassExtension
JSWeakmapKeyDelegateOp weakmapKeyDelegateOp;
};
#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr}
#define JS_NULL_CLASS_EXT {nullptr,nullptr,nullptr,false,nullptr}
struct ObjectOps
@ -592,9 +611,11 @@ namespace js {
struct Class
{
JS_CLASS_MEMBERS;
ClassSpec spec;
ClassExtension ext;
ObjectOps ops;
uint8_t pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
sizeof(ClassSpec) -
sizeof(ClassExtension) - sizeof(ObjectOps)];
/* Class is not native and its map is not a scope. */

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

@ -832,12 +832,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
Rooted(const Rooted &) MOZ_DELETE;
};
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
// Defined in vm/String.h.
template <>
class Rooted<JSStableString *>;
#endif
} /* namespace JS */
namespace js {

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

@ -21,7 +21,7 @@
namespace JS {
class Latin1CharsZ;
class StableCharPtr;
class ConstTwoByteChars;
class TwoByteChars;
class AutoFunctionVector;
@ -62,7 +62,7 @@ using JS::UndefinedValue;
using JS::IsPoisonedPtr;
using JS::Latin1CharsZ;
using JS::StableCharPtr;
using JS::ConstTwoByteChars;
using JS::TwoByteChars;
using JS::AutoFunctionVector;

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

@ -148,7 +148,7 @@ enum EvalJSONResult {
static EvalJSONResult
TryEvalJSON(JSContext *cx, JSScript *callerScript,
StableCharPtr chars, size_t length, MutableHandleValue rval)
ConstTwoByteChars chars, size_t length, MutableHandleValue rval)
{
// If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
// Try the JSON parser first because it's much faster. If the eval string
@ -280,12 +280,12 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
thisv = ObjectValue(*thisobj);
}
Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
if (!stableStr)
Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
if (!flatStr)
return false;
StableCharPtr chars = stableStr->chars();
size_t length = stableStr->length();
size_t length = flatStr->length();
ConstTwoByteChars chars(flatStr->chars(), length);
JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
@ -297,7 +297,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
EvalScriptGuard esg(cx);
if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
esg.lookupInEvalCache(stableStr, callerScript, pc);
esg.lookupInEvalCache(flatStr, callerScript, pc);
if (!esg.foundScript()) {
unsigned lineno;
@ -316,7 +316,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
.setOriginPrincipals(originPrincipals);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, options,
chars.get(), length, stableStr, staticLevel);
chars.get(), length, flatStr, staticLevel);
if (!compiled)
return false;
@ -347,12 +347,12 @@ js::DirectEvalStringFromIon(JSContext *cx,
unsigned staticLevel = callerScript->staticLevel() + 1;
Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
if (!stableStr)
Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
if (!flatStr)
return false;
StableCharPtr chars = stableStr->chars();
size_t length = stableStr->length();
size_t length = flatStr->length();
ConstTwoByteChars chars(flatStr->chars(), length);
EvalJSONResult ejr = TryEvalJSON(cx, callerScript, chars, length, vp);
if (ejr != EvalJSON_NotJSON)
@ -363,7 +363,7 @@ js::DirectEvalStringFromIon(JSContext *cx,
// Ion will not perform cross compartment direct eval calls.
JSPrincipals *principals = cx->compartment()->principals;
esg.lookupInEvalCache(stableStr, callerScript, pc);
esg.lookupInEvalCache(flatStr, callerScript, pc);
if (!esg.foundScript()) {
unsigned lineno;
@ -381,7 +381,7 @@ js::DirectEvalStringFromIon(JSContext *cx,
.setOriginPrincipals(originPrincipals);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, options,
chars.get(), length, stableStr, staticLevel);
chars.get(), length, flatStr, staticLevel);
if (!compiled)
return false;

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

@ -1313,6 +1313,7 @@ const Class CloneBufferObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
};

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

@ -2271,6 +2271,7 @@ const Class TypedObject::class_ = {
nullptr, /* construct */
nullptr, /* hasInstance */
TypedDatum::obj_trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
{
TypedDatum::obj_lookupGeneric,
@ -2438,6 +2439,7 @@ const Class TypedHandle::class_ = {
nullptr, /* construct */
nullptr, /* hasInstance */
TypedDatum::obj_trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
{
TypedDatum::obj_lookupGeneric,

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

@ -4820,10 +4820,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
return false;
RootedObject fieldType(cx, nullptr);
JSFlatString* flat = ExtractStructField(cx, item, fieldType.address());
if (!flat)
return false;
Rooted<JSStableString*> name(cx, flat->ensureStable(cx));
Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, fieldType.address()));
if (!name)
return false;
fieldRoots[i] = JS::ObjectValue(*fieldType);
@ -4837,7 +4834,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
// Add the field to the StructType's 'prototype' property.
if (!JS_DefineUCProperty(cx, prototype,
name->chars().get(), name->length(), JSVAL_VOID,
name->chars(), name->length(), JSVAL_VOID,
StructType::FieldGetter, StructType::FieldSetter,
JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

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

@ -96,7 +96,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
evalCaller(evalCaller),
topStmt(nullptr),
topScopeStmt(nullptr),
blockChain(sc->context),
staticScope(sc->context),
atomIndices(sc->context),
firstLine(lineNum),
stackDepth(0), maxStackDepth(0),
@ -493,7 +493,7 @@ class NonLocalExitScope {
savedScopeIndex(bce->blockScopeList.length()),
savedDepth(bce->stackDepth),
openScopeIndex(UINT32_MAX) {
if (bce->blockChain) {
if (bce->staticScope) {
StmtInfoBCE *stmt = bce->topStmt;
while (1) {
JS_ASSERT(stmt);
@ -578,8 +578,7 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
}
if (stmt->isBlockScope) {
JS_ASSERT(stmt->blockObj);
StaticBlockObject &blockObj = *stmt->blockObj;
StaticBlockObject &blockObj = stmt->staticBlock();
if (!popScopeForNonLocalExit(blockObj, stmt->blockScopeIndex))
return false;
npops += blockObj.slotCount();
@ -646,8 +645,8 @@ PushStatementBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StmtType type, ptrdiff
static JSObject *
EnclosingStaticScope(BytecodeEmitter *bce)
{
if (bce->blockChain)
return bce->blockChain;
if (bce->staticScope)
return bce->staticScope;
if (!bce->sc->isFunctionBox()) {
JS_ASSERT(!bce->parent);
@ -744,7 +743,7 @@ EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit
// An element in the "block scope array" specifies the PC range, and links to a
// StaticBlockObject in the object list of the script. That block is linked to
// the previous block in the scope, if any. The static block chain at any
// pre-retire PC can be retrieved using JSScript::getBlockScope(jsbytecode *pc).
// pre-retire PC can be retrieved using JSScript::getStaticScope(jsbytecode *pc).
//
// When PUSHBLOCKSCOPE is executed, it assumes that the block's locals are
// already on the stack. Initial values of "aliased" locals are copied from the
@ -783,9 +782,9 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O
unsigned extraSlots)
{
uint32_t parent = BlockScopeNote::NoBlockScopeIndex;
if (bce->blockChain) {
if (bce->staticScope) {
StmtInfoBCE *stmt = bce->topScopeStmt;
for (; stmt->blockObj != bce->blockChain; stmt = stmt->down) {}
for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {}
parent = stmt->blockScopeIndex;
}
@ -810,7 +809,7 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O
return false;
PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset());
blockObj->initEnclosingStaticScope(EnclosingStaticScope(bce));
blockObj->initEnclosingNestedScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, *blockObj);
JS_ASSERT(stmt->isBlockScope);
@ -846,12 +845,13 @@ LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce)
JS_ASSERT(bce->blockScopeList.list[blockScopeIndex].length == 0);
uint32_t blockObjIndex = bce->blockScopeList.list[blockScopeIndex].index;
ObjectBox *blockObjBox = bce->objectList.find(blockObjIndex);
StaticBlockObject *blockObj = &blockObjBox->object->as<StaticBlockObject>();
JS_ASSERT(stmt->blockObj == blockObj);
JS_ASSERT(blockObj == bce->blockChain);
NestedScopeObject *staticScope = &blockObjBox->object->as<NestedScopeObject>();
JS_ASSERT(stmt->staticScope == staticScope);
JS_ASSERT(staticScope == bce->staticScope);
#endif
bool blockOnChain = bce->blockChain->needsClone();
JS_ASSERT(bce->staticScope->is<StaticBlockObject>());
bool blockOnChain = bce->staticScope->as<StaticBlockObject>().needsClone();
if (!PopStatementBCE(cx, bce))
return false;
@ -998,16 +998,18 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmit
return true;
}
// Compute the number of nested scope objects that will actually be on the scope
// chain at runtime, given the BCE's current staticScope.
static unsigned
ClonedBlockDepth(BytecodeEmitter *bce)
DynamicNestedScopeDepth(BytecodeEmitter *bce)
{
unsigned clonedBlockDepth = 0;
for (StaticBlockObject *b = bce->blockChain; b; b = b->enclosingBlock()) {
if (b->needsClone())
++clonedBlockDepth;
unsigned depth = 0;
for (NestedScopeObject *b = bce->staticScope; b; b = b->enclosingNestedScope()) {
if (!b->is<StaticBlockObject>() || b->as<StaticBlockObject>().needsClone())
++depth;
}
return clonedBlockDepth;
return depth;
}
static bool
@ -1078,7 +1080,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *
* enclosing function scope of the definition being accessed.
*/
for (unsigned i = pn->pn_cookie.level(); i; i--) {
skippedScopes += ClonedBlockDepth(bceOfDef);
skippedScopes += DynamicNestedScopeDepth(bceOfDef);
FunctionBox *funbox = bceOfDef->sc->asFunctionBox();
if (funbox->isHeavyweight()) {
skippedScopes++;
@ -1093,30 +1095,33 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *
}
/*
* The final part of the skippedScopes computation depends on the type of variable. An arg or
* local variable is at the outer scope of a function and so includes the full
* ClonedBlockDepth. A let/catch-binding requires a search of the block chain to see how many
* (dynamic) block objects to skip.
* The final part of the skippedScopes computation depends on the type of
* variable. An arg or local variable is at the outer scope of a function
* and so includes the full DynamicNestedScopeDepth. A let/catch-binding
* requires a search of the block chain to see how many (dynamic) block
* objects to skip.
*/
ScopeCoordinate sc;
if (IsArgOp(pn->getOp())) {
if (!AssignHops(bce, pn, skippedScopes + ClonedBlockDepth(bceOfDef), &sc))
if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
return false;
JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
} else {
JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION));
uint32_t local = pn->pn_cookie.slot();
if (local < bceOfDef->script->bindings.numVars()) {
if (!AssignHops(bce, pn, skippedScopes + ClonedBlockDepth(bceOfDef), &sc))
if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
return false;
JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
} else {
uint32_t depth = local - bceOfDef->script->bindings.numVars();
Rooted<StaticBlockObject*> b(cx, bceOfDef->blockChain);
JS_ASSERT(bceOfDef->staticScope->is<StaticBlockObject>());
Rooted<StaticBlockObject*> b(cx, &bceOfDef->staticScope->as<StaticBlockObject>());
while (!b->containsVarAtDepth(depth)) {
if (b->needsClone())
skippedScopes++;
b = b->enclosingBlock();
JS_ASSERT(b);
}
if (!AssignHops(bce, pn, skippedScopes, &sc))
return false;
@ -2891,8 +2896,6 @@ enum VarEmitOption
InitializeVars = 2
};
#if JS_HAS_DESTRUCTURING
typedef bool
(*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
@ -3340,8 +3343,6 @@ MaybeEmitLetGroupDecl(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn,
return true;
}
#endif /* JS_HAS_DESTRUCTURING */
static bool
EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
bool isLet = false)
@ -3355,7 +3356,6 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
ParseNode *pn3;
if (!pn2->isKind(PNK_NAME)) {
#if JS_HAS_DESTRUCTURING
if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
/*
* Emit variable binding ops, but not destructuring ops. The
@ -3371,7 +3371,6 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
return false;
break;
}
#endif
/*
* A destructuring initialiser assignment preceded by var will
@ -3388,18 +3387,12 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
* function f(){} precedes the var, detect simple name assignment
* here and initialize the name.
*/
#if !JS_HAS_DESTRUCTURING
JS_ASSERT(pn2->pn_left->isKind(PNK_NAME));
#else
if (pn2->pn_left->isKind(PNK_NAME))
#endif
{
if (pn2->pn_left->isKind(PNK_NAME)) {
pn3 = pn2->pn_right;
pn2 = pn2->pn_left;
goto do_name;
}
#if JS_HAS_DESTRUCTURING
ptrdiff_t stackDepthBefore = bce->stackDepth;
JSOp op = JSOP_POP;
if (pn->pn_count == 1) {
@ -3447,7 +3440,6 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
break;
}
goto emit_note_pop;
#endif
}
/*
@ -3514,9 +3506,7 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
return false;
}
#if JS_HAS_DESTRUCTURING
emit_note_pop:
#endif
if (!next)
break;
if (Emit1(cx, bce, JSOP_POP) < 0)
@ -3578,11 +3568,9 @@ EmitAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp
return false;
offset += 2;
break;
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
break;
#endif
case PNK_CALL:
JS_ASSERT(lhs->pn_xflags & PNX_SETCALL);
if (!EmitTree(cx, bce, lhs))
@ -3724,13 +3712,11 @@ EmitAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp
if (Emit1(cx, bce, JSOP_SETELEM) < 0)
return false;
break;
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
if (!EmitDestructuringOps(cx, bce, lhs))
return false;
break;
#endif
default:
JS_ASSERT(0);
}
@ -3902,7 +3888,6 @@ EmitCatch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ParseNode *pn2 = pn->pn_kid1;
switch (pn2->getKind()) {
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
if (!EmitDestructuringOps(cx, bce, pn2))
@ -3910,7 +3895,6 @@ EmitCatch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (Emit1(cx, bce, JSOP_POP) < 0)
return false;
break;
#endif
case PNK_NAME:
/* Inline and specialize BindNameToSlot for pn2. */
@ -4679,13 +4663,11 @@ EmitNormalFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff
op = JSOP_NOP;
} else {
bce->emittingForInit = true;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(PNK_ASSIGN)) {
JS_ASSERT(pn3->isOp(JSOP_NOP));
if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, GroupIsNotDecl, &op))
return false;
}
#endif
if (op == JSOP_POP) {
if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
return false;
@ -4755,13 +4737,11 @@ EmitNormalFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff
if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
return false;
op = JSOP_POP;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(PNK_ASSIGN)) {
JS_ASSERT(pn3->isOp(JSOP_NOP));
if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, GroupIsNotDecl, &op))
return false;
}
#endif
if (op == JSOP_POP && !EmitTree(cx, bce, pn3))
return false;
@ -4865,7 +4845,7 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (fun->isInterpretedLazy()) {
if (!fun->lazyScript()->sourceObject()) {
JSObject *scope = bce->blockChain;
JSObject *scope = bce->staticScope;
if (!scope && bce->sc->isFunctionBox())
scope = bce->sc->asFunctionBox()->function();
JSObject *source = bce->script->sourceObject();
@ -5401,14 +5381,12 @@ EmitStatement(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (useful) {
JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
#if JS_HAS_DESTRUCTURING
if (!wantval &&
pn2->isKind(PNK_ASSIGN) &&
!MaybeEmitGroupAssignment(cx, bce, op, pn2, GroupIsNotDecl, &op))
{
return false;
}
#endif
if (op != JSOP_NOP) {
if (!EmitTree(cx, bce, pn2))
return false;
@ -5885,12 +5863,10 @@ EmitConditionalExpression(ExclusiveContext *cx, BytecodeEmitter *bce, Conditiona
MOZ_NEVER_INLINE static bool
EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
#if JS_HAS_DESTRUCTURING_SHORTHAND
if (pn->pn_xflags & PNX_DESTRUCT) {
bce->reportError(pn, JSMSG_BAD_OBJECT_INIT);
return false;
}
#endif
if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
return EmitSingletonInitialiser(cx, bce, pn);

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

@ -107,8 +107,8 @@ struct BytecodeEmitter
StmtInfoBCE *topStmt; /* top of statement info stack */
StmtInfoBCE *topScopeStmt; /* top lexical scope statement */
Rooted<StaticBlockObject *> blockChain;
/* compile time block scope chain */
Rooted<NestedScopeObject *> staticScope;
/* compile time scope chain */
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
unsigned firstLine; /* first line, for JSScript::initFromEmitter */

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

@ -326,8 +326,6 @@ Definition::kindString(Kind kind)
namespace js {
namespace frontend {
#if JS_HAS_DESTRUCTURING
/*
* This function assumes the cloned tree is for use in the same statement and
* binding context as the original tree.
@ -423,8 +421,6 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
return pn;
}
#endif /* JS_HAS_DESTRUCTURING */
/*
* Used by Parser::forStatement and comprehensionTail to clone the TARGET in
* for (var/const/let TARGET in EXPR)
@ -447,7 +443,6 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn)
pn->setDefn(opn->isDefn());
pn->setUsed(opn->isUsed());
#if JS_HAS_DESTRUCTURING
if (opn->isArity(PN_LIST)) {
JS_ASSERT(opn->isKind(PNK_ARRAY) || opn->isKind(PNK_OBJECT));
pn->makeEmpty();
@ -479,7 +474,6 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn)
pn->pn_xflags = opn->pn_xflags;
return pn;
}
#endif
JS_ASSERT(opn->isArity(PN_NAME));
JS_ASSERT(opn->isKind(PNK_NAME));

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

@ -49,6 +49,8 @@ namespace frontend {
typedef Rooted<StaticBlockObject*> RootedStaticBlockObject;
typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
typedef Rooted<NestedScopeObject*> RootedNestedScopeObject;
typedef Handle<NestedScopeObject*> HandleNestedScopeObject;
/*
@ -1505,7 +1507,6 @@ Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
return pc->define(tokenStream, name, argpn, Definition::ARG);
}
#if JS_HAS_DESTRUCTURING
template <typename ParseHandler>
/* static */ bool
Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler> *data,
@ -1524,7 +1525,6 @@ Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler> *data,
return pc->define(parser->tokenStream, name, data->pn, Definition::VAR);
}
#endif /* JS_HAS_DESTRUCTURING */
template <typename ParseHandler>
bool
@ -1558,9 +1558,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
if (parenFreeArrow || !tokenStream.matchToken(TOK_RP)) {
bool hasDefaults = false;
Node duplicatedArg = null();
#if JS_HAS_DESTRUCTURING
Node list = null();
#endif
do {
if (*hasRest) {
@ -1571,7 +1569,6 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
TokenKind tt = tokenStream.getToken();
JS_ASSERT_IF(parenFreeArrow, tt == TOK_NAME);
switch (tt) {
#if JS_HAS_DESTRUCTURING
case TOK_LB:
case TOK_LC:
{
@ -1628,7 +1625,6 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
}
break;
}
#endif /* JS_HAS_DESTRUCTURING */
case TOK_YIELD:
if (!checkYieldNameValidity())
@ -2017,7 +2013,6 @@ Parser<FullParseHandler>::finishFunctionDefinition(ParseNode *pn, FunctionBox *f
{
pn->pn_pos.end = pos().end;
#if JS_HAS_DESTRUCTURING
/*
* If there were destructuring formal parameters, prepend the initializing
* comma expression that we synthesized to body. If the body is a return
@ -2050,7 +2045,6 @@ Parser<FullParseHandler>::finishFunctionDefinition(ParseNode *pn, FunctionBox *f
++body->pn_count;
body->pn_xflags |= PNX_DESTRUCT;
}
#endif
JS_ASSERT(pn->pn_funbox == funbox);
pn->pn_body->append(body);
@ -2676,7 +2670,7 @@ Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, JSAtom *atom)
* must already be in such a scope.
*
* Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
* property for the new variable on the block object, pc->blockChain;
* property for the new variable on the block object, pc->staticScope;
* populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
* data->pn in a slot of the block object.
*/
@ -2779,15 +2773,18 @@ template <typename ParseHandler>
static void
PopStatementPC(TokenStream &ts, ParseContext<ParseHandler> *pc)
{
RootedStaticBlockObject blockObj(ts.context(), pc->topStmt->blockObj);
JS_ASSERT(!!blockObj == (pc->topStmt->isBlockScope));
RootedNestedScopeObject scopeObj(ts.context(), pc->topStmt->staticScope);
JS_ASSERT(!!scopeObj == (pc->topStmt->isBlockScope));
FinishPopStatement(pc);
if (blockObj) {
JS_ASSERT(!blockObj->inDictionaryMode());
ForEachLetDef(ts, pc, blockObj, PopLetDecl<ParseHandler>());
blockObj->resetPrevBlockChainFromParser();
if (scopeObj) {
if (scopeObj->is<StaticBlockObject>()) {
RootedStaticBlockObject blockObj(ts.context(), &scopeObj->as<StaticBlockObject>());
JS_ASSERT(!blockObj->inDictionaryMode());
ForEachLetDef(ts, pc, blockObj, PopLetDecl<ParseHandler>());
}
scopeObj->resetEnclosingNestedScopeFromParser();
}
}
@ -2820,7 +2817,7 @@ LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename ContextT::Stmt
if (!stmt->isBlockScope)
continue;
StaticBlockObject &blockObj = *stmt->blockObj;
StaticBlockObject &blockObj = stmt->staticBlock();
Shape *shape = blockObj.nativeLookup(ct->sc->context, id);
if (shape) {
JS_ASSERT(shape->hasShortID());
@ -2990,8 +2987,6 @@ Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
return true;
}
#if JS_HAS_DESTRUCTURING
template <>
bool
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn)
@ -3189,8 +3184,6 @@ Parser<ParseHandler>::destructuringExpr(BindData<ParseHandler> *data, TokenKind
return pn;
}
#endif /* JS_HAS_DESTRUCTURING */
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
@ -3202,7 +3195,7 @@ Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInf
return null();
PushStatementPC(pc, stmt, STMT_BLOCK);
blockObj->initPrevBlockChainFromParser(pc->blockChain);
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
FinishPushBlockScope(pc, stmt, *blockObj.get());
Node pn = handler.newLexicalScope(blockbox);
@ -3461,7 +3454,6 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
first = false;
TokenKind tt = tokenStream.getToken();
#if JS_HAS_DESTRUCTURING
if (tt == TOK_LB || tt == TOK_LC) {
if (psimple)
*psimple = false;
@ -3493,7 +3485,6 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
handler.addList(pn, pn2);
continue;
}
#endif /* JS_HAS_DESTRUCTURING */
if (tt != TOK_NAME) {
if (tt == TOK_YIELD) {
@ -3560,7 +3551,7 @@ Parser<FullParseHandler>::letDeclaration()
}
if (stmt && stmt->isBlockScope) {
JS_ASSERT(pc->blockChain == stmt->blockObj);
JS_ASSERT(pc->staticScope == stmt->staticScope);
} else {
if (pc->atBodyLevel()) {
/*
@ -3606,9 +3597,9 @@ Parser<FullParseHandler>::letDeclaration()
stmt->downScope = pc->topScopeStmt;
pc->topScopeStmt = stmt;
blockObj->initPrevBlockChainFromParser(pc->blockChain);
pc->blockChain = blockObj;
stmt->blockObj = blockObj;
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
pc->staticScope = blockObj;
stmt->staticScope = blockObj;
#ifdef DEBUG
ParseNode *tmp = pc->blockNode;
@ -3628,7 +3619,7 @@ Parser<FullParseHandler>::letDeclaration()
pc->blockNode = pn1;
}
pn = variables(PNK_LET, nullptr, pc->blockChain, HoistVars);
pn = variables(PNK_LET, nullptr, &pc->staticScope->as<StaticBlockObject>(), HoistVars);
if (!pn)
return null();
pn->pn_xflags = PNX_POPVAR;
@ -4063,7 +4054,6 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
if (pn1->isOp(JSOP_DEFCONST))
return false;
#if JS_HAS_DESTRUCTURING
// In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
// Hence all other destructuring decls are banned there.
if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN) {
@ -4076,7 +4066,6 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
if (lhs->isKind(PNK_ARRAY) && lhs->pn_count != 2)
return false;
}
#endif
return true;
}
@ -4087,7 +4076,6 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
case PNK_ELEM:
return true;
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
// In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
@ -4095,7 +4083,6 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN)
return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
return true;
#endif
default:
return false;
@ -4246,12 +4233,7 @@ Parser<FullParseHandler>::forStatement()
*/
if (isForDecl) {
pn2 = pn1->pn_head;
if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
#if JS_HAS_DESTRUCTURING
|| pn2->isKind(PNK_ASSIGN)
#endif
)
{
if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr()) || pn2->isKind(PNK_ASSIGN)) {
/*
* Declaration with initializer.
*
@ -4280,13 +4262,11 @@ Parser<FullParseHandler>::forStatement()
pn1->pn_xflags |= PNX_POPVAR;
pn1 = nullptr;
#if JS_HAS_DESTRUCTURING
if (pn2->isKind(PNK_ASSIGN)) {
pn2 = pn2->pn_left;
JS_ASSERT(pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT) ||
pn2->isKind(PNK_NAME));
}
#endif
}
} else {
/* Not a declaration. */
@ -4334,7 +4314,6 @@ Parser<FullParseHandler>::forStatement()
pn2->markAsAssigned();
break;
#if JS_HAS_DESTRUCTURING
case PNK_ASSIGN:
MOZ_ASSUME_UNREACHABLE("forStatement TOK_ASSIGN");
@ -4349,7 +4328,6 @@ Parser<FullParseHandler>::forStatement()
iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
}
break;
#endif
default:;
}
@ -5078,20 +5056,19 @@ Parser<ParseHandler>::tryStatement()
* scoped, not a property of a new Object instance. This is
* an intentional change that anticipates ECMA Ed. 4.
*/
data.initLet(HoistVars, *pc->blockChain, JSMSG_TOO_MANY_CATCH_VARS);
data.initLet(HoistVars, pc->staticScope->template as<StaticBlockObject>(),
JSMSG_TOO_MANY_CATCH_VARS);
JS_ASSERT(data.let.blockObj);
tt = tokenStream.getToken();
Node catchName;
switch (tt) {
#if JS_HAS_DESTRUCTURING
case TOK_LB:
case TOK_LC:
catchName = destructuringExpr(&data, tt);
if (!catchName)
return null();
break;
#endif
case TOK_YIELD:
if (!checkYieldNameValidity())
@ -5522,7 +5499,6 @@ Parser<FullParseHandler>::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentF
case PNK_ELEM:
break;
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
if (flavor == CompoundAssignment) {
@ -5532,7 +5508,6 @@ Parser<FullParseHandler>::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentF
if (!checkDestructuring(nullptr, pn))
return false;
break;
#endif
case PNK_CALL:
if (!makeSetCall(pn, JSMSG_BAD_LEFTSIDE_OF_ASS))
@ -6097,8 +6072,8 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
if (!transplanter.transplant(kid))
return null();
JS_ASSERT(pc->blockChain && pc->blockChain == pn->pn_objbox->object);
data.initLet(HoistVars, *pc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
data.initLet(HoistVars, pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
do {
/*
@ -6121,7 +6096,6 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
RootedPropertyName name(context);
tt = tokenStream.getToken();
switch (tt) {
#if JS_HAS_DESTRUCTURING
case TOK_LB:
case TOK_LC:
pc->inDeclDestructuring = true;
@ -6130,7 +6104,6 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
if (!pn3)
return null();
break;
#endif
case TOK_NAME:
name = tokenStream.currentName();
@ -6182,7 +6155,6 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
}
switch (tt) {
#if JS_HAS_DESTRUCTURING
case TOK_LB:
case TOK_LC:
if (!checkDestructuring(&data, pn3))
@ -6204,7 +6176,6 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
}
break;
#endif
case TOK_NAME:
data.pn = pn3;
@ -6635,15 +6606,15 @@ typename ParseHandler::Node
Parser<ParseHandler>::newRegExp()
{
// Create the regexp even when doing a syntax parse, to check the regexp's syntax.
const jschar *chars = tokenStream.getTokenbuf().begin();
size_t length = tokenStream.getTokenbuf().length();
const StableCharPtr chars(tokenStream.getTokenbuf().begin(), length);
RegExpFlag flags = tokenStream.currentToken().regExpFlags();
Rooted<RegExpObject*> reobj(context);
if (RegExpStatics *res = context->global()->getRegExpStatics())
reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
else
reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
if (!reobj)
return null();
@ -6915,7 +6886,6 @@ Parser<ParseHandler>::objectLiteral()
if (!handler.addPropertyDefinition(literal, propname, propexpr))
return null();
}
#if JS_HAS_DESTRUCTURING_SHORTHAND
else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
/*
* Support, e.g., |var {x, y} = o| as destructuring shorthand
@ -6934,7 +6904,6 @@ Parser<ParseHandler>::objectLiteral()
if (!handler.addShorthandPropertyDefinition(literal, propname))
return null();
}
#endif
else {
report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
return null();

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

@ -98,8 +98,7 @@ struct ParseContext : public GenericParseContext
StmtInfoPC *topStmt; /* top of statement info stack */
StmtInfoPC *topScopeStmt; /* top lexical scope statement */
Rooted<StaticBlockObject *> blockChain;
/* compile time block scope chain */
Rooted<NestedScopeObject *> staticScope; /* compile time scope chain */
Node maybeFunction; /* sc->isFunctionBox, the pn where pn->pn_funbox == sc */
const unsigned staticLevel; /* static compilation unit nesting level */
@ -250,7 +249,7 @@ struct ParseContext : public GenericParseContext
blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init()
topStmt(nullptr),
topScopeStmt(nullptr),
blockChain(prs->context),
staticScope(prs->context),
maybeFunction(maybeFunction),
staticLevel(staticLevel),
lastYieldOffset(NoYieldOffset),

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