Merge inbound to central, a=merge CLOSED TREE

MozReview-Commit-ID: GhBqmLvUpgQ
This commit is contained in:
Wes Kocher 2017-02-03 17:04:18 -08:00
commit b488ae9021
215 changed files with 3601 additions and 3603 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -455,6 +455,7 @@ this.ContentSearch = {
if (msg.target.contentWindow) {
engine.speculativeConnect({
window: msg.target.contentWindow,
originAttributes: msg.target.contentPrincipal.originAttributes
});
}
},

View File

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

View File

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

View File

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

View File

@ -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"
]
}

View File

@ -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"
]
}

View File

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

View File

@ -11,6 +11,5 @@
"python_path": "c:/mozilla-build/python/python.exe",
"cc": "cl.exe",
"cxx": "cl.exe",
"patches": {
}
"ml": "ml64.exe"
}

View File

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

View File

@ -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"
]
}

View File

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

View 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 "")

View File

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

View 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")

View File

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

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

View 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
+ }
+}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

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

View File

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

View File

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

View File

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

View 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);
});

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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