mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Merge inbound to central, a=merge CLOSED TREE
MozReview-Commit-ID: GhBqmLvUpgQ
This commit is contained in:
commit
b488ae9021
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Touch clobber because of bug 1336456
|
||||
|
@ -2087,11 +2087,13 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
||||
child->SetRelocated(true);
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
|
||||
// Create subtree before adjusting the insertion index, since subtree
|
||||
// creation may alter children in the container.
|
||||
CreateSubtree(child);
|
||||
FireEventsOnInsertion(aOwner);
|
||||
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
@ -532,6 +532,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ARIA owns on inaccessible span element that contains
|
||||
* accessible children. This will move children from the container for
|
||||
* the span.
|
||||
*/
|
||||
function test8()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, "t8_container")
|
||||
];
|
||||
|
||||
this.invoke = function test8_invoke()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ PUSHBUTTON: [] },
|
||||
{ ENTRY: [] },
|
||||
{ ENTRY: [] },
|
||||
{ ENTRY: [] }
|
||||
] };
|
||||
testAccessibleTree("t8_container", tree);
|
||||
|
||||
getNode(t8_container).setAttribute("aria-owns", "t8_span t8_button");
|
||||
}
|
||||
|
||||
this.finalCheck = function test8_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ TEXT: [
|
||||
{ ENTRY: [] },
|
||||
{ ENTRY: [] },
|
||||
{ ENTRY: [] }
|
||||
] },
|
||||
{ PUSHBUTTON: [] }
|
||||
] };
|
||||
testAccessibleTree("t8_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function test8_getID()
|
||||
{
|
||||
return `Set ARIA owns on inaccessible span element that contains accessible children`;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Test
|
||||
@ -580,6 +624,8 @@
|
||||
|
||||
gQueue.push(new setARIAOwnsOnElToRemove("t7_parent", "t7_child"));
|
||||
|
||||
gQueue.push(new test8());
|
||||
|
||||
gQueue.invoke(); // SimpleTest.finish() will be called in the end
|
||||
}
|
||||
|
||||
@ -638,6 +684,10 @@
|
||||
<div id="t7_child"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="t8_container">
|
||||
<input id="t8_button" type="button"><span id="t8_span"><input><input><input></span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -311,10 +311,21 @@ Site.prototype = {
|
||||
_speculativeConnect: function Site_speculativeConnect() {
|
||||
let sc = Services.io.QueryInterface(Ci.nsISpeculativeConnect);
|
||||
let uri = Services.io.newURI(this.url);
|
||||
|
||||
if (!uri.schemeIs("http") && !uri.schemeIs("https")) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// This can throw for certain internal URLs, when they wind up in
|
||||
// about:newtab. Be sure not to propagate the error.
|
||||
sc.speculativeConnect(uri, null);
|
||||
|
||||
// We use the URI's codebase principal here to open its speculative
|
||||
// connection.
|
||||
let originAttributes = document.docShell.getOriginAttributes();
|
||||
let principal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(uri, originAttributes);
|
||||
sc.speculativeConnect2(uri, principal, null);
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
|
@ -495,7 +495,9 @@
|
||||
<![CDATA[
|
||||
// Speculatively connect to the current engine's search URI (and
|
||||
// suggest URI, if different) to reduce request latency
|
||||
this.currentEngine.speculativeConnect({window});
|
||||
this.currentEngine.speculativeConnect({window,
|
||||
originAttributes: gBrowser.contentPrincipal
|
||||
.originAttributes});
|
||||
|
||||
if (this._ignoreFocus) {
|
||||
// This window has been re-focused, don't show the suggestions
|
||||
|
@ -2,6 +2,24 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
# The toolchain installed on our OSX 10.7 build machines is too old to support
|
||||
# MachO LC_DATA_IN_CODE load command, which newer LLVM generates, so we need to
|
||||
# use a newer toolchain that we build.
|
||||
#
|
||||
# Unfortunately setting $PATH is not enough, because the build system hardcodes
|
||||
# the default values for some of the build tools, which we also need to
|
||||
# override below. The default value for host ar and host ranlib is also
|
||||
# hardcoded so we need to override those separately.
|
||||
CCTOOLS_DIR="$topsrcdir/cctools/bin"
|
||||
export PATH="$CCTOOLS_DIR:$PATH"
|
||||
export AR="$CCTOOLS_DIR/ar"
|
||||
export HOST_AR="$CCTOOLS_DIR/ar"
|
||||
export RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export HOST_RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export LIPO="$CCTOOLS_DIR/lipo"
|
||||
export OTOOL="$CCTOOLS_DIR/otool"
|
||||
export STRIP="$CCTOOLS_DIR/strip"
|
||||
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-debug
|
||||
|
@ -1,8 +1,8 @@
|
||||
[
|
||||
{
|
||||
"version": "clang 3.8.0",
|
||||
"size": 133060926,
|
||||
"digest": "aff5ad3ac2d41db19d1ba0df5f97b189a7d7e1b6af8c56e22c2b0cced84d75fa98394ded6a4ba5713652e6684a0a46f47aeccf87991f9e849bf8d7d82e564f6f",
|
||||
"version": "clang 3.9.0",
|
||||
"size": 184678304,
|
||||
"digest": "cfde9a0f7f59823200f94422b4adb9a2fb5d4d07f240bbd1142c792434f6a1cbb4096d25c9853d77008fc40db0d827daa7003e78016f51241f621d6040ccc635",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2",
|
||||
"unpack": true
|
||||
@ -25,9 +25,9 @@
|
||||
"size": 1143715
|
||||
},
|
||||
{
|
||||
"version": "cctools port from commit hash db1f8d906cb28, ld only",
|
||||
"size": 634496,
|
||||
"digest": "037f31fcf29e7bb7fada0d2bdd5e95c7d4cb2692f2a5c98ed6f6a7561b9d81622d015f0d12b291d3667719655f1369e8ce8a0a4a4773aa0ee4753e04a8821173",
|
||||
"version": "cctools port from commit hash 84ce22dbb22a26ce7f392e9de0ee39c2efe6fd68",
|
||||
"size": 2174783,
|
||||
"digest": "8678348faff8f344b377075007975ae77a55a2a73488e36950a43c8ec27a79970cd8e34003e33e756a57d9cbf5c3e2e4461184102c6c03f793377a4d250a7f24",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cctools.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -16,12 +16,12 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 3008804,
|
||||
"size": 1349196,
|
||||
"visibility": "public",
|
||||
"digest": "ba6937f14f3d8b26dcb2d39490dee6b0a8afb60f672f5debb71d7b62c1ec52103201b4b1a3d258f945567de531384b36ddb2ce4aa73dc63d72305b11c146847c",
|
||||
"digest": "438a36523a74cbc4a58226647e0501fa64a1b63f32931dc364a75d699df8accb45afdf26f4cb61c6ac7f58be530205acb6da22008bec19603c6f6fda3a12a8cc",
|
||||
"algorithm": "sha512",
|
||||
"unpack": true,
|
||||
"filename": "cctools.tar.gz"
|
||||
"filename": "cctools.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 30823112,
|
||||
|
@ -1,3 +1,3 @@
|
||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.7.235
|
||||
Current extension version is: 1.7.242
|
||||
|
@ -23,8 +23,8 @@
|
||||
}
|
||||
}(this, function (exports) {
|
||||
'use strict';
|
||||
var pdfjsVersion = '1.7.235';
|
||||
var pdfjsBuild = '3f320f0b';
|
||||
var pdfjsVersion = '1.7.242';
|
||||
var pdfjsBuild = '6f0cf8c4';
|
||||
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
|
||||
var pdfjsLibs = {};
|
||||
(function pdfjsWrapper() {
|
||||
@ -1788,6 +1788,7 @@
|
||||
}(this, function (exports, sharedUtil, displayDOMUtils) {
|
||||
var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType;
|
||||
var AnnotationType = sharedUtil.AnnotationType;
|
||||
var stringToPDFString = sharedUtil.stringToPDFString;
|
||||
var Util = sharedUtil.Util;
|
||||
var addLinkAttributes = displayDOMUtils.addLinkAttributes;
|
||||
var LinkTarget = displayDOMUtils.LinkTarget;
|
||||
@ -2330,8 +2331,14 @@
|
||||
var FileAttachmentAnnotationElement = function FileAttachmentAnnotationElementClosure() {
|
||||
function FileAttachmentAnnotationElement(parameters) {
|
||||
AnnotationElement.call(this, parameters, true);
|
||||
this.filename = getFilenameFromUrl(parameters.data.file.filename);
|
||||
this.content = parameters.data.file.content;
|
||||
var file = this.data.file;
|
||||
this.filename = getFilenameFromUrl(file.filename);
|
||||
this.content = file.content;
|
||||
this.linkService.onFileAttachmentAnnotation({
|
||||
id: stringToPDFString(file.filename),
|
||||
filename: file.filename,
|
||||
content: file.content
|
||||
});
|
||||
}
|
||||
Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {
|
||||
render: function FileAttachmentAnnotationElement_render() {
|
||||
@ -2365,7 +2372,7 @@
|
||||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
var properties = {
|
||||
var element = annotationElementFactory.create({
|
||||
data: data,
|
||||
layer: parameters.div,
|
||||
page: parameters.page,
|
||||
@ -2374,8 +2381,7 @@
|
||||
downloadManager: parameters.downloadManager,
|
||||
imageResourcesPath: parameters.imageResourcesPath || getDefaultSetting('imageResourcesPath'),
|
||||
renderInteractiveForms: parameters.renderInteractiveForms || false
|
||||
};
|
||||
var element = annotationElementFactory.create(properties);
|
||||
});
|
||||
if (element.isRenderable) {
|
||||
parameters.div.appendChild(element.render());
|
||||
}
|
||||
@ -5565,7 +5571,6 @@
|
||||
var MessageHandler = sharedUtil.MessageHandler;
|
||||
var MissingPDFException = sharedUtil.MissingPDFException;
|
||||
var PageViewport = sharedUtil.PageViewport;
|
||||
var PasswordResponses = sharedUtil.PasswordResponses;
|
||||
var PasswordException = sharedUtil.PasswordException;
|
||||
var StatTimer = sharedUtil.StatTimer;
|
||||
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
|
||||
@ -6978,6 +6983,7 @@
|
||||
exports.renderTextLayer = pdfjsLibs.pdfjsDisplayTextLayer.renderTextLayer;
|
||||
exports.AnnotationLayer = pdfjsLibs.pdfjsDisplayAnnotationLayer.AnnotationLayer;
|
||||
exports.CustomStyle = pdfjsLibs.pdfjsDisplayDOMUtils.CustomStyle;
|
||||
exports.createPromiseCapability = pdfjsLibs.pdfjsSharedUtil.createPromiseCapability;
|
||||
exports.PasswordResponses = pdfjsLibs.pdfjsSharedUtil.PasswordResponses;
|
||||
exports.InvalidPDFException = pdfjsLibs.pdfjsSharedUtil.InvalidPDFException;
|
||||
exports.MissingPDFException = pdfjsLibs.pdfjsSharedUtil.MissingPDFException;
|
||||
|
317
browser/extensions/pdfjs/content/build/pdf.worker.js
vendored
317
browser/extensions/pdfjs/content/build/pdf.worker.js
vendored
@ -23,8 +23,8 @@
|
||||
}
|
||||
}(this, function (exports) {
|
||||
'use strict';
|
||||
var pdfjsVersion = '1.7.235';
|
||||
var pdfjsBuild = '3f320f0b';
|
||||
var pdfjsVersion = '1.7.242';
|
||||
var pdfjsBuild = '6f0cf8c4';
|
||||
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
|
||||
var pdfjsLibs = {};
|
||||
(function pdfjsWrapper() {
|
||||
@ -6080,7 +6080,6 @@
|
||||
var encoding = Object.create(null);
|
||||
var bytes = this.bytes;
|
||||
var predefined = false;
|
||||
var hasSupplement = false;
|
||||
var format, i, ii;
|
||||
var raw = null;
|
||||
function readSupplement() {
|
||||
@ -6130,7 +6129,6 @@
|
||||
if (format & 0x80) {
|
||||
bytes[dataStart] &= 0x7f;
|
||||
readSupplement();
|
||||
hasSupplement = true;
|
||||
}
|
||||
raw = bytes.subarray(dataStart, dataEnd);
|
||||
}
|
||||
@ -7444,8 +7442,7 @@
|
||||
subStream.end = start + length || this.end;
|
||||
subStream.dict = dict;
|
||||
return subStream;
|
||||
},
|
||||
isStream: true
|
||||
}
|
||||
};
|
||||
return ChunkedStream;
|
||||
}();
|
||||
@ -12848,14 +12845,12 @@
|
||||
var deltaHeight = decodeInteger(contextCache, 'IADH', decoder);
|
||||
currentHeight += deltaHeight;
|
||||
var currentWidth = 0;
|
||||
var totalWidth = 0;
|
||||
while (true) {
|
||||
var deltaWidth = decodeInteger(contextCache, 'IADW', decoder);
|
||||
if (deltaWidth === null) {
|
||||
break;
|
||||
}
|
||||
currentWidth += deltaWidth;
|
||||
totalWidth += currentWidth;
|
||||
var bitmap;
|
||||
if (refinement) {
|
||||
var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
|
||||
@ -13265,7 +13260,7 @@
|
||||
delete pageInfo.height;
|
||||
}
|
||||
var pageSegmentFlags = data[position + 16];
|
||||
var pageStripingInformation = readUint16(data, position + 17);
|
||||
readUint16(data, position + 17);
|
||||
pageInfo.lossless = !!(pageSegmentFlags & 1);
|
||||
pageInfo.refinement = !!(pageSegmentFlags & 2);
|
||||
pageInfo.defaultPixelValue = pageSegmentFlags >> 2 & 1;
|
||||
@ -13308,7 +13303,7 @@
|
||||
header.numberOfPages = readUint32(data, position);
|
||||
position += 4;
|
||||
}
|
||||
var segments = readSegments(header, data, position, end);
|
||||
readSegments(header, data, position, end);
|
||||
error('Not implemented');
|
||||
}
|
||||
function parseJbig2Chunks(chunks) {
|
||||
@ -14145,7 +14140,7 @@
|
||||
resetInterval = readUint16();
|
||||
break;
|
||||
case 0xFFDA:
|
||||
var scanLength = readUint16();
|
||||
readUint16();
|
||||
var selectorsCount = data[offset++];
|
||||
var components = [], component;
|
||||
for (i = 0; i < selectorsCount; i++) {
|
||||
@ -22560,7 +22555,6 @@
|
||||
var isArray = sharedUtil.isArray;
|
||||
var createObjectURL = sharedUtil.createObjectURL;
|
||||
var shadow = sharedUtil.shadow;
|
||||
var warn = sharedUtil.warn;
|
||||
var isSpace = sharedUtil.isSpace;
|
||||
var Dict = corePrimitives.Dict;
|
||||
var isDict = corePrimitives.isDict;
|
||||
@ -22642,8 +22636,7 @@
|
||||
},
|
||||
makeSubStream: function Stream_makeSubStream(start, length, dict) {
|
||||
return new Stream(this.bytes.buffer, start, length, dict);
|
||||
},
|
||||
isStream: true
|
||||
}
|
||||
};
|
||||
return Stream;
|
||||
}();
|
||||
@ -31220,264 +31213,6 @@
|
||||
return AES128Cipher;
|
||||
}();
|
||||
var AES256Cipher = function AES256CipherClosure() {
|
||||
var rcon = new Uint8Array([
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d
|
||||
]);
|
||||
var s = new Uint8Array([
|
||||
0x63,
|
||||
0x7c,
|
||||
@ -33036,9 +32771,9 @@
|
||||
function parseCmap(data, start, end) {
|
||||
var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16);
|
||||
var format = getUshort(data, start + offset);
|
||||
var length, ranges, p, i;
|
||||
var ranges, p, i;
|
||||
if (format === 4) {
|
||||
length = getUshort(data, start + offset + 2);
|
||||
getUshort(data, start + offset + 2);
|
||||
var segCount = getUshort(data, start + offset + 6) >> 1;
|
||||
p = start + offset + 14;
|
||||
ranges = [];
|
||||
@ -33065,7 +32800,7 @@
|
||||
}
|
||||
return ranges;
|
||||
} else if (format === 12) {
|
||||
length = getLong(data, start + offset + 4);
|
||||
getLong(data, start + offset + 4);
|
||||
var groups = getLong(data, start + offset + 12);
|
||||
p = start + offset + 16;
|
||||
ranges = [];
|
||||
@ -36162,7 +35897,7 @@
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
var wy = this.stack.pop();
|
||||
this.stack.pop();
|
||||
wx = this.stack.pop();
|
||||
var sby = this.stack.pop();
|
||||
sbx = this.stack.pop();
|
||||
@ -36414,7 +36149,7 @@
|
||||
}
|
||||
break;
|
||||
case 'Subrs':
|
||||
var num = this.readInt();
|
||||
this.readInt();
|
||||
this.getToken();
|
||||
while ((token = this.getToken()) === 'dup') {
|
||||
var index = this.readInt();
|
||||
@ -39067,9 +38802,6 @@
|
||||
this.sizes = [];
|
||||
this.missingFile = false;
|
||||
this.glyphCache = Object.create(null);
|
||||
var names = name.split('+');
|
||||
names = names.length > 1 ? names[1] : names[0];
|
||||
names = names.split(/[-,_]/g)[0];
|
||||
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
|
||||
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
||||
this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
|
||||
@ -39657,7 +39389,7 @@
|
||||
var segment;
|
||||
var start = (font.start ? font.start : 0) + cmap.offset;
|
||||
font.pos = start;
|
||||
var version = font.getUint16();
|
||||
font.getUint16();
|
||||
var numTables = font.getUint16();
|
||||
var potentialTable;
|
||||
var canBreak = false;
|
||||
@ -39703,8 +39435,8 @@
|
||||
};
|
||||
}
|
||||
var format = font.getUint16();
|
||||
var length = font.getUint16();
|
||||
var language = font.getUint16();
|
||||
font.getUint16();
|
||||
font.getUint16();
|
||||
var hasShortCmap = false;
|
||||
var mappings = [];
|
||||
var j, glyphId;
|
||||
@ -45192,22 +44924,11 @@
|
||||
var width = 0;
|
||||
var height = 0;
|
||||
var glyphs = font.charsToGlyphs(chars);
|
||||
var defaultVMetrics = font.defaultVMetrics;
|
||||
for (var i = 0; i < glyphs.length; i++) {
|
||||
var glyph = glyphs[i];
|
||||
var vMetricX = null;
|
||||
var vMetricY = null;
|
||||
var glyphWidth = null;
|
||||
if (font.vertical) {
|
||||
if (glyph.vmetric) {
|
||||
glyphWidth = glyph.vmetric[0];
|
||||
vMetricX = glyph.vmetric[1];
|
||||
vMetricY = glyph.vmetric[2];
|
||||
} else {
|
||||
glyphWidth = glyph.width;
|
||||
vMetricX = glyph.width * 0.5;
|
||||
vMetricY = defaultVMetrics[2];
|
||||
}
|
||||
if (font.vertical && glyph.vmetric) {
|
||||
glyphWidth = glyph.vmetric[0];
|
||||
} else {
|
||||
glyphWidth = glyph.width;
|
||||
}
|
||||
@ -47120,7 +46841,6 @@
|
||||
var AnnotationType = sharedUtil.AnnotationType;
|
||||
var OPS = sharedUtil.OPS;
|
||||
var Util = sharedUtil.Util;
|
||||
var isString = sharedUtil.isString;
|
||||
var isArray = sharedUtil.isArray;
|
||||
var isInt = sharedUtil.isInt;
|
||||
var stringToBytes = sharedUtil.stringToBytes;
|
||||
@ -48473,7 +48193,6 @@
|
||||
var MissingPDFException = sharedUtil.MissingPDFException;
|
||||
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
|
||||
var PasswordException = sharedUtil.PasswordException;
|
||||
var PasswordResponses = sharedUtil.PasswordResponses;
|
||||
var UnknownErrorException = sharedUtil.UnknownErrorException;
|
||||
var XRefParseException = sharedUtil.XRefParseException;
|
||||
var arrayByteLength = sharedUtil.arrayByteLength;
|
||||
@ -48739,7 +48458,7 @@
|
||||
var xhr = new XMLHttpRequest();
|
||||
var responseExists = 'response' in xhr;
|
||||
try {
|
||||
var dummy = xhr.responseType;
|
||||
xhr.responseType;
|
||||
} catch (e) {
|
||||
responseExists = false;
|
||||
}
|
||||
|
@ -1084,6 +1084,24 @@ html[dir="rtl"] #viewOutline.toolbarButton::before {
|
||||
content: url(images/toolbarButton-search.png);
|
||||
}
|
||||
|
||||
.toolbarButton.pdfSidebarNotification::after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 1px;
|
||||
/* Create a filled circle, with a diameter of 9 pixels, using only CSS: */
|
||||
content: '';
|
||||
background-color: #70DB55;
|
||||
height: 9px;
|
||||
width: 9px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
html[dir='ltr'] .toolbarButton.pdfSidebarNotification::after {
|
||||
left: 17px;
|
||||
}
|
||||
html[dir='rtl'] .toolbarButton.pdfSidebarNotification::after {
|
||||
right: 17px;
|
||||
}
|
||||
|
||||
.secondaryToolbarButton {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
|
@ -561,20 +561,26 @@ var pdfjsWebLibs;
|
||||
this.container = options.container;
|
||||
this.eventBus = options.eventBus;
|
||||
this.downloadManager = options.downloadManager;
|
||||
this._renderedCapability = pdfjsLib.createPromiseCapability();
|
||||
this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this));
|
||||
}
|
||||
PDFAttachmentViewer.prototype = {
|
||||
reset: function PDFAttachmentViewer_reset() {
|
||||
reset: function PDFAttachmentViewer_reset(keepRenderedCapability) {
|
||||
this.attachments = null;
|
||||
var container = this.container;
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
if (!keepRenderedCapability) {
|
||||
this._renderedCapability = pdfjsLib.createPromiseCapability();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
|
||||
this.eventBus.dispatch('attachmentsloaded', {
|
||||
source: this,
|
||||
attachmentsCount: attachmentsCount
|
||||
});
|
||||
this._renderedCapability.resolve();
|
||||
},
|
||||
_bindLink: function PDFAttachmentViewer_bindLink(button, content, filename) {
|
||||
button.onclick = function downloadFile(e) {
|
||||
@ -583,10 +589,12 @@ var pdfjsWebLibs;
|
||||
}.bind(this);
|
||||
},
|
||||
render: function PDFAttachmentViewer_render(params) {
|
||||
var attachments = params && params.attachments || null;
|
||||
params = params || {};
|
||||
var attachments = params.attachments || null;
|
||||
var attachmentsCount = 0;
|
||||
if (this.attachments) {
|
||||
this.reset();
|
||||
var keepRenderedCapability = params.keepRenderedCapability === true;
|
||||
this.reset(keepRenderedCapability);
|
||||
}
|
||||
this.attachments = attachments;
|
||||
if (!attachments) {
|
||||
@ -609,6 +617,28 @@ var pdfjsWebLibs;
|
||||
this.container.appendChild(div);
|
||||
}
|
||||
this._dispatchEvent(attachmentsCount);
|
||||
},
|
||||
_appendAttachment: function PDFAttachmentViewer_appendAttachment(item) {
|
||||
this._renderedCapability.promise.then(function (id, filename, content) {
|
||||
var attachments = this.attachments;
|
||||
if (!attachments) {
|
||||
attachments = Object.create(null);
|
||||
} else {
|
||||
for (var name in attachments) {
|
||||
if (id === name) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
attachments[id] = {
|
||||
filename: filename,
|
||||
content: content
|
||||
};
|
||||
this.render({
|
||||
attachments: attachments,
|
||||
keepRenderedCapability: true
|
||||
});
|
||||
}.bind(this, item.id, item.filename, item.content));
|
||||
}
|
||||
};
|
||||
return PDFAttachmentViewer;
|
||||
@ -752,234 +782,6 @@ var pdfjsWebLibs;
|
||||
}();
|
||||
exports.PDFOutlineViewer = PDFOutlineViewer;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFSidebar = {}, root.pdfjsWebPDFRenderingQueue);
|
||||
}(this, function (exports, pdfRenderingQueue) {
|
||||
var RenderingStates = pdfRenderingQueue.RenderingStates;
|
||||
var SidebarView = {
|
||||
NONE: 0,
|
||||
THUMBS: 1,
|
||||
OUTLINE: 2,
|
||||
ATTACHMENTS: 3
|
||||
};
|
||||
var PDFSidebar = function PDFSidebarClosure() {
|
||||
function PDFSidebar(options) {
|
||||
this.isOpen = false;
|
||||
this.active = SidebarView.THUMBS;
|
||||
this.isInitialViewSet = false;
|
||||
this.onToggled = null;
|
||||
this.pdfViewer = options.pdfViewer;
|
||||
this.pdfThumbnailViewer = options.pdfThumbnailViewer;
|
||||
this.pdfOutlineViewer = options.pdfOutlineViewer;
|
||||
this.mainContainer = options.mainContainer;
|
||||
this.outerContainer = options.outerContainer;
|
||||
this.eventBus = options.eventBus;
|
||||
this.toggleButton = options.toggleButton;
|
||||
this.thumbnailButton = options.thumbnailButton;
|
||||
this.outlineButton = options.outlineButton;
|
||||
this.attachmentsButton = options.attachmentsButton;
|
||||
this.thumbnailView = options.thumbnailView;
|
||||
this.outlineView = options.outlineView;
|
||||
this.attachmentsView = options.attachmentsView;
|
||||
this._addEventListeners();
|
||||
}
|
||||
PDFSidebar.prototype = {
|
||||
reset: function PDFSidebar_reset() {
|
||||
this.isInitialViewSet = false;
|
||||
this.close();
|
||||
this.switchView(SidebarView.THUMBS);
|
||||
this.outlineButton.disabled = false;
|
||||
this.attachmentsButton.disabled = false;
|
||||
},
|
||||
get visibleView() {
|
||||
return this.isOpen ? this.active : SidebarView.NONE;
|
||||
},
|
||||
get isThumbnailViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.THUMBS;
|
||||
},
|
||||
get isOutlineViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.OUTLINE;
|
||||
},
|
||||
get isAttachmentsViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.ATTACHMENTS;
|
||||
},
|
||||
setInitialView: function PDFSidebar_setInitialView(view) {
|
||||
if (this.isInitialViewSet) {
|
||||
return;
|
||||
}
|
||||
this.isInitialViewSet = true;
|
||||
if (this.isOpen && view === SidebarView.NONE) {
|
||||
this._dispatchEvent();
|
||||
return;
|
||||
}
|
||||
var isViewPreserved = view === this.visibleView;
|
||||
this.switchView(view, true);
|
||||
if (isViewPreserved) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
switchView: function PDFSidebar_switchView(view, forceOpen) {
|
||||
if (view === SidebarView.NONE) {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
var isViewChanged = view !== this.active;
|
||||
var shouldForceRendering = false;
|
||||
switch (view) {
|
||||
case SidebarView.THUMBS:
|
||||
this.thumbnailButton.classList.add('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.remove('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
if (this.isOpen && isViewChanged) {
|
||||
this._updateThumbnailViewer();
|
||||
shouldForceRendering = true;
|
||||
}
|
||||
break;
|
||||
case SidebarView.OUTLINE:
|
||||
if (this.outlineButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.add('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.remove('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
if (this.attachmentsButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.add('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.remove('hidden');
|
||||
break;
|
||||
default:
|
||||
console.error('PDFSidebar_switchView: "' + view + '" is an unsupported value.');
|
||||
return;
|
||||
}
|
||||
this.active = view | 0;
|
||||
if (forceOpen && !this.isOpen) {
|
||||
this.open();
|
||||
return;
|
||||
}
|
||||
if (shouldForceRendering) {
|
||||
this._forceRendering();
|
||||
}
|
||||
if (isViewChanged) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
open: function PDFSidebar_open() {
|
||||
if (this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.toggleButton.classList.add('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.add('sidebarOpen');
|
||||
if (this.active === SidebarView.THUMBS) {
|
||||
this._updateThumbnailViewer();
|
||||
}
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
close: function PDFSidebar_close() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.toggleButton.classList.remove('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.remove('sidebarOpen');
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
toggle: function PDFSidebar_toggle() {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFSidebar_dispatchEvent() {
|
||||
this.eventBus.dispatch('sidebarviewchanged', {
|
||||
source: this,
|
||||
view: this.visibleView
|
||||
});
|
||||
},
|
||||
_forceRendering: function PDFSidebar_forceRendering() {
|
||||
if (this.onToggled) {
|
||||
this.onToggled();
|
||||
} else {
|
||||
this.pdfViewer.forceRendering();
|
||||
this.pdfThumbnailViewer.forceRendering();
|
||||
}
|
||||
},
|
||||
_updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() {
|
||||
var pdfViewer = this.pdfViewer;
|
||||
var thumbnailViewer = this.pdfThumbnailViewer;
|
||||
var pagesCount = pdfViewer.pagesCount;
|
||||
for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
|
||||
var pageView = pdfViewer.getPageView(pageIndex);
|
||||
if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
|
||||
var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
|
||||
thumbnailView.setImage(pageView);
|
||||
}
|
||||
}
|
||||
thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
|
||||
},
|
||||
_addEventListeners: function PDFSidebar_addEventListeners() {
|
||||
var self = this;
|
||||
self.mainContainer.addEventListener('transitionend', function (evt) {
|
||||
if (evt.target === this) {
|
||||
self.outerContainer.classList.remove('sidebarMoving');
|
||||
}
|
||||
});
|
||||
self.thumbnailButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
});
|
||||
self.outlineButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.OUTLINE);
|
||||
});
|
||||
self.outlineButton.addEventListener('dblclick', function () {
|
||||
self.pdfOutlineViewer.toggleOutlineTree();
|
||||
});
|
||||
self.attachmentsButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.ATTACHMENTS);
|
||||
});
|
||||
self.eventBus.on('outlineloaded', function (e) {
|
||||
var outlineCount = e.outlineCount;
|
||||
self.outlineButton.disabled = !outlineCount;
|
||||
if (!outlineCount && self.active === SidebarView.OUTLINE) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('attachmentsloaded', function (e) {
|
||||
var attachmentsCount = e.attachmentsCount;
|
||||
self.attachmentsButton.disabled = !attachmentsCount;
|
||||
if (!attachmentsCount && self.active === SidebarView.ATTACHMENTS) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('presentationmodechanged', function (e) {
|
||||
if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) {
|
||||
self._updateThumbnailViewer();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return PDFSidebar;
|
||||
}();
|
||||
exports.SidebarView = SidebarView;
|
||||
exports.PDFSidebar = PDFSidebar;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebUIUtils = {}, root.pdfjsWebPDFJS);
|
||||
}(this, function (exports, pdfjsLib) {
|
||||
@ -2418,6 +2220,289 @@ var pdfjsWebLibs;
|
||||
}();
|
||||
exports.PDFPresentationMode = PDFPresentationMode;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFSidebar = {}, root.pdfjsWebPDFRenderingQueue, root.pdfjsWebUIUtils);
|
||||
}(this, function (exports, pdfRenderingQueue, uiUtils) {
|
||||
var RenderingStates = pdfRenderingQueue.RenderingStates;
|
||||
var mozL10n = uiUtils.mozL10n;
|
||||
var UI_NOTIFICATION_CLASS = 'pdfSidebarNotification';
|
||||
var SidebarView = {
|
||||
NONE: 0,
|
||||
THUMBS: 1,
|
||||
OUTLINE: 2,
|
||||
ATTACHMENTS: 3
|
||||
};
|
||||
var PDFSidebar = function PDFSidebarClosure() {
|
||||
function PDFSidebar(options) {
|
||||
this.isOpen = false;
|
||||
this.active = SidebarView.THUMBS;
|
||||
this.isInitialViewSet = false;
|
||||
this.onToggled = null;
|
||||
this.pdfViewer = options.pdfViewer;
|
||||
this.pdfThumbnailViewer = options.pdfThumbnailViewer;
|
||||
this.pdfOutlineViewer = options.pdfOutlineViewer;
|
||||
this.mainContainer = options.mainContainer;
|
||||
this.outerContainer = options.outerContainer;
|
||||
this.eventBus = options.eventBus;
|
||||
this.toggleButton = options.toggleButton;
|
||||
this.thumbnailButton = options.thumbnailButton;
|
||||
this.outlineButton = options.outlineButton;
|
||||
this.attachmentsButton = options.attachmentsButton;
|
||||
this.thumbnailView = options.thumbnailView;
|
||||
this.outlineView = options.outlineView;
|
||||
this.attachmentsView = options.attachmentsView;
|
||||
this.disableNotification = options.disableNotification || false;
|
||||
this._addEventListeners();
|
||||
}
|
||||
PDFSidebar.prototype = {
|
||||
reset: function PDFSidebar_reset() {
|
||||
this.isInitialViewSet = false;
|
||||
this._hideUINotification(null);
|
||||
this.switchView(SidebarView.THUMBS);
|
||||
this.outlineButton.disabled = false;
|
||||
this.attachmentsButton.disabled = false;
|
||||
},
|
||||
get visibleView() {
|
||||
return this.isOpen ? this.active : SidebarView.NONE;
|
||||
},
|
||||
get isThumbnailViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.THUMBS;
|
||||
},
|
||||
get isOutlineViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.OUTLINE;
|
||||
},
|
||||
get isAttachmentsViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.ATTACHMENTS;
|
||||
},
|
||||
setInitialView: function PDFSidebar_setInitialView(view) {
|
||||
if (this.isInitialViewSet) {
|
||||
return;
|
||||
}
|
||||
this.isInitialViewSet = true;
|
||||
if (this.isOpen && view === SidebarView.NONE) {
|
||||
this._dispatchEvent();
|
||||
return;
|
||||
}
|
||||
var isViewPreserved = view === this.visibleView;
|
||||
this.switchView(view, true);
|
||||
if (isViewPreserved) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
switchView: function PDFSidebar_switchView(view, forceOpen) {
|
||||
if (view === SidebarView.NONE) {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
var isViewChanged = view !== this.active;
|
||||
var shouldForceRendering = false;
|
||||
switch (view) {
|
||||
case SidebarView.THUMBS:
|
||||
this.thumbnailButton.classList.add('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.remove('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
if (this.isOpen && isViewChanged) {
|
||||
this._updateThumbnailViewer();
|
||||
shouldForceRendering = true;
|
||||
}
|
||||
break;
|
||||
case SidebarView.OUTLINE:
|
||||
if (this.outlineButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.add('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.remove('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
if (this.attachmentsButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.add('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.remove('hidden');
|
||||
break;
|
||||
default:
|
||||
console.error('PDFSidebar_switchView: "' + view + '" is an unsupported value.');
|
||||
return;
|
||||
}
|
||||
this.active = view | 0;
|
||||
if (forceOpen && !this.isOpen) {
|
||||
this.open();
|
||||
return;
|
||||
}
|
||||
if (shouldForceRendering) {
|
||||
this._forceRendering();
|
||||
}
|
||||
if (isViewChanged) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
this._hideUINotification(this.active);
|
||||
},
|
||||
open: function PDFSidebar_open() {
|
||||
if (this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.toggleButton.classList.add('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.add('sidebarOpen');
|
||||
if (this.active === SidebarView.THUMBS) {
|
||||
this._updateThumbnailViewer();
|
||||
}
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
this._hideUINotification(this.active);
|
||||
},
|
||||
close: function PDFSidebar_close() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.toggleButton.classList.remove('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.remove('sidebarOpen');
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
toggle: function PDFSidebar_toggle() {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFSidebar_dispatchEvent() {
|
||||
this.eventBus.dispatch('sidebarviewchanged', {
|
||||
source: this,
|
||||
view: this.visibleView
|
||||
});
|
||||
},
|
||||
_forceRendering: function PDFSidebar_forceRendering() {
|
||||
if (this.onToggled) {
|
||||
this.onToggled();
|
||||
} else {
|
||||
this.pdfViewer.forceRendering();
|
||||
this.pdfThumbnailViewer.forceRendering();
|
||||
}
|
||||
},
|
||||
_updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() {
|
||||
var pdfViewer = this.pdfViewer;
|
||||
var thumbnailViewer = this.pdfThumbnailViewer;
|
||||
var pagesCount = pdfViewer.pagesCount;
|
||||
for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
|
||||
var pageView = pdfViewer.getPageView(pageIndex);
|
||||
if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
|
||||
var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
|
||||
thumbnailView.setImage(pageView);
|
||||
}
|
||||
}
|
||||
thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
|
||||
},
|
||||
_showUINotification: function (view) {
|
||||
if (this.disableNotification) {
|
||||
return;
|
||||
}
|
||||
this.toggleButton.title = mozL10n.get('toggle_sidebar_notification.title', null, 'Toggle Sidebar (document contains outline/attachments)');
|
||||
if (!this.isOpen) {
|
||||
this.toggleButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
} else if (view === this.active) {
|
||||
return;
|
||||
}
|
||||
switch (view) {
|
||||
case SidebarView.OUTLINE:
|
||||
this.outlineButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
}
|
||||
},
|
||||
_hideUINotification: function (view) {
|
||||
if (this.disableNotification) {
|
||||
return;
|
||||
}
|
||||
var removeNotification = function (view) {
|
||||
switch (view) {
|
||||
case SidebarView.OUTLINE:
|
||||
this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
}
|
||||
}.bind(this);
|
||||
if (!this.isOpen && view !== null) {
|
||||
return;
|
||||
}
|
||||
this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
if (view !== null) {
|
||||
removeNotification(view);
|
||||
return;
|
||||
}
|
||||
for (view in SidebarView) {
|
||||
removeNotification(SidebarView[view]);
|
||||
}
|
||||
this.toggleButton.title = mozL10n.get('toggle_sidebar.title', null, 'Toggle Sidebar');
|
||||
},
|
||||
_addEventListeners: function PDFSidebar_addEventListeners() {
|
||||
var self = this;
|
||||
self.mainContainer.addEventListener('transitionend', function (evt) {
|
||||
if (evt.target === this) {
|
||||
self.outerContainer.classList.remove('sidebarMoving');
|
||||
}
|
||||
});
|
||||
self.thumbnailButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
});
|
||||
self.outlineButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.OUTLINE);
|
||||
});
|
||||
self.outlineButton.addEventListener('dblclick', function () {
|
||||
self.pdfOutlineViewer.toggleOutlineTree();
|
||||
});
|
||||
self.attachmentsButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.ATTACHMENTS);
|
||||
});
|
||||
self.eventBus.on('outlineloaded', function (e) {
|
||||
var outlineCount = e.outlineCount;
|
||||
self.outlineButton.disabled = !outlineCount;
|
||||
if (outlineCount) {
|
||||
self._showUINotification(SidebarView.OUTLINE);
|
||||
} else if (self.active === SidebarView.OUTLINE) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('attachmentsloaded', function (e) {
|
||||
var attachmentsCount = e.attachmentsCount;
|
||||
self.attachmentsButton.disabled = !attachmentsCount;
|
||||
if (attachmentsCount) {
|
||||
self._showUINotification(SidebarView.ATTACHMENTS);
|
||||
} else if (self.active === SidebarView.ATTACHMENTS) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('presentationmodechanged', function (e) {
|
||||
if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) {
|
||||
self._updateThumbnailViewer();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return PDFSidebar;
|
||||
}();
|
||||
exports.SidebarView = SidebarView;
|
||||
exports.PDFSidebar = PDFSidebar;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFThumbnailView = {}, root.pdfjsWebUIUtils, root.pdfjsWebPDFRenderingQueue);
|
||||
}(this, function (exports, uiUtils, pdfRenderingQueue) {
|
||||
@ -3745,6 +3830,14 @@ var pdfjsWebLibs;
|
||||
action: action
|
||||
});
|
||||
},
|
||||
onFileAttachmentAnnotation: function (params) {
|
||||
this.eventBus.dispatch('fileattachmentannotation', {
|
||||
source: this,
|
||||
id: params.id,
|
||||
filename: params.filename,
|
||||
content: params.content
|
||||
});
|
||||
},
|
||||
cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
|
||||
var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
|
||||
this._pagesRefCache[refStr] = pageNum;
|
||||
@ -3827,6 +3920,8 @@ var pdfjsWebLibs;
|
||||
},
|
||||
executeNamedAction: function (action) {
|
||||
},
|
||||
onFileAttachmentAnnotation: function (params) {
|
||||
},
|
||||
cachePageRef: function (pageNum, pageRef) {
|
||||
}
|
||||
};
|
||||
@ -4074,7 +4169,6 @@ var pdfjsWebLibs;
|
||||
this.renderingState = RenderingStates.RUNNING;
|
||||
var self = this;
|
||||
var pdfPage = this.pdfPage;
|
||||
var viewport = this.viewport;
|
||||
var div = this.div;
|
||||
var canvasWrapper = document.createElement('div');
|
||||
canvasWrapper.style.width = div.style.width;
|
||||
@ -4194,8 +4288,6 @@ var pdfjsWebLibs;
|
||||
renderTask.cancel();
|
||||
}
|
||||
};
|
||||
var self = this;
|
||||
var pdfPage = this.pdfPage;
|
||||
var viewport = this.viewport;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.id = 'page' + this.id;
|
||||
|
@ -101,6 +101,7 @@ print_progress_close=Cancel
|
||||
# (the _label strings are alt text for the buttons, the .title strings are
|
||||
# tooltips)
|
||||
toggle_sidebar.title=Toggle Sidebar
|
||||
toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments)
|
||||
toggle_sidebar_label=Toggle Sidebar
|
||||
document_outline.title=Show Document Outline (double-click to expand/collapse all items)
|
||||
document_outline_label=Document Outline
|
||||
|
@ -455,6 +455,7 @@ this.ContentSearch = {
|
||||
if (msg.target.contentWindow) {
|
||||
engine.speculativeConnect({
|
||||
window: msg.target.contentWindow,
|
||||
originAttributes: msg.target.contentPrincipal.originAttributes
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -42,8 +42,6 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||
dnl --cxxflags. We use sed to remove this argument so that builds work on OSX
|
||||
LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags | sed -e 's/-isysroot [[^ ]]*//'`
|
||||
|
||||
dnl We are loaded into clang, so we don't need to link to very many things,
|
||||
dnl we just need to link to clangASTMatchers because it is not used by clang
|
||||
LLVM_LDFLAGS=`$LLVMCONFIG --ldflags | tr '\n' ' '`
|
||||
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
@ -54,7 +52,14 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||
dnl access to all of the symbols which are undefined in our dylib as we
|
||||
dnl are building it right now, and also that we don't fail the build
|
||||
dnl due to undefined symbols (which will be provided by clang).
|
||||
CLANG_LDFLAGS="-Wl,-flat_namespace -Wl,-undefined,suppress -lclangASTMatchers"
|
||||
CLANG_LDFLAGS="-Wl,-flat_namespace -Wl,-undefined,suppress"
|
||||
dnl We are loaded into clang, so we don't need to link to very many things,
|
||||
dnl we just need to link to clangASTMatchers because it is not used by clang
|
||||
CLANG_LDFLAGS="$CLANG_LDFLAGS `$LLVMCONFIG --prefix`/lib/libclangASTMatchers.a"
|
||||
dnl We need to remove -L/path/to/clang/lib from LDFLAGS to ensure that we
|
||||
dnl don't accidentally link against the libc++ there which is a newer
|
||||
dnl version that what our build machines have installed.
|
||||
LLVM_LDFLAGS=`echo "$LLVM_LDFLAGS" | sed -E 's/-L[[^ ]]+\/clang\/lib//'`
|
||||
elif test "${HOST_OS_ARCH}" = "WINNT"; then
|
||||
CLANG_LDFLAGS="clang.lib"
|
||||
else
|
||||
|
@ -39,10 +39,12 @@ build-clang.py accepts a JSON config format with the following fields:
|
||||
* gcc_dir: Path to the gcc toolchain installation, only required on Linux.
|
||||
* cc: Path to the bootsraping C Compiler.
|
||||
* cxx: Path to the bootsraping C++ Compiler.
|
||||
* as: Path to the assembler tool.
|
||||
* ar: Path to the library archiver tool.
|
||||
* ranlib: Path to the ranlib tool.
|
||||
* ranlib: Path to the ranlib tool (optional).
|
||||
* libtool: Path to the libtool tool (optional).
|
||||
* ld: Path to the linker.
|
||||
* patches: Optional list of patches to apply per platform. Supported platforms: macosx64, linux32, linux64. The default is Release.
|
||||
* patches: Optional list of patches to apply.
|
||||
* build_type: The type of build to make. Supported types: Release, Debug, RelWithDebInfo or MinSizeRel.
|
||||
* build_libcxx: Whether to build with libcxx. The default is false.
|
||||
* build_clang_tidy: Whether to build clang-tidy with the Mozilla checks imported. The default is false.
|
||||
|
@ -170,24 +170,6 @@ def svn_update(directory, revision):
|
||||
run_in(directory, ["svn", "revert", "-q", "-R", revision])
|
||||
|
||||
|
||||
def get_platform():
|
||||
p = platform.system()
|
||||
if p == "Darwin":
|
||||
return "macosx64"
|
||||
elif p == "Linux":
|
||||
if platform.architecture() == "AMD64":
|
||||
return "linux64"
|
||||
else:
|
||||
return "linux32"
|
||||
elif p == "Windows":
|
||||
if platform.architecture() == "AMD64":
|
||||
return "win64"
|
||||
else:
|
||||
return "win32"
|
||||
else:
|
||||
raise NotImplementedError("Not supported platform")
|
||||
|
||||
|
||||
def is_darwin():
|
||||
return platform.system() == "Darwin"
|
||||
|
||||
@ -200,7 +182,7 @@ def is_windows():
|
||||
return platform.system() == "Windows"
|
||||
|
||||
|
||||
def build_one_stage(cc, cxx, ld, ar, ranlib,
|
||||
def build_one_stage(cc, cxx, asm, ld, ar, ranlib, libtool,
|
||||
src_dir, stage_dir, build_libcxx,
|
||||
osx_cross_compile, build_type, assertions,
|
||||
python_path, gcc_dir, libcxx_include_dir):
|
||||
@ -225,11 +207,12 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
||||
cmake_args = ["-GNinja",
|
||||
"-DCMAKE_C_COMPILER=%s" % slashify_path(cc[0]),
|
||||
"-DCMAKE_CXX_COMPILER=%s" % slashify_path(cxx[0]),
|
||||
"-DCMAKE_ASM_COMPILER=%s" % slashify_path(cc[0]),
|
||||
"-DCMAKE_ASM_COMPILER=%s" % slashify_path(asm[0]),
|
||||
"-DCMAKE_LINKER=%s" % slashify_path(ld[0]),
|
||||
"-DCMAKE_AR=%s" % slashify_path(ar),
|
||||
"-DCMAKE_C_FLAGS=%s" % ' '.join(cc[1:]),
|
||||
"-DCMAKE_CXX_FLAGS=%s" % ' '.join(cxx[1:]),
|
||||
"-DCMAKE_ASM_FLAGS=%s" % ' '.join(asm[1:]),
|
||||
"-DCMAKE_EXE_LINKER_FLAGS=%s" % ' '.join(ld[1:]),
|
||||
"-DCMAKE_SHARED_LINKER_FLAGS=%s" % ' '.join(ld[1:]),
|
||||
"-DCMAKE_BUILD_TYPE=%s" % build_type,
|
||||
@ -245,6 +228,8 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
||||
cmake_args.insert(-1, "-DLLVM_USE_CRT_RELEASE=MT")
|
||||
if ranlib is not None:
|
||||
cmake_args += ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib)]
|
||||
if libtool is not None:
|
||||
cmake_args += ["-DCMAKE_LIBTOOL=%s" % slashify_path(libtool)]
|
||||
if osx_cross_compile:
|
||||
cmake_args += ["-DCMAKE_SYSTEM_NAME=Darwin",
|
||||
"-DCMAKE_SYSTEM_VERSION=10.10",
|
||||
@ -258,7 +243,7 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
||||
"-DCMAKE_MACOSX_RPATH=@executable_path",
|
||||
"-DCMAKE_OSX_ARCHITECTURES=x86_64",
|
||||
"-DDARWIN_osx_ARCHS=x86_64",
|
||||
"-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin10"]
|
||||
"-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin11"]
|
||||
build_package(build_dir, cmake_args)
|
||||
|
||||
if is_linux():
|
||||
@ -464,9 +449,13 @@ if __name__ == "__main__":
|
||||
raise ValueError("Config file needs to set gcc_dir")
|
||||
cc = get_tool(config, "cc")
|
||||
cxx = get_tool(config, "cxx")
|
||||
asm = get_tool(config, "ml" if is_windows() else "as")
|
||||
ld = get_tool(config, "link" if is_windows() else "ld")
|
||||
ar = get_tool(config, "lib" if is_windows() else "ar")
|
||||
ranlib = None if is_windows() else get_tool(config, "ranlib")
|
||||
libtool = None
|
||||
if "libtool" in config:
|
||||
libtool = get_tool(config, "libtool")
|
||||
|
||||
if not os.path.exists(source_dir):
|
||||
os.makedirs(source_dir)
|
||||
@ -485,7 +474,7 @@ if __name__ == "__main__":
|
||||
checkout_or_update(libcxxabi_repo, libcxxabi_source_dir)
|
||||
if extra_repo:
|
||||
checkout_or_update(extra_repo, extra_source_dir)
|
||||
for p in config.get("patches", {}).get(get_platform(), []):
|
||||
for p in config.get("patches", []):
|
||||
patch(p, source_dir)
|
||||
|
||||
symlinks = [(source_dir + "/clang",
|
||||
@ -525,12 +514,14 @@ if __name__ == "__main__":
|
||||
extra_cxxflags = ["-stdlib=libc++"]
|
||||
extra_cflags2 = []
|
||||
extra_cxxflags2 = ["-stdlib=libc++"]
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
elif is_linux():
|
||||
extra_cflags = ["-static-libgcc"]
|
||||
extra_cxxflags = ["-static-libgcc", "-static-libstdc++"]
|
||||
extra_cflags2 = ["-fPIC"]
|
||||
extra_cxxflags2 = ["-fPIC", "-static-libstdc++"]
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
|
||||
if os.environ.has_key('LD_LIBRARY_PATH'):
|
||||
@ -545,6 +536,7 @@ if __name__ == "__main__":
|
||||
# Force things on.
|
||||
extra_cflags2 = []
|
||||
extra_cxxflags2 = ['-fms-compatibility-version=19.00.24213', '-Xclang', '-std=c++14']
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
|
||||
if osx_cross_compile:
|
||||
@ -554,7 +546,7 @@ if __name__ == "__main__":
|
||||
extra_cxxflags = ["-stdlib=libc++"]
|
||||
extra_cxxflags2 = ["-stdlib=libc++"]
|
||||
|
||||
extra_flags = ["-target", "x86_64-apple-darwin10", "-mlinker-version=136",
|
||||
extra_flags = ["-target", "x86_64-apple-darwin11", "-mlinker-version=137",
|
||||
"-B", "%s/bin" % os.getenv("CROSS_CCTOOLS_PATH"),
|
||||
"-isysroot", os.getenv("CROSS_SYSROOT"),
|
||||
# technically the sysroot flag there should be enough to deduce this,
|
||||
@ -565,14 +557,16 @@ if __name__ == "__main__":
|
||||
extra_cxxflags += extra_flags
|
||||
extra_cflags2 += extra_flags
|
||||
extra_cxxflags2 += extra_flags
|
||||
extra_asmflags += extra_flags
|
||||
extra_ldflags = ["-Wl,-syslibroot,%s" % os.getenv("CROSS_SYSROOT"),
|
||||
"-Wl,-dead_strip"]
|
||||
|
||||
build_one_stage(
|
||||
[cc] + extra_cflags,
|
||||
[cxx] + extra_cxxflags,
|
||||
[asm] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage1_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
@ -585,8 +579,10 @@ if __name__ == "__main__":
|
||||
(cc_name, exe_ext)] + extra_cflags2,
|
||||
[stage1_inst_dir + "/bin/%s%s" %
|
||||
(cxx_name, exe_ext)] + extra_cxxflags2,
|
||||
[stage1_inst_dir + "/bin/%s%s" %
|
||||
(cc_name, exe_ext)] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage2_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
@ -598,8 +594,10 @@ if __name__ == "__main__":
|
||||
(cc_name, exe_ext)] + extra_cflags2,
|
||||
[stage2_inst_dir + "/bin/%s%s" %
|
||||
(cxx_name, exe_ext)] + extra_cxxflags2,
|
||||
[stage2_inst_dir + "/bin/%s%s" %
|
||||
(cc_name, exe_ext)] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage3_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
|
@ -13,15 +13,8 @@
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++",
|
||||
"patches": {
|
||||
"macosx64": [
|
||||
"llvm-debug-frame.patch"
|
||||
],
|
||||
"linux64": [
|
||||
"llvm-debug-frame.patch"
|
||||
],
|
||||
"linux32": [
|
||||
"llvm-debug-frame.patch"
|
||||
]
|
||||
}
|
||||
"as": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"patches": [
|
||||
"llvm-debug-frame.patch"
|
||||
]
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
{
|
||||
"llvm_revision": "262557",
|
||||
"stages": "3",
|
||||
"llvm_revision": "290136",
|
||||
"stages": "1",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_380/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_380/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_380/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_380/final",
|
||||
"python_path": "/usr/local/bin/python2.7",
|
||||
"cc": "/Users/cltbld/clang/bin/clang",
|
||||
"cxx": "/Users/cltbld/clang/bin/clang++",
|
||||
"patches": {
|
||||
"macosx64": [
|
||||
"disable-mac-tsan.patch",
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
],
|
||||
"linux64": [
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
],
|
||||
"linux32": [
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
]
|
||||
}
|
||||
"osx_cross_compile": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_390/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_390/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_390/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_390/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_390/final",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"cxx": "/home/worker/workspace/build/src/clang/bin/clang++",
|
||||
"as": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ranlib",
|
||||
"libtool": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-libtool",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches":[
|
||||
"llvm-debug-frame.patch",
|
||||
"compiler-rt-cross-compile.patch",
|
||||
"pr28831-r280042.patch",
|
||||
"r277806.patch",
|
||||
"r285657.patch"
|
||||
]
|
||||
}
|
||||
|
@ -10,7 +10,5 @@
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"patches": {
|
||||
}
|
||||
"cxx": "cl.exe"
|
||||
}
|
||||
|
@ -11,6 +11,5 @@
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"patches": {
|
||||
}
|
||||
"ml": "ml64.exe"
|
||||
}
|
||||
|
@ -14,5 +14,6 @@
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++"
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++",
|
||||
"as": "/home/worker/workspace/build/src/gcc/bin/gcc"
|
||||
}
|
||||
|
@ -16,7 +16,12 @@
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"cxx": "/home/worker/workspace/build/src/clang/bin/clang++",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin10-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin10-ranlib",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang"
|
||||
"as": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ranlib",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches": [
|
||||
"llvm-debug-frame.patch",
|
||||
"compiler-rt-cross-compile.patch"
|
||||
]
|
||||
}
|
||||
|
@ -12,5 +12,6 @@
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe"
|
||||
"cxx": "cl.exe",
|
||||
"ml": "ml64.exe"
|
||||
}
|
||||
|
15
build/build-clang/compiler-rt-cross-compile.patch
Normal file
15
build/build-clang/compiler-rt-cross-compile.patch
Normal file
@ -0,0 +1,15 @@
|
||||
Add `-target x86_64-apple-darwin11' to the compiler-rt overridden CFLAGS
|
||||
|
||||
diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
index 28d398672..aac68bf36 100644
|
||||
--- a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
+++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
@@ -265,7 +265,7 @@ endfunction()
|
||||
macro(darwin_add_builtin_libraries)
|
||||
set(DARWIN_EXCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Darwin-excludes)
|
||||
|
||||
- set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer")
|
||||
+ set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer -target x86_64-apple-darwin11 -isysroot ${CMAKE_OSX_SYSROOT} -I${CMAKE_OSX_SYSROOT}/usr/include")
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
set(CMAKE_ASM_FLAGS "")
|
@ -1,11 +0,0 @@
|
||||
--- a/compiler-rt/cmake/config-ix.cmake
|
||||
+++ b/compiler-rt/cmake/config-ix.cmake
|
||||
@@ -617,7 +617,7 @@
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
|
||||
- OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
+ OS_NAME MATCHES "Linux|FreeBSD")
|
||||
set(COMPILER_RT_HAS_TSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_TSAN FALSE)
|
19
build/build-clang/pr28831-r280042.patch
Normal file
19
build/build-clang/pr28831-r280042.patch
Normal file
@ -0,0 +1,19 @@
|
||||
Backport the fix to PR28831 plus its follow-up (r280042)
|
||||
|
||||
diff --git a/libcxx/lib/CMakeLists.txt b/libcxx/lib/CMakeLists.txt
|
||||
index afc388e76..4f43f3711 100644
|
||||
--- a/libcxx/lib/CMakeLists.txt
|
||||
+++ b/libcxx/lib/CMakeLists.txt
|
||||
@@ -115,9 +115,9 @@ if ( APPLE AND (LIBCXX_CXX_ABI_LIBNAME STREQUAL "libcxxabi" OR
|
||||
"-Wl,-unexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/libc++unexp.exp"
|
||||
"/usr/lib/libSystem.B.dylib")
|
||||
else()
|
||||
- if ( ${CMAKE_OSX_SYSROOT} )
|
||||
- list(FIND ${CMAKE_OSX_ARCHITECTURES} "armv7" OSX_HAS_ARMV7)
|
||||
- if (OSX_HAS_ARMV7)
|
||||
+ if (DEFINED CMAKE_OSX_SYSROOT)
|
||||
+ list(FIND CMAKE_OSX_ARCHITECTURES "armv7" OSX_HAS_ARMV7)
|
||||
+ if (NOT OSX_HAS_ARMV7 EQUAL -1)
|
||||
set(OSX_RE_EXPORT_LINE
|
||||
"${CMAKE_OSX_SYSROOT}/usr/lib/libc++abi.dylib"
|
||||
"-Wl,-reexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/libc++sjlj-abi.exp")
|
@ -1,79 +0,0 @@
|
||||
commit 865b9340996f9f9d04b73b187248737dc6fd845e
|
||||
Author: Michael Wu <mwu@mozilla.com>
|
||||
Date: Mon Sep 14 17:47:21 2015 -0400
|
||||
|
||||
Add support for querying the visibility of a cursor
|
||||
|
||||
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
|
||||
index fad9cfa..311bfcb 100644
|
||||
--- a/clang/include/clang-c/Index.h
|
||||
+++ b/clang/include/clang-c/Index.h
|
||||
@@ -2440,6 +2440,24 @@ enum CXLinkageKind {
|
||||
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
|
||||
|
||||
/**
|
||||
+ * \brief Describe the visibility of the entity referred to by a cursor.
|
||||
+ */
|
||||
+enum CXVisibilityKind {
|
||||
+ /** \brief This value indicates that no visibility information is available
|
||||
+ * for a provided CXCursor. */
|
||||
+ CXVisibility_Invalid,
|
||||
+
|
||||
+ /** \brief Symbol not seen by the linker. */
|
||||
+ CXVisibility_Hidden,
|
||||
+ /** \brief Symbol seen by the linker but resolves to a symbol inside this object. */
|
||||
+ CXVisibility_Protected,
|
||||
+ /** \brief Symbol seen by the linker and acts like a normal symbol. */
|
||||
+ CXVisibility_Default,
|
||||
+};
|
||||
+
|
||||
+CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor);
|
||||
+
|
||||
+/**
|
||||
* \brief Determine the availability of the entity that this cursor refers to,
|
||||
* taking the current target platform into account.
|
||||
*
|
||||
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
|
||||
index 8225a6c..9fa18d3 100644
|
||||
--- a/clang/tools/libclang/CIndex.cpp
|
||||
+++ b/clang/tools/libclang/CIndex.cpp
|
||||
@@ -6361,6 +6361,27 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
|
||||
} // end: extern "C"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
+// Operations for querying visibility of a cursor.
|
||||
+//===----------------------------------------------------------------------===//
|
||||
+
|
||||
+extern "C" {
|
||||
+CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) {
|
||||
+ if (!clang_isDeclaration(cursor.kind))
|
||||
+ return CXVisibility_Invalid;
|
||||
+
|
||||
+ const Decl *D = cxcursor::getCursorDecl(cursor);
|
||||
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
|
||||
+ switch (ND->getVisibility()) {
|
||||
+ case HiddenVisibility: return CXVisibility_Hidden;
|
||||
+ case ProtectedVisibility: return CXVisibility_Protected;
|
||||
+ case DefaultVisibility: return CXVisibility_Default;
|
||||
+ };
|
||||
+
|
||||
+ return CXVisibility_Invalid;
|
||||
+}
|
||||
+} // end: extern "C"
|
||||
+
|
||||
+//===----------------------------------------------------------------------===//
|
||||
// Operations for querying language of a cursor.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports
|
||||
index f6a7175..a919a8e 100644
|
||||
--- a/clang/tools/libclang/libclang.exports
|
||||
+++ b/clang/tools/libclang/libclang.exports
|
||||
@@ -173,6 +173,7 @@ clang_getCursorSemanticParent
|
||||
clang_getCursorSpelling
|
||||
clang_getCursorType
|
||||
clang_getCursorUSR
|
||||
+clang_getCursorVisibility
|
||||
clang_getDeclObjCTypeEncoding
|
||||
clang_getDefinitionSpellingAndExtent
|
||||
clang_getDiagnostic
|
321
build/build-clang/r277806.patch
Normal file
321
build/build-clang/r277806.patch
Normal file
@ -0,0 +1,321 @@
|
||||
commit eca7f4535bffb1c86cb1620b9d9425ff3ce31ab9
|
||||
Author: John Brawn <john.brawn@arm.com>
|
||||
Date: Fri Aug 5 11:01:08 2016 +0000
|
||||
|
||||
Reapply r276973 "Adjust Registry interface to not require plugins to export a registry"
|
||||
|
||||
This differs from the previous version by being more careful about template
|
||||
instantiation/specialization in order to prevent errors when building with
|
||||
clang -Werror. Specifically:
|
||||
* begin is not defined in the template and is instead instantiated when Head
|
||||
is. I think the warning when we don't do that is wrong (PR28815) but for now
|
||||
at least do it this way to avoid the warning.
|
||||
* Instead of performing template specializations in LLVM_INSTANTIATE_REGISTRY
|
||||
instead provide a template definition then do explicit instantiation. No
|
||||
compiler I've tried has problems with doing it the other way, but strictly
|
||||
speaking it's not permitted by the C++ standard so better safe than sorry.
|
||||
|
||||
Original commit message:
|
||||
|
||||
Currently the Registry class contains the vestiges of a previous attempt to
|
||||
allow plugins to be used on Windows without using BUILD_SHARED_LIBS, where a
|
||||
plugin would have its own copy of a registry and export it to be imported by
|
||||
the tool that's loading the plugin. This only works if the plugin is entirely
|
||||
self-contained with the only interface between the plugin and tool being the
|
||||
registry, and in particular this conflicts with how IR pass plugins work.
|
||||
|
||||
This patch changes things so that instead the add_node function of the registry
|
||||
is exported by the tool and then imported by the plugin, which solves this
|
||||
problem and also means that instead of every plugin having to export every
|
||||
registry they use instead LLVM only has to export the add_node functions. This
|
||||
allows plugins that use a registry to work on Windows if
|
||||
LLVM_EXPORT_SYMBOLS_FOR_PLUGINS is used.
|
||||
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@277806 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
|
||||
diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h
|
||||
index 27f025fcd08..9557f56093b 100644
|
||||
--- a/llvm/include/llvm/Support/Registry.h
|
||||
+++ b/llvm/include/llvm/Support/Registry.h
|
||||
@@ -44,6 +44,7 @@ namespace llvm {
|
||||
template <typename T>
|
||||
class Registry {
|
||||
public:
|
||||
+ typedef T type;
|
||||
typedef SimpleRegistryEntry<T> entry;
|
||||
|
||||
class node;
|
||||
@@ -69,13 +70,14 @@ namespace llvm {
|
||||
node(const entry &V) : Next(nullptr), Val(V) {}
|
||||
};
|
||||
|
||||
- static void add_node(node *N) {
|
||||
- if (Tail)
|
||||
- Tail->Next = N;
|
||||
- else
|
||||
- Head = N;
|
||||
- Tail = N;
|
||||
- }
|
||||
+ /// Add a node to the Registry: this is the interface between the plugin and
|
||||
+ /// the executable.
|
||||
+ ///
|
||||
+ /// This function is exported by the executable and called by the plugin to
|
||||
+ /// add a node to the executable's registry. Therefore it's not defined here
|
||||
+ /// to avoid it being instantiated in the plugin and is instead defined in
|
||||
+ /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
|
||||
+ static void add_node(node *N);
|
||||
|
||||
/// Iterators for registry entries.
|
||||
///
|
||||
@@ -92,7 +94,9 @@ namespace llvm {
|
||||
const entry *operator->() const { return &Cur->Val; }
|
||||
};
|
||||
|
||||
- static iterator begin() { return iterator(Head); }
|
||||
+ // begin is not defined here in order to avoid usage of an undefined static
|
||||
+ // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
|
||||
+ static iterator begin();
|
||||
static iterator end() { return iterator(nullptr); }
|
||||
|
||||
static iterator_range<iterator> entries() {
|
||||
@@ -120,61 +124,37 @@ namespace llvm {
|
||||
add_node(&Node);
|
||||
}
|
||||
};
|
||||
-
|
||||
- /// A dynamic import facility. This is used on Windows to
|
||||
- /// import the entries added in the plugin.
|
||||
- static void import(sys::DynamicLibrary &DL, const char *RegistryName) {
|
||||
- typedef void *(*GetRegistry)();
|
||||
- std::string Name("LLVMGetRegistry_");
|
||||
- Name.append(RegistryName);
|
||||
- GetRegistry Getter =
|
||||
- (GetRegistry)(intptr_t)DL.getAddressOfSymbol(Name.c_str());
|
||||
- if (Getter) {
|
||||
- // Call the getter function in order to get the full copy of the
|
||||
- // registry defined in the plugin DLL, and copy them over to the
|
||||
- // current Registry.
|
||||
- typedef std::pair<const node *, const node *> Info;
|
||||
- Info *I = static_cast<Info *>(Getter());
|
||||
- iterator begin(I->first);
|
||||
- iterator end(I->second);
|
||||
- for (++end; begin != end; ++begin) {
|
||||
- // This Node object needs to remain alive for the
|
||||
- // duration of the program.
|
||||
- add_node(new node(*begin));
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /// Retrieve the data to be passed across DLL boundaries when
|
||||
- /// importing registries from another DLL on Windows.
|
||||
- static void *exportRegistry() {
|
||||
- static std::pair<const node *, const node *> Info(Head, Tail);
|
||||
- return &Info;
|
||||
- }
|
||||
};
|
||||
-
|
||||
-
|
||||
- // Since these are defined in a header file, plugins must be sure to export
|
||||
- // these symbols.
|
||||
- template <typename T>
|
||||
- typename Registry<T>::node *Registry<T>::Head;
|
||||
-
|
||||
- template <typename T>
|
||||
- typename Registry<T>::node *Registry<T>::Tail;
|
||||
} // end namespace llvm
|
||||
|
||||
-#ifdef LLVM_ON_WIN32
|
||||
-#define LLVM_EXPORT_REGISTRY(REGISTRY_CLASS) \
|
||||
- extern "C" { \
|
||||
- __declspec(dllexport) void *__cdecl LLVMGetRegistry_##REGISTRY_CLASS() { \
|
||||
- return REGISTRY_CLASS::exportRegistry(); \
|
||||
- } \
|
||||
+/// Instantiate a registry class.
|
||||
+///
|
||||
+/// This provides template definitions of add_node, begin, and the Head and Tail
|
||||
+/// pointers, then explicitly instantiates them. We could explicitly specialize
|
||||
+/// them, instead of the two-step process of define then instantiate, but
|
||||
+/// strictly speaking that's not allowed by the C++ standard (we would need to
|
||||
+/// have explicit specialization declarations in all translation units where the
|
||||
+/// specialization is used) so we don't.
|
||||
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
|
||||
+ namespace llvm { \
|
||||
+ template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
|
||||
+ template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
|
||||
+ template<typename T> \
|
||||
+ void Registry<T>::add_node(typename Registry<T>::node *N) { \
|
||||
+ if (Tail) \
|
||||
+ Tail->Next = N; \
|
||||
+ else \
|
||||
+ Head = N; \
|
||||
+ Tail = N; \
|
||||
+ } \
|
||||
+ template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
|
||||
+ return iterator(Head); \
|
||||
+ } \
|
||||
+ template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
|
||||
+ template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
|
||||
+ template \
|
||||
+ void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
|
||||
+ template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
|
||||
}
|
||||
-#define LLVM_IMPORT_REGISTRY(REGISTRY_CLASS, DL) \
|
||||
- REGISTRY_CLASS::import(DL, #REGISTRY_CLASS)
|
||||
-#else
|
||||
-#define LLVM_EXPORT_REGISTRY(REGISTRY_CLASS)
|
||||
-#define LLVM_IMPORT_REGISTRY(REGISTRY_CLASS, DL)
|
||||
-#endif
|
||||
|
||||
#endif // LLVM_SUPPORT_REGISTRY_H
|
||||
diff --git a/llvm/lib/CodeGen/GCMetadataPrinter.cpp b/llvm/lib/CodeGen/GCMetadataPrinter.cpp
|
||||
index bb8cfa1cc80..d183c7f2980 100644
|
||||
--- a/llvm/lib/CodeGen/GCMetadataPrinter.cpp
|
||||
+++ b/llvm/lib/CodeGen/GCMetadataPrinter.cpp
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||
using namespace llvm;
|
||||
|
||||
+LLVM_INSTANTIATE_REGISTRY(GCMetadataPrinterRegistry)
|
||||
+
|
||||
GCMetadataPrinter::GCMetadataPrinter() {}
|
||||
|
||||
GCMetadataPrinter::~GCMetadataPrinter() {}
|
||||
diff --git a/llvm/lib/CodeGen/GCStrategy.cpp b/llvm/lib/CodeGen/GCStrategy.cpp
|
||||
index 554d326942e..31ab86fdf27 100644
|
||||
--- a/llvm/lib/CodeGen/GCStrategy.cpp
|
||||
+++ b/llvm/lib/CodeGen/GCStrategy.cpp
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
+LLVM_INSTANTIATE_REGISTRY(GCRegistry)
|
||||
+
|
||||
GCStrategy::GCStrategy()
|
||||
: UseStatepoints(false), NeededSafePoints(0), CustomReadBarriers(false),
|
||||
CustomWriteBarriers(false), CustomRoots(false), InitRoots(true),
|
||||
|
||||
commit 0cfb8c87dfc0a8366d6db83f93aa50e9514dbf9d
|
||||
Author: John Brawn <john.brawn@arm.com>
|
||||
Date: Fri Aug 5 11:01:08 2016 +0000
|
||||
|
||||
Reapply r276973 "Adjust Registry interface to not require plugins to export a registry"
|
||||
|
||||
This differs from the previous version by being more careful about template
|
||||
instantiation/specialization in order to prevent errors when building with
|
||||
clang -Werror. Specifically:
|
||||
* begin is not defined in the template and is instead instantiated when Head
|
||||
is. I think the warning when we don't do that is wrong (PR28815) but for now
|
||||
at least do it this way to avoid the warning.
|
||||
* Instead of performing template specializations in LLVM_INSTANTIATE_REGISTRY
|
||||
instead provide a template definition then do explicit instantiation. No
|
||||
compiler I've tried has problems with doing it the other way, but strictly
|
||||
speaking it's not permitted by the C++ standard so better safe than sorry.
|
||||
|
||||
Original commit message:
|
||||
|
||||
Currently the Registry class contains the vestiges of a previous attempt to
|
||||
allow plugins to be used on Windows without using BUILD_SHARED_LIBS, where a
|
||||
plugin would have its own copy of a registry and export it to be imported by
|
||||
the tool that's loading the plugin. This only works if the plugin is entirely
|
||||
self-contained with the only interface between the plugin and tool being the
|
||||
registry, and in particular this conflicts with how IR pass plugins work.
|
||||
|
||||
This patch changes things so that instead the add_node function of the registry
|
||||
is exported by the tool and then imported by the plugin, which solves this
|
||||
problem and also means that instead of every plugin having to export every
|
||||
registry they use instead LLVM only has to export the add_node functions. This
|
||||
allows plugins that use a registry to work on Windows if
|
||||
LLVM_EXPORT_SYMBOLS_FOR_PLUGINS is used.
|
||||
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@277806 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
|
||||
diff --git a/clang/examples/AnnotateFunctions/CMakeLists.txt b/clang/examples/AnnotateFunctions/CMakeLists.txt
|
||||
index cf564d527d..5684abf238 100644
|
||||
--- a/clang/examples/AnnotateFunctions/CMakeLists.txt
|
||||
+++ b/clang/examples/AnnotateFunctions/CMakeLists.txt
|
||||
@@ -1,4 +1,4 @@
|
||||
-add_llvm_loadable_module(AnnotateFunctions AnnotateFunctions.cpp)
|
||||
+add_llvm_loadable_module(AnnotateFunctions AnnotateFunctions.cpp PLUGIN_TOOL clang)
|
||||
|
||||
if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN))
|
||||
target_link_libraries(AnnotateFunctions PRIVATE
|
||||
diff --git a/clang/examples/PrintFunctionNames/CMakeLists.txt b/clang/examples/PrintFunctionNames/CMakeLists.txt
|
||||
index 5a00d5036f..f5f818866c 100644
|
||||
--- a/clang/examples/PrintFunctionNames/CMakeLists.txt
|
||||
+++ b/clang/examples/PrintFunctionNames/CMakeLists.txt
|
||||
@@ -9,7 +9,7 @@ if( NOT MSVC ) # MSVC mangles symbols differently, and
|
||||
endif()
|
||||
endif()
|
||||
|
||||
-add_llvm_loadable_module(PrintFunctionNames PrintFunctionNames.cpp)
|
||||
+add_llvm_loadable_module(PrintFunctionNames PrintFunctionNames.cpp PLUGIN_TOOL clang)
|
||||
|
||||
if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN))
|
||||
target_link_libraries(PrintFunctionNames PRIVATE
|
||||
diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h
|
||||
index ecab630c12..9d7ee08d95 100644
|
||||
--- a/clang/include/clang/Frontend/FrontendPluginRegistry.h
|
||||
+++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h
|
||||
@@ -13,9 +13,6 @@
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "llvm/Support/Registry.h"
|
||||
|
||||
-// Instantiated in FrontendAction.cpp.
|
||||
-extern template class llvm::Registry<clang::PluginASTAction>;
|
||||
-
|
||||
namespace clang {
|
||||
|
||||
/// The frontend plugin registry.
|
||||
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
|
||||
index c9b712504e..000df6647f 100644
|
||||
--- a/clang/include/clang/Lex/Preprocessor.h
|
||||
+++ b/clang/include/clang/Lex/Preprocessor.h
|
||||
@@ -1972,6 +1972,4 @@ typedef llvm::Registry<PragmaHandler> PragmaHandlerRegistry;
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
-extern template class llvm::Registry<clang::PragmaHandler>;
|
||||
-
|
||||
#endif
|
||||
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
|
||||
index d2c2a80394..2945b8925f 100644
|
||||
--- a/clang/lib/Frontend/FrontendAction.cpp
|
||||
+++ b/clang/lib/Frontend/FrontendAction.cpp
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <system_error>
|
||||
using namespace clang;
|
||||
|
||||
-template class llvm::Registry<clang::PluginASTAction>;
|
||||
+LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)
|
||||
|
||||
namespace {
|
||||
|
||||
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
|
||||
index 8832c7f80c..f0d6872546 100644
|
||||
--- a/clang/lib/Lex/Preprocessor.cpp
|
||||
+++ b/clang/lib/Lex/Preprocessor.cpp
|
||||
@@ -54,7 +54,7 @@
|
||||
#include <utility>
|
||||
using namespace clang;
|
||||
|
||||
-template class llvm::Registry<clang::PragmaHandler>;
|
||||
+LLVM_INSTANTIATE_REGISTRY(PragmaHandlerRegistry)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
|
||||
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
|
||||
index 8fc4a1fe5b..6f95bf01f6 100644
|
||||
--- a/clang/lib/Tooling/CompilationDatabase.cpp
|
||||
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
|
||||
@@ -32,6 +32,8 @@
|
||||
using namespace clang;
|
||||
using namespace tooling;
|
||||
|
||||
+LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
|
||||
+
|
||||
CompilationDatabase::~CompilationDatabase() {}
|
||||
|
||||
std::unique_ptr<CompilationDatabase>
|
64
build/build-clang/r285657.patch
Normal file
64
build/build-clang/r285657.patch
Normal file
@ -0,0 +1,64 @@
|
||||
commit 783f98e4a55266c40b6ecee9b41381353f37013b
|
||||
Author: Tim Shen <timshen91@gmail.com>
|
||||
Date: Tue Nov 1 00:19:04 2016 +0000
|
||||
|
||||
[ReachableCode] Skip over ExprWithCleanups in isConfigurationValue
|
||||
|
||||
Summary: Fixes pr29152.
|
||||
|
||||
Reviewers: rsmith, pirama, krememek
|
||||
|
||||
Subscribers: cfe-commits
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D24010
|
||||
|
||||
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285657 91177308-0d34-0410-b5e6-96231b3b80d8
|
||||
|
||||
diff --git a/clang/include/clang/AST/Stmt.h a/clang/include/clang/AST/Stmt.h
|
||||
index 9381a44985..e28675d6a8 100644
|
||||
--- a/clang/include/clang/AST/Stmt.h
|
||||
+++ a/clang/include/clang/AST/Stmt.h
|
||||
@@ -387,6 +387,9 @@ public:
|
||||
/// Skip past any implicit AST nodes which might surround this
|
||||
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
|
||||
Stmt *IgnoreImplicit();
|
||||
+ const Stmt *IgnoreImplicit() const {
|
||||
+ return const_cast<Stmt *>(this)->IgnoreImplicit();
|
||||
+ }
|
||||
|
||||
/// \brief Skip no-op (attributed, compound) container stmts and skip captured
|
||||
/// stmt at the top, if \a IgnoreCaptured is true.
|
||||
diff --git a/clang/lib/Analysis/ReachableCode.cpp a/clang/lib/Analysis/ReachableCode.cpp
|
||||
index 8165b09f40..69d000c03b 100644
|
||||
--- a/clang/lib/Analysis/ReachableCode.cpp
|
||||
+++ a/clang/lib/Analysis/ReachableCode.cpp
|
||||
@@ -164,6 +164,8 @@ static bool isConfigurationValue(const Stmt *S,
|
||||
if (!S)
|
||||
return false;
|
||||
|
||||
+ S = S->IgnoreImplicit();
|
||||
+
|
||||
if (const Expr *Ex = dyn_cast<Expr>(S))
|
||||
S = Ex->IgnoreCasts();
|
||||
|
||||
diff --git a/clang/test/SemaCXX/PR29152.cpp a/clang/test/SemaCXX/PR29152.cpp
|
||||
new file mode 100644
|
||||
index 0000000000..63c9c9bed5
|
||||
--- /dev/null
|
||||
+++ a/clang/test/SemaCXX/PR29152.cpp
|
||||
@@ -0,0 +1,15 @@
|
||||
+// RUN: %clang_cc1 -fsyntax-only -Wunreachable-code -verify %s
|
||||
+
|
||||
+static const bool False = false;
|
||||
+
|
||||
+struct A {
|
||||
+ ~A();
|
||||
+ operator bool();
|
||||
+};
|
||||
+void Bar();
|
||||
+
|
||||
+void Foo() {
|
||||
+ if (False && A()) {
|
||||
+ Bar(); // expected-no-diagnostics
|
||||
+ }
|
||||
+}
|
@ -212,6 +212,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
||||
[browser_rules_selector-highlighter_02.js]
|
||||
[browser_rules_selector-highlighter_03.js]
|
||||
[browser_rules_selector-highlighter_04.js]
|
||||
[browser_rules_selector-highlighter_05.js]
|
||||
[browser_rules_selector_highlight.js]
|
||||
[browser_rules_strict-search-filter-computed-list_01.js]
|
||||
[browser_rules_strict-search-filter_01.js]
|
||||
|
@ -22,6 +22,8 @@ add_task(function* () {
|
||||
|
||||
let testActor = yield getTestActorWithoutToolbox(tab);
|
||||
let inspector = yield clickOnInspectMenuItem(testActor, "span");
|
||||
yield getRuleViewSelectorHighlighterIcon(inspector.ruleview.view,
|
||||
"element", 3);
|
||||
|
||||
checkRuleViewContent(inspector.ruleview.view);
|
||||
});
|
||||
@ -57,4 +59,3 @@ function checkRuleViewContent({styleDocument}) {
|
||||
is(propertyValues.length, 1, "There's only one property value, as expected");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ function* testSelectorHighlight(view, name) {
|
||||
info("Test creating selector highlighter");
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, name);
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, name);
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
@ -18,6 +18,7 @@ add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#test1", inspector);
|
||||
yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
|
||||
yield elementStyleInherit(inspector, view);
|
||||
});
|
||||
|
||||
|
@ -20,6 +20,7 @@ add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("a", inspector);
|
||||
yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
|
||||
yield elementStyleInherit(inspector, view);
|
||||
});
|
||||
|
||||
|
@ -23,7 +23,7 @@ add_task(function* () {
|
||||
let highlighters = view.highlighters;
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
@ -24,7 +24,7 @@ add_task(function* () {
|
||||
"No selectorhighlighter exist in the rule-view");
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
@ -46,7 +46,7 @@ add_task(function* () {
|
||||
// Inject the mock highlighter in the rule-view
|
||||
view.selectorHighlighter = HighlighterFront;
|
||||
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
|
||||
info("Checking that the HighlighterFront's show/hide methods are called");
|
||||
|
||||
@ -60,7 +60,7 @@ add_task(function* () {
|
||||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("p", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "p");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "p");
|
||||
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "P",
|
||||
@ -69,7 +69,7 @@ add_task(function* () {
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "BODY",
|
||||
"The right NodeFront is passed to the highlighter (2)");
|
||||
|
@ -39,7 +39,7 @@ add_task(function* () {
|
||||
|
||||
info("Select .node-1 and click on the .node-1 selector icon");
|
||||
yield selectNode(".node-1", inspector);
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown");
|
||||
|
||||
@ -48,12 +48,12 @@ add_task(function* () {
|
||||
ok(!HighlighterFront.isShown, "The highlighter is now hidden");
|
||||
|
||||
info("With .node-1 still selected, click on the div selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown again");
|
||||
|
||||
info("With .node-1 still selected, click again on the .node-1 selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown,
|
||||
"The highlighter is shown again since the clicked selector was different");
|
||||
@ -64,14 +64,14 @@ add_task(function* () {
|
||||
"The highlighter is still shown after selection");
|
||||
|
||||
info("With .node-2 selected, click on the div selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown,
|
||||
"The highlighter is shown still since the selected was different");
|
||||
|
||||
info("Switching back to .node-1 and clicking on the div selector");
|
||||
yield selectNode(".node-1", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(!HighlighterFront.isShown,
|
||||
"The highlighter is hidden now that the same selector was clicked");
|
||||
|
@ -39,7 +39,7 @@ add_task(function* () {
|
||||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("p", inspector);
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "P",
|
||||
|
@ -0,0 +1,64 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the selector highlighter is correctly shown when clicking on a
|
||||
// inherited element
|
||||
|
||||
// Note that in this test, we mock the highlighter front, merely testing the
|
||||
// behavior of the style-inspector UI for now
|
||||
|
||||
const TEST_URI = `
|
||||
<div style="cursor:pointer">
|
||||
A
|
||||
<div style="cursor:pointer">
|
||||
B<a>Cursor</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
|
||||
// Mock the highlighter front to get the reference of the NodeFront
|
||||
let HighlighterFront = {
|
||||
isShown: false,
|
||||
nodeFront: null,
|
||||
options: null,
|
||||
show: function (nodeFront, options) {
|
||||
this.nodeFront = nodeFront;
|
||||
this.options = options;
|
||||
this.isShown = true;
|
||||
},
|
||||
hide: function () {
|
||||
this.nodeFront = null;
|
||||
this.options = null;
|
||||
this.isShown = false;
|
||||
}
|
||||
};
|
||||
// Inject the mock highlighter in the rule-view
|
||||
view.selectorHighlighter = HighlighterFront;
|
||||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("a", inspector);
|
||||
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector,
|
||||
"body > div:nth-child(1) > div:nth-child(1) > a:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector,
|
||||
"body > div:nth-child(1) > div:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector, "body > div:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
});
|
@ -44,76 +44,6 @@ addTab = function (url) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
name: propName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element's inline style property value.
|
||||
* @param {TestActor} testActor
|
||||
@ -129,49 +59,6 @@ function getStyle(testActor, selector, propName) {
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* When a tooltip is closed, this ends up "commiting" the value changed within
|
||||
* the tooltip (e.g. the color in case of a colorpicker) which, in turn, ends up
|
||||
@ -219,109 +106,6 @@ var waitForSuccess = Task.async(function* (validatorFn, desc = "untitled") {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText) {
|
||||
let rule;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a color change in a given color picker tooltip, and optionally wait
|
||||
* for a given element in the page to have its style changed as a result.
|
||||
@ -452,34 +236,6 @@ var openCubicBezierAndChangeCoords = Task.async(function* (view, ruleIndex,
|
||||
return {propEditor, swatch, bezierTooltip};
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate adding a new property in an existing rule in the rule-view.
|
||||
*
|
||||
@ -625,74 +381,6 @@ var togglePropStatus = Task.async(function* (view, textProp) {
|
||||
yield onRuleViewRefreshed;
|
||||
});
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
|
||||
// Use bottom alignment to avoid scrolling out of the parent element area.
|
||||
ruleEditor.closeBrace.scrollIntoView(false);
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
let win = view.styleWindow;
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
synthesizeKeys(searchValue, win);
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/**
|
||||
* Reload the current page and wait for the inspector to be initialized after
|
||||
* the navigation
|
||||
@ -778,26 +466,6 @@ function* sendKeysAndWaitForFocus(view, element, keys) {
|
||||
yield onFocus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a markupmutation event on the inspector that is for a style modification.
|
||||
* @param {InspectorPanel} inspector
|
||||
|
@ -149,19 +149,34 @@ RuleEditor.prototype = {
|
||||
}
|
||||
|
||||
if (this.rule.domRule.type !== CSSRule.KEYFRAME_RULE) {
|
||||
let selector = this.rule.domRule.selectors
|
||||
? this.rule.domRule.selectors.join(", ")
|
||||
: this.ruleView.inspector.selectionCssSelector;
|
||||
Task.spawn(function* () {
|
||||
let selector;
|
||||
|
||||
let selectorHighlighter = createChild(header, "span", {
|
||||
class: "ruleview-selectorhighlighter" +
|
||||
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
|
||||
" highlighted" : ""),
|
||||
title: l10n("rule.selectorHighlighter.tooltip")
|
||||
});
|
||||
selectorHighlighter.addEventListener("click", () => {
|
||||
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
|
||||
});
|
||||
if (this.rule.domRule.selectors) {
|
||||
// This is a "normal" rule with a selector.
|
||||
selector = this.rule.domRule.selectors.join(", ");
|
||||
} else if (this.rule.inherited) {
|
||||
// This is an inline style from an inherited rule. Need to resolve the unique
|
||||
// selector from the node which rule this is inherited from.
|
||||
selector = yield this.rule.inherited.getUniqueSelector();
|
||||
} else {
|
||||
// This is an inline style from the current node.
|
||||
selector = this.ruleView.inspector.selectionCssSelector;
|
||||
}
|
||||
|
||||
let selectorHighlighter = createChild(header, "span", {
|
||||
class: "ruleview-selectorhighlighter" +
|
||||
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
|
||||
" highlighted" : ""),
|
||||
title: l10n("rule.selectorHighlighter.tooltip")
|
||||
});
|
||||
selectorHighlighter.addEventListener("click", () => {
|
||||
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
|
||||
});
|
||||
|
||||
this.uniqueSelector = selector;
|
||||
this.emit("selector-icon-created");
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.openBrace = createChild(header, "span", {
|
||||
|
@ -88,123 +88,6 @@ addTab = function (url) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
let data = {
|
||||
selector,
|
||||
pseudo,
|
||||
name: propName
|
||||
};
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
let data = {
|
||||
selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name
|
||||
};
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* Polls a given function waiting for it to return true.
|
||||
*
|
||||
@ -258,109 +141,6 @@ var getFontFamilyDataURL = Task.async(function* (font, nodeFront) {
|
||||
* This object contains functions to get rules, get properties, ...
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText) {
|
||||
let rule;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a color change in a given color picker tooltip, and optionally wait
|
||||
* for a given element in the page to have its style changed as a result
|
||||
@ -400,100 +180,6 @@ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker,
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
ruleEditor.closeBrace.scrollIntoView();
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
let win = view.styleWindow;
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
synthesizeKeys(searchValue, win);
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/* *********************************************
|
||||
* COMPUTED-VIEW
|
||||
* *********************************************
|
||||
@ -539,23 +225,3 @@ function getComputedViewPropertyValue(view, name, propertyName) {
|
||||
return getComputedViewProperty(view, name, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* globals registerTestActor, getTestActor, Task, openToolboxForTab, gBrowser */
|
||||
/* import-globals-from ../../framework/test/shared-head.js */
|
||||
|
||||
var {getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
|
||||
|
||||
// This file contains functions related to the inspector that are also of interest to
|
||||
// other test directores as well.
|
||||
@ -184,3 +187,356 @@ function manualThrottle() {
|
||||
|
||||
return throttle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
name: propName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @param {Number} index
|
||||
* If there are more than 1 rule with the same selector, you may pass a
|
||||
* index to determine which of the rules you want.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText, index = 0) {
|
||||
let rule;
|
||||
let pos = 0;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
if (index == pos) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @param {Number} index
|
||||
* If there are more than 1 rule with the same selector, use this index
|
||||
* to determine which one should be retrieved. Defaults to 0
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
var getRuleViewSelectorHighlighterIcon = Task.async(function* (view,
|
||||
selectorText, index = 0) {
|
||||
let rule = getRuleViewRule(view, selectorText, index);
|
||||
|
||||
let editor = rule._ruleEditor;
|
||||
if (!editor.uniqueSelector) {
|
||||
yield once(editor, "selector-icon-created");
|
||||
}
|
||||
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
|
||||
// Use bottom alignment to avoid scrolling out of the parent element area.
|
||||
ruleEditor.closeBrace.scrollIntoView(false);
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
|
||||
for (let key of searchValue.split("")) {
|
||||
EventUtils.synthesizeKey(key, {}, view.styleWindow);
|
||||
}
|
||||
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ const PropertiesView = createClass({
|
||||
// 2. the `value` object has a `value` property, only happend in Cookies panel
|
||||
// Put 2 here to not dup this method
|
||||
if (member.level === 0 ||
|
||||
(typeof member.value === "object" && member.value.value)) {
|
||||
(typeof member.value === "object" && member.value && member.value.value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ support-files =
|
||||
html_filter-test-page.html
|
||||
html_infinite-get-page.html
|
||||
html_json-b64.html
|
||||
html_json-basic.html
|
||||
html_json-custom-mime-test-page.html
|
||||
html_json-long-test-page.html
|
||||
html_json-malformed-test-page.html
|
||||
@ -41,6 +42,7 @@ support-files =
|
||||
sjs_cors-test-server.sjs
|
||||
sjs_https-redirect-test-server.sjs
|
||||
sjs_hsts-test-server.sjs
|
||||
sjs_json-test-server.sjs
|
||||
sjs_simple-test-server.sjs
|
||||
sjs_sorting-test-server.sjs
|
||||
sjs_status-codes-test-server.sjs
|
||||
@ -107,6 +109,7 @@ skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439
|
||||
[browser_net_icon-preview.js]
|
||||
[browser_net_image-tooltip.js]
|
||||
[browser_net_json-b64.js]
|
||||
[browser_net_json-null.js]
|
||||
[browser_net_json-long.js]
|
||||
[browser_net_json-malformed.js]
|
||||
[browser_net_json_custom_mime.js]
|
||||
|
78
devtools/client/netmonitor/test/browser_net_json-null.js
Normal file
78
devtools/client/netmonitor/test/browser_net_json-null.js
Normal file
@ -0,0 +1,78 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { L10N } = require("devtools/client/netmonitor/l10n");
|
||||
|
||||
/**
|
||||
* Tests if JSON responses containing null values are properly displayed.
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
let { tab, monitor } = yield initNetMonitor(JSON_BASIC_URL + "?name=null");
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
let wait = waitForNetworkEvents(monitor, 1);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
|
||||
content.wrappedJSObject.performRequests();
|
||||
});
|
||||
yield wait;
|
||||
|
||||
yield openResponsePanel(document);
|
||||
checkResponsePanelDisplaysJSON(document);
|
||||
|
||||
let tabpanel = document.querySelector("#response-panel");
|
||||
is(tabpanel.querySelectorAll(".tree-section").length, 1,
|
||||
"There should be 1 tree sections displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
|
||||
"There should be 1 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".empty-notice").length, 0,
|
||||
"The empty notice should not be displayed in this tabpanel.");
|
||||
|
||||
let labels = tabpanel
|
||||
.querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
|
||||
let values = tabpanel
|
||||
.querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
|
||||
|
||||
is(labels[0].textContent, "greeting", "The first json property name was incorrect.");
|
||||
is(values[0].textContent, "null", "The first json property value was incorrect.");
|
||||
|
||||
yield teardown(monitor);
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper to assert that the response panel found in the provided document is currently
|
||||
* showing a preview of a JSON object.
|
||||
*/
|
||||
function checkResponsePanelDisplaysJSON(doc) {
|
||||
let tabpanel = doc.querySelector("#response-panel");
|
||||
is(tabpanel.querySelector(".response-error-header") === null, true,
|
||||
"The response error header doesn't have the intended visibility.");
|
||||
let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
|
||||
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
|
||||
"The response json view has the intended visibility.");
|
||||
is(tabpanel.querySelector(".editor-mount iframe") === null, true,
|
||||
"The response editor doesn't have the intended visibility.");
|
||||
is(tabpanel.querySelector(".response-image-box") === null, true,
|
||||
"The response image box doesn't have the intended visibility.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the netmonitor details panel and switch to the response tab.
|
||||
* Returns a promise that will resolve when the response panel DOM element is available.
|
||||
*/
|
||||
function openResponsePanel(doc) {
|
||||
let onReponsePanelReady = waitForDOM(doc, "#response-panel");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "mousedown" },
|
||||
doc.getElementById("details-pane-toggle")
|
||||
);
|
||||
doc.querySelector("#response-tab").click();
|
||||
return onReponsePanelReady;
|
||||
}
|
@ -40,6 +40,7 @@ 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 JSON_B64_URL = EXAMPLE_URL + "html_json-b64.html";
|
||||
const JSON_BASIC_URL = EXAMPLE_URL + "html_json-basic.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";
|
||||
|
40
devtools/client/netmonitor/test/html_json-basic.html
Normal file
40
devtools/client/netmonitor/test/html_json-basic.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>JSON request test page</p>
|
||||
<p>Pass the JSON name (as supported by sjs_json-test-server.sjs) as a query parameter</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() {
|
||||
// Forward the query parameter for this page to sjs_json-test-server
|
||||
get("sjs_json-test-server.sjs" + window.location.search, function() {
|
||||
// Done.
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
22
devtools/client/netmonitor/test/sjs_json-test-server.sjs
Normal file
22
devtools/client/netmonitor/test/sjs_json-test-server.sjs
Normal file
@ -0,0 +1,22 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
response.setHeader("Content-Type", "application/json; charset=utf-8", false);
|
||||
|
||||
// This server checks the name parameter from the request to decide which JSON object to
|
||||
// return.
|
||||
let params = request.queryString.split("&");
|
||||
let name = (params.filter((s) => s.includes("name="))[0] || "").split("=")[1];
|
||||
switch (name) {
|
||||
case "null":
|
||||
response.write("{ \"greeting\": null }");
|
||||
break;
|
||||
}
|
||||
}
|
@ -366,8 +366,8 @@
|
||||
.ruleview-swatch {
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
width: 0.9em;
|
||||
height: 0.9em;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
/* align the swatch with its value */
|
||||
margin-top: -1px;
|
||||
|
@ -3594,9 +3594,8 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
|
||||
// it. So we get the firstPartyDomain from the nodePrincipal of the document
|
||||
// before we compare the originAttributes.
|
||||
if (OriginAttributes::IsFirstPartyEnabled()) {
|
||||
if (accessingDS == accessingRootDS &&
|
||||
aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
|
||||
!accessingDS->GetIsMozBrowser()) {
|
||||
if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
|
||||
(accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) {
|
||||
|
||||
nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
|
||||
|
||||
@ -3608,9 +3607,8 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
|
||||
}
|
||||
}
|
||||
|
||||
if (targetDS == targetRootDS &&
|
||||
aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
|
||||
!targetDS->GetIsMozBrowser()) {
|
||||
if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
|
||||
(targetDS == targetRootDS || targetDS->GetIsMozBrowser())) {
|
||||
|
||||
nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
|
||||
|
||||
@ -7942,7 +7940,9 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
||||
}
|
||||
} else if (url && NS_SUCCEEDED(aStatus)) {
|
||||
// If we have a host
|
||||
mozilla::net::PredictorLearnRedirect(url, aChannel, this);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
||||
mozilla::net::PredictorLearnRedirect(url, aChannel,
|
||||
loadInfo->GetOriginAttributes());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -9873,6 +9873,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
nsIContentPolicy::TYPE_INTERNAL_IFRAME : nsIContentPolicy::TYPE_INTERNAL_FRAME;
|
||||
} else {
|
||||
contentType = nsIContentPolicy::TYPE_DOCUMENT;
|
||||
isTargetTopLevelDocShell = true;
|
||||
}
|
||||
|
||||
// If there's no targetDocShell, that means we are about to create a new window,
|
||||
@ -10728,10 +10729,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
srcdoc = NullString();
|
||||
}
|
||||
|
||||
OriginAttributes attrs;
|
||||
bool isTopLevelDoc = mItemType == typeContent &&
|
||||
(isTargetTopLevelDocShell ||
|
||||
GetIsMozBrowser());
|
||||
attrs.Inherit(GetOriginAttributes());
|
||||
attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
|
||||
|
||||
net::PredictorLearn(aURI, nullptr,
|
||||
nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, this);
|
||||
nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
|
||||
net::PredictorPredict(aURI, nullptr,
|
||||
nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
|
||||
nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
|
||||
|
||||
nsCOMPtr<nsIRequest> req;
|
||||
rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer,
|
||||
@ -10963,9 +10971,9 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
// We have to do this in case our OriginAttributes are different from the
|
||||
// OriginAttributes of the parent document. Or in case there isn't a
|
||||
// parent document.
|
||||
bool isTopLevelDoc = aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT &&
|
||||
mItemType == typeContent &&
|
||||
!GetIsMozBrowser();
|
||||
bool isTopLevelDoc = mItemType == typeContent &&
|
||||
(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
|
||||
GetIsMozBrowser());
|
||||
|
||||
OriginAttributes attrs;
|
||||
attrs.Inherit(GetOriginAttributes());
|
||||
@ -14193,9 +14201,12 @@ nsDocShell::OnOverLink(nsIContent* aContent,
|
||||
rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OriginAttributes attrs;
|
||||
attrs.Inherit(aContent->NodePrincipal()->OriginAttributesRef());
|
||||
|
||||
mozilla::net::PredictorPredict(aURI, mCurrentURI,
|
||||
nsINetworkPredictor::PREDICT_LINK,
|
||||
this, nullptr);
|
||||
attrs, nullptr);
|
||||
|
||||
if (browserChrome2) {
|
||||
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
|
||||
|
@ -28,6 +28,7 @@ using namespace mozilla::dom;
|
||||
|
||||
DOMParser::DOMParser()
|
||||
: mAttemptedInit(false)
|
||||
, mOriginalPrincipalWasSystem(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -92,18 +93,12 @@ DOMParser::ParseFromString(const nsAString& str,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
|
||||
|
||||
// Keep the XULXBL state, base URL and principal setting in sync with the
|
||||
// XML case
|
||||
// Keep the XULXBL state in sync with the XML case.
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
|
||||
if (mOriginalPrincipalWasSystem) {
|
||||
document->ForceEnableXULXBL();
|
||||
}
|
||||
|
||||
// Make sure to give this document the right base URI
|
||||
document->SetBaseURI(mBaseURI);
|
||||
// And the right principal
|
||||
document->SetPrincipal(mPrincipal);
|
||||
|
||||
rv = nsContentUtils::ParseDocumentHTML(str, document, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -245,7 +240,7 @@ DOMParser::ParseFromStream(nsIInputStream *stream,
|
||||
NS_NewInputStreamChannel(getter_AddRefs(parserChannel),
|
||||
mDocumentURI,
|
||||
nullptr, // aStream
|
||||
mOriginalPrincipal,
|
||||
mPrincipal,
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nsDependentCString(contentType));
|
||||
@ -260,15 +255,13 @@ DOMParser::ParseFromStream(nsIInputStream *stream,
|
||||
|
||||
// Have to pass false for reset here, else the reset will remove
|
||||
// our event listener. Should that listener addition move to later
|
||||
// than this call? Then we wouldn't need to mess around with
|
||||
// SetPrincipal, etc, probably!
|
||||
// than this call?
|
||||
nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
|
||||
if (!document) return NS_ERROR_FAILURE;
|
||||
|
||||
// Keep the XULXBL state, base URL and principal setting in sync with the
|
||||
// HTML case
|
||||
// Keep the XULXBL state in sync with the HTML case
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
|
||||
if (mOriginalPrincipalWasSystem) {
|
||||
document->ForceEnableXULXBL();
|
||||
}
|
||||
|
||||
@ -277,12 +270,6 @@ DOMParser::ParseFromStream(nsIInputStream *stream,
|
||||
getter_AddRefs(listener),
|
||||
false);
|
||||
|
||||
// Make sure to give this document the right base URI
|
||||
document->SetBaseURI(mBaseURI);
|
||||
|
||||
// And the right principal
|
||||
document->SetPrincipal(mPrincipal);
|
||||
|
||||
if (NS_FAILED(rv) || !listener) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -353,12 +340,11 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
|
||||
OriginAttributes attrs;
|
||||
mPrincipal = BasePrincipal::CreateCodebasePrincipal(mDocumentURI, attrs);
|
||||
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
|
||||
mOriginalPrincipal = mPrincipal;
|
||||
} else {
|
||||
mOriginalPrincipal = mPrincipal;
|
||||
if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
|
||||
// Don't give DOMParsers the system principal. Use a null
|
||||
// principal instead.
|
||||
mOriginalPrincipalWasSystem = true;
|
||||
mPrincipal = nsNullPrincipal::Create();
|
||||
|
||||
if (!mDocumentURI) {
|
||||
@ -367,14 +353,10 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mBaseURI = baseURI;
|
||||
// Note: if mBaseURI is null, fine. Leave it like that; that will use the
|
||||
// documentURI as the base. Otherwise for null principals we'll get
|
||||
// nsDocument::SetBaseURI giving errors.
|
||||
|
||||
NS_POSTCONDITION(mPrincipal, "Must have principal");
|
||||
NS_POSTCONDITION(mOriginalPrincipal, "Must have original principal");
|
||||
NS_POSTCONDITION(mDocumentURI, "Must have document URI");
|
||||
return NS_OK;
|
||||
}
|
||||
@ -482,13 +464,9 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
|
||||
NS_ASSERTION(mPrincipal, "Must have principal by now");
|
||||
NS_ASSERTION(mDocumentURI, "Must have document URI by now");
|
||||
|
||||
// Here we have to cheat a little bit... Setting the base URI won't
|
||||
// work if the document has a null principal, so use
|
||||
// mOriginalPrincipal when creating the document, then reset the
|
||||
// principal.
|
||||
return NS_NewDOMDocument(aResult, EmptyString(), EmptyString(), nullptr,
|
||||
mDocumentURI, mBaseURI,
|
||||
mOriginalPrincipal,
|
||||
mPrincipal,
|
||||
true,
|
||||
scriptHandlingObject,
|
||||
aFlavor);
|
||||
|
@ -112,12 +112,12 @@ private:
|
||||
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mOriginalPrincipal;
|
||||
nsCOMPtr<nsIURI> mDocumentURI;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
nsWeakPtr mScriptHandlingObject;
|
||||
|
||||
|
||||
bool mAttemptedInit;
|
||||
bool mOriginalPrincipalWasSystem;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -17,31 +15,19 @@ namespace dom {
|
||||
/* static */ nsresult
|
||||
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
|
||||
{
|
||||
aKey.Truncate();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK; // aKey is the empty string
|
||||
}
|
||||
|
||||
// GetBaseDomain works fine if |uri| is null, but it outputs a warning
|
||||
// which ends up cluttering the logs.
|
||||
if (!uri) {
|
||||
return NS_OK; // aKey is the empty string
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (!tldService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = tldService->GetBaseDomain(uri, 0, aKey);
|
||||
// Use GetBaseDomain() to handle things like file URIs, IP address URIs,
|
||||
// etc. correctly.
|
||||
nsresult rv = aPrincipal->GetBaseDomain(aKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
// We don't really know what to do here. But we should be conservative,
|
||||
// otherwise it would be possible to reorder two events incorrectly in the
|
||||
// future if we interrupt at the DocGroup level, so to be safe, use an
|
||||
// empty string to classify all such documents as belonging to the same
|
||||
// DocGroup.
|
||||
aKey.Truncate();
|
||||
}
|
||||
|
||||
return NS_OK; // aKey may be the empty string
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9858,3 +9858,33 @@ nsContentUtils::GetContentPolicyTypeForUIImageLoading(nsIContent* aLoadingNode,
|
||||
}
|
||||
loadingPrincipal.forget(aLoadingPrincipal);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx,
|
||||
const Sequence<JSObject*>& aTransfer,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
if (aTransfer.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aTransfer.Length()));
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aTransfer.Length(); ++i) {
|
||||
JS::Rooted<JSObject*> object(aCx, aTransfer[i]);
|
||||
if (!object) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!JS_DefineElement(aCx, array, i, object,
|
||||
JSPROP_ENUMERATE))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
aValue.setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2746,6 +2746,11 @@ public:
|
||||
nsIPrincipal** aLoadingPrincipal,
|
||||
nsContentPolicyType& aContentPolicyType);
|
||||
|
||||
static nsresult
|
||||
CreateJSValueFromSequenceOfObject(JSContext* aCx,
|
||||
const mozilla::dom::Sequence<JSObject*>& aTransfer,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
@ -2127,15 +2127,7 @@ nsFocusManager::SendFocusOrBlurEvent(EventMessage aEventMessage,
|
||||
bool dontDispatchEvent =
|
||||
eventTargetDoc && nsContentUtils::IsUserFocusIgnored(eventTargetDoc);
|
||||
|
||||
// for focus events, if this event was from a mouse or key and event
|
||||
// handling on the document is suppressed, queue the event and fire it
|
||||
// later. For blur events, a non-zero value would be set for aFocusMethod.
|
||||
if (aFocusMethod && !dontDispatchEvent &&
|
||||
aDocument && aDocument->EventHandlingSuppressed()) {
|
||||
// aFlags is always 0 when aWindowRaised is true so this won't be called
|
||||
// on a window raise.
|
||||
NS_ASSERTION(!aWindowRaised, "aWindowRaised should not be set");
|
||||
|
||||
if (!dontDispatchEvent && aDocument && aDocument->EventHandlingSuppressed()) {
|
||||
for (uint32_t i = mDelayedBlurFocusEvents.Length(); i > 0; --i) {
|
||||
// if this event was already queued, remove it and append it to the end
|
||||
if (mDelayedBlurFocusEvents[i - 1].mEventMessage == aEventMessage &&
|
||||
|
@ -8846,28 +8846,20 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
void
|
||||
nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const nsAString& aTargetOrigin,
|
||||
const Optional<Sequence<JS::Value>>& aTransfer,
|
||||
const Sequence<JSObject*>& aTransfer,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aError)
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
|
||||
if (aTransfer.WasPassed()) {
|
||||
const Sequence<JS::Value >& values = aTransfer.Value();
|
||||
|
||||
// The input sequence only comes from the generated bindings code, which
|
||||
// ensures it is rooted.
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements());
|
||||
|
||||
transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements));
|
||||
if (transferArray.isNull()) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
|
||||
&transferArray);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray,
|
||||
aSubjectPrincipal, aError);
|
||||
aSubjectPrincipal, aRv);
|
||||
}
|
||||
|
||||
class nsCloseEvent : public Runnable {
|
||||
@ -9205,7 +9197,7 @@ nsGlobalWindow::EnterModalState()
|
||||
|
||||
topWin->mSuspendedDoc = topDoc;
|
||||
if (topDoc) {
|
||||
topDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
|
||||
topDoc->SuppressEventHandling(nsIDocument::eEvents);
|
||||
}
|
||||
|
||||
nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
|
||||
@ -9242,7 +9234,7 @@ nsGlobalWindow::LeaveModalState()
|
||||
|
||||
if (topWin->mSuspendedDoc) {
|
||||
nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
|
||||
topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
|
||||
topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
|
||||
currentDoc == topWin->mSuspendedDoc);
|
||||
topWin->mSuspendedDoc = nullptr;
|
||||
}
|
||||
|
@ -982,7 +982,7 @@ public:
|
||||
mozilla::ErrorResult& aError);
|
||||
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const nsAString& aTargetOrigin,
|
||||
const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer,
|
||||
const mozilla::dom::Sequence<JSObject*>& aTransfer,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aError);
|
||||
int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
|
||||
|
@ -1284,9 +1284,11 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest)
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(docshell));
|
||||
OriginAttributes attrs;
|
||||
attrs.Inherit(mDocument->NodePrincipal()->OriginAttributesRef());
|
||||
|
||||
mozilla::net::PredictorLearn(aRequest->mURI, mDocument->GetDocumentURI(),
|
||||
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, loadContext);
|
||||
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, attrs);
|
||||
|
||||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
|
||||
|
@ -51,11 +51,6 @@ ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
|
||||
NS_IMETHODIMP
|
||||
ErrorCallbackRunnable::Run()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
|
||||
if (NS_WARN_IF(!window)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<DOMException> exception = DOMException::Create(mError);
|
||||
mCallback->HandleEvent(*exception);
|
||||
return NS_OK;
|
||||
|
@ -18,6 +18,7 @@ support-files =
|
||||
small-shot-mono-expected.wav
|
||||
small-shot.ogg
|
||||
small-shot.mp3
|
||||
sweep-300-330-1sec.opus
|
||||
ting-44.1k-1ch.ogg
|
||||
ting-44.1k-2ch.ogg
|
||||
ting-48k-1ch.ogg
|
||||
@ -114,6 +115,7 @@ skip-if = (android_version == '18' && debug) # bug 1158417
|
||||
[test_decodeAudioDataOnDetachedBuffer.html]
|
||||
[test_decodeAudioDataPromise.html]
|
||||
[test_decodeMultichannel.html]
|
||||
[test_decodeOpusTail.html]
|
||||
[test_delayNode.html]
|
||||
[test_delayNodeAtMax.html]
|
||||
[test_delayNodeChannelChanges.html]
|
||||
|
BIN
dom/media/webaudio/test/sweep-300-330-1sec.opus
Normal file
BIN
dom/media/webaudio/test/sweep-300-330-1sec.opus
Normal file
Binary file not shown.
28
dom/media/webaudio/test/test_decodeOpusTail.html
Normal file
28
dom/media/webaudio/test/test_decodeOpusTail.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<title>Regression test to check that opus files don't have a tail at the end.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// This gets a 1 second Opus file and decodes it to a buffer. The opus file is
|
||||
// decoded at 48kHz, and the OfflineAudioContext is also at 48kHz, no resampling
|
||||
// is taking place.
|
||||
fetch('sweep-300-330-1sec.opus')
|
||||
.then(function(response) { return response.arrayBuffer(); })
|
||||
.then(function(buffer) {
|
||||
var off = new OfflineAudioContext(1, 128, 48000);
|
||||
off.decodeAudioData(buffer, function(decoded) {
|
||||
var pcm = decoded.getChannelData(0);
|
||||
is(pcm.length, 48000, "The length of the decoded file is correct.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
@ -393,49 +393,34 @@ MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
|
||||
void
|
||||
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// We *must* clone the data here, or the JS::Value could be modified
|
||||
// by script
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
|
||||
// Here we want to check if the transerable object list contains
|
||||
// this port. No other checks are done.
|
||||
for (const JS::Value& value : realTransferable) {
|
||||
if (!value.isObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MessagePort* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (port == this) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
// Here we want to check if the transerable object list contains
|
||||
// this port.
|
||||
for (uint32_t i = 0; i < aTransferable.Length(); ++i) {
|
||||
JSObject* object = aTransferable[i];
|
||||
if (!object) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The input sequence only comes from the generated bindings code, which
|
||||
// ensures it is rooted.
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
||||
realTransferable.Elements());
|
||||
|
||||
JSObject* array =
|
||||
JS_NewArrayObject(aCx, elements);
|
||||
if (!array) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
MessagePort* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, object, port);
|
||||
if (NS_SUCCEEDED(rv) && port == this) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
transferable.setObject(*array);
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
|
||||
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
|
||||
&transferable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Start();
|
||||
|
@ -28,6 +28,9 @@ skip-if = !e10s
|
||||
[browser_bug1238427.js]
|
||||
[browser_bug1316330.js]
|
||||
skip-if = !e10s
|
||||
[browser_cancel_keydown_keypress_event.js]
|
||||
support-files =
|
||||
prevent_return_key.html
|
||||
[browser_ConsoleAPI_originAttributes.js]
|
||||
[browser_ConsoleAPITests.js]
|
||||
skip-if = e10s
|
||||
@ -42,6 +45,9 @@ skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires
|
||||
skip-if = !e10s || (os == "win" && processor == "x86") # Large-Allocation requires e10s
|
||||
[browser_localStorage_privatestorageevent.js]
|
||||
[browser_test__content.js]
|
||||
[browser_test_focus_after_modal_state.js]
|
||||
support-files =
|
||||
focus_after_prompt.html
|
||||
[browser_test_new_window_from_content.js]
|
||||
tags = openwindow
|
||||
skip-if = toolkit == 'android' || (os == "linux" && debug) # see bug 1261495 for Linux debug time outs
|
||||
|
69
dom/tests/browser/browser_test_focus_after_modal_state.js
Normal file
69
dom/tests/browser/browser_test_focus_after_modal_state.js
Normal file
@ -0,0 +1,69 @@
|
||||
const TEST_URL =
|
||||
"https://example.com/browser/dom/tests/browser/focus_after_prompt.html";
|
||||
|
||||
function awaitAndClosePrompt() {
|
||||
return new Promise(resolve => {
|
||||
function onDialogShown(node) {
|
||||
Services.obs.removeObserver(onDialogShown, "tabmodal-dialog-loaded");
|
||||
let button = node.ui.button0;
|
||||
button.click();
|
||||
resolve();
|
||||
}
|
||||
Services.obs.addObserver(onDialogShown, "tabmodal-dialog-loaded");
|
||||
});
|
||||
}
|
||||
|
||||
let lastMessageReceived = "";
|
||||
function waitForMessage(message) {
|
||||
return new Promise((resolve, reject) => {
|
||||
messageManager.addMessageListener(message, function() {
|
||||
ok(true, "Received message: " + message);
|
||||
lastMessageReceived = message;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Focus on editable iframe.
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#edit", {}, browser);
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
is(content.document.activeElement, content.document.getElementById("edit"),
|
||||
"Focus should be on iframe element");
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.document.getElementById("edit").contentDocument.addEventListener(
|
||||
"focus", function(event) {
|
||||
sendAsyncMessage("Test:FocusReceived");
|
||||
});
|
||||
|
||||
content.document.getElementById("edit").contentDocument.addEventListener(
|
||||
"blur", function(event) {
|
||||
sendAsyncMessage("Test:BlurReceived");
|
||||
});
|
||||
});
|
||||
|
||||
// Click on div that triggers a prompt, and then check that focus is back on
|
||||
// the editable iframe.
|
||||
let dialogShown = awaitAndClosePrompt();
|
||||
let waitForBlur = waitForMessage("Test:BlurReceived");
|
||||
let waitForFocus = waitForMessage("Test:FocusReceived");
|
||||
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
|
||||
let div = content.document.getElementById("clickMeDiv");
|
||||
div.click();
|
||||
});
|
||||
yield dialogShown;
|
||||
yield Promise.all([waitForBlur, waitForFocus]);
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
is(content.document.activeElement, content.document.getElementById("edit"),
|
||||
"Focus should be back on iframe element");
|
||||
});
|
||||
is(lastMessageReceived, "Test:FocusReceived",
|
||||
"Should receive blur and then focus event");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
18
dom/tests/browser/focus_after_prompt.html
Normal file
18
dom/tests/browser/focus_after_prompt.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Cursor should not be lost after prompt</title>
|
||||
<script type="application/javascript">
|
||||
function init() {
|
||||
document.getElementById("edit").contentWindow.document.designMode = "on";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="init()">
|
||||
<div id="clickMeDiv" onclick="prompt('This is a dummy prompt!');"
|
||||
onmousedown="return false;">Click me!</div>
|
||||
<iframe id="edit"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -15,7 +15,7 @@ interface Client {
|
||||
readonly attribute DOMString id;
|
||||
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<Transferable> transfer);
|
||||
void postMessage(any message, optional sequence<object> transfer = []);
|
||||
};
|
||||
|
||||
[Exposed=ServiceWorker]
|
||||
|
@ -16,7 +16,7 @@
|
||||
Exposed=DedicatedWorker]
|
||||
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<any> transfer);
|
||||
void postMessage(any message, optional sequence<object> transfer = []);
|
||||
|
||||
void close();
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
[Exposed=(Window,Worker,System)]
|
||||
interface MessagePort : EventTarget {
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<Transferable> transferable);
|
||||
void postMessage(any message, optional sequence<object> transferable = []);
|
||||
|
||||
void start();
|
||||
void close();
|
||||
|
@ -19,9 +19,8 @@ interface ServiceWorker : EventTarget {
|
||||
|
||||
attribute EventHandler onstatechange;
|
||||
|
||||
// FIXME(catalinb): Should inherit this from Worker.
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<Transferable> transferable);
|
||||
void postMessage(any message, optional sequence<object> transferable = []);
|
||||
};
|
||||
|
||||
ServiceWorker implements AbstractWorker;
|
||||
|
@ -24,7 +24,6 @@ interface IID;
|
||||
interface nsIBrowserDOMWindow;
|
||||
interface nsIMessageBroadcaster;
|
||||
interface nsIDOMCrypto;
|
||||
typedef any Transferable;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/
|
||||
[PrimaryGlobal, LegacyUnenumerableNamedProperties, NeedResolve]
|
||||
@ -85,7 +84,7 @@ typedef any Transferable;
|
||||
any showModalDialog(DOMString url, optional any argument, optional DOMString options = "");
|
||||
|
||||
[Throws, CrossOriginCallable, NeedsSubjectPrincipal]
|
||||
void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
|
||||
void postMessage(any message, DOMString targetOrigin, optional sequence<object> transfer = []);
|
||||
|
||||
// also has obsolete members
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ interface Worker : EventTarget {
|
||||
void terminate();
|
||||
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<any> transfer);
|
||||
void postMessage(any message, optional sequence<object> transfer = []);
|
||||
|
||||
attribute EventHandler onmessage;
|
||||
};
|
||||
|
@ -80,7 +80,7 @@ ServiceWorker::GetScriptURL(nsString& aURL) const
|
||||
|
||||
void
|
||||
ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (State() == ServiceWorkerState::Redundant) {
|
||||
|
@ -64,8 +64,7 @@ public:
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
// This class can only be created from ServiceWorkerInfo::GetOrCreateInstance().
|
||||
|
@ -191,7 +191,7 @@ private:
|
||||
|
||||
void
|
||||
ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
@ -199,20 +199,11 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
||||
realTransferable.Elements());
|
||||
|
||||
JSObject* array = JS_NewArrayObject(aCx, elements);
|
||||
if (!array) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
transferable.setObject(*array);
|
||||
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
|
||||
&transferable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
|
||||
|
@ -92,8 +92,7 @@ public:
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
@ -1374,7 +1374,7 @@ void
|
||||
ServiceWorkerManager::WorkerIsIdle(ServiceWorkerInfo* aWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWorker);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorker);
|
||||
|
||||
RefPtr<ServiceWorkerRegistrationInfo> reg =
|
||||
GetRegistration(aWorker->GetPrincipal(), aWorker->Scope());
|
||||
|
@ -532,7 +532,7 @@ public:
|
||||
nsresult
|
||||
ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@ -543,17 +543,13 @@ ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedHandleValue);
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& value = aTransferable.Value();
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(value.Length(), value.Elements());
|
||||
|
||||
JSObject* array = JS_NewArrayObject(aCx, elements);
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
transferable.setObject(*array);
|
||||
rv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
|
||||
&transferable);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
|
||||
RefPtr<SendMesssageEventRunnable> runnable =
|
||||
new SendMesssageEventRunnable(mWorkerPrivate, token, Move(aClientInfo));
|
||||
@ -2076,7 +2072,11 @@ ServiceWorkerPrivate::ReleaseToken()
|
||||
--mTokenCount;
|
||||
if (!mTokenCount) {
|
||||
TerminateWorker();
|
||||
} else if (IsIdle()) {
|
||||
}
|
||||
|
||||
// mInfo can be nullptr here if NoteDeadServiceWorkerInfo() is called while
|
||||
// the KeepAliveToken is being proxy released as a runnable.
|
||||
else if (mInfo && IsIdle()) {
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (swm) {
|
||||
swm->WorkerIsIdle(mInfo);
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
|
||||
nsresult
|
||||
SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
|
||||
|
||||
// This is used to validate the worker script and continue the installation
|
||||
|
@ -145,7 +145,7 @@ SharedWorker::Close()
|
||||
|
||||
void
|
||||
SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -95,8 +95,7 @@ private:
|
||||
// Only called by MessagePort.
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -3077,11 +3077,10 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
WorkerPrivateParent<Derived>::PostMessageInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
|
||||
@ -3093,22 +3092,11 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
|
||||
// The input sequence only comes from the generated bindings code, which
|
||||
// ensures it is rooted.
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
||||
realTransferable.Elements());
|
||||
|
||||
JSObject* array =
|
||||
JS_NewArrayObject(aCx, elements);
|
||||
if (!array) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
transferable.setObject(*array);
|
||||
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
|
||||
&transferable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MessageEventRunnable> runnable =
|
||||
@ -3151,7 +3139,7 @@ template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::PostMessage(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, aRv);
|
||||
@ -5724,27 +5712,17 @@ void
|
||||
WorkerPrivate::PostMessageToParentInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
|
||||
// The input sequence only comes from the generated bindings code, which
|
||||
// ensures it is rooted.
|
||||
JS::HandleValueArray elements =
|
||||
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
|
||||
realTransferable.Elements());
|
||||
|
||||
JSObject* array = JS_NewArrayObject(aCx, elements);
|
||||
if (!array) {
|
||||
aRv = NS_ERROR_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
transferable.setObject(*array);
|
||||
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
|
||||
&transferable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MessageEventRunnable> runnable =
|
||||
|
@ -250,7 +250,7 @@ private:
|
||||
|
||||
void
|
||||
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
@ -361,7 +361,7 @@ public:
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
@ -1125,18 +1125,17 @@ public:
|
||||
void
|
||||
PostMessageToParent(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
PostMessageToParentMessagePort(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
PostMessageToParentMessagePort(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
EnterDebuggerEventLoop();
|
||||
@ -1457,7 +1456,7 @@ private:
|
||||
void
|
||||
PostMessageToParentInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
|
@ -517,7 +517,7 @@ DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
|
||||
void
|
||||
DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
@ -212,7 +212,7 @@ public:
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
|
@ -2259,6 +2259,10 @@ XMLHttpRequestMainThread::ChangeStateToDone()
|
||||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
|
||||
if (mFlagSynchronous) {
|
||||
UnsuppressEventHandlingAndResume();
|
||||
}
|
||||
|
||||
// Per spec, fire the last download progress event, if any,
|
||||
// before readystatechange=4/done. (Note that 0-sized responses
|
||||
// will have not sent a progress event yet, so one must be sent here).
|
||||
@ -2679,6 +2683,23 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant)
|
||||
return SendInternal(&body);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::UnsuppressEventHandlingAndResume()
|
||||
{
|
||||
MOZ_ASSERT(mFlagSynchronous);
|
||||
|
||||
if (mSuspendedDoc) {
|
||||
mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
|
||||
true);
|
||||
mSuspendedDoc = nullptr;
|
||||
}
|
||||
|
||||
if (mResumeTimeoutRunnable) {
|
||||
NS_DispatchToCurrentThread(mResumeTimeoutRunnable);
|
||||
mResumeTimeoutRunnable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
||||
{
|
||||
@ -2798,17 +2819,15 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
||||
if (mFlagSynchronous) {
|
||||
mFlagSyncLooping = true;
|
||||
|
||||
nsCOMPtr<nsIDocument> suspendedDoc;
|
||||
nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
|
||||
if (GetOwner()) {
|
||||
if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetOwner()->GetOuterWindow()->GetTop()) {
|
||||
if (nsCOMPtr<nsPIDOMWindowInner> topInner = topWindow->GetCurrentInnerWindow()) {
|
||||
suspendedDoc = topWindow->GetExtantDoc();
|
||||
if (suspendedDoc) {
|
||||
suspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
|
||||
mSuspendedDoc = topWindow->GetExtantDoc();
|
||||
if (mSuspendedDoc) {
|
||||
mSuspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
|
||||
}
|
||||
topInner->Suspend();
|
||||
resumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner);
|
||||
mResumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2822,7 +2841,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoSyncOperation sync(suspendedDoc);
|
||||
nsAutoSyncOperation sync(mSuspendedDoc);
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
while (mFlagSyncLooping) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
@ -2839,14 +2858,7 @@ XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
|
||||
CancelSyncTimeoutTimer();
|
||||
}
|
||||
|
||||
if (suspendedDoc) {
|
||||
suspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
|
||||
true);
|
||||
}
|
||||
|
||||
if (resumeTimeoutRunnable) {
|
||||
NS_DispatchToCurrentThread(resumeTimeoutRunnable);
|
||||
}
|
||||
UnsuppressEventHandlingAndResume();
|
||||
} else {
|
||||
// Now that we've successfully opened the channel, we can change state. Note
|
||||
// that this needs to come after the AsyncOpen() and rv check, because this
|
||||
|
@ -304,6 +304,8 @@ private:
|
||||
// interface ID.
|
||||
void PopulateNetworkInterfaceId();
|
||||
|
||||
void UnsuppressEventHandlingAndResume();
|
||||
|
||||
public:
|
||||
virtual void
|
||||
Send(JSContext* /*aCx*/, ErrorResult& aRv) override
|
||||
@ -698,6 +700,9 @@ protected:
|
||||
void StartTimeoutTimer();
|
||||
void HandleTimeoutCallback();
|
||||
|
||||
nsCOMPtr<nsIDocument> mSuspendedDoc;
|
||||
nsCOMPtr<nsIRunnable> mResumeTimeoutRunnable;
|
||||
|
||||
nsCOMPtr<nsITimer> mSyncTimeoutTimer;
|
||||
|
||||
enum SyncTimeoutType {
|
||||
|
@ -149,12 +149,14 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument,
|
||||
nsIScriptGlobalObject* sgo =
|
||||
source->GetScriptHandlingObject(hasHadScriptObject);
|
||||
NS_ENSURE_STATE(sgo || !hasHadScriptObject);
|
||||
mDocument->SetScriptHandlingObject(sgo);
|
||||
|
||||
NS_ASSERTION(mDocument, "Need document");
|
||||
|
||||
// Reset and set up document
|
||||
URIUtils::ResetWithSource(mDocument, aSourceDocument);
|
||||
// Only do this after resetting the document to ensure we have the
|
||||
// correct principal.
|
||||
mDocument->SetScriptHandlingObject(sgo);
|
||||
|
||||
// Set the charset
|
||||
if (!mOutputFormat.mEncoding.IsEmpty()) {
|
||||
|
@ -13,7 +13,6 @@ UNIFIED_SOURCES += [
|
||||
'src/base/file_path.cc',
|
||||
'src/base/file_util.cc',
|
||||
'src/base/histogram.cc',
|
||||
'src/base/lock.cc',
|
||||
'src/base/logging.cc',
|
||||
'src/base/message_loop.cc',
|
||||
'src/base/message_pump_default.cc',
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -67,7 +65,17 @@
|
||||
#ifndef BASE_CONDITION_VARIABLE_H_
|
||||
#define BASE_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/lock.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
class TimeDelta;
|
||||
@ -81,11 +89,13 @@ class ConditionVariable {
|
||||
~ConditionVariable();
|
||||
|
||||
// Wait() releases the caller's critical section atomically as it starts to
|
||||
// sleep, and the reacquires it when it is signaled.
|
||||
// sleep, and the reacquires it when it is signaled. The wait functions are
|
||||
// susceptible to spurious wakeups. (See usage note 1 for more details.)
|
||||
void Wait();
|
||||
void TimedWait(const base::TimeDelta& max_time);
|
||||
|
||||
// Broadcast() revives all waiting threads.
|
||||
// Broadcast() revives all waiting threads. (See usage note 2 for more
|
||||
// details.)
|
||||
void Broadcast();
|
||||
// Signal() revives one waiting thread.
|
||||
void Signal();
|
||||
@ -93,81 +103,11 @@ class ConditionVariable {
|
||||
private:
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
// Define Event class that is used to form circularly linked lists.
|
||||
// The list container is an element with NULL as its handle_ value.
|
||||
// The actual list elements have a non-zero handle_ value.
|
||||
// All calls to methods MUST be done under protection of a lock so that links
|
||||
// can be validated. Without the lock, some links might asynchronously
|
||||
// change, and the assertions would fail (as would list change operations).
|
||||
class Event {
|
||||
public:
|
||||
// Default constructor with no arguments creates a list container.
|
||||
Event();
|
||||
~Event();
|
||||
|
||||
// InitListElement transitions an instance from a container, to an element.
|
||||
void InitListElement();
|
||||
|
||||
// Methods for use on lists.
|
||||
bool IsEmpty() const;
|
||||
void PushBack(Event* other);
|
||||
Event* PopFront();
|
||||
Event* PopBack();
|
||||
|
||||
// Methods for use on list elements.
|
||||
// Accessor method.
|
||||
HANDLE handle() const;
|
||||
// Pull an element from a list (if it's in one).
|
||||
Event* Extract();
|
||||
|
||||
// Method for use on a list element or on a list.
|
||||
bool IsSingleton() const;
|
||||
|
||||
private:
|
||||
// Provide pre/post conditions to validate correct manipulations.
|
||||
bool ValidateAsDistinct(Event* other) const;
|
||||
bool ValidateAsItem() const;
|
||||
bool ValidateAsList() const;
|
||||
bool ValidateLinks() const;
|
||||
|
||||
HANDLE handle_;
|
||||
Event* next_;
|
||||
Event* prev_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Event);
|
||||
};
|
||||
|
||||
// Note that RUNNING is an unlikely number to have in RAM by accident.
|
||||
// This helps with defensive destructor coding in the face of user error.
|
||||
enum RunState { SHUTDOWN = 0, RUNNING = 64213 };
|
||||
|
||||
// Internal implementation methods supporting Wait().
|
||||
Event* GetEventForWaiting();
|
||||
void RecycleEvent(Event* used_event);
|
||||
|
||||
RunState run_state_;
|
||||
|
||||
// Private critical section for access to member data.
|
||||
Lock internal_lock_;
|
||||
|
||||
// Lock that is acquired before calling Wait().
|
||||
Lock& user_lock_;
|
||||
|
||||
// Events that threads are blocked on.
|
||||
Event waiting_list_;
|
||||
|
||||
// Free list for old events.
|
||||
Event recycling_list_;
|
||||
int recycling_list_size_;
|
||||
|
||||
// The number of allocated, but not yet deleted events.
|
||||
int allocation_counter_;
|
||||
|
||||
CONDITION_VARIABLE cv_;
|
||||
SRWLOCK* const srwlock_;
|
||||
#elif defined(OS_POSIX)
|
||||
|
||||
pthread_cond_t condition_;
|
||||
pthread_mutex_t* user_mutex_;
|
||||
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
|
||||
|
@ -1,27 +1,29 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/condition_variable.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "base/lock.h"
|
||||
#include "base/lock_impl.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/time.h"
|
||||
|
||||
using base::Time;
|
||||
using base::TimeDelta;
|
||||
#include "build/build_config.h"
|
||||
|
||||
ConditionVariable::ConditionVariable(Lock* user_lock)
|
||||
: user_mutex_(user_lock->lock_impl()->os_lock()) {
|
||||
: user_mutex_(user_lock->lock_.native_handle())
|
||||
{
|
||||
int rv = 0;
|
||||
#if !defined(OS_MACOSX) && \
|
||||
!(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
|
||||
// http://crbug.com/293736
|
||||
// NaCl doesn't support monotonic clock based absolute deadlines.
|
||||
// On older Android platform versions, it's supported through the
|
||||
// non-standard pthread_cond_timedwait_monotonic_np. Newer platform
|
||||
// versions have pthread_condattr_setclock.
|
||||
// Mac can use relative time deadlines.
|
||||
#if !defined(OS_MACOSX) && !defined(OS_NACL) && \
|
||||
!(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
|
||||
pthread_condattr_t attrs;
|
||||
rv = pthread_condattr_init(&attrs);
|
||||
DCHECK_EQ(0, rv);
|
||||
@ -35,38 +37,59 @@ ConditionVariable::ConditionVariable(Lock* user_lock)
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
#if defined(OS_MACOSX)
|
||||
// This hack is necessary to avoid a fatal pthreads subsystem bug in the
|
||||
// Darwin kernel. http://crbug.com/517681.
|
||||
{
|
||||
Lock lock;
|
||||
AutoLock l(lock);
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
|
||||
&ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
int rv = pthread_cond_destroy(&condition_);
|
||||
DCHECK(rv == 0);
|
||||
DCHECK_EQ(0, rv);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait() {
|
||||
int rv = pthread_cond_wait(&condition_, user_mutex_);
|
||||
DCHECK(rv == 0);
|
||||
DCHECK_EQ(0, rv);
|
||||
}
|
||||
|
||||
void ConditionVariable::TimedWait(const TimeDelta& max_time) {
|
||||
void ConditionVariable::TimedWait(const base::TimeDelta& max_time) {
|
||||
int64_t usecs = max_time.InMicroseconds();
|
||||
|
||||
struct timespec relative_time;
|
||||
relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
|
||||
relative_time.tv_sec = usecs / base::Time::kMicrosecondsPerSecond;
|
||||
relative_time.tv_nsec =
|
||||
(usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
|
||||
(usecs % base::Time::kMicrosecondsPerSecond) * base::Time::kNanosecondsPerMicrosecond;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
int rv = pthread_cond_timedwait_relative_np(
|
||||
&condition_, user_mutex_, &relative_time);
|
||||
#else
|
||||
// The timeout argument to pthread_cond_timedwait is in absolute time.
|
||||
struct timespec absolute_time;
|
||||
#if defined(OS_NACL)
|
||||
// See comment in constructor for why this is different in NaCl.
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
absolute_time.tv_sec = now.tv_sec;
|
||||
absolute_time.tv_nsec = now.tv_usec * base::Time::kNanosecondsPerMicrosecond;
|
||||
#else
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
struct timespec absolute_time;
|
||||
absolute_time.tv_sec = now.tv_sec;
|
||||
absolute_time.tv_nsec = now.tv_nsec;
|
||||
#endif
|
||||
|
||||
absolute_time.tv_sec += relative_time.tv_sec;
|
||||
absolute_time.tv_nsec += relative_time.tv_nsec;
|
||||
absolute_time.tv_sec += absolute_time.tv_nsec / Time::kNanosecondsPerSecond;
|
||||
absolute_time.tv_nsec %= Time::kNanosecondsPerSecond;
|
||||
absolute_time.tv_sec += absolute_time.tv_nsec / base::Time::kNanosecondsPerSecond;
|
||||
absolute_time.tv_nsec %= base::Time::kNanosecondsPerSecond;
|
||||
DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia
|
||||
|
||||
#if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
|
||||
@ -77,15 +100,17 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
|
||||
#endif // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
|
||||
#endif // OS_MACOSX
|
||||
|
||||
// On failure, we only expect the CV to timeout. Any other error value means
|
||||
// that we've unexpectedly woken up.
|
||||
DCHECK(rv == 0 || rv == ETIMEDOUT);
|
||||
}
|
||||
|
||||
void ConditionVariable::Broadcast() {
|
||||
int rv = pthread_cond_broadcast(&condition_);
|
||||
DCHECK(rv == 0);
|
||||
DCHECK_EQ(0, rv);
|
||||
}
|
||||
|
||||
void ConditionVariable::Signal() {
|
||||
int rv = pthread_cond_signal(&condition_);
|
||||
DCHECK(rv == 0);
|
||||
DCHECK_EQ(0, rv);
|
||||
}
|
||||
|
@ -1,448 +1,43 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/condition_variable.h"
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "base/lock.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/time.h"
|
||||
|
||||
using base::TimeDelta;
|
||||
|
||||
ConditionVariable::ConditionVariable(Lock* user_lock)
|
||||
: user_lock_(*user_lock),
|
||||
run_state_(RUNNING),
|
||||
allocation_counter_(0),
|
||||
recycling_list_size_(0) {
|
||||
: srwlock_(user_lock->lock_.native_handle())
|
||||
{
|
||||
DCHECK(user_lock);
|
||||
InitializeConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
AutoLock auto_lock(internal_lock_);
|
||||
run_state_ = SHUTDOWN; // Prevent any more waiting.
|
||||
|
||||
DCHECK_EQ(recycling_list_size_, allocation_counter_);
|
||||
if (recycling_list_size_ != allocation_counter_) { // Rare shutdown problem.
|
||||
// There are threads of execution still in this->TimedWait() and yet the
|
||||
// caller has instigated the destruction of this instance :-/.
|
||||
// A common reason for such "overly hasty" destruction is that the caller
|
||||
// was not willing to wait for all the threads to terminate. Such hasty
|
||||
// actions are a violation of our usage contract, but we'll give the
|
||||
// waiting thread(s) one last chance to exit gracefully (prior to our
|
||||
// destruction).
|
||||
// Note: waiting_list_ *might* be empty, but recycling is still pending.
|
||||
AutoUnlock auto_unlock(internal_lock_);
|
||||
Broadcast(); // Make sure all waiting threads have been signaled.
|
||||
Sleep(10); // Give threads a chance to grab internal_lock_.
|
||||
// All contained threads should be blocked on user_lock_ by now :-).
|
||||
} // Reacquire internal_lock_.
|
||||
|
||||
DCHECK_EQ(recycling_list_size_, allocation_counter_);
|
||||
}
|
||||
ConditionVariable::~ConditionVariable() = default;
|
||||
|
||||
void ConditionVariable::Wait() {
|
||||
// Default to "wait forever" timing, which means have to get a Signal()
|
||||
// or Broadcast() to come out of this wait state.
|
||||
TimedWait(TimeDelta::FromMilliseconds(INFINITE));
|
||||
TimedWait(base::TimeDelta::FromMilliseconds(INFINITE));
|
||||
}
|
||||
|
||||
void ConditionVariable::TimedWait(const TimeDelta& max_time) {
|
||||
Event* waiting_event;
|
||||
HANDLE handle;
|
||||
{
|
||||
AutoLock auto_lock(internal_lock_);
|
||||
if (RUNNING != run_state_) return; // Destruction in progress.
|
||||
waiting_event = GetEventForWaiting();
|
||||
handle = waiting_event->handle();
|
||||
DCHECK(handle);
|
||||
} // Release internal_lock.
|
||||
void ConditionVariable::TimedWait(const base::TimeDelta& max_time) {
|
||||
DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
|
||||
|
||||
{
|
||||
AutoUnlock unlock(user_lock_); // Release caller's lock
|
||||
WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds()));
|
||||
// Minimize spurious signal creation window by recycling asap.
|
||||
AutoLock auto_lock(internal_lock_);
|
||||
RecycleEvent(waiting_event);
|
||||
// Release internal_lock_
|
||||
} // Reacquire callers lock to depth at entry.
|
||||
if (!SleepConditionVariableSRW(&cv_, srwlock_, timeout, 0)) {
|
||||
// On failure, we only expect the CV to timeout. Any other error value means
|
||||
// that we've unexpectedly woken up.
|
||||
// Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
|
||||
// WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
|
||||
// used with GetLastError().
|
||||
DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had
|
||||
// a cv_event internally allocated for them) before Broadcast() was called.
|
||||
void ConditionVariable::Broadcast() {
|
||||
std::stack<HANDLE> handles; // See FAQ-question-10.
|
||||
{
|
||||
AutoLock auto_lock(internal_lock_);
|
||||
if (waiting_list_.IsEmpty())
|
||||
return;
|
||||
while (!waiting_list_.IsEmpty())
|
||||
// This is not a leak from waiting_list_. See FAQ-question 12.
|
||||
handles.push(waiting_list_.PopBack()->handle());
|
||||
} // Release internal_lock_.
|
||||
while (!handles.empty()) {
|
||||
SetEvent(handles.top());
|
||||
handles.pop();
|
||||
}
|
||||
WakeAllConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
// Signal() will select one of the waiting threads, and signal it (signal its
|
||||
// cv_event). For better performance we signal the thread that went to sleep
|
||||
// most recently (LIFO). If we want fairness, then we wake the thread that has
|
||||
// been sleeping the longest (FIFO).
|
||||
void ConditionVariable::Signal() {
|
||||
HANDLE handle;
|
||||
{
|
||||
AutoLock auto_lock(internal_lock_);
|
||||
if (waiting_list_.IsEmpty())
|
||||
return; // No one to signal.
|
||||
// Only performance option should be used.
|
||||
// This is not a leak from waiting_list. See FAQ-question 12.
|
||||
handle = waiting_list_.PopBack()->handle(); // LIFO.
|
||||
} // Release internal_lock_.
|
||||
SetEvent(handle);
|
||||
WakeConditionVariable(&cv_);
|
||||
}
|
||||
|
||||
// GetEventForWaiting() provides a unique cv_event for any caller that needs to
|
||||
// wait. This means that (worst case) we may over time create as many cv_event
|
||||
// objects as there are threads simultaneously using this instance's Wait()
|
||||
// functionality.
|
||||
ConditionVariable::Event* ConditionVariable::GetEventForWaiting() {
|
||||
// We hold internal_lock, courtesy of Wait().
|
||||
Event* cv_event;
|
||||
if (0 == recycling_list_size_) {
|
||||
DCHECK(recycling_list_.IsEmpty());
|
||||
cv_event = new Event();
|
||||
cv_event->InitListElement();
|
||||
allocation_counter_++;
|
||||
// CHECK_NE is not defined in our codebase, so we have to use CHECK
|
||||
CHECK(cv_event->handle());
|
||||
} else {
|
||||
cv_event = recycling_list_.PopFront();
|
||||
recycling_list_size_--;
|
||||
}
|
||||
waiting_list_.PushBack(cv_event);
|
||||
return cv_event;
|
||||
}
|
||||
|
||||
// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and
|
||||
// recycles it for use in future Wait() calls for this or other threads.
|
||||
// Note that there is a tiny chance that the cv_event is still signaled when we
|
||||
// obtain it, and that can cause spurious signals (if/when we re-use the
|
||||
// cv_event), but such is quite rare (see FAQ-question-5).
|
||||
void ConditionVariable::RecycleEvent(Event* used_event) {
|
||||
// We hold internal_lock, courtesy of Wait().
|
||||
// If the cv_event timed out, then it is necessary to remove it from
|
||||
// waiting_list_. If it was selected by Broadcast() or Signal(), then it is
|
||||
// already gone.
|
||||
used_event->Extract(); // Possibly redundant
|
||||
recycling_list_.PushBack(used_event);
|
||||
recycling_list_size_++;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// The next section provides the implementation for the private Event class.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Event provides a doubly-linked-list of events for use exclusively by the
|
||||
// ConditionVariable class.
|
||||
|
||||
// This custom container was crafted because no simple combination of STL
|
||||
// classes appeared to support the functionality required. The specific
|
||||
// unusual requirement for a linked-list-class is support for the Extract()
|
||||
// method, which can remove an element from a list, potentially for insertion
|
||||
// into a second list. Most critically, the Extract() method is idempotent,
|
||||
// turning the indicated element into an extracted singleton whether it was
|
||||
// contained in a list or not. This functionality allows one (or more) of
|
||||
// threads to do the extraction. The iterator that identifies this extractable
|
||||
// element (in this case, a pointer to the list element) can be used after
|
||||
// arbitrary manipulation of the (possibly) enclosing list container. In
|
||||
// general, STL containers do not provide iterators that can be used across
|
||||
// modifications (insertions/extractions) of the enclosing containers, and
|
||||
// certainly don't provide iterators that can be used if the identified
|
||||
// element is *deleted* (removed) from the container.
|
||||
|
||||
// It is possible to use multiple redundant containers, such as an STL list,
|
||||
// and an STL map, to achieve similar container semantics. This container has
|
||||
// only O(1) methods, while the corresponding (multiple) STL container approach
|
||||
// would have more complex O(log(N)) methods (yeah... N isn't that large).
|
||||
// Multiple containers also makes correctness more difficult to assert, as
|
||||
// data is redundantly stored and maintained, which is generally evil.
|
||||
|
||||
ConditionVariable::Event::Event() : handle_(0) {
|
||||
next_ = prev_ = this; // Self referencing circular.
|
||||
}
|
||||
|
||||
ConditionVariable::Event::~Event() {
|
||||
if (0 == handle_) {
|
||||
// This is the list holder
|
||||
while (!IsEmpty()) {
|
||||
Event* cv_event = PopFront();
|
||||
DCHECK(cv_event->ValidateAsItem());
|
||||
delete cv_event;
|
||||
}
|
||||
}
|
||||
DCHECK(IsSingleton());
|
||||
if (0 != handle_) {
|
||||
int ret_val = CloseHandle(handle_);
|
||||
DCHECK(ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
// Change a container instance permanently into an element of a list.
|
||||
void ConditionVariable::Event::InitListElement() {
|
||||
DCHECK(!handle_);
|
||||
handle_ = CreateEvent(NULL, false, false, NULL);
|
||||
CHECK(handle_);
|
||||
}
|
||||
|
||||
// Methods for use on lists.
|
||||
bool ConditionVariable::Event::IsEmpty() const {
|
||||
DCHECK(ValidateAsList());
|
||||
return IsSingleton();
|
||||
}
|
||||
|
||||
void ConditionVariable::Event::PushBack(Event* other) {
|
||||
DCHECK(ValidateAsList());
|
||||
DCHECK(other->ValidateAsItem());
|
||||
DCHECK(other->IsSingleton());
|
||||
// Prepare other for insertion.
|
||||
other->prev_ = prev_;
|
||||
other->next_ = this;
|
||||
// Cut into list.
|
||||
prev_->next_ = other;
|
||||
prev_ = other;
|
||||
DCHECK(ValidateAsDistinct(other));
|
||||
}
|
||||
|
||||
ConditionVariable::Event* ConditionVariable::Event::PopFront() {
|
||||
DCHECK(ValidateAsList());
|
||||
DCHECK(!IsSingleton());
|
||||
return next_->Extract();
|
||||
}
|
||||
|
||||
ConditionVariable::Event* ConditionVariable::Event::PopBack() {
|
||||
DCHECK(ValidateAsList());
|
||||
DCHECK(!IsSingleton());
|
||||
return prev_->Extract();
|
||||
}
|
||||
|
||||
// Methods for use on list elements.
|
||||
// Accessor method.
|
||||
HANDLE ConditionVariable::Event::handle() const {
|
||||
DCHECK(ValidateAsItem());
|
||||
return handle_;
|
||||
}
|
||||
|
||||
// Pull an element from a list (if it's in one).
|
||||
ConditionVariable::Event* ConditionVariable::Event::Extract() {
|
||||
DCHECK(ValidateAsItem());
|
||||
if (!IsSingleton()) {
|
||||
// Stitch neighbors together.
|
||||
next_->prev_ = prev_;
|
||||
prev_->next_ = next_;
|
||||
// Make extractee into a singleton.
|
||||
prev_ = next_ = this;
|
||||
}
|
||||
DCHECK(IsSingleton());
|
||||
return this;
|
||||
}
|
||||
|
||||
// Method for use on a list element or on a list.
|
||||
bool ConditionVariable::Event::IsSingleton() const {
|
||||
DCHECK(ValidateLinks());
|
||||
return next_ == this;
|
||||
}
|
||||
|
||||
// Provide pre/post conditions to validate correct manipulations.
|
||||
bool ConditionVariable::Event::ValidateAsDistinct(Event* other) const {
|
||||
return ValidateLinks() && other->ValidateLinks() && (this != other);
|
||||
}
|
||||
|
||||
bool ConditionVariable::Event::ValidateAsItem() const {
|
||||
return (0 != handle_) && ValidateLinks();
|
||||
}
|
||||
|
||||
bool ConditionVariable::Event::ValidateAsList() const {
|
||||
return (0 == handle_) && ValidateLinks();
|
||||
}
|
||||
|
||||
bool ConditionVariable::Event::ValidateLinks() const {
|
||||
// Make sure both of our neighbors have links that point back to us.
|
||||
// We don't do the O(n) check and traverse the whole loop, and instead only
|
||||
// do a local check to (and returning from) our immediate neighbors.
|
||||
return (next_->prev_ == this) && (prev_->next_ == this);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
FAQ On subtle implementation details:
|
||||
|
||||
1) What makes this problem subtle? Please take a look at "Strategies
|
||||
for Implementing POSIX Condition Variables on Win32" by Douglas
|
||||
C. Schmidt and Irfan Pyarali.
|
||||
http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes
|
||||
discussions of numerous flawed strategies for implementing this
|
||||
functionality. I'm not convinced that even the final proposed
|
||||
implementation has semantics that are as nice as this implementation
|
||||
(especially with regard to Broadcast() and the impact on threads that
|
||||
try to Wait() after a Broadcast() has been called, but before all the
|
||||
original waiting threads have been signaled).
|
||||
|
||||
2) Why can't you use a single wait_event for all threads that call
|
||||
Wait()? See FAQ-question-1, or consider the following: If a single
|
||||
event were used, then numerous threads calling Wait() could release
|
||||
their cs locks, and be preempted just before calling
|
||||
WaitForSingleObject(). If a call to Broadcast() was then presented on
|
||||
a second thread, it would be impossible to actually signal all
|
||||
waiting(?) threads. Some number of SetEvent() calls *could* be made,
|
||||
but there could be no guarantee that those led to to more than one
|
||||
signaled thread (SetEvent()'s may be discarded after the first!), and
|
||||
there could be no guarantee that the SetEvent() calls didn't just
|
||||
awaken "other" threads that hadn't even started waiting yet (oops).
|
||||
Without any limit on the number of requisite SetEvent() calls, the
|
||||
system would be forced to do many such calls, allowing many new waits
|
||||
to receive spurious signals.
|
||||
|
||||
3) How does this implementation cause spurious signal events? The
|
||||
cause in this implementation involves a race between a signal via
|
||||
time-out and a signal via Signal() or Broadcast(). The series of
|
||||
actions leading to this are:
|
||||
|
||||
a) Timer fires, and a waiting thread exits the line of code:
|
||||
|
||||
WaitForSingleObject(waiting_event, max_time.InMilliseconds());
|
||||
|
||||
b) That thread (in (a)) is randomly pre-empted after the above line,
|
||||
leaving the waiting_event reset (unsignaled) and still in the
|
||||
waiting_list_.
|
||||
|
||||
c) A call to Signal() (or Broadcast()) on a second thread proceeds, and
|
||||
selects the waiting cv_event (identified in step (b)) as the event to revive
|
||||
via a call to SetEvent().
|
||||
|
||||
d) The Signal() method (step c) calls SetEvent() on waiting_event (step b).
|
||||
|
||||
e) The waiting cv_event (step b) is now signaled, but no thread is
|
||||
waiting on it.
|
||||
|
||||
f) When that waiting_event (step b) is reused, it will immediately
|
||||
be signaled (spuriously).
|
||||
|
||||
|
||||
4) Why do you recycle events, and cause spurious signals? First off,
|
||||
the spurious events are very rare. They can only (I think) appear
|
||||
when the race described in FAQ-question-3 takes place. This should be
|
||||
very rare. Most(?) uses will involve only timer expiration, or only
|
||||
Signal/Broadcast() actions. When both are used, it will be rare that
|
||||
the race will appear, and it would require MANY Wait() and signaling
|
||||
activities. If this implementation did not recycle events, then it
|
||||
would have to create and destroy events for every call to Wait().
|
||||
That allocation/deallocation and associated construction/destruction
|
||||
would be costly (per wait), and would only be a rare benefit (when the
|
||||
race was "lost" and a spurious signal took place). That would be bad
|
||||
(IMO) optimization trade-off. Finally, such spurious events are
|
||||
allowed by the specification of condition variables (such as
|
||||
implemented in Vista), and hence it is better if any user accommodates
|
||||
such spurious events (see usage note in condition_variable.h).
|
||||
|
||||
5) Why don't you reset events when you are about to recycle them, or
|
||||
about to reuse them, so that the spurious signals don't take place?
|
||||
The thread described in FAQ-question-3 step c may be pre-empted for an
|
||||
arbitrary length of time before proceeding to step d. As a result,
|
||||
the wait_event may actually be re-used *before* step (e) is reached.
|
||||
As a result, calling reset would not help significantly.
|
||||
|
||||
6) How is it that the callers lock is released atomically with the
|
||||
entry into a wait state? We commit to the wait activity when we
|
||||
allocate the wait_event for use in a given call to Wait(). This
|
||||
allocation takes place before the caller's lock is released (and
|
||||
actually before our internal_lock_ is released). That allocation is
|
||||
the defining moment when "the wait state has been entered," as that
|
||||
thread *can* now be signaled by a call to Broadcast() or Signal().
|
||||
Hence we actually "commit to wait" before releasing the lock, making
|
||||
the pair effectively atomic.
|
||||
|
||||
8) Why do you need to lock your data structures during waiting, as the
|
||||
caller is already in possession of a lock? We need to Acquire() and
|
||||
Release() our internal lock during Signal() and Broadcast(). If we tried
|
||||
to use a callers lock for this purpose, we might conflict with their
|
||||
external use of the lock. For example, the caller may use to consistently
|
||||
hold a lock on one thread while calling Signal() on another, and that would
|
||||
block Signal().
|
||||
|
||||
9) Couldn't a more efficient implementation be provided if you
|
||||
preclude using more than one external lock in conjunction with a
|
||||
single ConditionVariable instance? Yes, at least it could be viewed
|
||||
as a simpler API (since you don't have to reiterate the lock argument
|
||||
in each Wait() call). One of the constructors now takes a specific
|
||||
lock as an argument, and a there are corresponding Wait() calls that
|
||||
don't specify a lock now. It turns that the resulting implmentation
|
||||
can't be made more efficient, as the internal lock needs to be used by
|
||||
Signal() and Broadcast(), to access internal data structures. As a
|
||||
result, I was not able to utilize the user supplied lock (which is
|
||||
being used by the user elsewhere presumably) to protect the private
|
||||
member access.
|
||||
|
||||
9) Since you have a second lock, how can be be sure that there is no
|
||||
possible deadlock scenario? Our internal_lock_ is always the last
|
||||
lock acquired, and the first one released, and hence a deadlock (due
|
||||
to critical section problems) is impossible as a consequence of our
|
||||
lock.
|
||||
|
||||
10) When doing a Broadcast(), why did you copy all the events into
|
||||
an STL queue, rather than making a linked-loop, and iterating over it?
|
||||
The iterating during Broadcast() is done so outside the protection
|
||||
of the internal lock. As a result, other threads, such as the thread
|
||||
wherein a related event is waiting, could asynchronously manipulate
|
||||
the links around a cv_event. As a result, the link structure cannot
|
||||
be used outside a lock. Broadcast() could iterate over waiting
|
||||
events by cycling in-and-out of the protection of the internal_lock,
|
||||
but that appears more expensive than copying the list into an STL
|
||||
stack.
|
||||
|
||||
11) Why did the lock.h file need to be modified so much for this
|
||||
change? Central to a Condition Variable is the atomic release of a
|
||||
lock during a Wait(). This places Wait() functionality exactly
|
||||
mid-way between the two classes, Lock and Condition Variable. Given
|
||||
that there can be nested Acquire()'s of locks, and Wait() had to
|
||||
Release() completely a held lock, it was necessary to augment the Lock
|
||||
class with a recursion counter. Even more subtle is the fact that the
|
||||
recursion counter (in a Lock) must be protected, as many threads can
|
||||
access it asynchronously. As a positive fallout of this, there are
|
||||
now some DCHECKS to be sure no one Release()s a Lock more than they
|
||||
Acquire()ed it, and there is ifdef'ed functionality that can detect
|
||||
nested locks (legal under windows, but not under Posix).
|
||||
|
||||
12) Why is it that the cv_events removed from list in Broadcast() and Signal()
|
||||
are not leaked? How are they recovered?? The cv_events that appear to leak are
|
||||
taken from the waiting_list_. For each element in that list, there is currently
|
||||
a thread in or around the WaitForSingleObject() call of Wait(), and those
|
||||
threads have references to these otherwise leaked events. They are passed as
|
||||
arguments to be recycled just aftre returning from WaitForSingleObject().
|
||||
|
||||
13) Why did you use a custom container class (the linked list), when STL has
|
||||
perfectly good containers, such as an STL list? The STL list, as with any
|
||||
container, does not guarantee the utility of an iterator across manipulation
|
||||
(such as insertions and deletions) of the underlying container. The custom
|
||||
double-linked-list container provided that assurance. I don't believe any
|
||||
combination of STL containers provided the services that were needed at the same
|
||||
O(1) efficiency as the custom linked list. The unusual requirement
|
||||
for the container class is that a reference to an item within a container (an
|
||||
iterator) needed to be maintained across an arbitrary manipulation of the
|
||||
container. This requirement exposes itself in the Wait() method, where a
|
||||
waiting_event must be selected prior to the WaitForSingleObject(), and then it
|
||||
must be used as part of recycling to remove the related instance from the
|
||||
waiting_list. A hash table (STL map) could be used, but I was embarrased to
|
||||
use a complex and relatively low efficiency container when a doubly linked list
|
||||
provided O(1) performance in all required operations. Since other operations
|
||||
to provide performance-and/or-fairness required queue (FIFO) and list (LIFO)
|
||||
containers, I would also have needed to use an STL list/queue as well as an STL
|
||||
map. In the end I decided it would be "fun" to just do it right, and I
|
||||
put so many assertions (DCHECKs) into the container class that it is trivial to
|
||||
code review and validate its correctness.
|
||||
|
||||
*/
|
||||
|
@ -1,9 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Lock class.
|
||||
|
||||
// Depricated file. See lock_impl_*.cc for platform specific versions.
|
@ -1,39 +1,60 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_LOCK_H_
|
||||
#define BASE_LOCK_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/lock_impl.h"
|
||||
#include "base/platform_thread.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// A convenient wrapper for an OS specific critical section.
|
||||
|
||||
class Lock {
|
||||
public:
|
||||
// Optimized wrapper implementation
|
||||
Lock() : lock_() {}
|
||||
~Lock() {}
|
||||
void Acquire() { lock_.Lock(); }
|
||||
void Release() { lock_.Unlock(); }
|
||||
|
||||
// If the lock is not held, take it and return true. If the lock is already
|
||||
// held by another thread, immediately return false.
|
||||
// held by another thread, immediately return false. This must not be called
|
||||
// by a thread already holding the lock (what happens is undefined and an
|
||||
// assertion may fail).
|
||||
bool Try() { return lock_.Try(); }
|
||||
|
||||
// In debug builds this method checks that the lock has been acquired by the
|
||||
// calling thread. If the lock has not been acquired, then the method
|
||||
// will DCHECK(). In non-debug builds, the LockImpl's implementation of
|
||||
// AssertAcquired() is an empty inline method.
|
||||
void AssertAcquired() const { return lock_.AssertAcquired(); }
|
||||
// Null implementation if not debug.
|
||||
void AssertAcquired() const {}
|
||||
|
||||
// Return the underlying lock implementation.
|
||||
// TODO(awalker): refactor lock and condition variables so that this is
|
||||
// unnecessary.
|
||||
LockImpl* lock_impl() { return &lock_; }
|
||||
// Whether Lock mitigates priority inversion when used from different thread
|
||||
// priorities.
|
||||
static bool HandlesMultipleThreadPriorities() {
|
||||
#if defined(OS_POSIX)
|
||||
// POSIX mitigates priority inversion by setting the priority of a thread
|
||||
// holding a Lock to the maximum priority of any other thread waiting on it.
|
||||
return base::internal::LockImpl::PriorityInheritanceAvailable();
|
||||
#elif defined(OS_WIN)
|
||||
// Windows mitigates priority inversion by randomly boosting the priority of
|
||||
// ready threads.
|
||||
// https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
|
||||
return true;
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_POSIX) || defined(OS_WIN)
|
||||
// Both Windows and POSIX implementations of ConditionVariable need to be
|
||||
// able to see our lock and tweak our debugging counters, as they release and
|
||||
// acquire locks inside of their condition variable APIs.
|
||||
friend class ConditionVariable;
|
||||
#endif
|
||||
|
||||
private:
|
||||
LockImpl lock_; // Platform specific underlying lock implementation.
|
||||
// Platform specific underlying lock implementation.
|
||||
::base::internal::LockImpl lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Lock);
|
||||
};
|
||||
@ -41,10 +62,16 @@ class Lock {
|
||||
// A helper class that acquires the given Lock while the AutoLock is in scope.
|
||||
class AutoLock {
|
||||
public:
|
||||
struct AlreadyAcquired {};
|
||||
|
||||
explicit AutoLock(Lock& lock) : lock_(lock) {
|
||||
lock_.Acquire();
|
||||
}
|
||||
|
||||
AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
|
||||
lock_.AssertAcquired();
|
||||
}
|
||||
|
||||
~AutoLock() {
|
||||
lock_.AssertAcquired();
|
||||
lock_.Release();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user