зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to graphics
MozReview-Commit-ID: EcjJhQuqDFI
This commit is contained in:
Коммит
2c58155ac0
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Touch clobber because of bug 1336456
|
||||
|
|
|
@ -2087,11 +2087,13 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
|||
child->SetRelocated(true);
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
|
||||
// Create subtree before adjusting the insertion index, since subtree
|
||||
// creation may alter children in the container.
|
||||
CreateSubtree(child);
|
||||
FireEventsOnInsertion(aOwner);
|
||||
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
|
|
@ -14,6 +14,7 @@ interface IGeckoCustom : IUnknown
|
|||
[propget] HRESULT anchorCount([out, retval] long* aCount);
|
||||
[propget] HRESULT DOMNodeID([out, retval] BSTR* aID);
|
||||
[propget] HRESULT minimumIncrement([out, retval] double* aIncrement);
|
||||
[propget] HRESULT mozState([out, retval] unsigned __int64* aState);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ ProxyAccessibleBase<Derived>::Shutdown()
|
|||
for (uint32_t idx = 0; idx < childCount; idx++)
|
||||
mChildren[idx]->Shutdown();
|
||||
} else {
|
||||
if (mChildren.Length() > 1)
|
||||
if (mChildren.Length() != 1)
|
||||
MOZ_CRASH("outer doc doesn't own adoc!");
|
||||
|
||||
mChildren[0]->AsDoc()->Unbind();
|
||||
|
@ -76,7 +76,9 @@ ProxyAccessibleBase<Derived>::ClearChildDoc(DocAccessibleParent* aChildDoc)
|
|||
// in SetChildDoc(). This could result in two subsequent calls to
|
||||
// ClearChildDoc() even though mChildren.Length() == 1.
|
||||
MOZ_ASSERT(mChildren.Length() <= 1);
|
||||
mChildren.RemoveElement(aChildDoc);
|
||||
if (mChildren.RemoveElement(aChildDoc)) {
|
||||
mOuterDoc = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
|
|
|
@ -193,18 +193,17 @@ ProxyAccessible::Description(nsString& aDesc) const
|
|||
uint64_t
|
||||
ProxyAccessible::State() const
|
||||
{
|
||||
uint64_t state = 0;
|
||||
RefPtr<IAccessible> acc;
|
||||
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
|
||||
return state;
|
||||
RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
|
||||
if (!custom) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VARIANT varState;
|
||||
HRESULT hr = acc->get_accState(kChildIdSelf, &varState);
|
||||
uint64_t state;
|
||||
HRESULT hr = custom->get_mozState(&state);
|
||||
if (FAILED(hr)) {
|
||||
return state;
|
||||
return 0;
|
||||
}
|
||||
return uint64_t(varState.lVal);
|
||||
return state;
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -50,3 +50,10 @@ GeckoCustom::get_minimumIncrement(double* aIncrement)
|
|||
*aIncrement = mAcc->Step();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GeckoCustom::get_mozState(uint64_t* aState)
|
||||
{
|
||||
*aState = mAcc->State();
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
virtual STDMETHODIMP get_DOMNodeID(BSTR* aID);
|
||||
virtual STDMETHODIMP get_ID(uint64_t* aID);
|
||||
virtual STDMETHODIMP get_minimumIncrement(double* aIncrement);
|
||||
virtual STDMETHODIMP get_mozState(uint64_t* aState);
|
||||
|
||||
private:
|
||||
GeckoCustom() = delete;
|
||||
|
|
|
@ -233,8 +233,7 @@ DEFAULT_TEST_PREFS = {
|
|||
# Disable useragent updates.
|
||||
'general.useragent.updates.enabled': False,
|
||||
'media.eme.enabled': True,
|
||||
'media.eme.apiVisible': True,
|
||||
# Don't forceably kill content processes after a timeout
|
||||
# Don't forcibly kill content processes after a timeout
|
||||
'dom.ipc.tabs.shutdownTimeoutSecs': 0,
|
||||
'general.useragent.locale': "en-US",
|
||||
'intl.locale.matchOS': "en-US",
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
"browser.download.panel.shown": true,
|
||||
"general.useragent.updates.enabled": false,
|
||||
"media.eme.enabled": true,
|
||||
"media.eme.apiVisible": true,
|
||||
"dom.ipc.tabs.shutdownTimeoutSecs": 0,
|
||||
"general.useragent.locale": "en-US",
|
||||
"intl.locale.matchOS": "en-US",
|
||||
|
|
|
@ -324,7 +324,6 @@ pref("media.gonk.enabled", true);
|
|||
|
||||
//Encrypted media extensions.
|
||||
pref("media.eme.enabled", true);
|
||||
pref("media.eme.apiVisible", true);
|
||||
// The default number of decoded video frames that are enqueued in
|
||||
// MediaDecoderReader's mVideoQueue.
|
||||
pref("media.video-queue.default-size", 3);
|
||||
|
|
|
@ -498,8 +498,6 @@
|
|||
@RESPATH@/components/formautofill.manifest
|
||||
@RESPATH@/components/FormAutofillContentService.js
|
||||
@RESPATH@/components/FormAutofillStartup.js
|
||||
@RESPATH@/components/CSSUnprefixingService.js
|
||||
@RESPATH@/components/CSSUnprefixingService.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.js
|
||||
@RESPATH@/components/messageWakeupService.js
|
||||
|
|
|
@ -534,7 +534,8 @@ pref("privacy.sanitize.migrateFx3Prefs", false);
|
|||
|
||||
pref("privacy.panicButton.enabled", true);
|
||||
|
||||
pref("privacy.firstparty.isolate", false);
|
||||
pref("privacy.firstparty.isolate", false);
|
||||
pref("privacy.firstparty.isolate.restrict_opener_access", true);
|
||||
|
||||
// Time until temporary permissions expire, in ms
|
||||
pref("privacy.temporary_permission_expire_time_ms", 3600000);
|
||||
|
@ -1375,7 +1376,6 @@ pref("media.eme.enabled", false);
|
|||
#else
|
||||
pref("media.eme.enabled", true);
|
||||
#endif
|
||||
pref("media.eme.apiVisible", true);
|
||||
|
||||
// Whether we should run a test-pattern through EME GMPs before assuming they'll
|
||||
// decode H.264.
|
||||
|
|
|
@ -3400,8 +3400,10 @@ var PrintPreviewListener = {
|
|||
return gBrowser.getBrowserForTab(this._printPreviewTab);
|
||||
},
|
||||
createSimplifiedBrowser() {
|
||||
let browser = this._tabBeforePrintPreview.linkedBrowser;
|
||||
this._simplifyPageTab = gBrowser.loadOneTab("about:blank",
|
||||
{ inBackground: true });
|
||||
{ inBackground: true,
|
||||
relatedBrowser: browser });
|
||||
return this.getSimplifiedSourceBrowser();
|
||||
},
|
||||
getSourceBrowser() {
|
||||
|
|
|
@ -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) {}
|
||||
},
|
||||
|
||||
|
|
|
@ -7109,14 +7109,6 @@
|
|||
this.removeAttribute("blocked");
|
||||
modifiedAttrs.push("blocked");
|
||||
|
||||
// We don't want sound icon flickering between "blocked", "none" and
|
||||
// "sound-playing", here adding the "soundplaying" is to keep the
|
||||
// transition smoothly.
|
||||
if (!this.hasAttribute("soundplaying")) {
|
||||
this.setAttribute("soundplaying", true);
|
||||
modifiedAttrs.push("soundplaying");
|
||||
}
|
||||
|
||||
browser.resumeMedia();
|
||||
hist.add(3 /* unblockByClickingIcon */);
|
||||
this.finishMediaBlockTimer();
|
||||
|
|
|
@ -81,11 +81,19 @@ const PAGECONTENT_TRANSLATED =
|
|||
"</div></body></html>";
|
||||
|
||||
const PAGECONTENT_COLORS =
|
||||
"<html><head><style>.blue { color: #fff; background-color: #00f; } .green { color: #800080; background-color: green; }</style>" +
|
||||
"<html><head><style>" +
|
||||
" .blue { color: #fff; background-color: #00f; }" +
|
||||
" .green { color: #800080; background-color: green; }" +
|
||||
" .defaultColor { color: -moz-ComboboxText; }" +
|
||||
" .defaultBackground { background-color: -moz-Combobox; }" +
|
||||
"</style>" +
|
||||
"<body><select id='one'>" +
|
||||
' <option value="One" style="color: #fff; background-color: #f00;">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(255, 0, 0)"}</option>' +
|
||||
' <option value="Two" class="blue">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 255)"}</option>' +
|
||||
' <option value="Three" class="green">{"color": "rgb(128, 0, 128)", "backgroundColor": "rgb(0, 128, 0)"}</option>' +
|
||||
' <option value="Four" class="defaultColor defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "transparent", "unstyled": "true"}</option>' +
|
||||
' <option value="Five" class="defaultColor">{"color": "-moz-ComboboxText", "backgroundColor": "transparent", "unstyled": "true"}</option>' +
|
||||
' <option value="Six" class="defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "transparent", "unstyled": "true"}</option>' +
|
||||
"</select></body></html>";
|
||||
|
||||
function openSelectPopup(selectPopup, mode = "key", selector = "select", win = window) {
|
||||
|
@ -738,11 +746,6 @@ add_task(function* test_somehidden() {
|
|||
});
|
||||
|
||||
add_task(function* test_colors_applied_to_popup() {
|
||||
function inverseRGBString(rgbString) {
|
||||
let [, r, g, b] = rgbString.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||
return `rgb(${255 - r}, ${255 - g}, ${255 - b})`;
|
||||
}
|
||||
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_COLORS);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
||||
|
@ -754,62 +757,39 @@ add_task(function* test_colors_applied_to_popup() {
|
|||
|
||||
// The label contains a JSON string of the expected colors for
|
||||
// `color` and `background-color`.
|
||||
is(selectPopup.parentNode.itemCount, 3, "Correct number of items");
|
||||
is(selectPopup.parentNode.itemCount, 6, "Correct number of items");
|
||||
let child = selectPopup.firstChild;
|
||||
let idx = 1;
|
||||
|
||||
ok(child.selected, "The first child should be selected");
|
||||
while (child) {
|
||||
let expectedColors = JSON.parse(child.label);
|
||||
let expected = JSON.parse(child.label);
|
||||
|
||||
// We need to use Canvas here to get the actual pixel color
|
||||
// because the computedStyle will only tell us the 'color' or
|
||||
// 'backgroundColor' of the element, but not what the displayed
|
||||
// color is due to composition of various CSS rules such as
|
||||
// 'filter' which is applied when elements have custom background
|
||||
// or foreground elements.
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas = document.documentElement.appendChild(canvas);
|
||||
let rect = child.getBoundingClientRect();
|
||||
canvas.setAttribute("width", rect.width);
|
||||
canvas.setAttribute("height", rect.height);
|
||||
canvas.mozOpaque = true;
|
||||
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawWindow(window, rect.x + rect.left, rect.y + rect.top, rect.width, rect.height, "#000", ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
|
||||
let frame = ctx.getImageData(0, 0, rect.width, rect.height);
|
||||
|
||||
let pixels = frame.data.length / 4;
|
||||
// Assume the inverse backgroundColor is the color of the first pixel.
|
||||
let [inverseBgR, inverseBgG, inverseBgB] = frame.data;
|
||||
let inverseBackgroundColor = `rgb(${inverseBgR}, ${inverseBgG}, ${inverseBgB})`;
|
||||
// Use the next different pixel color as the foreground color, assuming
|
||||
// no anti-aliasing.
|
||||
let inverseColor = inverseBackgroundColor;
|
||||
for (let i = 0; i < pixels; i++) {
|
||||
if (inverseBgR != frame.data[i * 4 + 0] &&
|
||||
inverseBgG != frame.data[i * 4 + 1] &&
|
||||
inverseBgB != frame.data[i * 4 + 2]) {
|
||||
inverseColor = `rgb(${frame.data[i * 4 + 0]}, ${frame.data[i * 4 + 1]}, ${frame.data[i * 4 + 2]})`;
|
||||
for (let color of Object.keys(expected)) {
|
||||
if (color.toLowerCase().includes("color") &&
|
||||
!expected[color].startsWith("rgb")) {
|
||||
// Need to convert system color to RGB color.
|
||||
let textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
|
||||
textarea.style.color = expected[color];
|
||||
expected[color] = getComputedStyle(textarea).color;
|
||||
}
|
||||
}
|
||||
// The canvas code above isn't getting the right colors for the pixels,
|
||||
// it always returns rgb(255,255,255).
|
||||
todo_is(inverseColor, inverseRGBString(getComputedStyle(child).color),
|
||||
"Item " + (idx) + " has correct inverse foreground color when selected");
|
||||
todo_is(inverseBackgroundColor, inverseRGBString(getComputedStyle(child).backgroundColor),
|
||||
"Item " + (idx) + " has correct inverse background color when selected");
|
||||
|
||||
canvas.remove();
|
||||
|
||||
// Press Down to move the selected item to the next item in the
|
||||
// list and check the colors of this item when it's not selected.
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
|
||||
is(getComputedStyle(child).color, expectedColors.color,
|
||||
"Item " + (idx) + " has correct foreground color");
|
||||
is(getComputedStyle(child).backgroundColor, expectedColors.backgroundColor,
|
||||
"Item " + (idx++) + " has correct background color");
|
||||
if (expected.unstyled) {
|
||||
ok(!child.hasAttribute("customoptionstyling"),
|
||||
`Item ${idx} should not have any custom option styling`);
|
||||
} else {
|
||||
is(getComputedStyle(child).color, expected.color,
|
||||
"Item " + (idx) + " has correct foreground color");
|
||||
is(getComputedStyle(child).backgroundColor, expected.backgroundColor,
|
||||
"Item " + (idx) + " has correct background color");
|
||||
}
|
||||
|
||||
idx++;
|
||||
child = child.nextSibling;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ add_task(function* setup() {
|
|||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.eme.apiVisible", true ],
|
||||
[ "media.mediasource.webm.enabled", true ],
|
||||
[ "media.clearkey.persistent-license.enabled", true ],
|
||||
]});
|
||||
|
|
|
@ -179,7 +179,6 @@ add_task(function* setup() {
|
|||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.eme.apiVisible", true ],
|
||||
[ "media.mediasource.webm.enabled", true ],
|
||||
[ "media.clearkey.persistent-license.enabled", true ],
|
||||
]});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,7 +11,7 @@ const Cu = Components.utils;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel",
|
||||
"resource:///modules/sessionstore/PrivacyLevel.jsm");
|
||||
"resource://gre/modules/sessionstore/PrivacyLevel.jsm");
|
||||
|
||||
/**
|
||||
* A module that provides methods to filter various kinds of data collected
|
||||
|
|
|
@ -15,7 +15,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel",
|
||||
"resource:///modules/sessionstore/PrivacyLevel.jsm");
|
||||
"resource://gre/modules/sessionstore/PrivacyLevel.jsm");
|
||||
|
||||
// MAX_EXPIRY should be 2^63-1, but JavaScript can't handle that precision.
|
||||
const MAX_EXPIRY = Math.pow(2, 62);
|
||||
|
|
|
@ -29,7 +29,6 @@ EXTRA_JS_MODULES.sessionstore = [
|
|||
'GlobalState.jsm',
|
||||
'PageStyle.jsm',
|
||||
'PrivacyFilter.jsm',
|
||||
'PrivacyLevel.jsm',
|
||||
'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
|
||||
'RunState.jsm',
|
||||
'SessionCookies.jsm',
|
||||
|
|
|
@ -2,6 +2,24 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
|||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
# The toolchain installed on our OSX 10.7 build machines is too old to support
|
||||
# MachO LC_DATA_IN_CODE load command, which newer LLVM generates, so we need to
|
||||
# use a newer toolchain that we build.
|
||||
#
|
||||
# Unfortunately setting $PATH is not enough, because the build system hardcodes
|
||||
# the default values for some of the build tools, which we also need to
|
||||
# override below. The default value for host ar and host ranlib is also
|
||||
# hardcoded so we need to override those separately.
|
||||
CCTOOLS_DIR="$topsrcdir/cctools/bin"
|
||||
export PATH="$CCTOOLS_DIR:$PATH"
|
||||
export AR="$CCTOOLS_DIR/ar"
|
||||
export HOST_AR="$CCTOOLS_DIR/ar"
|
||||
export RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export HOST_RANLIB="$CCTOOLS_DIR/ranlib"
|
||||
export LIPO="$CCTOOLS_DIR/lipo"
|
||||
export OTOOL="$CCTOOLS_DIR/otool"
|
||||
export STRIP="$CCTOOLS_DIR/strip"
|
||||
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-debug
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
[
|
||||
{
|
||||
"version": "clang 3.8.0",
|
||||
"size": 133060926,
|
||||
"digest": "aff5ad3ac2d41db19d1ba0df5f97b189a7d7e1b6af8c56e22c2b0cced84d75fa98394ded6a4ba5713652e6684a0a46f47aeccf87991f9e849bf8d7d82e564f6f",
|
||||
"version": "clang 3.9.0",
|
||||
"size": 184678304,
|
||||
"digest": "cfde9a0f7f59823200f94422b4adb9a2fb5d4d07f240bbd1142c792434f6a1cbb4096d25c9853d77008fc40db0d827daa7003e78016f51241f621d6040ccc635",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -25,9 +25,9 @@
|
|||
"size": 1143715
|
||||
},
|
||||
{
|
||||
"version": "cctools port from commit hash db1f8d906cb28, ld only",
|
||||
"size": 634496,
|
||||
"digest": "037f31fcf29e7bb7fada0d2bdd5e95c7d4cb2692f2a5c98ed6f6a7561b9d81622d015f0d12b291d3667719655f1369e8ce8a0a4a4773aa0ee4753e04a8821173",
|
||||
"version": "cctools port from commit hash 84ce22dbb22a26ce7f392e9de0ee39c2efe6fd68",
|
||||
"size": 2174783,
|
||||
"digest": "8678348faff8f344b377075007975ae77a55a2a73488e36950a43c8ec27a79970cd8e34003e33e756a57d9cbf5c3e2e4461184102c6c03f793377a4d250a7f24",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cctools.tar.bz2",
|
||||
"unpack": true
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 3008804,
|
||||
"size": 1349196,
|
||||
"visibility": "public",
|
||||
"digest": "ba6937f14f3d8b26dcb2d39490dee6b0a8afb60f672f5debb71d7b62c1ec52103201b4b1a3d258f945567de531384b36ddb2ce4aa73dc63d72305b11c146847c",
|
||||
"digest": "438a36523a74cbc4a58226647e0501fa64a1b63f32931dc364a75d699df8accb45afdf26f4cb61c6ac7f58be530205acb6da22008bec19603c6f6fda3a12a8cc",
|
||||
"algorithm": "sha512",
|
||||
"unpack": true,
|
||||
"filename": "cctools.tar.gz"
|
||||
"filename": "cctools.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 30823112,
|
||||
|
|
|
@ -14,11 +14,13 @@ Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
|||
const TEST_THRESHOLD = {
|
||||
"beta" : 0.5, // 50%
|
||||
"release" : 1.0, // 100%
|
||||
"esr" : 1.0, // 100%
|
||||
};
|
||||
|
||||
const ADDON_ROLLOUT_POLICY = {
|
||||
"beta" : "51alladdons", // Any WebExtension or addon except with mpc = false
|
||||
"release" : "51set1",
|
||||
"esr" : "esrA", // WebExtensions and Addons with mpc=true
|
||||
};
|
||||
|
||||
const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample";
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>e10srollout@mozilla.org</em:id>
|
||||
<em:version>1.8</em:version>
|
||||
<em:version>1.9</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.7.235
|
||||
Current extension version is: 1.7.242
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
}
|
||||
}(this, function (exports) {
|
||||
'use strict';
|
||||
var pdfjsVersion = '1.7.235';
|
||||
var pdfjsBuild = '3f320f0b';
|
||||
var pdfjsVersion = '1.7.242';
|
||||
var pdfjsBuild = '6f0cf8c4';
|
||||
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
|
||||
var pdfjsLibs = {};
|
||||
(function pdfjsWrapper() {
|
||||
|
@ -1788,6 +1788,7 @@
|
|||
}(this, function (exports, sharedUtil, displayDOMUtils) {
|
||||
var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType;
|
||||
var AnnotationType = sharedUtil.AnnotationType;
|
||||
var stringToPDFString = sharedUtil.stringToPDFString;
|
||||
var Util = sharedUtil.Util;
|
||||
var addLinkAttributes = displayDOMUtils.addLinkAttributes;
|
||||
var LinkTarget = displayDOMUtils.LinkTarget;
|
||||
|
@ -2330,8 +2331,14 @@
|
|||
var FileAttachmentAnnotationElement = function FileAttachmentAnnotationElementClosure() {
|
||||
function FileAttachmentAnnotationElement(parameters) {
|
||||
AnnotationElement.call(this, parameters, true);
|
||||
this.filename = getFilenameFromUrl(parameters.data.file.filename);
|
||||
this.content = parameters.data.file.content;
|
||||
var file = this.data.file;
|
||||
this.filename = getFilenameFromUrl(file.filename);
|
||||
this.content = file.content;
|
||||
this.linkService.onFileAttachmentAnnotation({
|
||||
id: stringToPDFString(file.filename),
|
||||
filename: file.filename,
|
||||
content: file.content
|
||||
});
|
||||
}
|
||||
Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {
|
||||
render: function FileAttachmentAnnotationElement_render() {
|
||||
|
@ -2365,7 +2372,7 @@
|
|||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
var properties = {
|
||||
var element = annotationElementFactory.create({
|
||||
data: data,
|
||||
layer: parameters.div,
|
||||
page: parameters.page,
|
||||
|
@ -2374,8 +2381,7 @@
|
|||
downloadManager: parameters.downloadManager,
|
||||
imageResourcesPath: parameters.imageResourcesPath || getDefaultSetting('imageResourcesPath'),
|
||||
renderInteractiveForms: parameters.renderInteractiveForms || false
|
||||
};
|
||||
var element = annotationElementFactory.create(properties);
|
||||
});
|
||||
if (element.isRenderable) {
|
||||
parameters.div.appendChild(element.render());
|
||||
}
|
||||
|
@ -5565,7 +5571,6 @@
|
|||
var MessageHandler = sharedUtil.MessageHandler;
|
||||
var MissingPDFException = sharedUtil.MissingPDFException;
|
||||
var PageViewport = sharedUtil.PageViewport;
|
||||
var PasswordResponses = sharedUtil.PasswordResponses;
|
||||
var PasswordException = sharedUtil.PasswordException;
|
||||
var StatTimer = sharedUtil.StatTimer;
|
||||
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
|
||||
|
@ -6978,6 +6983,7 @@
|
|||
exports.renderTextLayer = pdfjsLibs.pdfjsDisplayTextLayer.renderTextLayer;
|
||||
exports.AnnotationLayer = pdfjsLibs.pdfjsDisplayAnnotationLayer.AnnotationLayer;
|
||||
exports.CustomStyle = pdfjsLibs.pdfjsDisplayDOMUtils.CustomStyle;
|
||||
exports.createPromiseCapability = pdfjsLibs.pdfjsSharedUtil.createPromiseCapability;
|
||||
exports.PasswordResponses = pdfjsLibs.pdfjsSharedUtil.PasswordResponses;
|
||||
exports.InvalidPDFException = pdfjsLibs.pdfjsSharedUtil.InvalidPDFException;
|
||||
exports.MissingPDFException = pdfjsLibs.pdfjsSharedUtil.MissingPDFException;
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
}
|
||||
}(this, function (exports) {
|
||||
'use strict';
|
||||
var pdfjsVersion = '1.7.235';
|
||||
var pdfjsBuild = '3f320f0b';
|
||||
var pdfjsVersion = '1.7.242';
|
||||
var pdfjsBuild = '6f0cf8c4';
|
||||
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
|
||||
var pdfjsLibs = {};
|
||||
(function pdfjsWrapper() {
|
||||
|
@ -6080,7 +6080,6 @@
|
|||
var encoding = Object.create(null);
|
||||
var bytes = this.bytes;
|
||||
var predefined = false;
|
||||
var hasSupplement = false;
|
||||
var format, i, ii;
|
||||
var raw = null;
|
||||
function readSupplement() {
|
||||
|
@ -6130,7 +6129,6 @@
|
|||
if (format & 0x80) {
|
||||
bytes[dataStart] &= 0x7f;
|
||||
readSupplement();
|
||||
hasSupplement = true;
|
||||
}
|
||||
raw = bytes.subarray(dataStart, dataEnd);
|
||||
}
|
||||
|
@ -7444,8 +7442,7 @@
|
|||
subStream.end = start + length || this.end;
|
||||
subStream.dict = dict;
|
||||
return subStream;
|
||||
},
|
||||
isStream: true
|
||||
}
|
||||
};
|
||||
return ChunkedStream;
|
||||
}();
|
||||
|
@ -12848,14 +12845,12 @@
|
|||
var deltaHeight = decodeInteger(contextCache, 'IADH', decoder);
|
||||
currentHeight += deltaHeight;
|
||||
var currentWidth = 0;
|
||||
var totalWidth = 0;
|
||||
while (true) {
|
||||
var deltaWidth = decodeInteger(contextCache, 'IADW', decoder);
|
||||
if (deltaWidth === null) {
|
||||
break;
|
||||
}
|
||||
currentWidth += deltaWidth;
|
||||
totalWidth += currentWidth;
|
||||
var bitmap;
|
||||
if (refinement) {
|
||||
var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
|
||||
|
@ -13265,7 +13260,7 @@
|
|||
delete pageInfo.height;
|
||||
}
|
||||
var pageSegmentFlags = data[position + 16];
|
||||
var pageStripingInformation = readUint16(data, position + 17);
|
||||
readUint16(data, position + 17);
|
||||
pageInfo.lossless = !!(pageSegmentFlags & 1);
|
||||
pageInfo.refinement = !!(pageSegmentFlags & 2);
|
||||
pageInfo.defaultPixelValue = pageSegmentFlags >> 2 & 1;
|
||||
|
@ -13308,7 +13303,7 @@
|
|||
header.numberOfPages = readUint32(data, position);
|
||||
position += 4;
|
||||
}
|
||||
var segments = readSegments(header, data, position, end);
|
||||
readSegments(header, data, position, end);
|
||||
error('Not implemented');
|
||||
}
|
||||
function parseJbig2Chunks(chunks) {
|
||||
|
@ -14145,7 +14140,7 @@
|
|||
resetInterval = readUint16();
|
||||
break;
|
||||
case 0xFFDA:
|
||||
var scanLength = readUint16();
|
||||
readUint16();
|
||||
var selectorsCount = data[offset++];
|
||||
var components = [], component;
|
||||
for (i = 0; i < selectorsCount; i++) {
|
||||
|
@ -22560,7 +22555,6 @@
|
|||
var isArray = sharedUtil.isArray;
|
||||
var createObjectURL = sharedUtil.createObjectURL;
|
||||
var shadow = sharedUtil.shadow;
|
||||
var warn = sharedUtil.warn;
|
||||
var isSpace = sharedUtil.isSpace;
|
||||
var Dict = corePrimitives.Dict;
|
||||
var isDict = corePrimitives.isDict;
|
||||
|
@ -22642,8 +22636,7 @@
|
|||
},
|
||||
makeSubStream: function Stream_makeSubStream(start, length, dict) {
|
||||
return new Stream(this.bytes.buffer, start, length, dict);
|
||||
},
|
||||
isStream: true
|
||||
}
|
||||
};
|
||||
return Stream;
|
||||
}();
|
||||
|
@ -31220,264 +31213,6 @@
|
|||
return AES128Cipher;
|
||||
}();
|
||||
var AES256Cipher = function AES256CipherClosure() {
|
||||
var rcon = new Uint8Array([
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d,
|
||||
0x01,
|
||||
0x02,
|
||||
0x04,
|
||||
0x08,
|
||||
0x10,
|
||||
0x20,
|
||||
0x40,
|
||||
0x80,
|
||||
0x1b,
|
||||
0x36,
|
||||
0x6c,
|
||||
0xd8,
|
||||
0xab,
|
||||
0x4d,
|
||||
0x9a,
|
||||
0x2f,
|
||||
0x5e,
|
||||
0xbc,
|
||||
0x63,
|
||||
0xc6,
|
||||
0x97,
|
||||
0x35,
|
||||
0x6a,
|
||||
0xd4,
|
||||
0xb3,
|
||||
0x7d,
|
||||
0xfa,
|
||||
0xef,
|
||||
0xc5,
|
||||
0x91,
|
||||
0x39,
|
||||
0x72,
|
||||
0xe4,
|
||||
0xd3,
|
||||
0xbd,
|
||||
0x61,
|
||||
0xc2,
|
||||
0x9f,
|
||||
0x25,
|
||||
0x4a,
|
||||
0x94,
|
||||
0x33,
|
||||
0x66,
|
||||
0xcc,
|
||||
0x83,
|
||||
0x1d,
|
||||
0x3a,
|
||||
0x74,
|
||||
0xe8,
|
||||
0xcb,
|
||||
0x8d
|
||||
]);
|
||||
var s = new Uint8Array([
|
||||
0x63,
|
||||
0x7c,
|
||||
|
@ -33036,9 +32771,9 @@
|
|||
function parseCmap(data, start, end) {
|
||||
var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16);
|
||||
var format = getUshort(data, start + offset);
|
||||
var length, ranges, p, i;
|
||||
var ranges, p, i;
|
||||
if (format === 4) {
|
||||
length = getUshort(data, start + offset + 2);
|
||||
getUshort(data, start + offset + 2);
|
||||
var segCount = getUshort(data, start + offset + 6) >> 1;
|
||||
p = start + offset + 14;
|
||||
ranges = [];
|
||||
|
@ -33065,7 +32800,7 @@
|
|||
}
|
||||
return ranges;
|
||||
} else if (format === 12) {
|
||||
length = getLong(data, start + offset + 4);
|
||||
getLong(data, start + offset + 4);
|
||||
var groups = getLong(data, start + offset + 12);
|
||||
p = start + offset + 16;
|
||||
ranges = [];
|
||||
|
@ -36162,7 +35897,7 @@
|
|||
error = true;
|
||||
break;
|
||||
}
|
||||
var wy = this.stack.pop();
|
||||
this.stack.pop();
|
||||
wx = this.stack.pop();
|
||||
var sby = this.stack.pop();
|
||||
sbx = this.stack.pop();
|
||||
|
@ -36414,7 +36149,7 @@
|
|||
}
|
||||
break;
|
||||
case 'Subrs':
|
||||
var num = this.readInt();
|
||||
this.readInt();
|
||||
this.getToken();
|
||||
while ((token = this.getToken()) === 'dup') {
|
||||
var index = this.readInt();
|
||||
|
@ -39067,9 +38802,6 @@
|
|||
this.sizes = [];
|
||||
this.missingFile = false;
|
||||
this.glyphCache = Object.create(null);
|
||||
var names = name.split('+');
|
||||
names = names.length > 1 ? names[1] : names[0];
|
||||
names = names.split(/[-,_]/g)[0];
|
||||
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
|
||||
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
|
||||
this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
|
||||
|
@ -39657,7 +39389,7 @@
|
|||
var segment;
|
||||
var start = (font.start ? font.start : 0) + cmap.offset;
|
||||
font.pos = start;
|
||||
var version = font.getUint16();
|
||||
font.getUint16();
|
||||
var numTables = font.getUint16();
|
||||
var potentialTable;
|
||||
var canBreak = false;
|
||||
|
@ -39703,8 +39435,8 @@
|
|||
};
|
||||
}
|
||||
var format = font.getUint16();
|
||||
var length = font.getUint16();
|
||||
var language = font.getUint16();
|
||||
font.getUint16();
|
||||
font.getUint16();
|
||||
var hasShortCmap = false;
|
||||
var mappings = [];
|
||||
var j, glyphId;
|
||||
|
@ -45192,22 +44924,11 @@
|
|||
var width = 0;
|
||||
var height = 0;
|
||||
var glyphs = font.charsToGlyphs(chars);
|
||||
var defaultVMetrics = font.defaultVMetrics;
|
||||
for (var i = 0; i < glyphs.length; i++) {
|
||||
var glyph = glyphs[i];
|
||||
var vMetricX = null;
|
||||
var vMetricY = null;
|
||||
var glyphWidth = null;
|
||||
if (font.vertical) {
|
||||
if (glyph.vmetric) {
|
||||
glyphWidth = glyph.vmetric[0];
|
||||
vMetricX = glyph.vmetric[1];
|
||||
vMetricY = glyph.vmetric[2];
|
||||
} else {
|
||||
glyphWidth = glyph.width;
|
||||
vMetricX = glyph.width * 0.5;
|
||||
vMetricY = defaultVMetrics[2];
|
||||
}
|
||||
if (font.vertical && glyph.vmetric) {
|
||||
glyphWidth = glyph.vmetric[0];
|
||||
} else {
|
||||
glyphWidth = glyph.width;
|
||||
}
|
||||
|
@ -47120,7 +46841,6 @@
|
|||
var AnnotationType = sharedUtil.AnnotationType;
|
||||
var OPS = sharedUtil.OPS;
|
||||
var Util = sharedUtil.Util;
|
||||
var isString = sharedUtil.isString;
|
||||
var isArray = sharedUtil.isArray;
|
||||
var isInt = sharedUtil.isInt;
|
||||
var stringToBytes = sharedUtil.stringToBytes;
|
||||
|
@ -48473,7 +48193,6 @@
|
|||
var MissingPDFException = sharedUtil.MissingPDFException;
|
||||
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
|
||||
var PasswordException = sharedUtil.PasswordException;
|
||||
var PasswordResponses = sharedUtil.PasswordResponses;
|
||||
var UnknownErrorException = sharedUtil.UnknownErrorException;
|
||||
var XRefParseException = sharedUtil.XRefParseException;
|
||||
var arrayByteLength = sharedUtil.arrayByteLength;
|
||||
|
@ -48739,7 +48458,7 @@
|
|||
var xhr = new XMLHttpRequest();
|
||||
var responseExists = 'response' in xhr;
|
||||
try {
|
||||
var dummy = xhr.responseType;
|
||||
xhr.responseType;
|
||||
} catch (e) {
|
||||
responseExists = false;
|
||||
}
|
||||
|
|
|
@ -1084,6 +1084,24 @@ html[dir="rtl"] #viewOutline.toolbarButton::before {
|
|||
content: url(images/toolbarButton-search.png);
|
||||
}
|
||||
|
||||
.toolbarButton.pdfSidebarNotification::after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 1px;
|
||||
/* Create a filled circle, with a diameter of 9 pixels, using only CSS: */
|
||||
content: '';
|
||||
background-color: #70DB55;
|
||||
height: 9px;
|
||||
width: 9px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
html[dir='ltr'] .toolbarButton.pdfSidebarNotification::after {
|
||||
left: 17px;
|
||||
}
|
||||
html[dir='rtl'] .toolbarButton.pdfSidebarNotification::after {
|
||||
right: 17px;
|
||||
}
|
||||
|
||||
.secondaryToolbarButton {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
|
|
|
@ -561,20 +561,26 @@ var pdfjsWebLibs;
|
|||
this.container = options.container;
|
||||
this.eventBus = options.eventBus;
|
||||
this.downloadManager = options.downloadManager;
|
||||
this._renderedCapability = pdfjsLib.createPromiseCapability();
|
||||
this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this));
|
||||
}
|
||||
PDFAttachmentViewer.prototype = {
|
||||
reset: function PDFAttachmentViewer_reset() {
|
||||
reset: function PDFAttachmentViewer_reset(keepRenderedCapability) {
|
||||
this.attachments = null;
|
||||
var container = this.container;
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
if (!keepRenderedCapability) {
|
||||
this._renderedCapability = pdfjsLib.createPromiseCapability();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
|
||||
this.eventBus.dispatch('attachmentsloaded', {
|
||||
source: this,
|
||||
attachmentsCount: attachmentsCount
|
||||
});
|
||||
this._renderedCapability.resolve();
|
||||
},
|
||||
_bindLink: function PDFAttachmentViewer_bindLink(button, content, filename) {
|
||||
button.onclick = function downloadFile(e) {
|
||||
|
@ -583,10 +589,12 @@ var pdfjsWebLibs;
|
|||
}.bind(this);
|
||||
},
|
||||
render: function PDFAttachmentViewer_render(params) {
|
||||
var attachments = params && params.attachments || null;
|
||||
params = params || {};
|
||||
var attachments = params.attachments || null;
|
||||
var attachmentsCount = 0;
|
||||
if (this.attachments) {
|
||||
this.reset();
|
||||
var keepRenderedCapability = params.keepRenderedCapability === true;
|
||||
this.reset(keepRenderedCapability);
|
||||
}
|
||||
this.attachments = attachments;
|
||||
if (!attachments) {
|
||||
|
@ -609,6 +617,28 @@ var pdfjsWebLibs;
|
|||
this.container.appendChild(div);
|
||||
}
|
||||
this._dispatchEvent(attachmentsCount);
|
||||
},
|
||||
_appendAttachment: function PDFAttachmentViewer_appendAttachment(item) {
|
||||
this._renderedCapability.promise.then(function (id, filename, content) {
|
||||
var attachments = this.attachments;
|
||||
if (!attachments) {
|
||||
attachments = Object.create(null);
|
||||
} else {
|
||||
for (var name in attachments) {
|
||||
if (id === name) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
attachments[id] = {
|
||||
filename: filename,
|
||||
content: content
|
||||
};
|
||||
this.render({
|
||||
attachments: attachments,
|
||||
keepRenderedCapability: true
|
||||
});
|
||||
}.bind(this, item.id, item.filename, item.content));
|
||||
}
|
||||
};
|
||||
return PDFAttachmentViewer;
|
||||
|
@ -752,234 +782,6 @@ var pdfjsWebLibs;
|
|||
}();
|
||||
exports.PDFOutlineViewer = PDFOutlineViewer;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFSidebar = {}, root.pdfjsWebPDFRenderingQueue);
|
||||
}(this, function (exports, pdfRenderingQueue) {
|
||||
var RenderingStates = pdfRenderingQueue.RenderingStates;
|
||||
var SidebarView = {
|
||||
NONE: 0,
|
||||
THUMBS: 1,
|
||||
OUTLINE: 2,
|
||||
ATTACHMENTS: 3
|
||||
};
|
||||
var PDFSidebar = function PDFSidebarClosure() {
|
||||
function PDFSidebar(options) {
|
||||
this.isOpen = false;
|
||||
this.active = SidebarView.THUMBS;
|
||||
this.isInitialViewSet = false;
|
||||
this.onToggled = null;
|
||||
this.pdfViewer = options.pdfViewer;
|
||||
this.pdfThumbnailViewer = options.pdfThumbnailViewer;
|
||||
this.pdfOutlineViewer = options.pdfOutlineViewer;
|
||||
this.mainContainer = options.mainContainer;
|
||||
this.outerContainer = options.outerContainer;
|
||||
this.eventBus = options.eventBus;
|
||||
this.toggleButton = options.toggleButton;
|
||||
this.thumbnailButton = options.thumbnailButton;
|
||||
this.outlineButton = options.outlineButton;
|
||||
this.attachmentsButton = options.attachmentsButton;
|
||||
this.thumbnailView = options.thumbnailView;
|
||||
this.outlineView = options.outlineView;
|
||||
this.attachmentsView = options.attachmentsView;
|
||||
this._addEventListeners();
|
||||
}
|
||||
PDFSidebar.prototype = {
|
||||
reset: function PDFSidebar_reset() {
|
||||
this.isInitialViewSet = false;
|
||||
this.close();
|
||||
this.switchView(SidebarView.THUMBS);
|
||||
this.outlineButton.disabled = false;
|
||||
this.attachmentsButton.disabled = false;
|
||||
},
|
||||
get visibleView() {
|
||||
return this.isOpen ? this.active : SidebarView.NONE;
|
||||
},
|
||||
get isThumbnailViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.THUMBS;
|
||||
},
|
||||
get isOutlineViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.OUTLINE;
|
||||
},
|
||||
get isAttachmentsViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.ATTACHMENTS;
|
||||
},
|
||||
setInitialView: function PDFSidebar_setInitialView(view) {
|
||||
if (this.isInitialViewSet) {
|
||||
return;
|
||||
}
|
||||
this.isInitialViewSet = true;
|
||||
if (this.isOpen && view === SidebarView.NONE) {
|
||||
this._dispatchEvent();
|
||||
return;
|
||||
}
|
||||
var isViewPreserved = view === this.visibleView;
|
||||
this.switchView(view, true);
|
||||
if (isViewPreserved) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
switchView: function PDFSidebar_switchView(view, forceOpen) {
|
||||
if (view === SidebarView.NONE) {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
var isViewChanged = view !== this.active;
|
||||
var shouldForceRendering = false;
|
||||
switch (view) {
|
||||
case SidebarView.THUMBS:
|
||||
this.thumbnailButton.classList.add('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.remove('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
if (this.isOpen && isViewChanged) {
|
||||
this._updateThumbnailViewer();
|
||||
shouldForceRendering = true;
|
||||
}
|
||||
break;
|
||||
case SidebarView.OUTLINE:
|
||||
if (this.outlineButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.add('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.remove('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
if (this.attachmentsButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.add('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.remove('hidden');
|
||||
break;
|
||||
default:
|
||||
console.error('PDFSidebar_switchView: "' + view + '" is an unsupported value.');
|
||||
return;
|
||||
}
|
||||
this.active = view | 0;
|
||||
if (forceOpen && !this.isOpen) {
|
||||
this.open();
|
||||
return;
|
||||
}
|
||||
if (shouldForceRendering) {
|
||||
this._forceRendering();
|
||||
}
|
||||
if (isViewChanged) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
open: function PDFSidebar_open() {
|
||||
if (this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.toggleButton.classList.add('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.add('sidebarOpen');
|
||||
if (this.active === SidebarView.THUMBS) {
|
||||
this._updateThumbnailViewer();
|
||||
}
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
close: function PDFSidebar_close() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.toggleButton.classList.remove('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.remove('sidebarOpen');
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
toggle: function PDFSidebar_toggle() {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFSidebar_dispatchEvent() {
|
||||
this.eventBus.dispatch('sidebarviewchanged', {
|
||||
source: this,
|
||||
view: this.visibleView
|
||||
});
|
||||
},
|
||||
_forceRendering: function PDFSidebar_forceRendering() {
|
||||
if (this.onToggled) {
|
||||
this.onToggled();
|
||||
} else {
|
||||
this.pdfViewer.forceRendering();
|
||||
this.pdfThumbnailViewer.forceRendering();
|
||||
}
|
||||
},
|
||||
_updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() {
|
||||
var pdfViewer = this.pdfViewer;
|
||||
var thumbnailViewer = this.pdfThumbnailViewer;
|
||||
var pagesCount = pdfViewer.pagesCount;
|
||||
for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
|
||||
var pageView = pdfViewer.getPageView(pageIndex);
|
||||
if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
|
||||
var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
|
||||
thumbnailView.setImage(pageView);
|
||||
}
|
||||
}
|
||||
thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
|
||||
},
|
||||
_addEventListeners: function PDFSidebar_addEventListeners() {
|
||||
var self = this;
|
||||
self.mainContainer.addEventListener('transitionend', function (evt) {
|
||||
if (evt.target === this) {
|
||||
self.outerContainer.classList.remove('sidebarMoving');
|
||||
}
|
||||
});
|
||||
self.thumbnailButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
});
|
||||
self.outlineButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.OUTLINE);
|
||||
});
|
||||
self.outlineButton.addEventListener('dblclick', function () {
|
||||
self.pdfOutlineViewer.toggleOutlineTree();
|
||||
});
|
||||
self.attachmentsButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.ATTACHMENTS);
|
||||
});
|
||||
self.eventBus.on('outlineloaded', function (e) {
|
||||
var outlineCount = e.outlineCount;
|
||||
self.outlineButton.disabled = !outlineCount;
|
||||
if (!outlineCount && self.active === SidebarView.OUTLINE) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('attachmentsloaded', function (e) {
|
||||
var attachmentsCount = e.attachmentsCount;
|
||||
self.attachmentsButton.disabled = !attachmentsCount;
|
||||
if (!attachmentsCount && self.active === SidebarView.ATTACHMENTS) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('presentationmodechanged', function (e) {
|
||||
if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) {
|
||||
self._updateThumbnailViewer();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return PDFSidebar;
|
||||
}();
|
||||
exports.SidebarView = SidebarView;
|
||||
exports.PDFSidebar = PDFSidebar;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebUIUtils = {}, root.pdfjsWebPDFJS);
|
||||
}(this, function (exports, pdfjsLib) {
|
||||
|
@ -2418,6 +2220,289 @@ var pdfjsWebLibs;
|
|||
}();
|
||||
exports.PDFPresentationMode = PDFPresentationMode;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFSidebar = {}, root.pdfjsWebPDFRenderingQueue, root.pdfjsWebUIUtils);
|
||||
}(this, function (exports, pdfRenderingQueue, uiUtils) {
|
||||
var RenderingStates = pdfRenderingQueue.RenderingStates;
|
||||
var mozL10n = uiUtils.mozL10n;
|
||||
var UI_NOTIFICATION_CLASS = 'pdfSidebarNotification';
|
||||
var SidebarView = {
|
||||
NONE: 0,
|
||||
THUMBS: 1,
|
||||
OUTLINE: 2,
|
||||
ATTACHMENTS: 3
|
||||
};
|
||||
var PDFSidebar = function PDFSidebarClosure() {
|
||||
function PDFSidebar(options) {
|
||||
this.isOpen = false;
|
||||
this.active = SidebarView.THUMBS;
|
||||
this.isInitialViewSet = false;
|
||||
this.onToggled = null;
|
||||
this.pdfViewer = options.pdfViewer;
|
||||
this.pdfThumbnailViewer = options.pdfThumbnailViewer;
|
||||
this.pdfOutlineViewer = options.pdfOutlineViewer;
|
||||
this.mainContainer = options.mainContainer;
|
||||
this.outerContainer = options.outerContainer;
|
||||
this.eventBus = options.eventBus;
|
||||
this.toggleButton = options.toggleButton;
|
||||
this.thumbnailButton = options.thumbnailButton;
|
||||
this.outlineButton = options.outlineButton;
|
||||
this.attachmentsButton = options.attachmentsButton;
|
||||
this.thumbnailView = options.thumbnailView;
|
||||
this.outlineView = options.outlineView;
|
||||
this.attachmentsView = options.attachmentsView;
|
||||
this.disableNotification = options.disableNotification || false;
|
||||
this._addEventListeners();
|
||||
}
|
||||
PDFSidebar.prototype = {
|
||||
reset: function PDFSidebar_reset() {
|
||||
this.isInitialViewSet = false;
|
||||
this._hideUINotification(null);
|
||||
this.switchView(SidebarView.THUMBS);
|
||||
this.outlineButton.disabled = false;
|
||||
this.attachmentsButton.disabled = false;
|
||||
},
|
||||
get visibleView() {
|
||||
return this.isOpen ? this.active : SidebarView.NONE;
|
||||
},
|
||||
get isThumbnailViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.THUMBS;
|
||||
},
|
||||
get isOutlineViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.OUTLINE;
|
||||
},
|
||||
get isAttachmentsViewVisible() {
|
||||
return this.isOpen && this.active === SidebarView.ATTACHMENTS;
|
||||
},
|
||||
setInitialView: function PDFSidebar_setInitialView(view) {
|
||||
if (this.isInitialViewSet) {
|
||||
return;
|
||||
}
|
||||
this.isInitialViewSet = true;
|
||||
if (this.isOpen && view === SidebarView.NONE) {
|
||||
this._dispatchEvent();
|
||||
return;
|
||||
}
|
||||
var isViewPreserved = view === this.visibleView;
|
||||
this.switchView(view, true);
|
||||
if (isViewPreserved) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
},
|
||||
switchView: function PDFSidebar_switchView(view, forceOpen) {
|
||||
if (view === SidebarView.NONE) {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
var isViewChanged = view !== this.active;
|
||||
var shouldForceRendering = false;
|
||||
switch (view) {
|
||||
case SidebarView.THUMBS:
|
||||
this.thumbnailButton.classList.add('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.remove('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
if (this.isOpen && isViewChanged) {
|
||||
this._updateThumbnailViewer();
|
||||
shouldForceRendering = true;
|
||||
}
|
||||
break;
|
||||
case SidebarView.OUTLINE:
|
||||
if (this.outlineButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.add('toggled');
|
||||
this.attachmentsButton.classList.remove('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.remove('hidden');
|
||||
this.attachmentsView.classList.add('hidden');
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
if (this.attachmentsButton.disabled) {
|
||||
return;
|
||||
}
|
||||
this.thumbnailButton.classList.remove('toggled');
|
||||
this.outlineButton.classList.remove('toggled');
|
||||
this.attachmentsButton.classList.add('toggled');
|
||||
this.thumbnailView.classList.add('hidden');
|
||||
this.outlineView.classList.add('hidden');
|
||||
this.attachmentsView.classList.remove('hidden');
|
||||
break;
|
||||
default:
|
||||
console.error('PDFSidebar_switchView: "' + view + '" is an unsupported value.');
|
||||
return;
|
||||
}
|
||||
this.active = view | 0;
|
||||
if (forceOpen && !this.isOpen) {
|
||||
this.open();
|
||||
return;
|
||||
}
|
||||
if (shouldForceRendering) {
|
||||
this._forceRendering();
|
||||
}
|
||||
if (isViewChanged) {
|
||||
this._dispatchEvent();
|
||||
}
|
||||
this._hideUINotification(this.active);
|
||||
},
|
||||
open: function PDFSidebar_open() {
|
||||
if (this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.toggleButton.classList.add('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.add('sidebarOpen');
|
||||
if (this.active === SidebarView.THUMBS) {
|
||||
this._updateThumbnailViewer();
|
||||
}
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
this._hideUINotification(this.active);
|
||||
},
|
||||
close: function PDFSidebar_close() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.toggleButton.classList.remove('toggled');
|
||||
this.outerContainer.classList.add('sidebarMoving');
|
||||
this.outerContainer.classList.remove('sidebarOpen');
|
||||
this._forceRendering();
|
||||
this._dispatchEvent();
|
||||
},
|
||||
toggle: function PDFSidebar_toggle() {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
_dispatchEvent: function PDFSidebar_dispatchEvent() {
|
||||
this.eventBus.dispatch('sidebarviewchanged', {
|
||||
source: this,
|
||||
view: this.visibleView
|
||||
});
|
||||
},
|
||||
_forceRendering: function PDFSidebar_forceRendering() {
|
||||
if (this.onToggled) {
|
||||
this.onToggled();
|
||||
} else {
|
||||
this.pdfViewer.forceRendering();
|
||||
this.pdfThumbnailViewer.forceRendering();
|
||||
}
|
||||
},
|
||||
_updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() {
|
||||
var pdfViewer = this.pdfViewer;
|
||||
var thumbnailViewer = this.pdfThumbnailViewer;
|
||||
var pagesCount = pdfViewer.pagesCount;
|
||||
for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
|
||||
var pageView = pdfViewer.getPageView(pageIndex);
|
||||
if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
|
||||
var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
|
||||
thumbnailView.setImage(pageView);
|
||||
}
|
||||
}
|
||||
thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
|
||||
},
|
||||
_showUINotification: function (view) {
|
||||
if (this.disableNotification) {
|
||||
return;
|
||||
}
|
||||
this.toggleButton.title = mozL10n.get('toggle_sidebar_notification.title', null, 'Toggle Sidebar (document contains outline/attachments)');
|
||||
if (!this.isOpen) {
|
||||
this.toggleButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
} else if (view === this.active) {
|
||||
return;
|
||||
}
|
||||
switch (view) {
|
||||
case SidebarView.OUTLINE:
|
||||
this.outlineButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
}
|
||||
},
|
||||
_hideUINotification: function (view) {
|
||||
if (this.disableNotification) {
|
||||
return;
|
||||
}
|
||||
var removeNotification = function (view) {
|
||||
switch (view) {
|
||||
case SidebarView.OUTLINE:
|
||||
this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
case SidebarView.ATTACHMENTS:
|
||||
this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
break;
|
||||
}
|
||||
}.bind(this);
|
||||
if (!this.isOpen && view !== null) {
|
||||
return;
|
||||
}
|
||||
this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS);
|
||||
if (view !== null) {
|
||||
removeNotification(view);
|
||||
return;
|
||||
}
|
||||
for (view in SidebarView) {
|
||||
removeNotification(SidebarView[view]);
|
||||
}
|
||||
this.toggleButton.title = mozL10n.get('toggle_sidebar.title', null, 'Toggle Sidebar');
|
||||
},
|
||||
_addEventListeners: function PDFSidebar_addEventListeners() {
|
||||
var self = this;
|
||||
self.mainContainer.addEventListener('transitionend', function (evt) {
|
||||
if (evt.target === this) {
|
||||
self.outerContainer.classList.remove('sidebarMoving');
|
||||
}
|
||||
});
|
||||
self.thumbnailButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
});
|
||||
self.outlineButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.OUTLINE);
|
||||
});
|
||||
self.outlineButton.addEventListener('dblclick', function () {
|
||||
self.pdfOutlineViewer.toggleOutlineTree();
|
||||
});
|
||||
self.attachmentsButton.addEventListener('click', function () {
|
||||
self.switchView(SidebarView.ATTACHMENTS);
|
||||
});
|
||||
self.eventBus.on('outlineloaded', function (e) {
|
||||
var outlineCount = e.outlineCount;
|
||||
self.outlineButton.disabled = !outlineCount;
|
||||
if (outlineCount) {
|
||||
self._showUINotification(SidebarView.OUTLINE);
|
||||
} else if (self.active === SidebarView.OUTLINE) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('attachmentsloaded', function (e) {
|
||||
var attachmentsCount = e.attachmentsCount;
|
||||
self.attachmentsButton.disabled = !attachmentsCount;
|
||||
if (attachmentsCount) {
|
||||
self._showUINotification(SidebarView.ATTACHMENTS);
|
||||
} else if (self.active === SidebarView.ATTACHMENTS) {
|
||||
self.switchView(SidebarView.THUMBS);
|
||||
}
|
||||
});
|
||||
self.eventBus.on('presentationmodechanged', function (e) {
|
||||
if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) {
|
||||
self._updateThumbnailViewer();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return PDFSidebar;
|
||||
}();
|
||||
exports.SidebarView = SidebarView;
|
||||
exports.PDFSidebar = PDFSidebar;
|
||||
}));
|
||||
(function (root, factory) {
|
||||
factory(root.pdfjsWebPDFThumbnailView = {}, root.pdfjsWebUIUtils, root.pdfjsWebPDFRenderingQueue);
|
||||
}(this, function (exports, uiUtils, pdfRenderingQueue) {
|
||||
|
@ -3745,6 +3830,14 @@ var pdfjsWebLibs;
|
|||
action: action
|
||||
});
|
||||
},
|
||||
onFileAttachmentAnnotation: function (params) {
|
||||
this.eventBus.dispatch('fileattachmentannotation', {
|
||||
source: this,
|
||||
id: params.id,
|
||||
filename: params.filename,
|
||||
content: params.content
|
||||
});
|
||||
},
|
||||
cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
|
||||
var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
|
||||
this._pagesRefCache[refStr] = pageNum;
|
||||
|
@ -3827,6 +3920,8 @@ var pdfjsWebLibs;
|
|||
},
|
||||
executeNamedAction: function (action) {
|
||||
},
|
||||
onFileAttachmentAnnotation: function (params) {
|
||||
},
|
||||
cachePageRef: function (pageNum, pageRef) {
|
||||
}
|
||||
};
|
||||
|
@ -4074,7 +4169,6 @@ var pdfjsWebLibs;
|
|||
this.renderingState = RenderingStates.RUNNING;
|
||||
var self = this;
|
||||
var pdfPage = this.pdfPage;
|
||||
var viewport = this.viewport;
|
||||
var div = this.div;
|
||||
var canvasWrapper = document.createElement('div');
|
||||
canvasWrapper.style.width = div.style.width;
|
||||
|
@ -4194,8 +4288,6 @@ var pdfjsWebLibs;
|
|||
renderTask.cancel();
|
||||
}
|
||||
};
|
||||
var self = this;
|
||||
var pdfPage = this.pdfPage;
|
||||
var viewport = this.viewport;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.id = 'page' + this.id;
|
||||
|
|
|
@ -471,8 +471,6 @@
|
|||
@RESPATH@/components/formautofill.manifest
|
||||
@RESPATH@/components/FormAutofillContentService.js
|
||||
@RESPATH@/components/FormAutofillStartup.js
|
||||
@RESPATH@/components/CSSUnprefixingService.js
|
||||
@RESPATH@/components/CSSUnprefixingService.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.js
|
||||
@RESPATH@/browser/components/BrowserProfileMigrators.manifest
|
||||
|
|
|
@ -838,16 +838,10 @@ Function LaunchApp
|
|||
FunctionEnd
|
||||
|
||||
Function LaunchAppFromElevatedProcess
|
||||
; Find the installation directory when launching using GetFunctionAddress
|
||||
; from an elevated installer since $INSTDIR will not be set in this installer
|
||||
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
||||
ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
|
||||
${GetPathFromString} "$0" $0
|
||||
${GetParent} "$0" $1
|
||||
; Set our current working directory to the application's install directory
|
||||
; otherwise the 7-Zip temp directory will be in use and won't be deleted.
|
||||
SetOutPath "$1"
|
||||
Exec "$\"$0$\""
|
||||
SetOutPath "$INSTDIR"
|
||||
Exec "$\"$INSTDIR\${FileMainEXE}$\""
|
||||
FunctionEnd
|
||||
|
||||
################################################################################
|
||||
|
|
|
@ -2065,15 +2065,9 @@ Function LaunchApp
|
|||
FunctionEnd
|
||||
|
||||
Function LaunchAppFromElevatedProcess
|
||||
; Find the installation directory when launching using GetFunctionAddress
|
||||
; from an elevated installer since $INSTDIR will not be set in this installer
|
||||
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
||||
ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
|
||||
${GetPathFromString} "$0" $0
|
||||
; Set the current working directory to the installation directory
|
||||
${GetParent} "$0" $1
|
||||
SetOutPath "$1"
|
||||
Exec "$\"$0$\""
|
||||
SetOutPath "$INSTDIR"
|
||||
Exec "$\"$INSTDIR\${FileMainEXE}$\""
|
||||
FunctionEnd
|
||||
|
||||
Function CopyPostSigningData
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,6 +4,38 @@
|
|||
"google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
|
||||
]
|
||||
},
|
||||
"regionOverrides": {
|
||||
"US": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"CA": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"KZ": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"BY": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"RU": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"TR": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"UA": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"CN": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"TW": {
|
||||
"google": "google-nocodes"
|
||||
},
|
||||
"HK": {
|
||||
"google": "google-nocodes"
|
||||
}
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"default": {
|
||||
|
@ -11,16 +43,6 @@
|
|||
"google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
|
||||
]
|
||||
},
|
||||
"US": {
|
||||
"visibleDefaultEngines": [
|
||||
"yahoo", "google-nocodes", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
|
||||
]
|
||||
},
|
||||
"CA": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
|
||||
]
|
||||
},
|
||||
"experimental-hidden": {
|
||||
"visibleDefaultEngines": [
|
||||
"yahoo-en-CA"
|
||||
|
@ -396,31 +418,6 @@
|
|||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
},
|
||||
"KZ": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
},
|
||||
"BY": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
},
|
||||
"RU": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
},
|
||||
"TR": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
},
|
||||
"UA": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-kk", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
|
||||
]
|
||||
}
|
||||
},
|
||||
"km": {
|
||||
|
@ -596,31 +593,6 @@
|
|||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
},
|
||||
"RU": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
},
|
||||
"BY": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
},
|
||||
"KZ": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
},
|
||||
"TR": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
},
|
||||
"UA": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-ru", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
|
||||
]
|
||||
}
|
||||
},
|
||||
"si": {
|
||||
|
@ -705,31 +677,6 @@
|
|||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
},
|
||||
"TR": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
},
|
||||
"BY": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
},
|
||||
"KZ": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
},
|
||||
"RU": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
},
|
||||
"UA": {
|
||||
"visibleDefaultEngines": [
|
||||
"yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
|
||||
]
|
||||
}
|
||||
},
|
||||
"uk": {
|
||||
|
@ -737,31 +684,6 @@
|
|||
"visibleDefaultEngines": [
|
||||
"google", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
},
|
||||
"UA": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
},
|
||||
"TR": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
},
|
||||
"BY": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
},
|
||||
"KZ": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
},
|
||||
"RU": {
|
||||
"visibleDefaultEngines": [
|
||||
"google-nocodes", "yandex-uk", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ur": {
|
||||
|
@ -811,16 +733,6 @@
|
|||
"visibleDefaultEngines": [
|
||||
"yahoo-zh-TW", "google", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW-HK", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
|
||||
]
|
||||
},
|
||||
"TW": {
|
||||
"visibleDefaultEngines": [
|
||||
"yahoo-zh-TW", "google-nocodes", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW-HK", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
|
||||
]
|
||||
},
|
||||
"HK": {
|
||||
"visibleDefaultEngines": [
|
||||
"yahoo-zh-TW-HK", "google-nocodes", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -455,6 +455,7 @@ this.ContentSearch = {
|
|||
if (msg.target.contentWindow) {
|
||||
engine.speculativeConnect({
|
||||
window: msg.target.contentWindow,
|
||||
originAttributes: msg.target.contentPrincipal.originAttributes
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
color: ButtonText;
|
||||
}
|
||||
|
||||
#placesToolbar > toolbarbutton[disabled=true] {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
/* back button */
|
||||
|
||||
#back-button {
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<style type="text/css">
|
||||
path {
|
||||
stroke: #bb3817;
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
<path d="M6.6,9c0.3,0,0.5-0.3,0.6-0.6C7,7.7,7,6.9,7.1,6.2c0.1-0.3,0.3-0.4,0.6-0.4c0.3,0,0.3,0.4,1,0.4
|
||||
c0.3,0,0.8-0.1,0.8-1.1S9,3.9,8.7,3.9c-0.6,0-0.7,0.5-1,0.5c-0.3,0-0.5-0.2-0.6-0.5c0-0.3,0-0.7,0-1c0-0.3-0.2-0.5-0.5-0.6
|
||||
c0,0,0,0-0.1,0c-0.5,0-1,0.1-1.6,0C4.7,2.3,4.5,2.1,4.6,1.8c0-0.4,0.4-0.3,0.4-1C5,0.5,4.9,0,3.8,0S2.7,0.5,2.7,0.8
|
||||
c0,0.6,0.5,0.7,0.5,1c0,0.3-0.2,0.5-0.5,0.5C2.1,2.4,1.6,2.4,1,2.4c-0.3,0-0.5,0.2-0.6,0.5c0,0,0,0,0,0.1v0.7c0,0-0.1,0.8,0.6,0.8
|
||||
C1.5,4.5,1.6,4,2.2,4c0.3,0,0.7,0.7,0.7,1.3S2.4,6.6,2.2,6.6C1.6,6.6,1.5,6,1.1,6C0.4,5.9,0.5,6.7,0.5,6.7v1.7C0.4,8.7,0.7,9,1,9
|
||||
c0,0,0,0,0,0h2.1C3.1,9,4,9,4,8.4c0-0.4-0.7-0.6-0.7-1.2C3.5,6.7,4,6.3,4.5,6.3c0.6,0,1.2,0.6,1.2,0.8c0,0.6-0.6,0.8-0.6,1.2
|
||||
C5.1,9,5.9,9,5.9,9L6.6,9z"/>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -157,7 +157,7 @@
|
|||
|
||||
#PanelUI-menu-button[badge-status="addon-alert"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
height: 13px;
|
||||
background: transparent url(chrome://browser/skin/addons/addon-badge.svg) no-repeat center;
|
||||
background: #FFBF00 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
|
||||
}
|
||||
|
||||
.panel-subviews {
|
||||
|
@ -589,7 +589,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton {
|
||||
background-color: #C7F5FF;
|
||||
background-color: #FFEFBF;
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
width: calc(@menuPanelWidth@ + 30px);
|
||||
|
@ -597,13 +597,21 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
border-inline-start-style: none;
|
||||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton:hover {
|
||||
background-color: #FFE8A2;
|
||||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton:active {
|
||||
background-color: #FFE38F;
|
||||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton > .toolbarbutton-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton::after {
|
||||
background-image: url(chrome://browser/skin/addons/addon-badge.svg);
|
||||
background: #FFBF00 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
|
||||
}
|
||||
|
||||
#PanelUI-fxa-status {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
skin/classic/browser/aboutTabCrashed.css (../shared/aboutTabCrashed.css)
|
||||
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
|
||||
skin/classic/browser/content-contextmenu.svg (../shared/content-contextmenu.svg)
|
||||
skin/classic/browser/addons/addon-badge.svg (../shared/addons/addon-badge.svg)
|
||||
skin/classic/browser/addons/addon-install-blocked.svg (../shared/addons/addon-install-blocked.svg)
|
||||
skin/classic/browser/addons/addon-install-confirm.svg (../shared/addons/addon-install-confirm.svg)
|
||||
skin/classic/browser/addons/addon-install-downloading.svg (../shared/addons/addon-install-downloading.svg)
|
||||
|
|
|
@ -746,7 +746,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
|||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[type=menu]:not(#PanelUI-menu-button):not(#back-button):not(#forward-button) > .toolbarbutton-icon {
|
||||
#nav-bar .toolbarbutton-1[type=menu]:not(#PanelUI-menu-button):not(#back-button):not(#forward-button):not(#new-tab-button) > .toolbarbutton-icon {
|
||||
/* horizontal padding + border + icon width */
|
||||
max-width: 43px;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,6 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
|||
dnl --cxxflags. We use sed to remove this argument so that builds work on OSX
|
||||
LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags | sed -e 's/-isysroot [[^ ]]*//'`
|
||||
|
||||
dnl We are loaded into clang, so we don't need to link to very many things,
|
||||
dnl we just need to link to clangASTMatchers because it is not used by clang
|
||||
LLVM_LDFLAGS=`$LLVMCONFIG --ldflags | tr '\n' ' '`
|
||||
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
|
@ -54,7 +52,14 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
|||
dnl access to all of the symbols which are undefined in our dylib as we
|
||||
dnl are building it right now, and also that we don't fail the build
|
||||
dnl due to undefined symbols (which will be provided by clang).
|
||||
CLANG_LDFLAGS="-Wl,-flat_namespace -Wl,-undefined,suppress -lclangASTMatchers"
|
||||
CLANG_LDFLAGS="-Wl,-flat_namespace -Wl,-undefined,suppress"
|
||||
dnl We are loaded into clang, so we don't need to link to very many things,
|
||||
dnl we just need to link to clangASTMatchers because it is not used by clang
|
||||
CLANG_LDFLAGS="$CLANG_LDFLAGS `$LLVMCONFIG --prefix`/lib/libclangASTMatchers.a"
|
||||
dnl We need to remove -L/path/to/clang/lib from LDFLAGS to ensure that we
|
||||
dnl don't accidentally link against the libc++ there which is a newer
|
||||
dnl version that what our build machines have installed.
|
||||
LLVM_LDFLAGS=`echo "$LLVM_LDFLAGS" | sed -E 's/-L[[^ ]]+\/clang\/lib//'`
|
||||
elif test "${HOST_OS_ARCH}" = "WINNT"; then
|
||||
CLANG_LDFLAGS="clang.lib"
|
||||
else
|
||||
|
|
|
@ -39,10 +39,12 @@ build-clang.py accepts a JSON config format with the following fields:
|
|||
* gcc_dir: Path to the gcc toolchain installation, only required on Linux.
|
||||
* cc: Path to the bootsraping C Compiler.
|
||||
* cxx: Path to the bootsraping C++ Compiler.
|
||||
* as: Path to the assembler tool.
|
||||
* ar: Path to the library archiver tool.
|
||||
* ranlib: Path to the ranlib tool.
|
||||
* ranlib: Path to the ranlib tool (optional).
|
||||
* libtool: Path to the libtool tool (optional).
|
||||
* ld: Path to the linker.
|
||||
* patches: Optional list of patches to apply per platform. Supported platforms: macosx64, linux32, linux64. The default is Release.
|
||||
* patches: Optional list of patches to apply.
|
||||
* build_type: The type of build to make. Supported types: Release, Debug, RelWithDebInfo or MinSizeRel.
|
||||
* build_libcxx: Whether to build with libcxx. The default is false.
|
||||
* build_clang_tidy: Whether to build clang-tidy with the Mozilla checks imported. The default is false.
|
||||
|
|
|
@ -170,24 +170,6 @@ def svn_update(directory, revision):
|
|||
run_in(directory, ["svn", "revert", "-q", "-R", revision])
|
||||
|
||||
|
||||
def get_platform():
|
||||
p = platform.system()
|
||||
if p == "Darwin":
|
||||
return "macosx64"
|
||||
elif p == "Linux":
|
||||
if platform.architecture() == "AMD64":
|
||||
return "linux64"
|
||||
else:
|
||||
return "linux32"
|
||||
elif p == "Windows":
|
||||
if platform.architecture() == "AMD64":
|
||||
return "win64"
|
||||
else:
|
||||
return "win32"
|
||||
else:
|
||||
raise NotImplementedError("Not supported platform")
|
||||
|
||||
|
||||
def is_darwin():
|
||||
return platform.system() == "Darwin"
|
||||
|
||||
|
@ -200,7 +182,7 @@ def is_windows():
|
|||
return platform.system() == "Windows"
|
||||
|
||||
|
||||
def build_one_stage(cc, cxx, ld, ar, ranlib,
|
||||
def build_one_stage(cc, cxx, asm, ld, ar, ranlib, libtool,
|
||||
src_dir, stage_dir, build_libcxx,
|
||||
osx_cross_compile, build_type, assertions,
|
||||
python_path, gcc_dir, libcxx_include_dir):
|
||||
|
@ -225,11 +207,12 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
|||
cmake_args = ["-GNinja",
|
||||
"-DCMAKE_C_COMPILER=%s" % slashify_path(cc[0]),
|
||||
"-DCMAKE_CXX_COMPILER=%s" % slashify_path(cxx[0]),
|
||||
"-DCMAKE_ASM_COMPILER=%s" % slashify_path(cc[0]),
|
||||
"-DCMAKE_ASM_COMPILER=%s" % slashify_path(asm[0]),
|
||||
"-DCMAKE_LINKER=%s" % slashify_path(ld[0]),
|
||||
"-DCMAKE_AR=%s" % slashify_path(ar),
|
||||
"-DCMAKE_C_FLAGS=%s" % ' '.join(cc[1:]),
|
||||
"-DCMAKE_CXX_FLAGS=%s" % ' '.join(cxx[1:]),
|
||||
"-DCMAKE_ASM_FLAGS=%s" % ' '.join(asm[1:]),
|
||||
"-DCMAKE_EXE_LINKER_FLAGS=%s" % ' '.join(ld[1:]),
|
||||
"-DCMAKE_SHARED_LINKER_FLAGS=%s" % ' '.join(ld[1:]),
|
||||
"-DCMAKE_BUILD_TYPE=%s" % build_type,
|
||||
|
@ -245,6 +228,8 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
|||
cmake_args.insert(-1, "-DLLVM_USE_CRT_RELEASE=MT")
|
||||
if ranlib is not None:
|
||||
cmake_args += ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib)]
|
||||
if libtool is not None:
|
||||
cmake_args += ["-DCMAKE_LIBTOOL=%s" % slashify_path(libtool)]
|
||||
if osx_cross_compile:
|
||||
cmake_args += ["-DCMAKE_SYSTEM_NAME=Darwin",
|
||||
"-DCMAKE_SYSTEM_VERSION=10.10",
|
||||
|
@ -258,7 +243,7 @@ def build_one_stage(cc, cxx, ld, ar, ranlib,
|
|||
"-DCMAKE_MACOSX_RPATH=@executable_path",
|
||||
"-DCMAKE_OSX_ARCHITECTURES=x86_64",
|
||||
"-DDARWIN_osx_ARCHS=x86_64",
|
||||
"-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin10"]
|
||||
"-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin11"]
|
||||
build_package(build_dir, cmake_args)
|
||||
|
||||
if is_linux():
|
||||
|
@ -464,9 +449,13 @@ if __name__ == "__main__":
|
|||
raise ValueError("Config file needs to set gcc_dir")
|
||||
cc = get_tool(config, "cc")
|
||||
cxx = get_tool(config, "cxx")
|
||||
asm = get_tool(config, "ml" if is_windows() else "as")
|
||||
ld = get_tool(config, "link" if is_windows() else "ld")
|
||||
ar = get_tool(config, "lib" if is_windows() else "ar")
|
||||
ranlib = None if is_windows() else get_tool(config, "ranlib")
|
||||
libtool = None
|
||||
if "libtool" in config:
|
||||
libtool = get_tool(config, "libtool")
|
||||
|
||||
if not os.path.exists(source_dir):
|
||||
os.makedirs(source_dir)
|
||||
|
@ -485,7 +474,7 @@ if __name__ == "__main__":
|
|||
checkout_or_update(libcxxabi_repo, libcxxabi_source_dir)
|
||||
if extra_repo:
|
||||
checkout_or_update(extra_repo, extra_source_dir)
|
||||
for p in config.get("patches", {}).get(get_platform(), []):
|
||||
for p in config.get("patches", []):
|
||||
patch(p, source_dir)
|
||||
|
||||
symlinks = [(source_dir + "/clang",
|
||||
|
@ -525,12 +514,14 @@ if __name__ == "__main__":
|
|||
extra_cxxflags = ["-stdlib=libc++"]
|
||||
extra_cflags2 = []
|
||||
extra_cxxflags2 = ["-stdlib=libc++"]
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
elif is_linux():
|
||||
extra_cflags = ["-static-libgcc"]
|
||||
extra_cxxflags = ["-static-libgcc", "-static-libstdc++"]
|
||||
extra_cflags2 = ["-fPIC"]
|
||||
extra_cxxflags2 = ["-fPIC", "-static-libstdc++"]
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
|
||||
if os.environ.has_key('LD_LIBRARY_PATH'):
|
||||
|
@ -545,6 +536,7 @@ if __name__ == "__main__":
|
|||
# Force things on.
|
||||
extra_cflags2 = []
|
||||
extra_cxxflags2 = ['-fms-compatibility-version=19.00.24213', '-Xclang', '-std=c++14']
|
||||
extra_asmflags = []
|
||||
extra_ldflags = []
|
||||
|
||||
if osx_cross_compile:
|
||||
|
@ -554,7 +546,7 @@ if __name__ == "__main__":
|
|||
extra_cxxflags = ["-stdlib=libc++"]
|
||||
extra_cxxflags2 = ["-stdlib=libc++"]
|
||||
|
||||
extra_flags = ["-target", "x86_64-apple-darwin10", "-mlinker-version=136",
|
||||
extra_flags = ["-target", "x86_64-apple-darwin11", "-mlinker-version=137",
|
||||
"-B", "%s/bin" % os.getenv("CROSS_CCTOOLS_PATH"),
|
||||
"-isysroot", os.getenv("CROSS_SYSROOT"),
|
||||
# technically the sysroot flag there should be enough to deduce this,
|
||||
|
@ -565,14 +557,16 @@ if __name__ == "__main__":
|
|||
extra_cxxflags += extra_flags
|
||||
extra_cflags2 += extra_flags
|
||||
extra_cxxflags2 += extra_flags
|
||||
extra_asmflags += extra_flags
|
||||
extra_ldflags = ["-Wl,-syslibroot,%s" % os.getenv("CROSS_SYSROOT"),
|
||||
"-Wl,-dead_strip"]
|
||||
|
||||
build_one_stage(
|
||||
[cc] + extra_cflags,
|
||||
[cxx] + extra_cxxflags,
|
||||
[asm] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage1_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
|
@ -585,8 +579,10 @@ if __name__ == "__main__":
|
|||
(cc_name, exe_ext)] + extra_cflags2,
|
||||
[stage1_inst_dir + "/bin/%s%s" %
|
||||
(cxx_name, exe_ext)] + extra_cxxflags2,
|
||||
[stage1_inst_dir + "/bin/%s%s" %
|
||||
(cc_name, exe_ext)] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage2_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
|
@ -598,8 +594,10 @@ if __name__ == "__main__":
|
|||
(cc_name, exe_ext)] + extra_cflags2,
|
||||
[stage2_inst_dir + "/bin/%s%s" %
|
||||
(cxx_name, exe_ext)] + extra_cxxflags2,
|
||||
[stage2_inst_dir + "/bin/%s%s" %
|
||||
(cc_name, exe_ext)] + extra_asmflags,
|
||||
[ld] + extra_ldflags,
|
||||
ar, ranlib,
|
||||
ar, ranlib, libtool,
|
||||
llvm_source_dir, stage3_dir, build_libcxx, osx_cross_compile,
|
||||
build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
|
||||
|
||||
|
|
|
@ -13,15 +13,8 @@
|
|||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++",
|
||||
"patches": {
|
||||
"macosx64": [
|
||||
"llvm-debug-frame.patch"
|
||||
],
|
||||
"linux64": [
|
||||
"llvm-debug-frame.patch"
|
||||
],
|
||||
"linux32": [
|
||||
"llvm-debug-frame.patch"
|
||||
]
|
||||
}
|
||||
"as": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"patches": [
|
||||
"llvm-debug-frame.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
{
|
||||
"llvm_revision": "262557",
|
||||
"stages": "3",
|
||||
"llvm_revision": "290136",
|
||||
"stages": "1",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_380/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_380/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_380/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_380/final",
|
||||
"python_path": "/usr/local/bin/python2.7",
|
||||
"cc": "/Users/cltbld/clang/bin/clang",
|
||||
"cxx": "/Users/cltbld/clang/bin/clang++",
|
||||
"patches": {
|
||||
"macosx64": [
|
||||
"disable-mac-tsan.patch",
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
],
|
||||
"linux64": [
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
],
|
||||
"linux32": [
|
||||
"llvm-debug-frame.patch",
|
||||
"return-empty-string-non-mangled.patch"
|
||||
]
|
||||
}
|
||||
"osx_cross_compile": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_390/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_390/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_390/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_390/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_390/final",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"cxx": "/home/worker/workspace/build/src/clang/bin/clang++",
|
||||
"as": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ranlib",
|
||||
"libtool": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-libtool",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches":[
|
||||
"llvm-debug-frame.patch",
|
||||
"compiler-rt-cross-compile.patch",
|
||||
"pr28831-r280042.patch",
|
||||
"r277806.patch",
|
||||
"r285657.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -10,7 +10,5 @@
|
|||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"patches": {
|
||||
}
|
||||
"cxx": "cl.exe"
|
||||
}
|
||||
|
|
|
@ -11,6 +11,5 @@
|
|||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"patches": {
|
||||
}
|
||||
"ml": "ml64.exe"
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++"
|
||||
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++",
|
||||
"as": "/home/worker/workspace/build/src/gcc/bin/gcc"
|
||||
}
|
||||
|
|
|
@ -16,7 +16,12 @@
|
|||
"gcc_dir": "/home/worker/workspace/build/src/gcc",
|
||||
"cc": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"cxx": "/home/worker/workspace/build/src/clang/bin/clang++",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin10-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin10-ranlib",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang"
|
||||
"as": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"ar": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ar",
|
||||
"ranlib": "/home/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ranlib",
|
||||
"ld": "/home/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches": [
|
||||
"llvm-debug-frame.patch",
|
||||
"compiler-rt-cross-compile.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe"
|
||||
"cxx": "cl.exe",
|
||||
"ml": "ml64.exe"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Add `-target x86_64-apple-darwin11' to the compiler-rt overridden CFLAGS
|
||||
|
||||
diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
index 28d398672..aac68bf36 100644
|
||||
--- a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
+++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
|
||||
@@ -265,7 +265,7 @@ endfunction()
|
||||
macro(darwin_add_builtin_libraries)
|
||||
set(DARWIN_EXCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Darwin-excludes)
|
||||
|
||||
- set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer")
|
||||
+ set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer -target x86_64-apple-darwin11 -isysroot ${CMAKE_OSX_SYSROOT} -I${CMAKE_OSX_SYSROOT}/usr/include")
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
set(CMAKE_ASM_FLAGS "")
|
|
@ -1,11 +0,0 @@
|
|||
--- a/compiler-rt/cmake/config-ix.cmake
|
||||
+++ b/compiler-rt/cmake/config-ix.cmake
|
||||
@@ -617,7 +617,7 @@
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
|
||||
- OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
+ OS_NAME MATCHES "Linux|FreeBSD")
|
||||
set(COMPILER_RT_HAS_TSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_TSAN FALSE)
|
|
@ -0,0 +1,19 @@
|
|||
Backport the fix to PR28831 plus its follow-up (r280042)
|
||||
|
||||
diff --git a/libcxx/lib/CMakeLists.txt b/libcxx/lib/CMakeLists.txt
|
||||
index afc388e76..4f43f3711 100644
|
||||
--- a/libcxx/lib/CMakeLists.txt
|
||||
+++ b/libcxx/lib/CMakeLists.txt
|
||||
@@ -115,9 +115,9 @@ if ( APPLE AND (LIBCXX_CXX_ABI_LIBNAME STREQUAL "libcxxabi" OR
|
||||
"-Wl,-unexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/libc++unexp.exp"
|
||||
"/usr/lib/libSystem.B.dylib")
|
||||
else()
|
||||
- if ( ${CMAKE_OSX_SYSROOT} )
|
||||
- list(FIND ${CMAKE_OSX_ARCHITECTURES} "armv7" OSX_HAS_ARMV7)
|
||||
- if (OSX_HAS_ARMV7)
|
||||
+ if (DEFINED CMAKE_OSX_SYSROOT)
|
||||
+ list(FIND CMAKE_OSX_ARCHITECTURES "armv7" OSX_HAS_ARMV7)
|
||||
+ if (NOT OSX_HAS_ARMV7 EQUAL -1)
|
||||
set(OSX_RE_EXPORT_LINE
|
||||
"${CMAKE_OSX_SYSROOT}/usr/lib/libc++abi.dylib"
|
||||
"-Wl,-reexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/libc++sjlj-abi.exp")
|
|
@ -1,79 +0,0 @@
|
|||
commit 865b9340996f9f9d04b73b187248737dc6fd845e
|
||||
Author: Michael Wu <mwu@mozilla.com>
|
||||
Date: Mon Sep 14 17:47:21 2015 -0400
|
||||
|
||||
Add support for querying the visibility of a cursor
|
||||
|
||||
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
|
||||
index fad9cfa..311bfcb 100644
|
||||
--- a/clang/include/clang-c/Index.h
|
||||
+++ b/clang/include/clang-c/Index.h
|
||||
@@ -2440,6 +2440,24 @@ enum CXLinkageKind {
|
||||
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
|
||||
|
||||
/**
|
||||
+ * \brief Describe the visibility of the entity referred to by a cursor.
|
||||
+ */
|
||||
+enum CXVisibilityKind {
|
||||
+ /** \brief This value indicates that no visibility information is available
|
||||
+ * for a provided CXCursor. */
|
||||
+ CXVisibility_Invalid,
|
||||
+
|
||||
+ /** \brief Symbol not seen by the linker. */
|
||||
+ CXVisibility_Hidden,
|
||||
+ /** \brief Symbol seen by the linker but resolves to a symbol inside this object. */
|
||||
+ CXVisibility_Protected,
|
||||
+ /** \brief Symbol seen by the linker and acts like a normal symbol. */
|
||||
+ CXVisibility_Default,
|
||||
+};
|
||||
+
|
||||
+CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor);
|
||||
+
|
||||
+/**
|
||||
* \brief Determine the availability of the entity that this cursor refers to,
|
||||
* taking the current target platform into account.
|
||||
*
|
||||
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
|
||||
index 8225a6c..9fa18d3 100644
|
||||
--- a/clang/tools/libclang/CIndex.cpp
|
||||
+++ b/clang/tools/libclang/CIndex.cpp
|
||||
@@ -6361,6 +6361,27 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
|
||||
} // end: extern "C"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
+// Operations for querying visibility of a cursor.
|
||||
+//===----------------------------------------------------------------------===//
|
||||
+
|
||||
+extern "C" {
|
||||
+CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) {
|
||||
+ if (!clang_isDeclaration(cursor.kind))
|
||||
+ return CXVisibility_Invalid;
|
||||
+
|
||||
+ const Decl *D = cxcursor::getCursorDecl(cursor);
|
||||
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
|
||||
+ switch (ND->getVisibility()) {
|
||||
+ case HiddenVisibility: return CXVisibility_Hidden;
|
||||
+ case ProtectedVisibility: return CXVisibility_Protected;
|
||||
+ case DefaultVisibility: return CXVisibility_Default;
|
||||
+ };
|
||||
+
|
||||
+ return CXVisibility_Invalid;
|
||||
+}
|
||||
+} // end: extern "C"
|
||||
+
|
||||
+//===----------------------------------------------------------------------===//
|
||||
// Operations for querying language of a cursor.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports
|
||||
index f6a7175..a919a8e 100644
|
||||
--- a/clang/tools/libclang/libclang.exports
|
||||
+++ b/clang/tools/libclang/libclang.exports
|
||||
@@ -173,6 +173,7 @@ clang_getCursorSemanticParent
|
||||
clang_getCursorSpelling
|
||||
clang_getCursorType
|
||||
clang_getCursorUSR
|
||||
+clang_getCursorVisibility
|
||||
clang_getDeclObjCTypeEncoding
|
||||
clang_getDefinitionSpellingAndExtent
|
||||
clang_getDiagnostic
|
|
@ -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>
|
|
@ -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
|
||||
+ }
|
||||
+}
|
|
@ -18,6 +18,7 @@ gyp_vars.update({
|
|||
'include_pulse_audio': 1 if CONFIG['MOZ_PULSEAUDIO'] else 0,
|
||||
# basic stuff for everything
|
||||
'include_internal_video_render': 0,
|
||||
'clang': 1 if CONFIG['CLANG_CXX'] else 0,
|
||||
'clang_use_chrome_plugins': 0,
|
||||
'enable_protobuf': 0,
|
||||
'include_tests': 0,
|
||||
|
|
|
@ -284,6 +284,31 @@ OriginAttributes::IsFirstPartyEnabled()
|
|||
return sFirstPartyIsolation;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
OriginAttributes::IsRestrictOpenerAccessForFPI()
|
||||
{
|
||||
bool isFirstPartyEnabled = IsFirstPartyEnabled();
|
||||
|
||||
// Cache the privacy.firstparty.isolate.restrict_opener_access pref.
|
||||
static bool sRestrictedOpenerAccess = false;
|
||||
static bool sCachedRestrictedAccessPref = false;
|
||||
if (!sCachedRestrictedAccessPref) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sCachedRestrictedAccessPref = true;
|
||||
Preferences::AddBoolVarCache(&sRestrictedOpenerAccess,
|
||||
"privacy.firstparty.isolate.restrict_opener_access");
|
||||
}
|
||||
|
||||
// We always want to restrict window.opener if first party isolation is
|
||||
// disabled.
|
||||
if (!isFirstPartyEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isFirstPartyEnabled && sRestrictedOpenerAccess;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin)
|
||||
|
@ -388,6 +413,24 @@ BasePrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SubsumesConsideringDomainIgnoringFPD(nsIPrincipal *aOther,
|
||||
bool *aResult)
|
||||
{
|
||||
NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (Kind() == eCodebasePrincipal &&
|
||||
!dom::ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
|
||||
OriginAttributesRef(), aOther->OriginAttributesRef())) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aResult = SubsumesInternal(aOther, ConsiderDocumentDomain);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal)
|
||||
{
|
||||
|
|
|
@ -103,6 +103,11 @@ public:
|
|||
// check if "privacy.firstparty.isolate" is enabled.
|
||||
static bool IsFirstPartyEnabled();
|
||||
|
||||
// check if the access of window.opener across different FPDs is restricted.
|
||||
// We only restrict the access of window.opener when first party isolation
|
||||
// is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on.
|
||||
static bool IsRestrictOpenerAccessForFPI();
|
||||
|
||||
// returns true if the originAttributes suffix has mPrivateBrowsingId value
|
||||
// different than 0.
|
||||
static bool IsPrivateBrowsing(const nsACString& aOrigin);
|
||||
|
@ -210,6 +215,7 @@ public:
|
|||
NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
|
||||
NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
|
||||
NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
|
@ -234,8 +240,6 @@ public:
|
|||
|
||||
virtual bool AddonHasPermission(const nsAString& aPerm);
|
||||
|
||||
virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
|
||||
|
||||
virtual bool IsCodebasePrincipal() const { return false; };
|
||||
|
||||
static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
|
||||
|
|
|
@ -25,7 +25,7 @@ interface nsIDOMDocument;
|
|||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
[ref] native const_OriginAttributes(const mozilla::OriginAttributes);
|
||||
|
||||
[scriptable, builtinclass, uuid(3da7b133-f1a0-4de9-a2bc-5c49014c1077)]
|
||||
[scriptable, builtinclass, uuid(f75f502d-79fd-48be-a079-e5a7b8f80c8b)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
|
@ -94,6 +94,12 @@ interface nsIPrincipal : nsISerializable
|
|||
*/
|
||||
boolean subsumesConsideringDomain(in nsIPrincipal other);
|
||||
|
||||
/**
|
||||
* Same as the subsumesConsideringDomain(), but ignores the first party
|
||||
* domain in its originAttributes.
|
||||
*/
|
||||
boolean subsumesConsideringDomainIgnoringFPD(in nsIPrincipal other);
|
||||
|
||||
%{C++
|
||||
inline bool Subsumes(nsIPrincipal* aOther) {
|
||||
bool subsumes = false;
|
||||
|
@ -104,6 +110,11 @@ interface nsIPrincipal : nsISerializable
|
|||
bool subsumes = false;
|
||||
return NS_SUCCEEDED(SubsumesConsideringDomain(aOther, &subsumes)) && subsumes;
|
||||
}
|
||||
|
||||
inline bool SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther) {
|
||||
bool subsumes = false;
|
||||
return NS_SUCCEEDED(SubsumesConsideringDomainIgnoringFPD(aOther, &subsumes)) && subsumes;
|
||||
}
|
||||
%}
|
||||
|
||||
/**
|
||||
|
@ -339,15 +350,6 @@ interface nsIPrincipal : nsISerializable
|
|||
* Returns true iff this is the system principal.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isSystemPrincipal;
|
||||
|
||||
/**
|
||||
* Returns true if this principal's origin is recognized as being on the
|
||||
* whitelist of sites that can use the CSS Unprefixing Service.
|
||||
*
|
||||
* (This interface provides a trivial implementation, just returning false;
|
||||
* subclasses can implement something more complex as-needed.)
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] bool IsOnCSSUnprefixingWhitelist();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
static bool gIsWhitelistingTestDomains = false;
|
||||
static bool gCodeBasePrincipalSupport = false;
|
||||
|
||||
static bool URIIsImmutable(nsIURI* aURI)
|
||||
|
@ -58,10 +57,6 @@ NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal,
|
|||
/* static */ void
|
||||
nsPrincipal::InitializeStatics()
|
||||
{
|
||||
Preferences::AddBoolVarCache(
|
||||
&gIsWhitelistingTestDomains,
|
||||
"layout.css.unprefixing-service.include-test-domains");
|
||||
|
||||
Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport,
|
||||
"signed.applets.codebase_principal_support",
|
||||
false);
|
||||
|
@ -464,196 +459,6 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper-function to indicate whether the CSS Unprefixing Service
|
||||
// whitelist should include dummy domains that are only intended for
|
||||
// use in testing. (Controlled by a pref.)
|
||||
static inline bool
|
||||
IsWhitelistingTestDomains()
|
||||
{
|
||||
return gIsWhitelistingTestDomains;
|
||||
}
|
||||
|
||||
// Checks if the given URI's host is on our "full domain" whitelist
|
||||
// (i.e. if it's an exact match against a domain that needs unprefixing)
|
||||
static bool
|
||||
IsOnFullDomainWhitelist(nsIURI* aURI)
|
||||
{
|
||||
nsAutoCString hostStr;
|
||||
nsresult rv = aURI->GetHost(hostStr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// NOTE: This static whitelist is expected to be short. If that changes,
|
||||
// we should consider a different representation; e.g. hash-set, prefix tree.
|
||||
static const nsLiteralCString sFullDomainsOnWhitelist[] = {
|
||||
// 0th entry only active when testing:
|
||||
NS_LITERAL_CSTRING("test1.example.org"),
|
||||
NS_LITERAL_CSTRING("map.baidu.com"),
|
||||
NS_LITERAL_CSTRING("3g.163.com"),
|
||||
NS_LITERAL_CSTRING("3glogo.gtimg.com"), // for 3g.163.com
|
||||
NS_LITERAL_CSTRING("info.3g.qq.com"), // for 3g.qq.com
|
||||
NS_LITERAL_CSTRING("3gimg.qq.com"), // for 3g.qq.com
|
||||
NS_LITERAL_CSTRING("img.m.baidu.com"), // for [shucheng|ks].baidu.com
|
||||
NS_LITERAL_CSTRING("m.mogujie.com"),
|
||||
NS_LITERAL_CSTRING("touch.qunar.com"),
|
||||
NS_LITERAL_CSTRING("mjs.sinaimg.cn"), // for sina.cn
|
||||
NS_LITERAL_CSTRING("static.qiyi.com"), // for m.iqiyi.com
|
||||
NS_LITERAL_CSTRING("cdn.kuaidi100.com"), // for m.kuaidi100.com
|
||||
NS_LITERAL_CSTRING("m.pc6.com"),
|
||||
NS_LITERAL_CSTRING("m.haosou.com"),
|
||||
NS_LITERAL_CSTRING("m.mi.com"),
|
||||
NS_LITERAL_CSTRING("wappass.baidu.com"),
|
||||
NS_LITERAL_CSTRING("m.video.baidu.com"),
|
||||
NS_LITERAL_CSTRING("m.video.baidu.com"),
|
||||
NS_LITERAL_CSTRING("imgcache.gtimg.cn"), // for m.v.qq.com
|
||||
NS_LITERAL_CSTRING("s.tabelog.jp"),
|
||||
NS_LITERAL_CSTRING("s.yimg.jp"), // for s.tabelog.jp
|
||||
NS_LITERAL_CSTRING("i.yimg.jp"), // for *.yahoo.co.jp
|
||||
NS_LITERAL_CSTRING("ai.yimg.jp"), // for *.yahoo.co.jp
|
||||
NS_LITERAL_CSTRING("m.finance.yahoo.co.jp"),
|
||||
NS_LITERAL_CSTRING("daily.c.yimg.jp"), // for sp.daily.co.jp
|
||||
NS_LITERAL_CSTRING("stat100.ameba.jp"), // for ameblo.jp
|
||||
NS_LITERAL_CSTRING("user.ameba.jp"), // for ameblo.jp
|
||||
NS_LITERAL_CSTRING("www.goo.ne.jp"),
|
||||
NS_LITERAL_CSTRING("x.gnst.jp"), // for mobile.gnavi.co.jp
|
||||
NS_LITERAL_CSTRING("c.x.gnst.jp"), // for mobile.gnavi.co.jp
|
||||
NS_LITERAL_CSTRING("www.smbc-card.com"),
|
||||
NS_LITERAL_CSTRING("static.card.jp.rakuten-static.com"), // for rakuten-card.co.jp
|
||||
NS_LITERAL_CSTRING("img.travel.rakuten.co.jp"), // for travel.rakuten.co.jp
|
||||
NS_LITERAL_CSTRING("img.mixi.net"), // for mixi.jp
|
||||
NS_LITERAL_CSTRING("girlschannel.net"),
|
||||
NS_LITERAL_CSTRING("www.fancl.co.jp"),
|
||||
NS_LITERAL_CSTRING("s.cosme.net"),
|
||||
NS_LITERAL_CSTRING("www.sapporobeer.jp"),
|
||||
NS_LITERAL_CSTRING("www.mapion.co.jp"),
|
||||
NS_LITERAL_CSTRING("touch.navitime.co.jp"),
|
||||
NS_LITERAL_CSTRING("sp.mbga.jp"),
|
||||
NS_LITERAL_CSTRING("ava-a.sp.mbga.jp"), // for sp.mbga.jp
|
||||
NS_LITERAL_CSTRING("www.ntv.co.jp"),
|
||||
NS_LITERAL_CSTRING("mobile.suntory.co.jp"), // for suntory.jp
|
||||
NS_LITERAL_CSTRING("www.aeonsquare.net"),
|
||||
NS_LITERAL_CSTRING("mw.nikkei.com"),
|
||||
NS_LITERAL_CSTRING("www.nhk.or.jp"),
|
||||
NS_LITERAL_CSTRING("www.tokyo-sports.co.jp"),
|
||||
NS_LITERAL_CSTRING("www.bellemaison.jp"),
|
||||
NS_LITERAL_CSTRING("www.kuronekoyamato.co.jp"),
|
||||
NS_LITERAL_CSTRING("formassist.jp"), // for orico.jp
|
||||
NS_LITERAL_CSTRING("sp.m.reuters.co.jp"),
|
||||
NS_LITERAL_CSTRING("www.atre.co.jp"),
|
||||
NS_LITERAL_CSTRING("www.jtb.co.jp"),
|
||||
NS_LITERAL_CSTRING("www.sharp.co.jp"),
|
||||
NS_LITERAL_CSTRING("www.biccamera.com"),
|
||||
NS_LITERAL_CSTRING("weathernews.jp"),
|
||||
NS_LITERAL_CSTRING("cache.ymail.jp"), // for www.yamada-denkiweb.com
|
||||
};
|
||||
static const size_t sNumFullDomainsOnWhitelist =
|
||||
MOZ_ARRAY_LENGTH(sFullDomainsOnWhitelist);
|
||||
|
||||
// Skip 0th (dummy) entry in whitelist, unless a pref is enabled.
|
||||
const size_t firstWhitelistIdx = IsWhitelistingTestDomains() ? 0 : 1;
|
||||
|
||||
for (size_t i = firstWhitelistIdx; i < sNumFullDomainsOnWhitelist; ++i) {
|
||||
if (hostStr == sFullDomainsOnWhitelist[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks if the given URI's host is on our "base domain" whitelist
|
||||
// (i.e. if it's a subdomain of some host that we've whitelisted as needing
|
||||
// unprefixing for all its subdomains)
|
||||
static bool
|
||||
IsOnBaseDomainWhitelist(nsIURI* aURI)
|
||||
{
|
||||
static const nsLiteralCString sBaseDomainsOnWhitelist[] = {
|
||||
// 0th entry only active when testing:
|
||||
NS_LITERAL_CSTRING("test2.example.org"),
|
||||
NS_LITERAL_CSTRING("tbcdn.cn"), // for m.taobao.com
|
||||
NS_LITERAL_CSTRING("alicdn.com"), // for m.taobao.com
|
||||
NS_LITERAL_CSTRING("dpfile.com"), // for m.dianping.com
|
||||
NS_LITERAL_CSTRING("hao123img.com"), // for hao123.com
|
||||
NS_LITERAL_CSTRING("tabelog.k-img.com"), // for s.tabelog.com
|
||||
NS_LITERAL_CSTRING("tsite.jp"), // for *.tsite.jp
|
||||
};
|
||||
static const size_t sNumBaseDomainsOnWhitelist =
|
||||
MOZ_ARRAY_LENGTH(sBaseDomainsOnWhitelist);
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
|
||||
if (tldService) {
|
||||
// Skip 0th test-entry in whitelist, unless the testing pref is enabled.
|
||||
const size_t firstWhitelistIdx = IsWhitelistingTestDomains() ? 0 : 1;
|
||||
|
||||
// Right now, the test base-domain "test2.example.org" is the only entry in
|
||||
// its whitelist with a nonzero "depth". So we'll only bother going beyond
|
||||
// 0 depth (to 1) if that entry is enabled. (No point in slowing down the
|
||||
// normal codepath, for the benefit of a disabled test domain.) If we add a
|
||||
// "real" base-domain with a depth of >= 1 to our whitelist, we can get rid
|
||||
// of this conditional & just make this a static variable.
|
||||
const uint32_t maxSubdomainDepth = IsWhitelistingTestDomains() ? 1 : 0;
|
||||
|
||||
for (uint32_t subdomainDepth = 0;
|
||||
subdomainDepth <= maxSubdomainDepth; ++subdomainDepth) {
|
||||
|
||||
// Get the base domain (to depth |subdomainDepth|) from passed-in URI:
|
||||
nsAutoCString baseDomainStr;
|
||||
nsresult rv = tldService->GetBaseDomain(aURI, subdomainDepth,
|
||||
baseDomainStr);
|
||||
if (NS_FAILED(rv)) {
|
||||
// aURI doesn't have |subdomainDepth| levels of subdomains. If we got
|
||||
// here without a match yet, then aURI is not on our whitelist.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare the base domain against each entry in our whitelist:
|
||||
for (size_t i = firstWhitelistIdx; i < sNumBaseDomainsOnWhitelist; ++i) {
|
||||
if (baseDomainStr == sBaseDomainsOnWhitelist[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The actual (non-cached) implementation of IsOnCSSUnprefixingWhitelist():
|
||||
static bool
|
||||
IsOnCSSUnprefixingWhitelistImpl(nsIURI* aURI)
|
||||
{
|
||||
// Check scheme, so we can drop any non-HTTP/HTTPS URIs right away
|
||||
nsAutoCString schemeStr;
|
||||
nsresult rv = aURI->GetScheme(schemeStr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Only proceed if scheme is "http" or "https"
|
||||
if (!(StringBeginsWith(schemeStr, NS_LITERAL_CSTRING("http")) &&
|
||||
(schemeStr.Length() == 4 ||
|
||||
(schemeStr.Length() == 5 && schemeStr[4] == 's')))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (IsOnFullDomainWhitelist(aURI) ||
|
||||
IsOnBaseDomainWhitelist(aURI));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
nsPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
if (mIsOnCSSUnprefixingWhitelist.isNothing()) {
|
||||
// Value not cached -- perform our lazy whitelist-check.
|
||||
// (NOTE: If our URI is mutable, we just assume it's not on the whitelist,
|
||||
// since our caching strategy won't work. This isn't expected to be common.)
|
||||
mIsOnCSSUnprefixingWhitelist.emplace(
|
||||
mCodebaseImmutable &&
|
||||
IsOnCSSUnprefixingWhitelistImpl(mCodebase));
|
||||
}
|
||||
|
||||
return *mIsOnCSSUnprefixingWhitelist;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
NS_IMPL_CLASSINFO(nsExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
|
||||
|
@ -818,15 +623,6 @@ nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsExpandedPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
// CSS Unprefixing Whitelist is a per-origin thing; doesn't really make sense
|
||||
// for an expanded principal. (And probably shouldn't be needed.)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,6 @@ public:
|
|||
NS_IMETHOD GetDomain(nsIURI** aDomain) override;
|
||||
NS_IMETHOD SetDomain(nsIURI* aDomain) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
virtual bool IsOnCSSUnprefixingWhitelist() override;
|
||||
bool IsCodebasePrincipal() const override { return true; }
|
||||
nsresult GetOriginInternal(nsACString& aOrigin) override;
|
||||
|
||||
|
@ -51,7 +50,6 @@ public:
|
|||
bool mCodebaseImmutable;
|
||||
bool mDomainImmutable;
|
||||
bool mInitialized;
|
||||
mozilla::Maybe<bool> mIsOnCSSUnprefixingWhitelist; // Lazily-computed
|
||||
|
||||
protected:
|
||||
virtual ~nsPrincipal();
|
||||
|
@ -77,7 +75,6 @@ public:
|
|||
NS_IMETHOD SetDomain(nsIURI* aDomain) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
virtual bool AddonHasPermission(const nsAString& aPerm) override;
|
||||
virtual bool IsOnCSSUnprefixingWhitelist() override;
|
||||
virtual nsresult GetScriptLocation(nsACString &aStr) override;
|
||||
nsresult GetOriginInternal(nsACString& aOrigin) override;
|
||||
|
||||
|
|
|
@ -212,6 +212,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
[browser_rules_selector-highlighter_02.js]
|
||||
[browser_rules_selector-highlighter_03.js]
|
||||
[browser_rules_selector-highlighter_04.js]
|
||||
[browser_rules_selector-highlighter_05.js]
|
||||
[browser_rules_selector_highlight.js]
|
||||
[browser_rules_strict-search-filter-computed-list_01.js]
|
||||
[browser_rules_strict-search-filter_01.js]
|
||||
|
|
|
@ -22,6 +22,8 @@ add_task(function* () {
|
|||
|
||||
let testActor = yield getTestActorWithoutToolbox(tab);
|
||||
let inspector = yield clickOnInspectMenuItem(testActor, "span");
|
||||
yield getRuleViewSelectorHighlighterIcon(inspector.ruleview.view,
|
||||
"element", 3);
|
||||
|
||||
checkRuleViewContent(inspector.ruleview.view);
|
||||
});
|
||||
|
@ -57,4 +59,3 @@ function checkRuleViewContent({styleDocument}) {
|
|||
is(propertyValues.length, 1, "There's only one property value, as expected");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ function* testSelectorHighlight(view, name) {
|
|||
info("Test creating selector highlighter");
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, name);
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, name);
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
|
|
@ -18,6 +18,7 @@ add_task(function* () {
|
|||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#test1", inspector);
|
||||
yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
|
||||
yield elementStyleInherit(inspector, view);
|
||||
});
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ add_task(function* () {
|
|||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("a", inspector);
|
||||
yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
|
||||
yield elementStyleInherit(inspector, view);
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ add_task(function* () {
|
|||
let highlighters = view.highlighters;
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
|
|
@ -24,7 +24,7 @@ add_task(function* () {
|
|||
"No selectorhighlighter exist in the rule-view");
|
||||
|
||||
info("Clicking on a selector icon");
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
|
||||
|
||||
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
|
||||
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
|
||||
|
|
|
@ -46,7 +46,7 @@ add_task(function* () {
|
|||
// Inject the mock highlighter in the rule-view
|
||||
view.selectorHighlighter = HighlighterFront;
|
||||
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
|
||||
info("Checking that the HighlighterFront's show/hide methods are called");
|
||||
|
||||
|
@ -60,7 +60,7 @@ add_task(function* () {
|
|||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("p", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "p");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "p");
|
||||
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "P",
|
||||
|
@ -69,7 +69,7 @@ add_task(function* () {
|
|||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "BODY",
|
||||
"The right NodeFront is passed to the highlighter (2)");
|
||||
|
|
|
@ -39,7 +39,7 @@ add_task(function* () {
|
|||
|
||||
info("Select .node-1 and click on the .node-1 selector icon");
|
||||
yield selectNode(".node-1", inspector);
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown");
|
||||
|
||||
|
@ -48,12 +48,12 @@ add_task(function* () {
|
|||
ok(!HighlighterFront.isShown, "The highlighter is now hidden");
|
||||
|
||||
info("With .node-1 still selected, click on the div selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown again");
|
||||
|
||||
info("With .node-1 still selected, click again on the .node-1 selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown,
|
||||
"The highlighter is shown again since the clicked selector was different");
|
||||
|
@ -64,14 +64,14 @@ add_task(function* () {
|
|||
"The highlighter is still shown after selection");
|
||||
|
||||
info("With .node-2 selected, click on the div selector icon");
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(HighlighterFront.isShown,
|
||||
"The highlighter is shown still since the selected was different");
|
||||
|
||||
info("Switching back to .node-1 and clicking on the div selector");
|
||||
yield selectNode(".node-1", inspector);
|
||||
icon = getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
ok(!HighlighterFront.isShown,
|
||||
"The highlighter is hidden now that the same selector was clicked");
|
||||
|
|
|
@ -39,7 +39,7 @@ add_task(function* () {
|
|||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("p", inspector);
|
||||
let icon = getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.nodeFront.tagName, "P",
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the selector highlighter is correctly shown when clicking on a
|
||||
// inherited element
|
||||
|
||||
// Note that in this test, we mock the highlighter front, merely testing the
|
||||
// behavior of the style-inspector UI for now
|
||||
|
||||
const TEST_URI = `
|
||||
<div style="cursor:pointer">
|
||||
A
|
||||
<div style="cursor:pointer">
|
||||
B<a>Cursor</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
|
||||
// Mock the highlighter front to get the reference of the NodeFront
|
||||
let HighlighterFront = {
|
||||
isShown: false,
|
||||
nodeFront: null,
|
||||
options: null,
|
||||
show: function (nodeFront, options) {
|
||||
this.nodeFront = nodeFront;
|
||||
this.options = options;
|
||||
this.isShown = true;
|
||||
},
|
||||
hide: function () {
|
||||
this.nodeFront = null;
|
||||
this.options = null;
|
||||
this.isShown = false;
|
||||
}
|
||||
};
|
||||
// Inject the mock highlighter in the rule-view
|
||||
view.selectorHighlighter = HighlighterFront;
|
||||
|
||||
info("Checking that the right NodeFront reference and options are passed");
|
||||
yield selectNode("a", inspector);
|
||||
|
||||
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector,
|
||||
"body > div:nth-child(1) > div:nth-child(1) > a:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector,
|
||||
"body > div:nth-child(1) > div:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
|
||||
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
|
||||
yield clickSelectorIcon(icon, view);
|
||||
is(HighlighterFront.options.selector, "body > div:nth-child(1)",
|
||||
"The right selector option is passed to the highlighter (1)");
|
||||
});
|
|
@ -44,76 +44,6 @@ addTab = function (url) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
name: propName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element's inline style property value.
|
||||
* @param {TestActor} testActor
|
||||
|
@ -129,49 +59,6 @@ function getStyle(testActor, selector, propName) {
|
|||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* When a tooltip is closed, this ends up "commiting" the value changed within
|
||||
* the tooltip (e.g. the color in case of a colorpicker) which, in turn, ends up
|
||||
|
@ -219,109 +106,6 @@ var waitForSuccess = Task.async(function* (validatorFn, desc = "untitled") {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText) {
|
||||
let rule;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a color change in a given color picker tooltip, and optionally wait
|
||||
* for a given element in the page to have its style changed as a result.
|
||||
|
@ -452,34 +236,6 @@ var openCubicBezierAndChangeCoords = Task.async(function* (view, ruleIndex,
|
|||
return {propEditor, swatch, bezierTooltip};
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate adding a new property in an existing rule in the rule-view.
|
||||
*
|
||||
|
@ -625,74 +381,6 @@ var togglePropStatus = Task.async(function* (view, textProp) {
|
|||
yield onRuleViewRefreshed;
|
||||
});
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
|
||||
// Use bottom alignment to avoid scrolling out of the parent element area.
|
||||
ruleEditor.closeBrace.scrollIntoView(false);
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
let win = view.styleWindow;
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
synthesizeKeys(searchValue, win);
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/**
|
||||
* Reload the current page and wait for the inspector to be initialized after
|
||||
* the navigation
|
||||
|
@ -778,26 +466,6 @@ function* sendKeysAndWaitForFocus(view, element, keys) {
|
|||
yield onFocus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a markupmutation event on the inspector that is for a style modification.
|
||||
* @param {InspectorPanel} inspector
|
||||
|
|
|
@ -149,19 +149,34 @@ RuleEditor.prototype = {
|
|||
}
|
||||
|
||||
if (this.rule.domRule.type !== CSSRule.KEYFRAME_RULE) {
|
||||
let selector = this.rule.domRule.selectors
|
||||
? this.rule.domRule.selectors.join(", ")
|
||||
: this.ruleView.inspector.selectionCssSelector;
|
||||
Task.spawn(function* () {
|
||||
let selector;
|
||||
|
||||
let selectorHighlighter = createChild(header, "span", {
|
||||
class: "ruleview-selectorhighlighter" +
|
||||
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
|
||||
" highlighted" : ""),
|
||||
title: l10n("rule.selectorHighlighter.tooltip")
|
||||
});
|
||||
selectorHighlighter.addEventListener("click", () => {
|
||||
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
|
||||
});
|
||||
if (this.rule.domRule.selectors) {
|
||||
// This is a "normal" rule with a selector.
|
||||
selector = this.rule.domRule.selectors.join(", ");
|
||||
} else if (this.rule.inherited) {
|
||||
// This is an inline style from an inherited rule. Need to resolve the unique
|
||||
// selector from the node which rule this is inherited from.
|
||||
selector = yield this.rule.inherited.getUniqueSelector();
|
||||
} else {
|
||||
// This is an inline style from the current node.
|
||||
selector = this.ruleView.inspector.selectionCssSelector;
|
||||
}
|
||||
|
||||
let selectorHighlighter = createChild(header, "span", {
|
||||
class: "ruleview-selectorhighlighter" +
|
||||
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
|
||||
" highlighted" : ""),
|
||||
title: l10n("rule.selectorHighlighter.tooltip")
|
||||
});
|
||||
selectorHighlighter.addEventListener("click", () => {
|
||||
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
|
||||
});
|
||||
|
||||
this.uniqueSelector = selector;
|
||||
this.emit("selector-icon-created");
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.openBrace = createChild(header, "span", {
|
||||
|
|
|
@ -88,123 +88,6 @@ addTab = function (url) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
let data = {
|
||||
selector,
|
||||
pseudo,
|
||||
name: propName
|
||||
};
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
let data = {
|
||||
selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name
|
||||
};
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* Polls a given function waiting for it to return true.
|
||||
*
|
||||
|
@ -258,109 +141,6 @@ var getFontFamilyDataURL = Task.async(function* (font, nodeFront) {
|
|||
* This object contains functions to get rules, get properties, ...
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText) {
|
||||
let rule;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a color change in a given color picker tooltip, and optionally wait
|
||||
* for a given element in the page to have its style changed as a result
|
||||
|
@ -400,100 +180,6 @@ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker,
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
ruleEditor.closeBrace.scrollIntoView();
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
let win = view.styleWindow;
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
synthesizeKeys(searchValue, win);
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/* *********************************************
|
||||
* COMPUTED-VIEW
|
||||
* *********************************************
|
||||
|
@ -539,23 +225,3 @@ function getComputedViewPropertyValue(view, name, propertyName) {
|
|||
return getComputedViewProperty(view, name, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* globals registerTestActor, getTestActor, Task, openToolboxForTab, gBrowser */
|
||||
/* import-globals-from ../../framework/test/shared-head.js */
|
||||
|
||||
var {getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
|
||||
|
||||
// This file contains functions related to the inspector that are also of interest to
|
||||
// other test directores as well.
|
||||
|
@ -184,3 +187,356 @@ function manualThrottle() {
|
|||
|
||||
return throttle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a content -> chrome message on the message manager (the window
|
||||
* messagemanager is used).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name
|
||||
* @return {Promise} A promise that resolves to the response data when the
|
||||
* message has been received
|
||||
*/
|
||||
function waitForContentMessage(name) {
|
||||
info("Expecting message " + name + " from content");
|
||||
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let def = defer();
|
||||
mm.addMessageListener(name, function onMessage(msg) {
|
||||
mm.removeMessageListener(name, onMessage);
|
||||
def.resolve(msg.data);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script (chrome -> content) and wait for a
|
||||
* response message with the same name (content -> chrome).
|
||||
*
|
||||
* @param {String} name
|
||||
* The message name. Should be one of the messages defined
|
||||
* in doc_frame_script.js
|
||||
* @param {Object} data
|
||||
* Optional data to send along
|
||||
* @param {Object} objects
|
||||
* Optional CPOW objects to send along
|
||||
* @param {Boolean} expectResponse
|
||||
* If set to false, don't wait for a response with the same name
|
||||
* from the content script. Defaults to true.
|
||||
* @return {Promise} Resolves to the response data if a response is expected,
|
||||
* immediately resolves otherwise
|
||||
*/
|
||||
function executeInContent(name, data = {}, objects = {},
|
||||
expectResponse = true) {
|
||||
info("Sending message " + name + " to content");
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.sendAsyncMessage(name, data, objects);
|
||||
if (expectResponse) {
|
||||
return waitForContentMessage(name);
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and get back the requested
|
||||
* computed style property.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} name
|
||||
* name of the property.
|
||||
*/
|
||||
function* getComputedStyleProperty(selector, pseudo, propName) {
|
||||
return yield executeInContent("Test:GetComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
name: propName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an async message to the frame script and wait until the requested
|
||||
* computed style property has the expected value.
|
||||
*
|
||||
* @param {String} selector
|
||||
* The selector used to obtain the element.
|
||||
* @param {String} pseudo
|
||||
* pseudo id to query, or null.
|
||||
* @param {String} prop
|
||||
* name of the property.
|
||||
* @param {String} expected
|
||||
* expected value of property
|
||||
* @param {String} name
|
||||
* the name used in test message
|
||||
*/
|
||||
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
|
||||
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
|
||||
{selector,
|
||||
pseudo,
|
||||
expected,
|
||||
name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an inplace editable element, click to switch it to edit mode, wait for
|
||||
* focus
|
||||
*
|
||||
* @return a promise that resolves to the inplace-editor element when ready
|
||||
*/
|
||||
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
|
||||
yOffset = 1, options = {}) {
|
||||
let onFocus = once(editable.parentNode, "focus", true);
|
||||
info("Clicking on editable field to turn to edit mode");
|
||||
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
|
||||
editable.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
|
||||
info("Editable field gained focus, returning the input field now");
|
||||
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
|
||||
|
||||
return onEdit;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
|
||||
* selector.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view for which the rule
|
||||
* object is wanted
|
||||
* @param {Number} index
|
||||
* If there are more than 1 rule with the same selector, you may pass a
|
||||
* index to determine which of the rules you want.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getRuleViewRule(view, selectorText, index = 0) {
|
||||
let rule;
|
||||
let pos = 0;
|
||||
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
|
||||
let selector = r.querySelector(".ruleview-selectorcontainer, " +
|
||||
".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
if (index == pos) {
|
||||
rule = r;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get references to the name and value span nodes corresponding to a given
|
||||
* selector and property name in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
|
||||
*/
|
||||
function getRuleViewProperty(view, selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
for (let p of rule.querySelectorAll(".ruleview-property")) {
|
||||
let nameSpan = p.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = p.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given selector and name
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for the property in
|
||||
* @param {String} propertyName
|
||||
* The name of the property
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getRuleViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getRuleViewProperty(view, selectorText, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selector DOM element corresponding to a given selector
|
||||
* in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @return {DOMNode} The selector DOM element
|
||||
*/
|
||||
function getRuleViewSelector(view, selectorText) {
|
||||
let rule = getRuleViewRule(view, selectorText);
|
||||
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the selectorhighlighter icon DOM element corresponding to
|
||||
* a given selector in the rule-view
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} selectorText
|
||||
* The selector in the rule-view to look for
|
||||
* @param {Number} index
|
||||
* If there are more than 1 rule with the same selector, use this index
|
||||
* to determine which one should be retrieved. Defaults to 0
|
||||
* @return {DOMNode} The selectorhighlighter icon DOM element
|
||||
*/
|
||||
var getRuleViewSelectorHighlighterIcon = Task.async(function* (view,
|
||||
selectorText, index = 0) {
|
||||
let rule = getRuleViewRule(view, selectorText, index);
|
||||
|
||||
let editor = rule._ruleEditor;
|
||||
if (!editor.uniqueSelector) {
|
||||
yield once(editor, "selector-icon-created");
|
||||
}
|
||||
|
||||
return rule.querySelector(".ruleview-selectorhighlighter");
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a rule-link from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {DOMNode} The link if any at this index
|
||||
*/
|
||||
function getRuleViewLinkByIndex(view, index) {
|
||||
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {Number} index
|
||||
* The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".ruleview-rule-source-label").textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* An instance of RuleEditor that will receive the new property
|
||||
* @return a promise that resolves to the newly created editor when ready and
|
||||
* focused
|
||||
*/
|
||||
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
|
||||
info("Clicking on a close ruleEditor brace to start editing a new property");
|
||||
|
||||
// Use bottom alignment to avoid scrolling out of the parent element area.
|
||||
ruleEditor.closeBrace.scrollIntoView(false);
|
||||
let editor = yield focusEditableField(ruleEditor.ruleView,
|
||||
ruleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(ruleEditor.newPropSpan), editor,
|
||||
"Focused editor is the new property editor.");
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new property name in the rule-view, focusing a new property editor
|
||||
* by clicking on the close brace, and then entering the given text.
|
||||
* Keep in mind that the rule-view knows how to handle strings with multiple
|
||||
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
|
||||
*
|
||||
* @param {RuleEditor} ruleEditor
|
||||
* The instance of RuleEditor that will receive the new property(ies)
|
||||
* @param {String} inputValue
|
||||
* The text to be entered in the new property name field
|
||||
* @return a promise that resolves when the new property name has been entered
|
||||
* and once the value field is focused
|
||||
*/
|
||||
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
|
||||
info("Creating a new property editor");
|
||||
let editor = yield focusNewRuleViewProperty(ruleEditor);
|
||||
|
||||
info("Entering the value " + inputValue);
|
||||
editor.input.value = inputValue;
|
||||
|
||||
info("Submitting the new value and waiting for value field focus");
|
||||
let onFocus = once(ruleEditor.element, "focus", true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {},
|
||||
ruleEditor.element.ownerDocument.defaultView);
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the search value for the rule-view filter styles search box.
|
||||
*
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @param {String} searchValue
|
||||
* The filter search value
|
||||
* @return a promise that resolves when the rule-view is filtered for the
|
||||
* search term
|
||||
*/
|
||||
var setSearchFilter = Task.async(function* (view, searchValue) {
|
||||
info("Setting filter text to \"" + searchValue + "\"");
|
||||
|
||||
let searchField = view.searchField;
|
||||
searchField.focus();
|
||||
|
||||
for (let key of searchValue.split("")) {
|
||||
EventUtils.synthesizeKey(key, {}, view.styleWindow);
|
||||
}
|
||||
|
||||
yield view.inspector.once("ruleview-filtered");
|
||||
});
|
||||
|
||||
/**
|
||||
* Open the style editor context menu and return all of it's items in a flat array
|
||||
* @param {CssRuleView} view
|
||||
* The instance of the rule-view panel
|
||||
* @return An array of MenuItems
|
||||
*/
|
||||
function openStyleContextMenuAndGetAllItems(view, target) {
|
||||
let menu = view._contextmenu._openMenu({target: target});
|
||||
|
||||
// Flatten all menu items into a single array to make searching through it easier
|
||||
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
|
||||
if (item.submenu) {
|
||||
return addItem(item.submenu.items);
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
|
|
@ -224,22 +224,36 @@ ToolSidebar.prototype = {
|
|||
|
||||
let previousTool = this._currentTool;
|
||||
if (previousTool) {
|
||||
if (this._telemetry) {
|
||||
this._telemetry.toolClosed(previousTool);
|
||||
}
|
||||
this.emit(previousTool + "-unselected");
|
||||
}
|
||||
|
||||
this._currentTool = id;
|
||||
|
||||
if (this._telemetry) {
|
||||
this._telemetry.toolOpened(this._currentTool);
|
||||
}
|
||||
|
||||
this.updateTelemetryOnChange(id, previousTool);
|
||||
this.emit(this._currentTool + "-selected");
|
||||
this.emit("select", this._currentTool);
|
||||
},
|
||||
|
||||
/**
|
||||
* Log toolClosed and toolOpened events on telemetry.
|
||||
*
|
||||
* @param {String} currentToolId
|
||||
* id of the tool being selected.
|
||||
* @param {String} previousToolId
|
||||
* id of the previously selected tool.
|
||||
*/
|
||||
updateTelemetryOnChange: function (currentToolId, previousToolId) {
|
||||
if (currentToolId === previousToolId || !this._telemetry) {
|
||||
// Skip telemetry if the tool id did not change or telemetry is unavailable.
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousToolId) {
|
||||
this._telemetry.toolClosed(previousToolId);
|
||||
}
|
||||
this._telemetry.toolOpened(currentToolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the sidebar.
|
||||
*
|
||||
|
@ -249,14 +263,9 @@ ToolSidebar.prototype = {
|
|||
show: function (id) {
|
||||
this._tabbox.removeAttribute("hidden");
|
||||
|
||||
// If an id is given, select the corresponding sidebar tab and record the
|
||||
// tool opened.
|
||||
// If an id is given, select the corresponding sidebar tab.
|
||||
if (id) {
|
||||
this._currentTool = id;
|
||||
|
||||
if (this._telemetry) {
|
||||
this._telemetry.toolOpened(this._currentTool);
|
||||
}
|
||||
this.select(id);
|
||||
}
|
||||
|
||||
this.emit("show");
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { L10N } = require("../l10n");
|
||||
const Actions = require("../actions/index");
|
||||
|
||||
const { button } = DOM;
|
||||
|
||||
/*
|
||||
* Clear button component
|
||||
* A type of tool button is responsible for cleaning network requests.
|
||||
*/
|
||||
function ClearButton({ onClick }) {
|
||||
return button({
|
||||
id: "requests-menu-clear-button",
|
||||
className: "devtools-button devtools-clear-icon",
|
||||
title: L10N.getStr("netmonitor.toolbar.clear"),
|
||||
onClick,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
undefined,
|
||||
dispatch => ({
|
||||
onClick: () => dispatch(Actions.clearRequests())
|
||||
})
|
||||
)(ClearButton);
|
|
@ -1,50 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { L10N } = require("../l10n");
|
||||
const Actions = require("../actions/index");
|
||||
|
||||
const { button, div } = DOM;
|
||||
|
||||
function FilterButtons({
|
||||
requestFilterTypes,
|
||||
toggleRequestFilterType,
|
||||
}) {
|
||||
const buttons = requestFilterTypes.entrySeq().map(([type, checked]) => {
|
||||
let classList = ["menu-filter-button"];
|
||||
checked && classList.push("checked");
|
||||
|
||||
return button({
|
||||
id: `requests-menu-filter-${type}-button`,
|
||||
key: type,
|
||||
className: classList.join(" "),
|
||||
"data-key": type,
|
||||
onClick: toggleRequestFilterType,
|
||||
onKeyDown: toggleRequestFilterType,
|
||||
}, L10N.getStr(`netmonitor.toolbar.filter.${type}`));
|
||||
}).toArray();
|
||||
|
||||
return div({ id: "requests-menu-filter-buttons" }, buttons);
|
||||
}
|
||||
|
||||
FilterButtons.propTypes = {
|
||||
requestFilterTypes: PropTypes.object.isRequired,
|
||||
toggleRequestFilterType: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({ requestFilterTypes: state.filters.requestFilterTypes }),
|
||||
(dispatch) => ({
|
||||
toggleRequestFilterType: (evt) => {
|
||||
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
|
||||
return;
|
||||
}
|
||||
dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key));
|
||||
},
|
||||
})
|
||||
)(FilterButtons);
|
|
@ -3,16 +3,12 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'clear-button.js',
|
||||
'filter-buttons.js',
|
||||
'request-list-content.js',
|
||||
'request-list-empty.js',
|
||||
'request-list-header.js',
|
||||
'request-list-item.js',
|
||||
'request-list-tooltip.js',
|
||||
'request-list.js',
|
||||
'search-box.js',
|
||||
'summary-button.js',
|
||||
'toggle-button.js',
|
||||
'statistics-panel.js',
|
||||
'toolbar.js',
|
||||
)
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const SearchBox = require("devtools/client/shared/components/search-box");
|
||||
const { L10N } = require("../l10n");
|
||||
const Actions = require("../actions/index");
|
||||
const { FILTER_SEARCH_DELAY } = require("../constants");
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
delay: FILTER_SEARCH_DELAY,
|
||||
keyShortcut: L10N.getStr("netmonitor.toolbar.filterFreetext.key"),
|
||||
placeholder: L10N.getStr("netmonitor.toolbar.filterFreetext.label"),
|
||||
type: "filter",
|
||||
}),
|
||||
(dispatch) => ({
|
||||
onChange: (text) => dispatch(Actions.setRequestFilterText(text)),
|
||||
})
|
||||
)(SearchBox);
|
|
@ -0,0 +1,229 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* globals document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { Chart } = require("devtools/client/shared/widgets/Chart");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const Actions = require("../actions/index");
|
||||
const { Filters } = require("../filter-predicates");
|
||||
const { L10N } = require("../l10n");
|
||||
const {
|
||||
getSizeWithDecimals,
|
||||
getTimeWithDecimals
|
||||
} = require("../utils/format-utils");
|
||||
|
||||
const { button, div } = DOM;
|
||||
|
||||
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
|
||||
const BACK_BUTTON = L10N.getStr("netmonitor.backButton");
|
||||
const CHARTS_CACHE_ENABLED = L10N.getStr("charts.cacheEnabled");
|
||||
const CHARTS_CACHE_DISABLED = L10N.getStr("charts.cacheDisabled");
|
||||
|
||||
/*
|
||||
* Statistics panel component
|
||||
* Performance analysis tool which shows you how long the browser takes to
|
||||
* download the different parts of your site.
|
||||
*/
|
||||
const StatisticsPanel = createClass({
|
||||
displayName: "StatisticsPanel",
|
||||
|
||||
propTypes: {
|
||||
closeStatistics: PropTypes.func.isRequired,
|
||||
enableRequestFilterTypeOnly: PropTypes.func.isRequired,
|
||||
requests: PropTypes.object,
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { requests } = this.props;
|
||||
let ready = requests && requests.every((req) =>
|
||||
req.contentSize !== undefined && req.mimeType && req.responseHeaders &&
|
||||
req.status !== undefined && req.totalTime !== undefined
|
||||
);
|
||||
|
||||
this.createChart({
|
||||
id: "primedCacheChart",
|
||||
title: CHARTS_CACHE_ENABLED,
|
||||
data: ready ? this.sanitizeChartDataSource(requests, false) : null,
|
||||
});
|
||||
|
||||
this.createChart({
|
||||
id: "emptyCacheChart",
|
||||
title: CHARTS_CACHE_DISABLED,
|
||||
data: ready ? this.sanitizeChartDataSource(requests, true) : null,
|
||||
});
|
||||
},
|
||||
|
||||
createChart({ id, title, data }) {
|
||||
// Create a new chart.
|
||||
let chart = Chart.PieTable(document, {
|
||||
diameter: NETWORK_ANALYSIS_PIE_CHART_DIAMETER,
|
||||
title,
|
||||
data,
|
||||
strings: {
|
||||
size: (value) =>
|
||||
L10N.getFormatStr("charts.sizeKB", getSizeWithDecimals(value / 1024)),
|
||||
time: (value) =>
|
||||
L10N.getFormatStr("charts.totalS", getTimeWithDecimals(value / 1000)),
|
||||
},
|
||||
totals: {
|
||||
cached: (total) => L10N.getFormatStr("charts.totalCached", total),
|
||||
count: (total) => L10N.getFormatStr("charts.totalCount", total),
|
||||
size: (total) =>
|
||||
L10N.getFormatStr("charts.totalSize", getSizeWithDecimals(total / 1024)),
|
||||
time: (total) => {
|
||||
let seconds = total / 1000;
|
||||
let string = getTimeWithDecimals(seconds);
|
||||
return PluralForm.get(seconds,
|
||||
L10N.getStr("charts.totalSeconds")).replace("#1", string);
|
||||
},
|
||||
},
|
||||
sorted: true,
|
||||
});
|
||||
|
||||
chart.on("click", (_, { label }) => {
|
||||
// Reset FilterButtons and enable one filter exclusively
|
||||
this.props.closeStatistics();
|
||||
this.props.enableRequestFilterTypeOnly(label);
|
||||
});
|
||||
|
||||
let container = this.refs[id];
|
||||
|
||||
// Nuke all existing charts of the specified type.
|
||||
while (container.hasChildNodes()) {
|
||||
container.firstChild.remove();
|
||||
}
|
||||
|
||||
container.appendChild(chart.node);
|
||||
},
|
||||
|
||||
sanitizeChartDataSource(requests, emptyCache) {
|
||||
let data = [
|
||||
"html", "css", "js", "xhr", "fonts", "images", "media", "flash", "ws", "other"
|
||||
].map((type) => ({ cached: 0, count: 0, label: type, size: 0, time: 0 }));
|
||||
|
||||
for (let request of requests) {
|
||||
let type;
|
||||
|
||||
if (Filters.html(request)) {
|
||||
// "html"
|
||||
type = 0;
|
||||
} else if (Filters.css(request)) {
|
||||
// "css"
|
||||
type = 1;
|
||||
} else if (Filters.js(request)) {
|
||||
// "js"
|
||||
type = 2;
|
||||
} else if (Filters.fonts(request)) {
|
||||
// "fonts"
|
||||
type = 4;
|
||||
} else if (Filters.images(request)) {
|
||||
// "images"
|
||||
type = 5;
|
||||
} else if (Filters.media(request)) {
|
||||
// "media"
|
||||
type = 6;
|
||||
} else if (Filters.flash(request)) {
|
||||
// "flash"
|
||||
type = 7;
|
||||
} else if (Filters.ws(request)) {
|
||||
// "ws"
|
||||
type = 8;
|
||||
} else if (Filters.xhr(request)) {
|
||||
// Verify XHR last, to categorize other mime types in their own blobs.
|
||||
// "xhr"
|
||||
type = 3;
|
||||
} else {
|
||||
// "other"
|
||||
type = 9;
|
||||
}
|
||||
|
||||
if (emptyCache || !this.responseIsFresh(request)) {
|
||||
data[type].time += request.totalTime || 0;
|
||||
data[type].size += request.contentSize || 0;
|
||||
} else {
|
||||
data[type].cached++;
|
||||
}
|
||||
data[type].count++;
|
||||
}
|
||||
|
||||
return data.filter(e => e.count > 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the "Expiration Calculations" defined in section 13.2.4 of the
|
||||
* "HTTP/1.1: Caching in HTTP" spec holds true for a collection of headers.
|
||||
*
|
||||
* @param object
|
||||
* An object containing the { responseHeaders, status } properties.
|
||||
* @return boolean
|
||||
* True if the response is fresh and loaded from cache.
|
||||
*/
|
||||
responseIsFresh({ responseHeaders, status }) {
|
||||
// Check for a "304 Not Modified" status and response headers availability.
|
||||
if (status != 304 || !responseHeaders) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let list = responseHeaders.headers;
|
||||
let cacheControl = list.find(e => e.name.toLowerCase() === "cache-control");
|
||||
let expires = list.find(e => e.name.toLowerCase() === "expires");
|
||||
|
||||
// Check the "Cache-Control" header for a maximum age value.
|
||||
if (cacheControl) {
|
||||
let maxAgeMatch =
|
||||
cacheControl.value.match(/s-maxage\s*=\s*(\d+)/) ||
|
||||
cacheControl.value.match(/max-age\s*=\s*(\d+)/);
|
||||
|
||||
if (maxAgeMatch && maxAgeMatch.pop() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the "Expires" header for a valid date.
|
||||
if (expires && Date.parse(expires.value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { closeStatistics } = this.props;
|
||||
return (
|
||||
div({ className: "statistics-panel" },
|
||||
button({
|
||||
className: "back-button devtools-toolbarbutton",
|
||||
"data-text-only": "true",
|
||||
title: BACK_BUTTON,
|
||||
onClick: closeStatistics,
|
||||
}, BACK_BUTTON),
|
||||
div({ className: "charts-container devtools-responsive-container" },
|
||||
div({ ref: "primedCacheChart", className: "charts primed-cache-chart" }),
|
||||
div({ className: "splitter devtools-side-splitter" }),
|
||||
div({ ref: "emptyCacheChart", className: "charts empty-cache-chart" }),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
requests: state.requests.requests.valueSeq(),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
closeStatistics: () => dispatch(Actions.openStatistics(false)),
|
||||
enableRequestFilterTypeOnly: (label) =>
|
||||
dispatch(Actions.enableRequestFilterTypeOnly(label)),
|
||||
})
|
||||
)(StatisticsPanel);
|
|
@ -1,54 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const { L10N } = require("../l10n");
|
||||
const { getDisplayedRequestsSummary } = require("../selectors/index");
|
||||
const Actions = require("../actions/index");
|
||||
const {
|
||||
getSizeWithDecimals,
|
||||
getTimeWithDecimals,
|
||||
} = require("../utils/format-utils");
|
||||
|
||||
const { button, span } = DOM;
|
||||
|
||||
function SummaryButton({
|
||||
summary,
|
||||
triggerSummary,
|
||||
}) {
|
||||
let { count, bytes, millis } = summary;
|
||||
const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
||||
PluralForm.get(count, L10N.getStr("networkMenu.summary"))
|
||||
.replace("#1", count)
|
||||
.replace("#2", getSizeWithDecimals(bytes / 1024))
|
||||
.replace("#3", getTimeWithDecimals(millis / 1000));
|
||||
|
||||
return button({
|
||||
id: "requests-menu-network-summary-button",
|
||||
className: "devtools-button",
|
||||
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
|
||||
onClick: triggerSummary,
|
||||
},
|
||||
span({ className: "summary-info-icon" }),
|
||||
span({ className: "summary-info-text" }, text));
|
||||
}
|
||||
|
||||
SummaryButton.propTypes = {
|
||||
summary: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
summary: getDisplayedRequestsSummary(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
triggerSummary: () => {
|
||||
dispatch(Actions.openStatistics(true));
|
||||
},
|
||||
})
|
||||
)(SummaryButton);
|
|
@ -1,51 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { L10N } = require("../l10n");
|
||||
const Actions = require("../actions/index");
|
||||
const { isSidebarToggleButtonDisabled } = require("../selectors/index");
|
||||
|
||||
const { button } = DOM;
|
||||
|
||||
function ToggleButton({
|
||||
disabled,
|
||||
open,
|
||||
onToggle,
|
||||
}) {
|
||||
let className = ["devtools-button"];
|
||||
if (!open) {
|
||||
className.push("pane-collapsed");
|
||||
}
|
||||
|
||||
const title = open ? L10N.getStr("collapseDetailsPane") :
|
||||
L10N.getStr("expandDetailsPane");
|
||||
|
||||
return button({
|
||||
id: "details-pane-toggle",
|
||||
className: className.join(" "),
|
||||
title,
|
||||
disabled,
|
||||
tabIndex: "0",
|
||||
onMouseDown: onToggle,
|
||||
});
|
||||
}
|
||||
|
||||
ToggleButton.propTypes = {
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
disabled: isSidebarToggleButtonDisabled(state),
|
||||
open: state.ui.sidebarOpen,
|
||||
}),
|
||||
(dispatch) => ({
|
||||
onToggle: () => dispatch(Actions.toggleSidebar())
|
||||
})
|
||||
)(ToggleButton);
|
|
@ -7,31 +7,150 @@
|
|||
const {
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const ClearButton = createFactory(require("./clear-button"));
|
||||
const FilterButtons = createFactory(require("./filter-buttons"));
|
||||
const ToolbarSearchBox = createFactory(require("./search-box"));
|
||||
const SummaryButton = createFactory(require("./summary-button"));
|
||||
const ToggleButton = createFactory(require("./toggle-button"));
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const Actions = require("../actions/index");
|
||||
const { L10N } = require("../l10n");
|
||||
const {
|
||||
getDisplayedRequestsSummary,
|
||||
isSidebarToggleButtonDisabled,
|
||||
} = require("../selectors/index");
|
||||
const {
|
||||
getSizeWithDecimals,
|
||||
getTimeWithDecimals,
|
||||
} = require("../utils/format-utils");
|
||||
const { FILTER_SEARCH_DELAY } = require("../constants");
|
||||
|
||||
const { span } = DOM;
|
||||
// Components
|
||||
const SearchBox = createFactory(require("devtools/client/shared/components/search-box"));
|
||||
|
||||
const { button, div, span } = DOM;
|
||||
|
||||
const COLLPASE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
|
||||
const EXPAND_DETAILS_PANE = L10N.getStr("expandDetailsPane");
|
||||
const SEARCH_KEY_SHORTCUT = L10N.getStr("netmonitor.toolbar.filterFreetext.key");
|
||||
const SEARCH_PLACE_HOLDER = L10N.getStr("netmonitor.toolbar.filterFreetext.label");
|
||||
const TOOLBAR_CLEAR = L10N.getStr("netmonitor.toolbar.clear");
|
||||
|
||||
/*
|
||||
* Network monitor toolbar component
|
||||
* Toolbar contains a set of useful tools to control network requests
|
||||
*/
|
||||
function Toolbar() {
|
||||
return span({ className: "devtools-toolbar devtools-toolbar-container" },
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
ClearButton(),
|
||||
FilterButtons()
|
||||
),
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
SummaryButton(),
|
||||
ToolbarSearchBox(),
|
||||
ToggleButton()
|
||||
function Toolbar({
|
||||
clearRequests,
|
||||
openStatistics,
|
||||
requestFilterTypes,
|
||||
setRequestFilterText,
|
||||
sidebarToggleDisabled,
|
||||
sidebarOpen,
|
||||
summary,
|
||||
toggleRequestFilterType,
|
||||
toggleSidebar,
|
||||
}) {
|
||||
let toggleButtonClassName = ["devtools-button"];
|
||||
if (!sidebarOpen) {
|
||||
toggleButtonClassName.push("pane-collapsed");
|
||||
}
|
||||
|
||||
let { count, bytes, millis } = summary;
|
||||
const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
||||
PluralForm.get(count, L10N.getStr("networkMenu.summary"))
|
||||
.replace("#1", count)
|
||||
.replace("#2", getSizeWithDecimals(bytes / 1024))
|
||||
.replace("#3", getTimeWithDecimals(millis / 1000));
|
||||
|
||||
const buttons = requestFilterTypes.entrySeq().map(([type, checked]) => {
|
||||
let classList = ["menu-filter-button"];
|
||||
checked && classList.push("checked");
|
||||
|
||||
return (
|
||||
button({
|
||||
id: `requests-menu-filter-${type}-button`,
|
||||
key: type,
|
||||
className: classList.join(" "),
|
||||
"data-key": type,
|
||||
onClick: toggleRequestFilterType,
|
||||
onKeyDown: toggleRequestFilterType,
|
||||
},
|
||||
L10N.getStr(`netmonitor.toolbar.filter.${type}`)
|
||||
)
|
||||
);
|
||||
}).toArray();
|
||||
|
||||
return (
|
||||
span({ className: "devtools-toolbar devtools-toolbar-container" },
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-clear-button",
|
||||
className: "devtools-button devtools-clear-icon",
|
||||
title: TOOLBAR_CLEAR,
|
||||
onClick: clearRequests,
|
||||
}),
|
||||
div({ id: "requests-menu-filter-buttons" }, buttons),
|
||||
),
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-network-summary-button",
|
||||
className: "devtools-button",
|
||||
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
|
||||
onClick: openStatistics,
|
||||
},
|
||||
span({ className: "summary-info-icon" }),
|
||||
span({ className: "summary-info-text" }, text),
|
||||
),
|
||||
SearchBox({
|
||||
delay: FILTER_SEARCH_DELAY,
|
||||
keyShortcut: SEARCH_KEY_SHORTCUT,
|
||||
placeholder: SEARCH_PLACE_HOLDER,
|
||||
type: "filter",
|
||||
onChange: setRequestFilterText,
|
||||
}),
|
||||
button({
|
||||
id: "details-pane-toggle",
|
||||
className: toggleButtonClassName.join(" "),
|
||||
title: sidebarOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE,
|
||||
disabled: sidebarToggleDisabled,
|
||||
tabIndex: "0",
|
||||
onMouseDown: toggleSidebar,
|
||||
}),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = Toolbar;
|
||||
Toolbar.displayName = "Toolbar";
|
||||
|
||||
Toolbar.propTypes = {
|
||||
clearRequests: PropTypes.func.isRequired,
|
||||
openStatistics: PropTypes.func.isRequired,
|
||||
requestFilterTypes: PropTypes.object.isRequired,
|
||||
setRequestFilterText: PropTypes.func.isRequired,
|
||||
sidebarToggleDisabled: PropTypes.bool.isRequired,
|
||||
sidebarOpen: PropTypes.bool.isRequired,
|
||||
summary: PropTypes.object.isRequired,
|
||||
toggleRequestFilterType: PropTypes.func.isRequired,
|
||||
toggleSidebar: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
sidebarToggleDisabled: isSidebarToggleButtonDisabled(state),
|
||||
sidebarOpen: state.ui.sidebarOpen,
|
||||
requestFilterTypes: state.filters.requestFilterTypes,
|
||||
summary: getDisplayedRequestsSummary(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
clearRequests: () => dispatch(Actions.clearRequests()),
|
||||
openStatistics: () => dispatch(Actions.openStatistics(true)),
|
||||
setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)),
|
||||
toggleRequestFilterType: (evt) => {
|
||||
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
|
||||
return;
|
||||
}
|
||||
dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key));
|
||||
},
|
||||
toggleSidebar: () => dispatch(Actions.toggleSidebar()),
|
||||
})
|
||||
)(Toolbar);
|
||||
|
|
|
@ -28,9 +28,7 @@ DevToolsModules(
|
|||
'requests-menu-view.js',
|
||||
'sidebar-view.js',
|
||||
'sort-predicates.js',
|
||||
'statistics-view.js',
|
||||
'store.js',
|
||||
'toolbar-view.js',
|
||||
'waterfall-background.js',
|
||||
)
|
||||
|
||||
|
|
|
@ -2,36 +2,26 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
/* globals $, gStore, NetMonitorController, dumpn */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { testing: isTesting } = require("devtools/shared/flags");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { RequestsMenuView } = require("./requests-menu-view");
|
||||
const { CustomRequestView } = require("./custom-request-view");
|
||||
const { ToolbarView } = require("./toolbar-view");
|
||||
const { SidebarView } = require("./sidebar-view");
|
||||
const { StatisticsView } = require("./statistics-view");
|
||||
const { ACTIVITY_TYPE } = require("./constants");
|
||||
const { Prefs } = require("./prefs");
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const Actions = require("./actions/index");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
|
||||
|
||||
// Components
|
||||
const DetailsPanel = createFactory(require("./shared/components/details-panel"));
|
||||
|
||||
// ms
|
||||
const WDA_DEFAULT_VERIFY_INTERVAL = 50;
|
||||
|
||||
// Use longer timeout during testing as the tests need this process to succeed
|
||||
// and two seconds is quite short on slow debug builds. The timeout here should
|
||||
// be at least equal to the general mochitest timeout of 45 seconds so that this
|
||||
// never gets hit during testing.
|
||||
// ms
|
||||
const WDA_DEFAULT_GIVE_UP_TIMEOUT = isTesting ? 45000 : 2000;
|
||||
const StatisticsPanel = createFactory(require("./components/statistics-panel"));
|
||||
const Toolbar = createFactory(require("./components/toolbar"));
|
||||
|
||||
/**
|
||||
* Object defining the network monitor view components.
|
||||
|
@ -43,11 +33,6 @@ var NetMonitorView = {
|
|||
initialize: function () {
|
||||
this._initializePanes();
|
||||
|
||||
this.Toolbar.initialize(gStore);
|
||||
this.RequestsMenu.initialize(gStore);
|
||||
this.CustomRequest.initialize();
|
||||
this.Statistics.initialize(gStore);
|
||||
|
||||
this.detailsPanel = $("#react-details-panel-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
|
@ -55,6 +40,23 @@ var NetMonitorView = {
|
|||
DetailsPanel({ toolbox: NetMonitorController._toolbox }),
|
||||
), this.detailsPanel);
|
||||
|
||||
this.statisticsPanel = $("#statistics-panel");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
StatisticsPanel(),
|
||||
), this.statisticsPanel);
|
||||
|
||||
this.toolbar = $("#react-toolbar-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
Toolbar(),
|
||||
), this.toolbar);
|
||||
|
||||
this.RequestsMenu.initialize(gStore);
|
||||
this.CustomRequest.initialize();
|
||||
|
||||
// Store watcher here is for observing the statisticsOpen state change.
|
||||
// It should be removed once we migrate to react and apply react/redex binding.
|
||||
this.unsubscribeStore = gStore.subscribe(storeWatcher(
|
||||
|
@ -69,11 +71,11 @@ var NetMonitorView = {
|
|||
*/
|
||||
destroy: function () {
|
||||
this._isDestroyed = true;
|
||||
this.Toolbar.destroy();
|
||||
this.RequestsMenu.destroy();
|
||||
this.CustomRequest.destroy();
|
||||
this.Statistics.destroy();
|
||||
ReactDOM.unmountComponentAtNode(this.detailsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.statisticsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.toolbar);
|
||||
this.unsubscribeStore();
|
||||
|
||||
this._destroyPanes();
|
||||
|
@ -141,10 +143,6 @@ var NetMonitorView = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current mode for this tool.
|
||||
* @return string (e.g, "network-inspector-view" or "network-statistics-view")
|
||||
*/
|
||||
get currentFrontendMode() {
|
||||
// The getter may be called from a timeout after the panel is destroyed.
|
||||
if (!this._body.selectedPanel) {
|
||||
|
@ -153,9 +151,6 @@ var NetMonitorView = {
|
|||
return this._body.selectedPanel.id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles between the frontend view modes ("Inspector" vs. "Statistics").
|
||||
*/
|
||||
toggleFrontendMode: function () {
|
||||
if (gStore.getState().ui.statisticsOpen) {
|
||||
this.showNetworkStatisticsView();
|
||||
|
@ -164,45 +159,13 @@ var NetMonitorView = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the "Inspector" frontend view mode.
|
||||
*/
|
||||
showNetworkInspectorView: function () {
|
||||
this._body.selectedPanel = $("#network-inspector-view");
|
||||
this._body.selectedPanel = $("#inspector-panel");
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the "Statistics" frontend view mode.
|
||||
*/
|
||||
showNetworkStatisticsView: function () {
|
||||
this._body.selectedPanel = $("#network-statistics-view");
|
||||
|
||||
let controller = NetMonitorController;
|
||||
let requestsView = this.RequestsMenu;
|
||||
let statisticsView = this.Statistics;
|
||||
|
||||
Task.spawn(function* () {
|
||||
statisticsView.displayPlaceholderCharts();
|
||||
yield controller.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
|
||||
try {
|
||||
// • The response headers and status code are required for determining
|
||||
// whether a response is "fresh" (cacheable).
|
||||
// • The response content size and request total time are necessary for
|
||||
// populating the statistics view.
|
||||
// • The response mime type is used for categorization.
|
||||
yield whenDataAvailable(requestsView.store, [
|
||||
"responseHeaders", "status", "contentSize", "mimeType", "totalTime"
|
||||
]);
|
||||
} catch (ex) {
|
||||
// Timed out while waiting for data. Continue with what we have.
|
||||
console.error(ex);
|
||||
}
|
||||
|
||||
const requests = requestsView.store.getState().requests.requests.valueSeq();
|
||||
statisticsView.createPrimedCacheChart(requests);
|
||||
statisticsView.createEmptyCacheChart(requests);
|
||||
});
|
||||
this._body.selectedPanel = $("#statistics-panel");
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
},
|
||||
|
||||
reloadPage: function () {
|
||||
|
@ -214,41 +177,6 @@ var NetMonitorView = {
|
|||
_detailsPane: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes sure certain properties are available on all objects in a data store.
|
||||
*
|
||||
* @param Store dataStore
|
||||
* A Redux store for which to check the availability of properties.
|
||||
* @param array mandatoryFields
|
||||
* A list of strings representing properties of objects in dataStore.
|
||||
* @return object
|
||||
* A promise resolved when all objects in dataStore contain the
|
||||
* properties defined in mandatoryFields.
|
||||
*/
|
||||
function whenDataAvailable(dataStore, mandatoryFields) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let interval = setInterval(() => {
|
||||
const { requests } = dataStore.getState().requests;
|
||||
const allFieldsPresent = !requests.isEmpty() && requests.every(
|
||||
item => mandatoryFields.every(
|
||||
field => item.get(field) !== undefined
|
||||
)
|
||||
);
|
||||
|
||||
if (allFieldsPresent) {
|
||||
clearInterval(interval);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
}, WDA_DEFAULT_VERIFY_INTERVAL);
|
||||
|
||||
let timer = setTimeout(() => {
|
||||
clearInterval(interval);
|
||||
reject(new Error("Timed out while waiting for data"));
|
||||
}, WDA_DEFAULT_GIVE_UP_TIMEOUT);
|
||||
});
|
||||
}
|
||||
|
||||
// A smart store watcher to notify store changes as necessary
|
||||
function storeWatcher(initialValue, reduceValue, onChange) {
|
||||
let currentValue = initialValue;
|
||||
|
@ -265,10 +193,8 @@ function storeWatcher(initialValue, reduceValue, onChange) {
|
|||
/**
|
||||
* Preliminary setup for the NetMonitorView object.
|
||||
*/
|
||||
NetMonitorView.Toolbar = new ToolbarView();
|
||||
NetMonitorView.Sidebar = new SidebarView();
|
||||
NetMonitorView.RequestsMenu = new RequestsMenuView();
|
||||
NetMonitorView.CustomRequest = new CustomRequestView();
|
||||
NetMonitorView.Statistics = new StatisticsView();
|
||||
|
||||
exports.NetMonitorView = NetMonitorView;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
flex="1"
|
||||
data-localization-bundle="devtools/client/locales/netmonitor.properties">
|
||||
|
||||
<vbox id="network-inspector-view" flex="1">
|
||||
<vbox id="inspector-panel" flex="1">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-toolbar-hook"/>
|
||||
<hbox id="network-table-and-sidebar"
|
||||
|
@ -101,19 +101,8 @@
|
|||
|
||||
</vbox>
|
||||
|
||||
<html:div id="network-statistics-view">
|
||||
<html:div id="network-statistics-toolbar"
|
||||
class="devtools-toolbar">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-statistics-back-hook"/>
|
||||
</html:div>
|
||||
<html:div id="network-statistics-charts"
|
||||
class="devtools-responsive-container">
|
||||
<html:div id="primed-cache-chart"/>
|
||||
<html:div id="network-statistics-view-splitter"
|
||||
class="split-box devtools-side-splitter"/>
|
||||
<html:div id="empty-cache-chart"/>
|
||||
</html:div>
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="statistics-panel">
|
||||
</html:div>
|
||||
</deck>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,288 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
/* globals $, window, document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const { Filters } = require("./filter-predicates");
|
||||
const { L10N } = require("./l10n");
|
||||
const { EVENTS } = require("./events");
|
||||
const { DOM } = require("devtools/client/shared/vendor/react");
|
||||
const { button } = DOM;
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
const Actions = require("./actions/index");
|
||||
const { Chart } = require("devtools/client/shared/widgets/Chart");
|
||||
const {
|
||||
getSizeWithDecimals,
|
||||
getTimeWithDecimals
|
||||
} = require("./utils/format-utils");
|
||||
|
||||
// px
|
||||
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
|
||||
|
||||
/**
|
||||
* Functions handling the performance statistics view.
|
||||
*/
|
||||
function StatisticsView() {
|
||||
}
|
||||
|
||||
StatisticsView.prototype = {
|
||||
/**
|
||||
* Initialization function, called when the statistics view is started.
|
||||
*/
|
||||
initialize: function (store) {
|
||||
this.store = store;
|
||||
this.Chart = Chart;
|
||||
this._backButton = $("#react-statistics-back-hook");
|
||||
|
||||
let backStr = L10N.getStr("netmonitor.backButton");
|
||||
ReactDOM.render(button({
|
||||
id: "network-statistics-back-button",
|
||||
className: "devtools-toolbarbutton",
|
||||
"data-text-only": "true",
|
||||
title: backStr,
|
||||
onClick: () => {
|
||||
this.store.dispatch(Actions.openStatistics(false));
|
||||
},
|
||||
}, backStr), this._backButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function, called when the statistics view is closed.
|
||||
*/
|
||||
destroy: function () {
|
||||
ReactDOM.unmountComponentAtNode(this._backButton);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes and displays empty charts in this container.
|
||||
*/
|
||||
displayPlaceholderCharts: function () {
|
||||
this._createChart({
|
||||
id: "#primed-cache-chart",
|
||||
title: "charts.cacheEnabled"
|
||||
});
|
||||
this._createChart({
|
||||
id: "#empty-cache-chart",
|
||||
title: "charts.cacheDisabled"
|
||||
});
|
||||
window.emit(EVENTS.PLACEHOLDER_CHARTS_DISPLAYED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates and displays the primed cache chart in this container.
|
||||
*
|
||||
* @param array items
|
||||
* @see this._sanitizeChartDataSource
|
||||
*/
|
||||
createPrimedCacheChart: function (items) {
|
||||
this._createChart({
|
||||
id: "#primed-cache-chart",
|
||||
title: "charts.cacheEnabled",
|
||||
data: this._sanitizeChartDataSource(items),
|
||||
strings: this._commonChartStrings,
|
||||
totals: this._commonChartTotals,
|
||||
sorted: true
|
||||
});
|
||||
window.emit(EVENTS.PRIMED_CACHE_CHART_DISPLAYED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates and displays the empty cache chart in this container.
|
||||
*
|
||||
* @param array items
|
||||
* @see this._sanitizeChartDataSource
|
||||
*/
|
||||
createEmptyCacheChart: function (items) {
|
||||
this._createChart({
|
||||
id: "#empty-cache-chart",
|
||||
title: "charts.cacheDisabled",
|
||||
data: this._sanitizeChartDataSource(items, true),
|
||||
strings: this._commonChartStrings,
|
||||
totals: this._commonChartTotals,
|
||||
sorted: true
|
||||
});
|
||||
window.emit(EVENTS.EMPTY_CACHE_CHART_DISPLAYED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Common stringifier predicates used for items and totals in both the
|
||||
* "primed" and "empty" cache charts.
|
||||
*/
|
||||
_commonChartStrings: {
|
||||
size: value => {
|
||||
let string = getSizeWithDecimals(value / 1024);
|
||||
return L10N.getFormatStr("charts.sizeKB", string);
|
||||
},
|
||||
time: value => {
|
||||
let string = getTimeWithDecimals(value / 1000);
|
||||
return L10N.getFormatStr("charts.totalS", string);
|
||||
}
|
||||
},
|
||||
_commonChartTotals: {
|
||||
size: total => {
|
||||
let string = getSizeWithDecimals(total / 1024);
|
||||
return L10N.getFormatStr("charts.totalSize", string);
|
||||
},
|
||||
time: total => {
|
||||
let seconds = total / 1000;
|
||||
let string = getTimeWithDecimals(seconds);
|
||||
return PluralForm.get(seconds,
|
||||
L10N.getStr("charts.totalSeconds")).replace("#1", string);
|
||||
},
|
||||
cached: total => {
|
||||
return L10N.getFormatStr("charts.totalCached", total);
|
||||
},
|
||||
count: total => {
|
||||
return L10N.getFormatStr("charts.totalCount", total);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a specific chart to this container.
|
||||
*
|
||||
* @param object
|
||||
* An object containing all or some the following properties:
|
||||
* - id: either "#primed-cache-chart" or "#empty-cache-chart"
|
||||
* - title/data/strings/totals/sorted: @see Chart.js for details
|
||||
*/
|
||||
_createChart: function ({ id, title, data, strings, totals, sorted }) {
|
||||
let container = $(id);
|
||||
|
||||
// Nuke all existing charts of the specified type.
|
||||
while (container.hasChildNodes()) {
|
||||
container.firstChild.remove();
|
||||
}
|
||||
|
||||
// Create a new chart.
|
||||
let chart = this.Chart.PieTable(document, {
|
||||
diameter: NETWORK_ANALYSIS_PIE_CHART_DIAMETER,
|
||||
title: L10N.getStr(title),
|
||||
data: data,
|
||||
strings: strings,
|
||||
totals: totals,
|
||||
sorted: sorted
|
||||
});
|
||||
|
||||
chart.on("click", (_, item) => {
|
||||
// Reset FilterButtons and enable one filter exclusively
|
||||
this.store.dispatch(Actions.enableRequestFilterTypeOnly(item.label));
|
||||
this.store.dispatch(Actions.openStatistics(false));
|
||||
});
|
||||
|
||||
container.appendChild(chart.node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitizes the data source used for creating charts, to follow the
|
||||
* data format spec defined in Chart.js.
|
||||
*
|
||||
* @param array items
|
||||
* A collection of request items used as the data source for the chart.
|
||||
* @param boolean emptyCache
|
||||
* True if the cache is considered enabled, false for disabled.
|
||||
*/
|
||||
_sanitizeChartDataSource: function (items, emptyCache) {
|
||||
let data = [
|
||||
"html", "css", "js", "xhr", "fonts", "images", "media", "flash", "ws", "other"
|
||||
].map(e => ({
|
||||
cached: 0,
|
||||
count: 0,
|
||||
label: e,
|
||||
size: 0,
|
||||
time: 0
|
||||
}));
|
||||
|
||||
for (let requestItem of items) {
|
||||
let details = requestItem;
|
||||
let type;
|
||||
|
||||
if (Filters.html(details)) {
|
||||
// "html"
|
||||
type = 0;
|
||||
} else if (Filters.css(details)) {
|
||||
// "css"
|
||||
type = 1;
|
||||
} else if (Filters.js(details)) {
|
||||
// "js"
|
||||
type = 2;
|
||||
} else if (Filters.fonts(details)) {
|
||||
// "fonts"
|
||||
type = 4;
|
||||
} else if (Filters.images(details)) {
|
||||
// "images"
|
||||
type = 5;
|
||||
} else if (Filters.media(details)) {
|
||||
// "media"
|
||||
type = 6;
|
||||
} else if (Filters.flash(details)) {
|
||||
// "flash"
|
||||
type = 7;
|
||||
} else if (Filters.ws(details)) {
|
||||
// "ws"
|
||||
type = 8;
|
||||
} else if (Filters.xhr(details)) {
|
||||
// Verify XHR last, to categorize other mime types in their own blobs.
|
||||
// "xhr"
|
||||
type = 3;
|
||||
} else {
|
||||
// "other"
|
||||
type = 9;
|
||||
}
|
||||
|
||||
if (emptyCache || !responseIsFresh(details)) {
|
||||
data[type].time += details.totalTime || 0;
|
||||
data[type].size += details.contentSize || 0;
|
||||
} else {
|
||||
data[type].cached++;
|
||||
}
|
||||
data[type].count++;
|
||||
}
|
||||
|
||||
return data.filter(e => e.count > 0);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the "Expiration Calculations" defined in section 13.2.4 of the
|
||||
* "HTTP/1.1: Caching in HTTP" spec holds true for a collection of headers.
|
||||
*
|
||||
* @param object
|
||||
* An object containing the { responseHeaders, status } properties.
|
||||
* @return boolean
|
||||
* True if the response is fresh and loaded from cache.
|
||||
*/
|
||||
function responseIsFresh({ responseHeaders, status }) {
|
||||
// Check for a "304 Not Modified" status and response headers availability.
|
||||
if (status != 304 || !responseHeaders) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let list = responseHeaders.headers;
|
||||
let cacheControl = list.find(e => e.name.toLowerCase() == "cache-control");
|
||||
let expires = list.find(e => e.name.toLowerCase() == "expires");
|
||||
|
||||
// Check the "Cache-Control" header for a maximum age value.
|
||||
if (cacheControl) {
|
||||
let maxAgeMatch =
|
||||
cacheControl.value.match(/s-maxage\s*=\s*(\d+)/) ||
|
||||
cacheControl.value.match(/max-age\s*=\s*(\d+)/);
|
||||
|
||||
if (maxAgeMatch && maxAgeMatch.pop() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the "Expires" header for a valid date.
|
||||
if (expires && Date.parse(expires.value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
exports.StatisticsView = StatisticsView;
|
|
@ -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]
|
||||
|
|
|
@ -11,8 +11,8 @@ add_task(function* () {
|
|||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
const { Chart } = NetMonitorView.Statistics;
|
||||
let { document, windowRequire } = monitor.panelWin;
|
||||
let { Chart } = windowRequire("devtools/client/shared/widgets/Chart");
|
||||
|
||||
let pie = Chart.Pie(document, {
|
||||
width: 100,
|
||||
|
|
|
@ -14,8 +14,8 @@ add_task(function* () {
|
|||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { Chart } = NetMonitorView.Statistics;
|
||||
let { document, windowRequire } = monitor.panelWin;
|
||||
let { Chart } = windowRequire("devtools/client/shared/widgets/Chart");
|
||||
|
||||
let pie = Chart.Pie(document, {
|
||||
data: null,
|
||||
|
|
|
@ -13,8 +13,8 @@ add_task(function* () {
|
|||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { Chart } = NetMonitorView.Statistics;
|
||||
let { document, windowRequire } = monitor.panelWin;
|
||||
let { Chart } = windowRequire("devtools/client/shared/widgets/Chart");
|
||||
|
||||
let table = Chart.Table(document, {
|
||||
title: "Table title",
|
||||
|
|
|
@ -14,8 +14,8 @@ add_task(function* () {
|
|||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { Chart } = NetMonitorView.Statistics;
|
||||
let { document, windowRequire } = monitor.panelWin;
|
||||
let { Chart } = windowRequire("devtools/client/shared/widgets/Chart");
|
||||
|
||||
let table = Chart.Table(document, {
|
||||
title: "Table title",
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче