Merge m-c to b-i

CLOSED TREE
This commit is contained in:
Phil Ringnalda 2013-10-25 19:55:48 -07:00
commit c73dcc6e46
244 changed files with 3232 additions and 1856 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 922160 needs a clobber due to WebIDL binding dependency issues (bug 928195).
Bug 914270 needs a clobber since moving variables to moz.build always requires a clobber (bug 852814)

View File

@ -11,7 +11,7 @@ interface nsIAccessible;
/**
* This interface gives access to an accessible's set of relations.
*/
[scriptable, uuid(9f85fc0d-2969-48e6-b822-68140f7e5770)]
[scriptable, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)]
interface nsIAccessibleRelation : nsISupports
{
/**
@ -109,6 +109,21 @@ interface nsIAccessibleRelation : nsISupports
*/
const unsigned long RELATION_DEFAULT_BUTTON = 0x10;
/**
* The target object is the containing document object.
*/
const unsigned long RELATION_CONTAINING_DOCUMENT = 0x11;
/**
* The target object is the topmost containing document object in the tab pane.
*/
const unsigned long RELATION_CONTAINING_TAB_PANE = 0x12;
/**
* The target object is the containing application object.
*/
const unsigned long RELATION_CONTAINING_APPLICATION = 0x14;
/**
* Returns the type of the relation.
*/

View File

@ -109,7 +109,27 @@ MOZ_BEGIN_ENUM_CLASS(RelationType)
*/
DEFAULT_BUTTON = 0x10,
LAST = DEFAULT_BUTTON
/**
* The target object is the containing document object.
*/
CONTAINING_DOCUMENT = 0x11,
/**
* The target object is the topmost containing document object in the tab pane.
*/
CONTAINING_TAB_PANE = 0x12,
/**
* The target object is the containing window object.
*/
CONTAINING_WINDOW = 0x13,
/**
* The target object is the containing application object.
*/
CONTAINING_APPLICATION = 0x14,
LAST = CONTAINING_APPLICATION
MOZ_END_ENUM_CLASS(RelationType)

View File

@ -110,3 +110,21 @@ RELATIONTYPE(DEFAULT_BUTTON,
ATK_RELATION_NULL,
NAVRELATION_DEFAULT_BUTTON,
IA2_RELATION_NULL)
RELATIONTYPE(CONTAINING_DOCUMENT,
"containing document",
ATK_RELATION_NULL,
NAVRELATION_CONTAINING_DOCUMENT,
IA2_RELATION_CONTAINING_DOCUMENT)
RELATIONTYPE(CONTAINING_TAB_PANE,
"containing tab pane",
ATK_RELATION_NULL,
NAVRELATION_CONTAINING_TAB_PANE,
IA2_RELATION_CONTAINING_TAB_PANE)
RELATIONTYPE(CONTAINING_APPLICATION,
"containing application",
ATK_RELATION_NULL,
NAVRELATION_CONTAINING_APPLICATION,
IA2_RELATION_CONTAINING_APPLICATION)

View File

@ -13,6 +13,8 @@
#include "nsAccUtils.h"
#include "nsAccessibleRelation.h"
#include "nsAccessibilityService.h"
#include "ApplicationAccessible.h"
#include "nsCoreUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsIAccessibleRole.h"
#include "nsEventShell.h"
@ -2180,6 +2182,33 @@ Accessible::RelationByType(RelationType aType)
return Relation();
}
case RelationType::CONTAINING_DOCUMENT:
return Relation(mDoc);
case RelationType::CONTAINING_TAB_PANE: {
nsCOMPtr<nsIDocShell> docShell =
nsCoreUtils::GetDocShellFor(GetNode());
if (docShell) {
// Walk up the parent chain without crossing the boundary at which item
// types change, preventing us from walking up out of tab content.
nsCOMPtr<nsIDocShellTreeItem> root;
docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
if (root) {
// If the item type is typeContent, we assume we are in browser tab
// content. Note, this includes content such as about:addons,
// for consistency.
int32_t itemType = 0;
root->GetItemType(&itemType);
if (itemType == nsIDocShellTreeItem::typeContent)
return Relation(nsAccUtils::GetDocAccessibleFor(root));
}
}
return Relation();
}
case RelationType::CONTAINING_APPLICATION:
return Relation(ApplicationAcc());
default:
return Relation();
}
@ -2214,7 +2243,10 @@ Accessible::GetRelations(nsIArray **aRelations)
nsIAccessibleRelation::RELATION_EMBEDDED_BY,
nsIAccessibleRelation::RELATION_POPUP_FOR,
nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF,
nsIAccessibleRelation::RELATION_DEFAULT_BUTTON
nsIAccessibleRelation::RELATION_DEFAULT_BUTTON,
nsIAccessibleRelation::RELATION_CONTAINING_DOCUMENT,
nsIAccessibleRelation::RELATION_CONTAINING_TAB_PANE,
nsIAccessibleRelation::RELATION_CONTAINING_APPLICATION
};
for (uint32_t idx = 0; idx < ArrayLength(relationTypes); idx++) {

View File

@ -202,7 +202,10 @@ protected:
NAVRELATION_DEFAULT_BUTTON = 0x100d,
NAVRELATION_DESCRIBED_BY = 0x100e,
NAVRELATION_DESCRIPTION_FOR = 0x100f,
NAVRELATION_NODE_PARENT_OF = 0x1010
NAVRELATION_NODE_PARENT_OF = 0x1010,
NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
NAVRELATION_CONTAINING_APPLICATION = 0x1014
};
};

View File

@ -11,6 +11,7 @@
#include "DocAccessible.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "Relation.h"
#include "uiaRawElmProvider.h"
#include "mozilla/Preferences.h"
@ -60,33 +61,12 @@ ServiceProvider::QueryService(REFGUID aGuidService, REFIID aIID,
if (aIID != IID_IAccessible)
return E_NOINTERFACE;
nsCOMPtr<nsIDocShell> docShell =
nsCoreUtils::GetDocShellFor(mAccessible->GetNode());
if (!docShell)
return E_UNEXPECTED;
// Walk up the parent chain without crossing the boundary at which item
// types change, preventing us from walking up out of tab content.
nsCOMPtr<nsIDocShellTreeItem> root;
docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
if (!root)
return E_UNEXPECTED;
// If the item type is typeContent, we assume we are in browser tab content.
// Note this includes content such as about:addons, for consistency.
int32_t itemType;
root->GetItemType(&itemType);
if (itemType != nsIDocShellTreeItem::typeContent)
Relation rel = mAccessible->RelationByType(RelationType::CONTAINING_TAB_PANE);
AccessibleWrap* tabDoc = static_cast<AccessibleWrap*>(rel.Next());
if (!tabDoc)
return E_NOINTERFACE;
// Make sure this is a document.
DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
if (!docAcc)
return E_UNEXPECTED;
*aInstancePtr = static_cast<IAccessible*>(docAcc);
*aInstancePtr = static_cast<IAccessible*>(tabDoc);
(reinterpret_cast<IUnknown*>(*aInstancePtr))->AddRef();
return S_OK;
}

View File

@ -18,6 +18,9 @@ const RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF;
const RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF;
const RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR;
const RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF;
const RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
const RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
const RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
////////////////////////////////////////////////////////////////////////////////
// General

View File

@ -167,6 +167,11 @@
testRelation("legend", RELATION_LABEL_FOR, "fieldset");
testRelation("fieldset", RELATION_LABELLED_BY, "legend");
// containing relations
testRelation("control1_1", RELATION_CONTAINING_DOCUMENT, document);
testRelation("control1_1", RELATION_CONTAINING_TAB_PANE, getTabDocAccessible("control1_1"));
testRelation("control1_1", RELATION_CONTAINING_APPLICATION, getApplicationAccessible());
// finish test
SimpleTest.finish();
}

View File

@ -78,6 +78,12 @@ support-files =
title_test.svg
video.ogg
zoom_test.html
test_no_mcb_on_http_site_img.html
test_no_mcb_on_http_site_img.css
test_no_mcb_on_http_site_font.html
test_no_mcb_on_http_site_font.css
test_no_mcb_on_http_site_font2.html
test_no_mcb_on_http_site_font2.css
[browser_CTP_data_urls.js]
[browser_CTP_drag_drop.js]
@ -288,3 +294,4 @@ support-files =
[browser_zbug569342.js]
[browser_registerProtocolHandler_notification.js]
[browser_registerProtocolHandler_notification.html]
[browser_no_mcb_on_http_site.js]

View File

@ -179,18 +179,3 @@ function MixedTest6D() {
ok(content.document.getElementById('f1').contentDocument.getElementById('p1').innerHTML == "hello","Mixed script didn't load in Test 6");
MixedTestsCompleted();
}
function waitForCondition(condition, nextTest, errorMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
moveOn();
}
tries++;
}, 100);
var moveOn = function() { clearInterval(interval); nextTest(); };
}

View File

@ -41,26 +41,6 @@ function cleanUpAfterTests() {
window.focus();
finish();
}
/*
* Whenever we disable the Mixed Content Blocker of the page
* we have to make sure that our condition is properly loaded.
*/
function waitForCondition(condition, nextTest, errorMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
moveOn();
}
tries++;
}, 100);
var moveOn = function() {
clearInterval(interval); nextTest();
};
}
//------------------------ Test 1 ------------------------------

View File

@ -0,0 +1,138 @@
/*
* Description of the Tests for
* - Bug 909920 - Mixed content warning should not show on a HTTP site
*
* Description of the tests:
* Test 1:
* 1) Load an http page
* 2) The page includes a css file using https
* 3) The css file loads an |IMAGE| << over http
*
* Test 2:
* 1) Load an http page
* 2) The page includes a css file using https
* 3) The css file loads a |FONT| over http
*
* Test 3:
* 1) Load an http page
* 2) The page includes a css file using https
* 3) The css file imports (@import) another css file using http
* 3) The imported css file loads a |FONT| over http
*
* Since the top-domain is >> NOT << served using https, the MCB
* should >> NOT << trigger a warning.
*/
const PREF_ACTIVE = "security.mixed_content.block_active_content";
const PREF_DISPLAY = "security.mixed_content.block_display_content";
const gHttpTestRoot = "http://example.com/browser/browser/base/content/test/general/";
var origBlockActive, origBlockDisplay;
var gTestBrowser = null;
registerCleanupFunction(function() {
// Set preferences back to their original values
Services.prefs.setBoolPref(PREF_ACTIVE, origBlockActive);
Services.prefs.setBoolPref(PREF_DISPLAY, origBlockDisplay);
});
function cleanUpAfterTests() {
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function waitForCondition(condition, nextTest, errorMsg, okMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
ok(true, okMsg)
moveOn();
}
tries++;
}, 100);
var moveOn = function() {
clearInterval(interval); nextTest();
};
}
//------------- TEST 1 -----------------------------------------
function test1A() {
gTestBrowser.removeEventListener("load", test1A, true);
var expected = "Verifying MCB does not trigger warning/error for an http page ";
expected += "with https css that includes http image";
waitForCondition(
function() content.document.getElementById('testDiv').innerHTML == expected,
test1B, "Error: Waited too long for status in Test 1!",
"OK: Expected result in innerHTML!");
}
function test1B() {
// set up test 2
gTestBrowser.addEventListener("load", test2A, true);
var url = gHttpTestRoot + "test_no_mcb_on_http_site_font.html";
gTestBrowser.contentWindow.location = url;
}
//------------- TEST 2 -----------------------------------------
function test2A() {
gTestBrowser.removeEventListener("load", test2A, true);
var expected = "Verifying MCB does not trigger warning/error for an http page ";
expected += "with https css that includes http font";
waitForCondition(
function() content.document.getElementById('testDiv').innerHTML == expected,
test2B, "Error: Waited too long for status in Test 2!",
"OK: Expected result in innerHTML!");
}
function test2B() {
// set up test 3
gTestBrowser.addEventListener("load", test3, true);
var url = gHttpTestRoot + "test_no_mcb_on_http_site_font2.html";
gTestBrowser.contentWindow.location = url;
}
//------------- TEST 3 -----------------------------------------
function test3() {
gTestBrowser.removeEventListener("load", test3, true);
var expected = "Verifying MCB does not trigger warning/error for an http page "
expected += "with https css that imports another http css which includes http font";
waitForCondition(
function() content.document.getElementById('testDiv').innerHTML == expected,
cleanUpAfterTests, "Error: Waited too long for status in Test 3!",
"OK: Expected result in innerHTML!");
}
//------------------------------------------------------
function test() {
// Performing async calls, e.g. 'onload', we have to wait till all of them finished
waitForExplicitFinish();
// Store original preferences so we can restore settings after testing
origBlockActive = Services.prefs.getBoolPref(PREF_ACTIVE);
origBlockDisplay = Services.prefs.getBoolPref(PREF_DISPLAY);
Services.prefs.setBoolPref(PREF_ACTIVE, true);
Services.prefs.setBoolPref(PREF_DISPLAY, true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
newTab.linkedBrowser.stop();
gTestBrowser.addEventListener("load", test1A, true);
var url = gHttpTestRoot + "test_no_mcb_on_http_site_img.html";
gTestBrowser.contentWindow.location = url;
}

View File

@ -89,7 +89,14 @@ function waitForCondition(condition, nextTest, errorMsg) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
var conditionPassed;
try {
conditionPassed = condition();
} catch (e) {
ok(false, e + "\n" + e.stack);
conditionPassed = false;
}
if (conditionPassed) {
moveOn();
}
tries++;

View File

@ -0,0 +1,10 @@
@font-face {
font-family: testFont;
src: url(http://example.com/browser/browser/devtools/fontinspector/test/browser_font.woff);
}
body {
font-family: Arial;
}
div {
font-family: testFont;
}

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
Test 2 for Bug 909920 - See file browser_no_mcb_on_http_site.js for description.
https://bugzilla.mozilla.org/show_bug.cgi?id=909920
-->
<head>
<meta charset="utf-8">
<title>Test 2 for Bug 909920</title>
<link rel="stylesheet" type="text/css" href="https://example.com/browser/browser/base/content/test/general/test_no_mcb_on_http_site_font.css" />
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript">
function checkLoadStates() {
var ui = SpecialPowers.wrap(window)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.securityUI;
var loadedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT);
is(loadedMixedActive, false, "OK: Should not load mixed active content!");
var blockedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT);
is(blockedMixedActive, false, "OK: Should not block mixed active content!");
var loadedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT);
is(loadedMixedDisplay, false, "OK: Should not load mixed display content!");
var blockedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT);
is(blockedMixedDisplay, false, "OK: Should not block mixed display content!");
var newValue = "Verifying MCB does not trigger warning/error for an http page with https css that includes http font";
document.getElementById("testDiv").innerHTML = newValue;
}
</script>
</head>
<body onload="checkLoadStates()">
<div class="testDiv" id="testDiv">
Testing MCB does not trigger warning/error for an http page with https css that includes http font
</div>
</body>
</html>

View File

@ -0,0 +1 @@
@import url(http://example.com/browser/browser/base/content/test/general/test_no_mcb_on_http_site_font.css);

View File

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<!--
Test 3 for Bug 909920 - See file browser_no_mcb_on_http_site.js for description.
https://bugzilla.mozilla.org/show_bug.cgi?id=909920
-->
<head>
<meta charset="utf-8">
<title>Test 3 for Bug 909920</title>
<link rel="stylesheet" type="text/css" href="https://example.com/browser/browser/base/content/test/general/test_no_mcb_on_http_site_font2.css" />
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript">
function checkLoadStates() {
var ui = SpecialPowers.wrap(window)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.securityUI;
var loadedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT);
is(loadedMixedActive, false, "OK: Should not load mixed active content!");
var blockedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT);
is(blockedMixedActive, false, "OK: Should not block mixed active content!");
var loadedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT);
is(loadedMixedDisplay, false, "OK: Should not load mixed display content!");
var blockedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT);
is(blockedMixedDisplay, false, "OK: Should not block mixed display content!");
var newValue = "Verifying MCB does not trigger warning/error for an http page ";
newValue += "with https css that imports another http css which includes http font";
document.getElementById("testDiv").innerHTML = newValue;
}
</script>
</head>
<body onload="checkLoadStates()">
<div class="testDiv" id="testDiv">
Testing MCB does not trigger warning/error for an http page with https css that imports another http css which includes http font
</div>
</body>
</html>

View File

@ -0,0 +1,3 @@
#testDiv {
background: url(http://example.com/tests/image/test/mochitest/blue.png)
}

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
Test 1 for Bug 909920 - See file browser_no_mcb_on_http_site.js for description.
https://bugzilla.mozilla.org/show_bug.cgi?id=909920
-->
<head>
<meta charset="utf-8">
<title>Test 1 for Bug 909920</title>
<link rel="stylesheet" type="text/css" href="https://example.com/browser/browser/base/content/test/general/test_no_mcb_on_http_site_img.css" />
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript">
function checkLoadStates() {
var ui = SpecialPowers.wrap(window)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.securityUI;
var loadedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT);
is(loadedMixedActive, false, "OK: Should not load mixed active content!");
var blockedMixedActive = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT);
is(blockedMixedActive, false, "OK: Should not block mixed active content!");
var loadedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT);
is(loadedMixedDisplay, false, "OK: Should not load mixed display content!");
var blockedMixedDisplay = ui &&
(ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT);
is(blockedMixedDisplay, false, "OK: Should not block mixed display content!");
var newValue = "Verifying MCB does not trigger warning/error for an http page with https css that includes http image";
document.getElementById("testDiv").innerHTML = newValue;
}
</script>
</head>
<body onload="checkLoadStates()">
<div class="testDiv" id="testDiv">
Testing MCB does not trigger warning/error for an http page with https css that includes http image
</div>
</body>
</html>

View File

@ -18,7 +18,14 @@ function waitForCondition(condition, nextTest, errorMsg) {
ok(false, errorMsg);
moveOn();
}
if (condition()) {
var conditionPassed;
try {
conditionPassed = condition();
} catch (e) {
ok(false, e + "\n" + e.stack);
conditionPassed = false;
}
if (conditionPassed) {
moveOn();
}
tries++;

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1
LOCAL_INCLUDES = -I$(srcdir)/../build

View File

@ -16,3 +16,4 @@ SOURCES += [
LIBRARY_NAME = 'browserabout_s'
FORCE_STATIC_LIB = True

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1
LOCAL_INCLUDES = -I$(srcdir)/../build

View File

@ -19,3 +19,5 @@ LIBRARY_NAME = 'browserdir_s'
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini',
]
FORCE_STATIC_LIB = True

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1
DEFINES += \

View File

@ -22,3 +22,4 @@ EXTRA_PP_COMPONENTS += [
LIBRARY_NAME = 'browser_feeds_s'
FORCE_STATIC_LIB = True

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1

View File

@ -42,3 +42,4 @@ EXTRA_PP_JS_MODULES += [
'MigrationUtils.jsm',
]
FORCE_STATIC_LIB = True

View File

@ -3,7 +3,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1

View File

@ -26,3 +26,5 @@ EXTRA_COMPONENTS += [
'nsSetDefaultBrowser.js',
'nsSetDefaultBrowser.manifest',
]
FORCE_STATIC_LIB = True

View File

@ -102,6 +102,7 @@
<button class="action-primary" onclick="UI.installSimulator()" title="&connection.installOneSimulatorTooltip;">&connection.installOneSimulator;</button>
</div>
<div class="found-simulator">
<span>&connection.startRegisteredSimulator;</span>
<span template-loop='{"arrayPath":"simulators.versions","childSelector":"#simulator-item-template"}'></span>
<button class="action-primary" onclick="UI.installSimulator()" title="&connection.installAnotherSimulatorTooltip;">&connection.installAnotherSimulator;</button>
</div>
@ -124,7 +125,7 @@
<template id="simulator-item-template">
<span>
<button class="simulator-item" onclick="UI.startSimulator(this.dataset.version)" template='{"type":"attribute","path":"version","name":"data-version"}' title="&connection.startSimulatorTooltip;">
<button class="simulator-item action-primary" onclick="UI.startSimulator(this.dataset.version)" template='{"type":"attribute","path":"version","name":"data-version"}' title="&connection.startSimulatorTooltip;">
<span template='{"type":"textContent", "path":"version"}'></span>
</button>
</span>

View File

@ -21,6 +21,7 @@ const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
const {HTMLEditor} = require("devtools/markupview/html-editor");
const {OutputParser} = require("devtools/output-parser");
const promise = require("sdk/core/promise");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
Cu.import("resource://gre/modules/devtools/Templater.jsm");
@ -374,7 +375,7 @@ MarkupView.prototype = {
this._elt.appendChild(container.elt);
this._rootNode = aNode;
} else {
var container = new MarkupContainer(this, aNode);
var container = new MarkupContainer(this, aNode, this._inspector);
if (aFlashNode) {
container.flashMutation();
}
@ -1046,12 +1047,15 @@ MarkupView.prototype = {
* The markup view that owns this container.
* @param DOMNode aNode
* The node to display.
* @param Inspector aInspector
* The inspector tool container the markup-view
*/
function MarkupContainer(aMarkupView, aNode) {
function MarkupContainer(aMarkupView, aNode, aInspector) {
this.markup = aMarkupView;
this.doc = this.markup.doc;
this.undo = this.markup.undo;
this.node = aNode;
this._inspector = aInspector;
if (aNode.nodeType == Ci.nsIDOMNode.TEXT_NODE) {
this.editor = new TextEditor(this, aNode, "text");
@ -1094,6 +1098,9 @@ function MarkupContainer(aMarkupView, aNode) {
this._onMouseDown = this._onMouseDown.bind(this);
this.elt.addEventListener("mousedown", this._onMouseDown, false);
this.tooltip = null;
this._attachTooltipIfNeeded();
}
MarkupContainer.prototype = {
@ -1101,6 +1108,39 @@ MarkupContainer.prototype = {
return "[MarkupContainer for " + this.node + "]";
},
_attachTooltipIfNeeded: function() {
if (this.node.tagName) {
let tagName = this.node.tagName.toLowerCase();
let isImage = tagName === "img" &&
this.editor.getAttributeElement("src");
let isCanvas = tagName && tagName === "canvas";
// Get the image data for later so that when the user actually hovers over
// the element, the tooltip does contain the image
if (isImage || isCanvas) {
this.tooltip = new Tooltip(this._inspector.panelDoc);
this.node.getImageData().then(data => {
if (data) {
data.string().then(str => {
this.tooltip.setImageContent(str);
});
}
});
}
// If it's an image, show the tooltip on the src attribute
if (isImage) {
this.tooltip.startTogglingOnHover(this.editor.getAttributeElement("src"));
}
// If it's a canvas, show it on the tag
if (isCanvas) {
this.tooltip.startTogglingOnHover(this.editor.tag);
}
}
},
/**
* True if the current node has children. The MarkupView
* will set this attribute for the MarkupContainer.
@ -1335,6 +1375,12 @@ MarkupContainer.prototype = {
// Destroy my editor
this.editor.destroy();
// Destroy the tooltip if any
if (this.tooltip) {
this.tooltip.destroy();
this.tooltip = null;
}
}
};
@ -1348,7 +1394,7 @@ function RootContainer(aMarkupView, aNode) {
this.elt.container = this;
this.children = this.elt;
this.node = aNode;
this.toString = function() { return "[root container]"}
this.toString = () => "[root container]";
}
RootContainer.prototype = {
@ -1578,6 +1624,16 @@ ElementEditor.prototype = {
return this.node.startModifyingAttributes();
},
/**
* Get the element used for one of the attributes of this element
* @param string attrName The name of the attribute to get the element for
* @return DOMElement
*/
getAttributeElement: function(attrName) {
return this.attrList.querySelector(
".attreditor[data-attr=" + attrName + "] .attr-value");
},
_createAttribute: function(aAttr, aBefore = null) {
// Create the template editor, which will save some variables here.
let data = {

View File

@ -15,3 +15,5 @@ skip-if = true
[browser_inspector_markup_navigation.js]
[browser_inspector_markup_subset.html]
[browser_inspector_markup_subset.js]
[browser_inspector_markup_765105_tooltip.js]
[browser_inspector_markup_765105_tooltip.png]

View File

@ -0,0 +1,137 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let {PanelFactory} = devtools.require("devtools/shared/widgets/Tooltip");
let contentDoc;
let inspector;
let markup;
const PAGE_CONTENT = [
'<img class="local" src="chrome://branding/content/about-logo.png" />',
'<img class="data" src="data:image/png;base64,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" />',
'<img class="remote" src="http://mochi.test:8888/browser/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.png" />',
'<canvas class="canvas" width="600" height="600"></canvas>'
].join("\n");
const TEST_NODES = [
"img.local",
"img.data",
"img.remote",
".canvas"
];
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
contentDoc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,markup view tooltip test";
}
function createDocument() {
contentDoc.body.innerHTML = PAGE_CONTENT;
var target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
inspector = toolbox.getCurrentPanel();
markup = inspector.markup;
startTests();
});
}
function startTests() {
// Draw something in the canvas :)
let doc = content.document;
let context = doc.querySelector(".canvas").getContext("2d");
context.beginPath();
context.moveTo(300, 0);
context.lineTo(600, 600);
context.lineTo(0, 600);
context.closePath();
context.fillStyle = "#ffc821";
context.fill();
// Actually start testing
inspector.selection.setNode(contentDoc.querySelector("img"));
inspector.once("inspector-updated", () => {
testImageTooltip(0);
});
}
function endTests() {
contentDoc = inspector = markup = null;
gBrowser.removeCurrentTab();
finish();
}
function testImageTooltip(index) {
if (index === TEST_NODES.length) {
return endTests();
}
let node = contentDoc.querySelector(TEST_NODES[index]);
ok(node, "We have the [" + TEST_NODES[index] + "] image node to test for tooltip");
let isImg = node.tagName.toLowerCase() === "img";
let container = getContainerForRawNode(markup, node);
let target = container.editor.tag;
if (isImg) {
target = container.editor.getAttributeElement("src");
}
assertTooltipShownOn(container.tooltip, target, () => {
let images = container.tooltip.panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip for [" + TEST_NODES[index] + "] contains an image");
if (isImg) {
compareImageData(node, images[0].src);
}
container.tooltip.hide();
testImageTooltip(index + 1);
});
}
function compareImageData(img, imgData) {
let canvas = content.document.createElement("canvas");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
let ctx = canvas.getContext("2d");
let data = "";
try {
ctx.drawImage(img, 0, 0);
data = canvas.toDataURL("image/png");
} catch (e) {}
is(data, imgData, "Tooltip image has the right content");
}
function assertTooltipShownOn(tooltip, element, cb) {
// If there is indeed a show-on-hover on element, the xul panel will be shown
tooltip.panel.addEventListener("popupshown", function shown() {
tooltip.panel.removeEventListener("popupshown", shown, true);
// Poll until the image gets loaded in the tooltip. This is required because
// markup containers only load images in their associated tooltips when
// the image data comes back from the server. However, this test is executed
// synchronously as soon as "inspector-updated" is fired, which is before
// the data for images is known.
let hasImage = () => tooltip.panel.getElementsByTagName("image").length;
let poll = setInterval(() => {
if (hasImage()) {
clearInterval(poll);
cb();
}
}, 200);
}, true);
tooltip._showOnHover(element);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -9,3 +9,4 @@ libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
$(NSINSTALL) $(srcdir)/widgets/*.jsm $(FINAL_TARGET)/modules/devtools
$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/shared
$(NSINSTALL) $(srcdir)/widgets/*.js $(FINAL_TARGET)/modules/devtools/shared/widgets

View File

@ -0,0 +1,420 @@
/* 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 {Cc, Cu, Ci} = require("chrome");
const promise = require("sdk/core/promise");
const IOService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
const GRADIENT_RE = /\b(repeating-)?(linear|radial)-gradient\(((rgb|hsl)a?\(.+?\)|[^\)])+\)/gi;
const BORDERCOLOR_RE = /^border-[-a-z]*color$/ig;
const BORDER_RE = /^border(-(top|bottom|left|right))?$/ig;
const BACKGROUND_IMAGE_RE = /url\([\'\"]?(.*?)[\'\"]?\)/;
/**
* Tooltip widget.
*
* This widget is intended at any tool that may need to show rich content in the
* form of floating panels.
* A common use case is image previewing in the CSS rule view, but more complex
* use cases may include color pickers, object inspection, etc...
*
* Tooltips are based on XUL (namely XUL arrow-type <panel>s), and therefore
* need a XUL Document to live in.
* This is pretty much the only requirement they have on their environment.
*
* The way to use a tooltip is simply by instantiating a tooltip yourself and
* attaching some content in it, or using one of the ready-made content types.
*
* A convenient `startTogglingOnHover` method may avoid having to register event
* handlers yourself if the tooltip has to be shown when hovering over a
* specific element or group of elements (which is usually the most common case)
*/
/**
* The low level structure of a tooltip is a XUL element (a <panel>, although
* <tooltip> is supported too, it won't have the nice arrow shape).
*/
let PanelFactory = {
get: function(doc, xulTag="panel") {
// Create the tooltip
let panel = doc.createElement(xulTag);
panel.setAttribute("hidden", true);
if (xulTag === "panel") {
// Prevent the click used to close the panel from being consumed
panel.setAttribute("consumeoutsideclicks", false);
panel.setAttribute("type", "arrow");
panel.setAttribute("level", "top");
}
panel.setAttribute("class", "devtools-tooltip devtools-tooltip-" + xulTag);
doc.querySelector("window").appendChild(panel);
return panel;
}
};
/**
* Tooltip class.
*
* Basic usage:
* let t = new Tooltip(xulDoc);
* t.content = someXulContent;
* t.show();
* t.hide();
* t.destroy();
*
* Better usage:
* let t = new Tooltip(xulDoc);
* t.startTogglingOnHover(container, target => {
* if (<condition based on target>) {
* t.setImageContent("http://image.png");
* return true;
* }
* });
* t.destroy();
*
* @param XULDocument doc
* The XUL document hosting this tooltip
*/
function Tooltip(doc) {
this.doc = doc;
this.panel = PanelFactory.get(doc);
// Used for namedTimeouts in the mouseover handling
this.uid = "tooltip-" + Date.now();
}
module.exports.Tooltip = Tooltip;
Tooltip.prototype = {
/**
* Show the tooltip. It might be wise to append some content first if you
* don't want the tooltip to be empty. You may access the content of the
* tooltip by setting a XUL node to t.tooltip.content.
* @param {node} anchor
* Which node should the tooltip be shown on
* @param {string} position
* https://developer.mozilla.org/en-US/docs/XUL/PopupGuide/Positioning
* Defaults to before_start
*/
show: function(anchor, position="before_start") {
this.panel.hidden = false;
this.panel.openPopup(anchor, position);
},
/**
* Hide the tooltip
*/
hide: function() {
this.panel.hidden = true;
this.panel.hidePopup();
},
/**
* Empty the tooltip's content
*/
empty: function() {
while (this.panel.hasChildNodes()) {
this.panel.removeChild(this.panel.firstChild);
}
},
/**
* Get rid of references and event listeners
*/
destroy: function () {
this.hide();
this.content = null;
this.doc = null;
this.panel.parentNode.removeChild(this.panel);
this.panel = null;
if (this._basedNode) {
this.stopTogglingOnHover();
}
},
/**
* Show/hide the tooltip when the mouse hovers over particular nodes.
*
* 2 Ways to make this work:
* - Provide a single node to attach the tooltip to, as the baseNode, and
* omit the second targetNodeCb argument
* - Provide a baseNode that is the container of possibly numerous children
* elements that may receive a tooltip. In this case, provide the second
* targetNodeCb argument to decide wether or not a child should receive
* a tooltip.
*
* This works by tracking mouse movements on a base container node (baseNode)
* and showing the tooltip when the mouse stops moving. The targetNodeCb
* callback is used to know whether or not the particular element being
* hovered over should indeed receive the tooltip. If you don't provide it
* it's equivalent to a function that always returns true.
*
* Note that if you call this function a second time, it will itself call
* stopTogglingOnHover before adding mouse tracking listeners again.
*
* @param {node} baseNode
* The container for all target nodes
* @param {Function} targetNodeCb
* A function that accepts a node argument and returns true or false
* to signify if the tooltip should be shown on that node or not.
* Additionally, the function receives a second argument which is the
* tooltip instance itself, to be used to add/modify the content of the
* tooltip if needed. If omitted, the tooltip will be shown everytime.
* @param {Number} showDelay
* An optional delay that will be observed before showing the tooltip.
* Defaults to 750ms
*/
startTogglingOnHover: function(baseNode, targetNodeCb, showDelay = 750) {
if (this._basedNode) {
this.stopTogglingOnHover();
}
this._basedNode = baseNode;
this._showDelay = showDelay;
this._targetNodeCb = targetNodeCb || (() => true);
this._onBaseNodeMouseMove = this._onBaseNodeMouseMove.bind(this);
this._onBaseNodeMouseLeave = this._onBaseNodeMouseLeave.bind(this);
baseNode.addEventListener("mousemove", this._onBaseNodeMouseMove, false);
baseNode.addEventListener("mouseleave", this._onBaseNodeMouseLeave, false);
},
/**
* If the startTogglingOnHover function has been used previously, and you want
* to get rid of this behavior, then call this function to remove the mouse
* movement tracking
*/
stopTogglingOnHover: function() {
clearNamedTimeout(this.uid);
this._basedNode.removeEventListener("mousemove",
this._onBaseNodeMouseMove, false);
this._basedNode.removeEventListener("mouseleave",
this._onBaseNodeMouseLeave, false);
this._basedNode = null;
this._targetNodeCb = null;
this._lastHovered = null;
},
_onBaseNodeMouseMove: function(event) {
if (event.target !== this._lastHovered) {
this.hide();
this._lastHovered = null;
setNamedTimeout(this.uid, this._showDelay, () => {
this._showOnHover(event.target);
});
}
},
_showOnHover: function(target) {
if (this._targetNodeCb && this._targetNodeCb(target, this)) {
this.show(target);
this._lastHovered = target;
}
},
_onBaseNodeMouseLeave: function() {
clearNamedTimeout(this.uid);
this._lastHovered = null;
},
/**
* Set the content of this tooltip. Will first empty the tooltip and then
* append the new content element.
* Consider using one of the set<type>Content() functions instead.
* @param {node} content
* A node that can be appended in the tooltip XUL element
*/
set content(content) {
this.empty();
if (content) {
this.panel.appendChild(content);
}
},
get content() {
return this.panel.firstChild;
},
/**
* Fill the tooltip with an image, displayed over a tiled background useful
* for transparent images.
* Also adds the image dimension as a label at the bottom.
*/
setImageContent: function(imageUrl, maxDim=400) {
// Main container
let vbox = this.doc.createElement("vbox");
vbox.setAttribute("align", "center")
// Transparency tiles (image will go in there)
let tiles = createTransparencyTiles(this.doc, vbox);
// Temporary label during image load
let label = this.doc.createElement("label");
label.classList.add("devtools-tooltip-caption");
label.textContent = l10n.strings.GetStringFromName("previewTooltip.image.brokenImage");
vbox.appendChild(label);
// Display the image
let image = this.doc.createElement("image");
image.setAttribute("src", imageUrl);
if (maxDim) {
image.style.maxWidth = maxDim + "px";
image.style.maxHeight = maxDim + "px";
}
tiles.appendChild(image);
this.content = vbox;
// Load the image to get dimensions and display it when done
let imgObj = new this.doc.defaultView.Image();
imgObj.src = imageUrl;
imgObj.onload = () => {
imgObj.onload = null;
// Display dimensions
label.textContent = imgObj.naturalWidth + " x " + imgObj.naturalHeight;
if (imgObj.naturalWidth > maxDim ||
imgObj.naturalHeight > maxDim) {
label.textContent += " *";
}
}
},
/**
* Exactly the same as the `image` function but takes a css background image
* value instead : url(....)
*/
setCssBackgroundImageContent: function(cssBackground, sheetHref, maxDim=400) {
let uri = getBackgroundImageUri(cssBackground, sheetHref);
if (uri) {
this.setImageContent(uri, maxDim);
}
},
setCssGradientContent: function(cssGradient) {
let tiles = createTransparencyTiles(this.doc);
let gradientBox = this.doc.createElement("box");
gradientBox.width = "100";
gradientBox.height = "100";
gradientBox.style.background = this.cssGradient;
gradientBox.style.borderRadius = "2px";
gradientBox.style.boxShadow = "inset 0 0 4px #333";
tiles.appendChild(gradientBox)
this.content = tiles;
},
_setSimpleCssPropertiesContent: function(properties, width, height) {
let tiles = createTransparencyTiles(this.doc);
let box = this.doc.createElement("box");
box.width = width + "";
box.height = height + "";
properties.forEach(({name, value}) => {
box.style[name] = value;
});
tiles.appendChild(box);
this.content = tiles;
},
setCssColorContent: function(cssColor) {
this._setSimpleCssPropertiesContent([
{name: "background", value: cssColor},
{name: "borderRadius", value: "2px"},
{name: "boxShadow", value: "inset 0 0 4px #333"},
], 50, 50);
},
setCssBoxShadowContent: function(cssBoxShadow) {
this._setSimpleCssPropertiesContent([
{name: "background", value: "white"},
{name: "boxShadow", value: cssBoxShadow}
], 80, 80);
},
setCssBorderContent: function(cssBorder) {
this._setSimpleCssPropertiesContent([
{name: "background", value: "white"},
{name: "border", value: cssBorder}
], 80, 80);
}
};
/**
* Internal utility function that creates a tiled background useful for
* displaying semi-transparent images
*/
function createTransparencyTiles(doc, parentEl) {
let tiles = doc.createElement("box");
tiles.classList.add("devtools-tooltip-tiles");
if (parentEl) {
parentEl.appendChild(tiles);
}
return tiles;
}
/**
* Internal util, checks whether a css declaration is a gradient
*/
function isGradientRule(property, value) {
return (property === "background" || property === "background-image") &&
value.match(GRADIENT_RE);
}
/**
* Internal util, checks whether a css declaration is a color
*/
function isColorOnly(property, value) {
return property === "background-color" ||
property === "color" ||
property.match(BORDERCOLOR_RE);
}
/**
* Internal util, returns the background image uri if any
*/
function getBackgroundImageUri(value, sheetHref) {
let uriMatch = BACKGROUND_IMAGE_RE.exec(value);
let uri = null;
if (uriMatch && uriMatch[1]) {
uri = uriMatch[1];
if (sheetHref) {
let sheetUri = IOService.newURI(sheetHref, null, null);
uri = sheetUri.resolve(uri);
}
}
return uri;
}
/**
* L10N utility class
*/
function L10N() {}
L10N.prototype = {};
let l10n = new L10N();
loader.lazyGetter(L10N.prototype, "strings", () => {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/inspector.properties");
});

View File

@ -11,8 +11,8 @@ let {CssLogic} = require("devtools/styleinspector/css-logic");
let {ELEMENT_STYLE} = require("devtools/server/actors/styles");
let promise = require("sdk/core/promise");
let {EventEmitter} = require("devtools/shared/event-emitter");
const {OutputParser} = require("devtools/output-parser");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PluralForm.jsm");
@ -169,6 +169,11 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
// The element that we're inspecting, and the document that it comes from.
this.viewedElement = null;
// Properties preview tooltip
this.tooltip = new Tooltip(this.styleInspector.inspector.panelDoc);
this.tooltip.startTogglingOnHover(this.propertyContainer,
this._buildTooltipContent.bind(this));
this._buildContextMenu();
this.createStyleViews();
}
@ -490,6 +495,29 @@ CssHtmlTree.prototype = {
win.focus();
},
/**
* Verify that target is indeed a css value we want a tooltip on, and if yes
* prepare some content for the tooltip
*/
_buildTooltipContent: function(target)
{
// If the hovered element is not a property view and is not a background
// image, then don't show a tooltip
let isPropertyValue = target.classList.contains("property-value");
if (!isPropertyValue) {
return false;
}
let propName = target.parentNode.querySelector(".property-name");
let isBackgroundImage = propName.textContent === "background-image";
if (!isBackgroundImage) {
return false;
}
// Fill some content
this.tooltip.setCssBackgroundImageContent(target.textContent);
return true;
},
/**
* Create a context menu.
*/
@ -648,6 +676,9 @@ CssHtmlTree.prototype = {
this._contextmenu = null;
}
this.tooltip.stopTogglingOnHover(this.propertyContainer);
this.tooltip.destroy();
// Remove bound listeners
this.styleDocument.removeEventListener("contextmenu", this._onContextMenu);
this.styleDocument.removeEventListener("copy", this._onCopy);
@ -831,9 +862,8 @@ PropertyView.prototype = {
{
let doc = this.tree.styleDocument;
this.onMatchedToggle = this.onMatchedToggle.bind(this);
// Build the container element
this.onMatchedToggle = this.onMatchedToggle.bind(this);
this.element = doc.createElementNS(HTML_NS, "div");
this.element.setAttribute("class", this.propertyHeaderClassName);
this.element.addEventListener("dblclick", this.onMatchedToggle, false);
@ -858,6 +888,8 @@ PropertyView.prototype = {
this.matchedExpander.addEventListener("click", this.onMatchedToggle, false);
this.element.appendChild(this.matchedExpander);
this.focusElement = () => this.element.focus();
// Build the style name element
this.nameNode = doc.createElementNS(HTML_NS, "div");
this.nameNode.setAttribute("class", "property-name theme-fg-color5");
@ -1034,7 +1066,7 @@ PropertyView.prototype = {
};
/**
* A container to view us easy access to display data from a CssRule
* A container to give us easy access to display data from a CssRule
* @param CssHtmlTree aTree, the owning CssHtmlTree
* @param aSelectorInfo
*/

View File

@ -13,6 +13,7 @@ let {CssLogic} = require("devtools/styleinspector/css-logic");
let {InplaceEditor, editableField, editableItem} = require("devtools/shared/inplace-editor");
let {ELEMENT_STYLE, PSEUDO_ELEMENTS} = require("devtools/server/actors/styles");
let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
let {Tooltip} = require("devtools/shared/widgets/Tooltip");
const {OutputParser} = require("devtools/output-parser");
@ -1029,6 +1030,7 @@ TextProperty.prototype = {
* apply to a given element. After construction, the 'element'
* property will be available with the user interface.
*
* @param {Inspector} aInspector
* @param {Document} aDoc
* The document that will contain the rule view.
* @param {object} aStore
@ -1039,8 +1041,9 @@ TextProperty.prototype = {
* The PageStyleFront for communicating with the remote server.
* @constructor
*/
function CssRuleView(aDoc, aStore, aPageStyle)
function CssRuleView(aInspector, aDoc, aStore, aPageStyle)
{
this.inspector = aInspector;
this.doc = aDoc;
this.store = aStore || {};
this.pageStyle = aPageStyle;
@ -1067,6 +1070,9 @@ function CssRuleView(aDoc, aStore, aPageStyle)
};
this.popup = new AutocompletePopup(aDoc.defaultView.parent.document, options);
this.tooltip = new Tooltip(this.inspector.panelDoc);
this.tooltip.startTogglingOnHover(this.element, this._buildTooltipContent.bind(this));
this._buildContextMenu();
this._showEmpty();
}
@ -1107,6 +1113,37 @@ CssRuleView.prototype = {
popupset.appendChild(this._contextmenu);
},
/**
* Verify that target is indeed a css value we want a tooltip on, and if yes
* prepare some content for the tooltip
*/
_buildTooltipContent: function(target) {
let isValueWithImage = target.classList.contains("ruleview-propertyvalue") &&
target.querySelector(".theme-link");
let isImageHref = target.classList.contains("theme-link") &&
target.parentNode.classList.contains("ruleview-propertyvalue");
if (isImageHref) {
target = target.parentNode;
}
let isEditing = this.isEditing;
// If the inplace-editor is visible or if this is not a background image
// don't show the tooltip
if (this.isEditing || (!isImageHref && !isValueWithImage)) {
return false;
}
// Retrieve the TextProperty for the hovered element
let property = target.textProperty;
let href = property.rule.domRule.href;
// Fill some content
this.tooltip.setCssBackgroundImageContent(property.value, href);
return true;
},
/**
* Update the context menu. This means enabling or disabling menuitems as
* appropriate.
@ -1240,6 +1277,9 @@ CssRuleView.prototype = {
// We manage the popupNode ourselves so we also need to destroy it.
this.doc.popupNode = null;
this.tooltip.stopTogglingOnHover(this.element);
this.tooltip.destroy();
if (this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
@ -1307,7 +1347,6 @@ CssRuleView.prototype = {
}
this._createEditors();
// Notify anyone that cares that we refreshed.
var evt = this.doc.createEvent("Events");
evt.initEvent("CssRuleViewRefreshed", true, false);
@ -1853,6 +1892,10 @@ TextPropertyEditor.prototype = {
tabindex: "0",
});
// Storing the TextProperty on the valuespan for easy access
// (for instance by the tooltip)
this.valueSpan.textProperty = this.prop;
// Save the initial value as the last committed value,
// for restoring after pressing escape.
this.committed = { name: this.prop.name,
@ -1971,7 +2014,6 @@ TextPropertyEditor.prototype = {
});
a.addEventListener("click", (aEvent) => {
// Clicks within the link shouldn't trigger editing.
aEvent.stopPropagation();
aEvent.preventDefault();
@ -2133,6 +2175,7 @@ TextPropertyEditor.prototype = {
{
this.element.parentNode.removeChild(this.element);
this.ruleEditor.rule.editClosestTextProperty(this.prop);
this.valueSpan.textProperty = null;
this.prop.remove();
},

View File

@ -25,7 +25,7 @@ function RuleViewTool(aInspector, aWindow, aIFrame)
this.doc = aWindow.document;
this.outerIFrame = aIFrame;
this.view = new RuleView.CssRuleView(this.doc);
this.view = new RuleView.CssRuleView(aInspector, this.doc);
this.doc.documentElement.appendChild(this.view.element);
this._changeHandler = () => {

View File

@ -38,6 +38,7 @@ MOCHITEST_BROWSER_FILES = \
browser_ruleview_pseudoelement.js \
browser_computedview_bug835808_keyboard_nav.js \
browser_bug913014_matched_expand.js \
browser_bug765105_background_image_tooltip.js \
head.js \
$(NULL)

View File

@ -0,0 +1,162 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let contentDoc;
let inspector;
let ruleView;
let computedView;
const PAGE_CONTENT = [
'<style type="text/css">',
' body {',
' padding: 1em;',
' background-image: url(data:image/png;base64,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);',
' background-repeat: repeat-y;',
' background-position: right top;',
' }',
' .test-element {',
' font-family: verdana;',
' color: #333;',
' background: url(chrome://global/skin/icons/warning-64.png) no-repeat left center;',
' padding-left: 70px;',
' }',
'</style>',
'<div class="test-element">test element</div>',
'<div class="test-element-2">test element 2</div>'
].join("\n");
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
contentDoc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,rule view tooltip test";
}
function createDocument() {
contentDoc.body.innerHTML = PAGE_CONTENT;
openRuleView((aInspector, aRuleView) => {
inspector = aInspector;
ruleView = aRuleView;
startTests();
});
}
function startTests() {
// let testElement = contentDoc.querySelector(".test-element");
inspector.selection.setNode(contentDoc.body);
inspector.once("inspector-updated", testBodyRuleView);
}
function endTests() {
contentDoc = inspector = ruleView = computedView = null;
gBrowser.removeCurrentTab();
finish();
}
function assertTooltipShownOn(tooltip, element, cb) {
// If there is indeed a show-on-hover on element, the xul panel will be shown
tooltip.panel.addEventListener("popupshown", function shown() {
tooltip.panel.removeEventListener("popupshown", shown, true);
cb();
}, true);
tooltip._showOnHover(element);
}
function testBodyRuleView() {
info("Testing tooltips in the rule view");
let panel = ruleView.tooltip.panel;
// Check that the rule view has a tooltip and that a XUL panel has been created
ok(ruleView.tooltip, "Tooltip instance exists");
ok(panel, "XUL panel exists");
// Get the background-image property inside the rule view
let {nameSpan, valueSpan} = getRuleViewProperty("background-image");
// And verify that the tooltip gets shown on this property
assertTooltipShownOn(ruleView.tooltip, valueSpan, () => {
let images = panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip contains an image");
ok(images[0].src.indexOf("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHe") !== -1, "The image URL seems fine");
ruleView.tooltip.hide();
inspector.selection.setNode(contentDoc.querySelector(".test-element"));
inspector.once("inspector-updated", testDivRuleView);
});
}
function testDivRuleView() {
let panel = ruleView.tooltip.panel;
// Get the background property inside the rule view
let {nameSpan, valueSpan} = getRuleViewProperty("background");
let uriSpan = valueSpan.querySelector(".theme-link");
// And verify that the tooltip gets shown on this property
assertTooltipShownOn(ruleView.tooltip, uriSpan, () => {
let images = panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip contains an image");
ok(images[0].src === "chrome://global/skin/icons/warning-64.png");
ruleView.tooltip.hide();
testComputedView();
});
}
function testComputedView() {
info("Testing tooltips in the computed view");
inspector.sidebar.select("computedview");
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
let doc = computedView.styleDocument;
let panel = computedView.tooltip.panel;
let {nameSpan, valueSpan} = getComputedViewProperty("background-image");
assertTooltipShownOn(computedView.tooltip, valueSpan, () => {
let images = panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip contains an image");
ok(images[0].src === "chrome://global/skin/icons/warning-64.png");
computedView.tooltip.hide();
endTests();
});
}
function getRuleViewProperty(name) {
let prop = null;
[].forEach.call(ruleView.doc.querySelectorAll(".ruleview-property"), property => {
let nameSpan = property.querySelector(".ruleview-propertyname");
let valueSpan = property.querySelector(".ruleview-propertyvalue");
if (nameSpan.textContent === name) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
}
});
return prop;
}
function getComputedViewProperty(name) {
let prop = null;
[].forEach.call(computedView.styleDocument.querySelectorAll(".property-view"), property => {
let nameSpan = property.querySelector(".property-name");
let valueSpan = property.querySelector(".property-value");
if (nameSpan.textContent === name) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
}
});
return prop;
}

View File

@ -57,6 +57,7 @@
<!ENTITY connection.installOneSimulatorTooltip "Install a version of the Simulator by downloading the relevant add-on.">
<!ENTITY connection.installAnotherSimulator "Add">
<!ENTITY connection.installAnotherSimulatorTooltip "Install an additional version of the Simulator by downloading the relevant add-on.">
<!ENTITY connection.startRegisteredSimulator "Start:">
<!ENTITY projects.localApps "Local Apps">
<!ENTITY projects.addApp "Add">

View File

@ -31,7 +31,6 @@ debuggerPausedWarning.message=Debugger is paused. Some features like mouse selec
# the node is selected.
nodeMenu.tooltiptext=Node operations
# LOCALIZATION NOTE (inspector.*)
# Used for the menuitem in the tool menu
inspector.label=Inspector
@ -44,3 +43,6 @@ inspector.accesskey=I
markupView.more.showing=Some nodes were hidden.
markupView.more.showAll=Show All %S Nodes
inspector.tooltip=DOM and Style Inspector
#LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
previewTooltip.image.brokenImage=Could not load the image

View File

@ -17,6 +17,13 @@
-moz-border-start-color: transparent;
}
/* Sources toolbar */
#sources-toolbar {
border: none; /* Remove the devtools-toolbar's black bottom border. */
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#pretty-print {
min-width: 0;
font-weight: bold;
@ -435,3 +442,8 @@
#body[layout=vertical] .side-menu-widget-item-arrow {
background-image: none !important;
}
#body[layout=vertical] .side-menu-widget-group,
#body[layout=vertical] .side-menu-widget-item {
-moz-margin-end: 0;
}

View File

@ -279,6 +279,8 @@
color: #000;
}
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
@ -287,6 +289,18 @@
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-item {
/* To compensate for the arrow image's dark margin. */
-moz-margin-end: -1px;
}
/* SideMenuWidget groups */
.side-menu-widget-group-title {
padding: 4px;
}
@ -308,6 +322,8 @@
padding: 0;
}
/* SideMenuWidget items */
.side-menu-widget-item[theme="dark"] {
border-top: 1px solid hsla(210,8%,5%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
@ -343,15 +359,17 @@
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: url(itemArrow-ltr.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-ltr.png), linear-gradient(to right, #222426, #222426);
background-position: center right, top right;
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: url(itemArrow-rtl.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-rtl.png), linear-gradient(to right, #222426, #222426);
background-position: center left, top left;
}
/* SideMenuWidget items contents */
.side-menu-widget-item-label {
padding: 4px 0px;
}
@ -385,6 +403,8 @@
text-shadow: 0 1px 1px #111;
}
/* SideMenuWidget misc */
.side-menu-widget-empty-notice-container {
padding: 12px;
}

View File

@ -19,6 +19,13 @@
-moz-border-start-color: transparent;
}
/* Sources toolbar */
#sources-toolbar {
border: none; /* Remove the devtools-toolbar's black bottom border. */
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#pretty-print {
min-width: 0;
font-weight: bold;
@ -437,3 +444,8 @@
#body[layout=vertical] .side-menu-widget-item-arrow {
background-image: none !important;
}
#body[layout=vertical] .side-menu-widget-group,
#body[layout=vertical] .side-menu-widget-item {
-moz-margin-end: 0;
}

View File

@ -279,6 +279,8 @@
color: #000;
}
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
@ -287,6 +289,18 @@
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-item {
/* To compensate for the arrow image's dark margin. */
-moz-margin-end: -1px;
}
/* SideMenuWidget groups */
.side-menu-widget-group-title {
padding: 4px;
}
@ -308,6 +322,8 @@
padding: 0;
}
/* SideMenuWidget items */
.side-menu-widget-item[theme="dark"] {
border-top: 1px solid hsla(210,8%,5%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
@ -343,15 +359,17 @@
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: url(itemArrow-ltr.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-ltr.png), linear-gradient(to right, #222426, #222426);
background-position: center right, top right;
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: url(itemArrow-rtl.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-rtl.png), linear-gradient(to right, #222426, #222426);
background-position: center left, top left;
}
/* SideMenuWidget items contents */
.side-menu-widget-item-label {
padding: 4px 0px;
}
@ -385,6 +403,8 @@
text-shadow: 0 1px 1px #111;
}
/* SideMenuWidget misc */
.side-menu-widget-empty-notice-container {
padding: 12px;
}

View File

@ -111,3 +111,25 @@
max-height: 75vh;
}
}
/* Tooltip widget (see browser/devtools/shared/widgets/Tooltip.js) */
.devtools-tooltip.devtools-tooltip-tooltip {
/* If the tooltip uses a <tooltip> XUL element */
-moz-appearance: none;
padding: 4px;
background: #eee;
border-radius: 3px;
}
.devtools-tooltip.devtools-tooltip-panel .panel-arrowcontent {
/* If the tooltip uses a <panel> XUL element instead */
padding: 4px;
}
.devtools-tooltip-tiles {
background-color: #eee;
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),
linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
}

View File

@ -17,6 +17,13 @@
-moz-border-start-color: transparent;
}
/* Sources toolbar */
#sources-toolbar {
border: none; /* Remove the devtools-toolbar's black bottom border. */
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#pretty-print {
min-width: 0;
font-weight: bold;
@ -440,3 +447,8 @@
#body[layout=vertical] .side-menu-widget-item-arrow {
background-image: none !important;
}
#body[layout=vertical] .side-menu-widget-group,
#body[layout=vertical] .side-menu-widget-item {
-moz-margin-end: 0;
}

View File

@ -283,6 +283,8 @@
color: #000;
}
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
@ -291,6 +293,18 @@
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-item {
/* To compensate for the arrow image's dark margin. */
-moz-margin-end: -1px;
}
/* SideMenuWidget groups */
.side-menu-widget-group-title {
padding: 4px;
}
@ -312,6 +326,8 @@
padding: 0;
}
/* SideMenuWidget items */
.side-menu-widget-item[theme="dark"] {
border-top: 1px solid hsla(210,8%,5%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
@ -347,15 +363,17 @@
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: url(itemArrow-ltr.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-ltr.png), linear-gradient(to right, #222426, #222426);
background-position: center right, top right;
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: url(itemArrow-rtl.png), linear-gradient(to right, black, black);
background-image: url(itemArrow-rtl.png), linear-gradient(to right, #222426, #222426);
background-position: center left, top left;
}
/* SideMenuWidget items contents */
.side-menu-widget-item-label {
padding: 4px 0px;
}
@ -388,6 +406,8 @@
color: #f5f7fa;
}
/* SideMenuWidget misc */
.side-menu-widget-empty-notice-container {
padding: 12px;
}

View File

@ -2,19 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JAVA_JAR_TARGETS += annotationProcessors
annotationProcessors_DEST := annotationProcessors.jar
annotationProcessors_JAVAFILES := \
AnnotationProcessor.java \
CodeGenerator.java \
MethodWithAnnotationInfo.java \
classloader/IterableJarLoadingURLClassLoader.java \
classloader/JarClassIterator.java \
utils/AlphabeticMethodComparator.java \
utils/GeneratableEntryPointIterator.java \
utils/Utils.java \
$(NULL)
include $(topsrcdir)/config/rules.mk
JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar

View File

@ -3,3 +3,15 @@
# 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/.
jar = add_java_jar('annotationProcessors')
jar.sources += [
'AnnotationProcessor.java',
'CodeGenerator.java',
'MethodWithAnnotationInfo.java',
'classloader/IterableJarLoadingURLClassLoader.java',
'classloader/JarClassIterator.java',
'utils/AlphabeticMethodComparator.java',
'utils/GeneratableEntryPointIterator.java',
'utils/Utils.java',
]

View File

@ -3,7 +3,6 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
MODULES = stlport
FORCE_STATIC_LIB = 1
STL_FLAGS =
# Force to build a static library, instead of a fake library, without

View File

@ -6,3 +6,4 @@
LIBRARY_NAME = 'stlport_static'
FORCE_STATIC_LIB = True

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB= 1
STL_FLAGS =
NO_EXPAND_LIBS = 1
NO_PROFILE_GUIDED_OPTIMIZE = 1

View File

@ -16,3 +16,4 @@ if CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']:
'stdc++compat.cpp',
]
FORCE_STATIC_LIB = True

View File

@ -41,12 +41,14 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
DIRS \
EXTRA_PP_COMPONENTS \
EXTRA_PP_JS_MODULES \
FORCE_STATIC_LIB \
GTEST_CMMSRCS \
GTEST_CPPSRCS \
GTEST_CSRCS \
HOST_CSRCS \
HOST_LIBRARY_NAME \
IS_COMPONENT \
JAVA_JAR_TARGETS \
JS_MODULES_PATH \
LIBRARY_NAME \
LIBXUL_LIBRARY \

View File

@ -986,7 +986,6 @@ CSPSourceList.fromString = function(aStr, aCSPRep, self, enforceSelfChecks) {
// if a source is a *, then we can permit all sources
if (src.permitAll) {
slObj._permitAllSources = true;
return slObj;
} else {
slObj._sources.push(src);
}

View File

@ -343,54 +343,85 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
return NS_OK;
}
// We need aRequestingLocation to pull out the scheme. If it isn't passed
// in, get it from the aRequestingPricipal
if (!aRequestingLocation) {
if (!aRequestPrincipal) {
// If we don't have aRequestPrincipal, try getting it from the
// DOM node using aRequestingContext
nsCOMPtr<nsINode> node = do_QueryInterface(aRequestingContext);
if (node) {
aRequestPrincipal = node->NodePrincipal();
} else {
// Try using the window's script object principal if it's not a node.
nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aRequestingContext);
if (scriptObjPrin) {
aRequestPrincipal = scriptObjPrin->GetPrincipal();
}
}
}
if (aRequestPrincipal) {
nsCOMPtr<nsIURI> principalUri;
nsresult rvalue = aRequestPrincipal->GetURI(getter_AddRefs(principalUri));
if (NS_SUCCEEDED(rvalue)) {
aRequestingLocation = principalUri;
}
}
// Since there are cases where aRequestingLocation and aRequestPrincipal are
// definitely not the owning document, we try to ignore them by extracting the
// requestingLocation in the following order:
// 1) from the aRequestingContext, either extracting
// a) the node's principal, or the
// b) script object's principal.
// 2) if aRequestingContext yields a principal but no location, we check
// if its the system principal. If it is, allow the load.
// 3) Special case handling for:
// a) speculative loads, where shouldLoad is called twice (bug 839235)
// and the first speculative load does not include a context.
// In this case we use aRequestingLocation to set requestingLocation.
// b) TYPE_CSP_REPORT which does not provide a context. In this case we
// use aRequestingLocation to set requestingLocation.
// c) content scripts from addon code that do not provide aRequestingContext
// or aRequestingLocation, but do provide aRequestPrincipal.
// If aRequestPrincipal is an expanded principal, we allow the load.
// 4) If we still end up not having a requestingLocation, we reject the load.
if (!aRequestingLocation) {
// If content scripts from an addon are causing this load, they have an
// ExpandedPrincipal instead of a Principal. This is pseudo-privileged code, so allow
// the load. Or if this is system principal, allow the load.
nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aRequestPrincipal);
if (expanded || (aRequestPrincipal && nsContentUtils::IsSystemPrincipal(aRequestPrincipal))) {
*aDecision = ACCEPT;
return NS_OK;
} else {
// We still don't have a requesting location and there is no Expanded Principal.
// We can't tell if this is a mixed content load. Deny to be safe.
*aDecision = REJECT_REQUEST;
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal;
// 1a) Try to get the principal if aRequestingContext is a node.
nsCOMPtr<nsINode> node = do_QueryInterface(aRequestingContext);
if (node) {
principal = node->NodePrincipal();
}
// 1b) Try using the window's script object principal if it's not a node.
if (!principal) {
nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aRequestingContext);
if (scriptObjPrin) {
principal = scriptObjPrin->GetPrincipal();
}
}
nsCOMPtr<nsIURI> requestingLocation;
if (principal) {
principal->GetURI(getter_AddRefs(requestingLocation));
}
// 2) if aRequestingContext yields a principal but no location, we check if its a system principal.
if (principal && !requestingLocation) {
if (nsContentUtils::IsSystemPrincipal(principal)) {
*aDecision = ACCEPT;
return NS_OK;
}
}
// 3a,b) Special case handling for speculative loads and TYPE_CSP_REPORT. In
// such cases, aRequestingContext doesn't exist, so we use aRequestingLocation.
// Unfortunately we can not distinguish between speculative and normal loads here,
// otherwise we could special case this assignment.
if (!requestingLocation) {
requestingLocation = aRequestingLocation;
}
// 3c) Special case handling for content scripts from addons code, which only
// provide a aRequestPrincipal; aRequestingContext and aRequestingLocation are
// both null; if the aRequestPrincipal is an expandedPrincipal, we allow the load.
if (!principal && !requestingLocation && aRequestPrincipal) {
nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aRequestPrincipal);
if (expanded) {
*aDecision = ACCEPT;
return NS_OK;
}
}
// 4) Giving up. We still don't have a requesting location, therefore we can't tell
// if this is a mixed content load. Deny to be safe.
if (!requestingLocation) {
*aDecision = REJECT_REQUEST;
return NS_OK;
}
// Check the parent scheme. If it is not an HTTPS page then mixed content
// restrictions do not apply.
bool parentIsHttps;
nsresult rv = aRequestingLocation->SchemeIs("https", &parentIsHttps);
nsresult rv = requestingLocation->SchemeIs("https", &parentIsHttps);
if (NS_FAILED(rv)) {
NS_ERROR("aRequestingLocation->SchemeIs failed");
NS_ERROR("requestingLocation->SchemeIs failed");
*aDecision = REJECT_REQUEST;
return NS_OK;
}

View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<!-- file_CSP.sjs mocks a resource load -->
<link rel='stylesheet' type='text/css'
href='file_CSP.sjs?testid=noneExternalStylesBlocked&type=text/css' />
</head>
<body>
<p id="inline-style">This should be green</p>
<p id="inline-script">This should be black</p>
<style>
p#inline-style { color:rgb(0, 128, 0); }
</style>
<script>
// Use inline script to set a style attribute
document.getElementById("inline-script").style.color = "rgb(0, 128, 0)";
</script>
<img src="file_CSP.sjs?testid=noneExternalImgLoaded&type=img/png" />
</body>
</html>

View File

@ -0,0 +1 @@
Content-Security-Policy: default-src * ; style-src 'none' 'unsafe-inline';

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<link rel='stylesheet' type='text/css'
href='file_CSP.sjs?testid=starExternalStylesLoaded&type=text/css' />
</head>
<body>
<p id="inline-style">This should be green</p>
<p id="inline-script">This should be black</p>
<style>
p#inline-style { color:rgb(0, 128, 0); }
</style>
<script>
// Use inline script to set a style attribute
document.getElementById("inline-script").style.color = "rgb(0, 128, 0)";
</script>
<img src="file_CSP.sjs?testid=starExternalImgLoaded&type=img/png" />
</body>
</html>

View File

@ -0,0 +1 @@
Content-Security-Policy: default-src *; style-src * 'unsafe-inline';

View File

@ -78,6 +78,10 @@ support-files =
file_CSP_bug910139.sjs
file_CSP_bug910139.xml
file_CSP_bug910139.xsl
file_CSP_bug909029_star.html
file_CSP_bug909029_star.html^headers^
file_CSP_bug909029_none.html
file_CSP_bug909029_none.html^headers^
[test_CSP.html]
[test_CSP_bug663567.html]
@ -94,3 +98,4 @@ support-files =
[test_bug836922_npolicies.html]
[test_csp_redirects.html]
[test_CSP_bug910139.html]
[test_CSP_bug909029.html]

View File

@ -0,0 +1,140 @@
<!doctype html>
<html>
<head>
<title>Bug 909029 - CSP source-lists ignore some source expressions like 'unsafe-inline' when * or 'none' are used (e.g., style-src, script-src)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id=content style="visibility:hidden">
<iframe id=testframe1></iframe>
<iframe id=testframe2></iframe>
</div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
window.tests = {
starExternalStylesLoaded: -1,
starExternalImgLoaded: -1,
noneExternalStylesBlocked: -1,
noneExternalImgLoaded: -1,
starInlineStyleAllowed: -1,
starInlineScriptBlocked: -1,
noneInlineStyleAllowed: -1,
noneInlineScriptBlocked: -1
}
function examiner() {
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
SpecialPowers.addObserver(this, "http-on-modify-request", false);
}
examiner.prototype = {
observe: function(subject, topic, data) {
// subject should be an nsURI, and should be either allowed or blocked.
if (!SpecialPowers.can_QI(subject))
return;
var testpat = new RegExp("testid=([a-zA-Z]+)");
if (topic === "http-on-modify-request") {
//these things were allowed by CSP
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
if (!testpat.test(asciiSpec))
return;
var testid = testpat.exec(asciiSpec)[1];
window.testResult(testid,
/Loaded/.test(testid),
"resource loaded");
}
if(topic === "csp-on-violate-policy") {
// these were blocked... record that they were blocked
// try because the subject could be an nsIURI or an nsISupportsCString
try {
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
if (!testpat.test(asciiSpec)) return;
var testid = testpat.exec(asciiSpec)[1];
window.testResult(testid,
/Blocked/.test(testid),
"resource blocked by CSP");
} catch(e) {
// if that fails, the subject is probably a string. Strings are only
// reported for inline and eval violations. Since we are testing those
// via the observed effects of script on CSSOM, we can simply ignore
// these subjects.
}
}
},
// must eventually call this to remove the listener,
// or mochitests might get borked.
remove: function() {
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
SpecialPowers.removeObserver(this, "http-on-modify-request");
}
}
window.examiner = new examiner();
window.testResult = function(testname, result, msg) {
//dump("in testResult: testname = " + testname + "\n");
//test already complete.... forget it... remember the first result.
if (window.tests[testname] != -1)
return;
window.tests[testname] = result;
is(result, true, testname + ' test: ' + msg);
// if any test is incomplete, keep waiting
for (var v in window.tests)
if(tests[v] == -1)
return;
// ... otherwise, finish
window.examiner.remove();
SimpleTest.finish();
}
// Helpers for inline script/style checks
var black = 'rgb(0, 0, 0)';
var green = 'rgb(0, 128, 0)';
function getElementColorById(doc, id) {
return window.getComputedStyle(doc.contentDocument.getElementById(id)).color;
}
function checkInlineWithStar() {
var testframe = document.getElementById('testframe1');
window.testResult("starInlineStyleAllowed",
getElementColorById(testframe, 'inline-style') === green,
"Inline styles should be allowed (style-src 'unsafe-inline' with star)");
window.testResult("starInlineScriptBlocked",
getElementColorById(testframe, 'inline-script') === black,
"Inline scripts should be blocked (style-src 'unsafe-inline' with star)");
}
function checkInlineWithNone() {
// If a directive has 'none' in addition to other sources, 'none' is ignored
// and the other sources are used. 'none' is only a valid source if it is
// used by itself.
var testframe = document.getElementById('testframe2');
window.testResult("noneInlineStyleAllowed",
getElementColorById(testframe, 'inline-style') === green,
"Inline styles should be allowed (style-src 'unsafe-inline' with none)");
window.testResult("noneInlineScriptBlocked",
getElementColorById(testframe, 'inline-script') === black,
"Inline scripts should be blocked (style-src 'unsafe-inline' with none)");
}
SpecialPowers.pushPrefEnv(
{'set':[["security.csp.speccompliant", true]]},
function () {
document.getElementById('testframe1').src = 'file_CSP_bug909029_star.html';
document.getElementById('testframe1').addEventListener('load', checkInlineWithStar, false);
document.getElementById('testframe2').src = 'file_CSP_bug909029_none.html';
document.getElementById('testframe2').addEventListener('load', checkInlineWithNone, false);
}
);
</script>
</body>
</html>

View File

@ -2,8 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk
INCLUDES += \

View File

@ -18,3 +18,4 @@ LIBRARY_NAME = 'mediaresourcemanager'
include('/ipc/chromium/chromium-config.mozbuild')
FORCE_STATIC_LIB = True

View File

@ -4,9 +4,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SHORT_LIBNAME = mozsqlt3
ifdef MOZ_FOLD_LIBS
FORCE_STATIC_LIB = 1
else
ifndef MOZ_FOLD_LIBS
FORCE_SHARED_LIB = 1
endif
VISIBILITY_FLAGS =

View File

@ -16,3 +16,5 @@ SOURCES += [
'sqlite3.c',
]
if CONFIG['MOZ_FOLD_LIBS']:
FORCE_STATIC_LIB = True

View File

@ -717,6 +717,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
cairo_matrix_multiply(&m, &m, &surface->ctm);
SaveDC (surface->dc);
_cairo_matrix_to_win32_xform (&m, &xform);

View File

@ -17,7 +17,6 @@ include $(srcdir)/files.mk
# on Windows, we're going to link graphite with gkmedias instead of libxul
ifeq (WINNT,$(OS_TARGET))
VISIBILITY_FLAGS =
FORCE_STATIC_LIB = 1
endif
ifeq (WINNT,$(OS_TARGET))

View File

@ -6,11 +6,10 @@
MODULE = 'graphite2'
if CONFIG['OS_TARGET'] != 'WINNT':
LIBXUL_LIBRARY = True
if CONFIG['OS_TARGET'] == 'WINNT':
FORCE_STATIC_LIB = True
else:
# FORCE_STATIC_LIB = True
pass
LIBXUL_LIBRARY = True
# This should contain all of the _PUBLIC_HEADERS from files.mk
EXPORTS.graphite2 += [

View File

@ -24,11 +24,6 @@
# Mozilla author(s): Jonathan Kew
#
ifeq ($(OS_ARCH),WINNT)
FORCE_STATIC_LIB = 1
endif
LOCAL_INCLUDES += -I$(srcdir)

View File

@ -6,11 +6,10 @@
MODULE = 'harfbuzz'
if CONFIG['OS_ARCH'] != 'WINNT':
LIBXUL_LIBRARY = True
if CONFIG['OS_ARCH'] == 'WINNT':
FORCE_STATIC_LIB = True
else:
# FORCE_STATIC_LIB = True
pass
LIBXUL_LIBRARY = True
EXPORTS.harfbuzz += [
'hb-blob.h',

View File

@ -27,7 +27,6 @@
ifeq (WINNT,$(OS_TARGET))
VISIBILITY_FLAGS =
FORCE_STATIC_LIB = 1
endif
CSRCS = \

View File

@ -6,11 +6,10 @@
MODULE = 'ots'
if CONFIG['OS_TARGET'] != 'WINNT':
LIBXUL_LIBRARY = True
if CONFIG['OS_TARGET'] == 'WINNT':
FORCE_STATIC_LIB = True
else:
# FORCE_STATIC_LIB = True
pass
LIBXUL_LIBRARY = True
EXPORTS += [
'../include/opentype-sanitiser.h',

View File

@ -125,7 +125,7 @@ gfxWindowsSurface::CreateSimilarSurface(gfxContentType aContent,
}
cairo_surface_t *surface;
if (GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
if (!mForPrinting && GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
// When creating a similar surface to a transparent surface, ensure
// the new surface uses a DIB. cairo_surface_create_similar won't
// use a DIB for a GFX_CONTENT_COLOR surface if this surface doesn't

View File

@ -10,7 +10,6 @@
DIST_INSTALL = 1
SDK_LIBRARY = $(LIBRARY)
FORCE_STATIC_LIB = 1
USE_STATIC_LIBS = 1
LOCAL_INCLUDES += -I$(srcdir)/../src

View File

@ -13,6 +13,4 @@ MOZILLA_INTERNAL_API = 1
LOCAL_INCLUDES += -I$(srcdir)/.. \
-I$(srcdir)/../../src
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk

View File

@ -14,3 +14,4 @@ LIBRARY_NAME = 'unicharutil_s'
EXPORT_LIBRARY = True
FORCE_STATIC_LIB = True

View File

@ -21,3 +21,5 @@ include('objs.mozbuild')
SOURCES += intl_unicharutil_util_cppsrcs
LIBRARY_NAME = 'unicharutil_external_s'
FORCE_STATIC_LIB = True

View File

@ -31,7 +31,6 @@ LIBS = $(NSPR_LIBS)
ifdef JS_SHARED_LIBRARY
FORCE_SHARED_LIB = 1
endif
FORCE_STATIC_LIB = 1
DIST_INSTALL = 1
###############################################

View File

@ -41,12 +41,14 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
DIRS \
EXTRA_PP_COMPONENTS \
EXTRA_PP_JS_MODULES \
FORCE_STATIC_LIB \
GTEST_CMMSRCS \
GTEST_CPPSRCS \
GTEST_CSRCS \
HOST_CSRCS \
HOST_LIBRARY_NAME \
IS_COMPONENT \
JAVA_JAR_TARGETS \
JS_MODULES_PATH \
LIBRARY_NAME \
LIBXUL_LIBRARY \

View File

@ -4,7 +4,5 @@
# 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/.
FORCE_STATIC_LIB = 1
DEFINES += -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX \
-DHAVE_STDLIB -DUNIQUE_HISTORY

View File

@ -11,3 +11,4 @@ SOURCES += [
'sysunix.c',
]
FORCE_STATIC_LIB = True

View File

@ -2358,8 +2358,13 @@ CodeGenerator::visitCallDirectEval(LCallDirectEval *lir)
static const uint32_t EntryTempMask = Registers::TempMask & ~(1 << OsrFrameReg.code());
bool
CodeGenerator::generateArgumentsChecks()
CodeGenerator::generateArgumentsChecks(bool bailout)
{
// This function can be used the normal way to check the argument types,
// before entering the function and bailout when arguments don't match.
// For debug purpose, this is can also be used to force/check that the
// arguments are correct. Upon fail it will hit a breakpoint.
MIRGraph &mir = gen->graph();
MResumePoint *rp = mir.entryResumePoint();
@ -2389,8 +2394,18 @@ CodeGenerator::generateArgumentsChecks()
masm.guardTypeSet(Address(StackPointer, offset), types, temp, &miss);
}
if (miss.used() && !bailoutFrom(&miss, graph.entrySnapshot()))
return false;
if (miss.used()) {
if (bailout) {
if (!bailoutFrom(&miss, graph.entrySnapshot()))
return false;
} else {
Label success;
masm.jump(&success);
masm.bind(&miss);
masm.breakpoint();
masm.bind(&success);
}
}
masm.freeStack(frameSize());
@ -5679,6 +5694,12 @@ CodeGenerator::generate()
masm.bind(&skip);
#endif
#ifdef DEBUG
// Assert that the argument types are correct.
if (!generateArgumentsChecks(/* bailout = */ false))
return false;
#endif
if (!generatePrologue())
return false;
if (!generateBody())

View File

@ -43,7 +43,7 @@ class OutOfLineCallPostWriteBarrier;
class CodeGenerator : public CodeGeneratorSpecific
{
bool generateArgumentsChecks();
bool generateArgumentsChecks(bool bailout = true);
bool generateBody();
public:

View File

@ -160,6 +160,14 @@ MacroAssembler::guardObjectType(Register obj, const TypeSet *types,
}
if (hasTypeObjects) {
// We are possibly going to overwrite the obj register. So already
// emit the branch, since branch depends on previous value of obj
// register and there is definitely a branch following. So no need
// to invert the condition.
if (lastBranch.isInitialized())
lastBranch.emit(*this);
lastBranch = BranchGCPtr();
// Note: Some platforms give the same register for obj and scratch.
// Make sure when writing to scratch, the obj register isn't used anymore!
loadPtr(Address(obj, JSObject::offsetOfType()), scratch);

View File

@ -2857,8 +2857,6 @@ class MToFloat32
}
void computeRange();
bool truncate();
bool isOperandTruncated(size_t index) const;
bool canConsumeFloat32() const { return true; }
bool canProduceFloat32() const { return true; }

View File

@ -2095,20 +2095,6 @@ MToDouble::truncate()
return true;
}
bool
MToFloat32::truncate()
{
JS_ASSERT(type() == MIRType_Float32);
// We use the return type to flag that this MToFloat32 sould be replaced by a
// MTruncateToInt32 when modifying the graph.
setResultType(MIRType_Int32);
if (range())
range()->wrapAroundToInt32();
return true;
}
bool
MLoadTypedArrayElementStatic::truncate()
{
@ -2160,14 +2146,6 @@ MToDouble::isOperandTruncated(size_t index) const
return type() == MIRType_Int32;
}
bool
MToFloat32::isOperandTruncated(size_t index) const
{
// The return type is used to flag that we are replacing this Float32 by a
// Truncate of its operand if needed.
return type() == MIRType_Int32;
}
bool
MStoreTypedArrayElement::isOperandTruncated(size_t index) const
{

View File

@ -658,9 +658,9 @@ WorkerThread::handleAsmJSWorkload(WorkerThreadState &state)
// On failure, signal parent for harvesting in CancelOutstandingJobs().
if (!success) {
asmData = nullptr;
state.noteAsmJSFailure(asmData->func);
state.notifyAll(WorkerThreadState::CONSUMER);
asmData = nullptr;
return;
}

View File

@ -354,3 +354,5 @@ HOST_SOURCES += [
'jskwgen.cpp',
'jsoplengen.cpp',
]
FORCE_STATIC_LIB = True

View File

@ -538,7 +538,7 @@ ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buf
if (buffer->isAsmJSArrayBuffer())
return true;
if (!buffer->copyData(cx))
if (!buffer->ensureNonInline(cx))
return false;
JS_ASSERT(buffer->hasDynamicElements());

View File

@ -1,4 +1,10 @@
function f(stdlib, foreign, buffer) {
function f1() { "use asm"; function g() {} return g }
if (this.jsFuns) {
ok(jsFuns.isAsmJSModule(f1), "f1 is an asm.js module");
ok(jsFuns.isAsmJSFunction(f1()), "f1.g is an asm.js function");
}
function f2(stdlib, foreign, buffer) {
"use asm";
var i32 = new stdlib.Int32Array(buffer);
function main(n) {
@ -10,17 +16,56 @@ function f(stdlib, foreign, buffer) {
}
return main;
}
var i32 = new Int32Array(4096/4);
for (var i = 0; i < 100; i++)
if (this.jsFuns)
ok(jsFuns.isAsmJSModule(f2), "f2 is an asm.js module");
var i32 = new Int32Array(1024);
for (var i = 0; i < i32.length; i++)
i32[i] = i;
var f2Main = f2(this, null, i32.buffer);
if (this.jsFuns)
ok(jsFuns.isAsmJSFunction(f2Main), "f2.main is an asm.js function");
if (f2Main(4) !== 6)
throw "f2Main(4)";
if (f2Main(100) !== 4950)
throw "f2.main(100)";
var sum = (((i32.length - 1) * i32.length) / 2);
if (f2Main(i32.length) !== sum)
throw "f2.main(" + i32.length + ")";
if (f2Main(i32.length + 100) !== sum)
throw "f2.main(" + i32.length + ")";
var fMain = f(this, null, i32.buffer);
if (fMain(4) !== 6)
throw "f.main(4)";
if (fMain(100) !== 4950)
throw "f.main(100)";
if (fMain(5000) !== 4950)
throw "f.main(5000)";
function f3(stdlib, foreign, buffer) {
"use asm";
var done = foreign.done;
var i32 = new stdlib.Int32Array(buffer);
function main() {
var i = 0, sum = 0;
while (1) {
for (i = 0; (i|0) < 1000; i=(i+1)|0)
sum = (sum + i)|0;
if (done(sum|0)|0)
break;
}
return sum|0;
}
return main;
}
var begin;
var lastSum;
function done(sum) {
if (sum !== ((lastSum + 499500)|0))
throw "bad sum: " + sum + ", " + lastSum + ", " + ((lastSum + 499500)|0);
lastSum = sum;
return (Date.now() - begin) > 3000;
}
var f3Main = f3(this, {done:done}, i32.buffer);
if (this.jsFuns)
ok(jsFuns.isAsmJSFunction(f3Main), "f3.main is an asm.js function");
postMessage("ok");
begin = Date.now();
lastSum = 0;
if (f3Main() !== lastSum)
throw "f3.main()";
if (!this.jsFuns)
postMessage("ok");

View File

@ -10,70 +10,27 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=854209
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=854209">asm.js browser tests</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=854209">asm.js browser tests</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
<script>
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
ok(jsFuns.isAsmJSCompilationAvailable());
</script>
ok(jsFuns.isAsmJSCompilationAvailable());
<script src="http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_asmjs.js"></script>
function f1() { "use asm"; function g() {} return g }
ok(jsFuns.isAsmJSModule(f1), "f1 is an asm.js module");
ok(jsFuns.isAsmJSFunction(f1()), "f1.g is an asm.js function");
<script>
var w = new Worker('http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_asmjs.js');
w.onmessage = function(e) {
ok(e.data === "ok", "Worker asm.js tests");
SimpleTest.finish();
}
function f2(stdlib, foreign, buffer) {
"use asm";
var i32 = new stdlib.Int32Array(buffer);
function main(n) {
n = n|0;
var i = 0, sum = 0;
for (; (i|0) < (n|0); i=(i+1)|0)
sum = (sum + (i32[(i<<2)>>2]|0))|0;
return sum|0;
}
return main;
}
ok(jsFuns.isAsmJSModule(f2), "f2 is an asm.js module");
var i32 = new Int32Array(4096/4);
for (var i = 0; i < 100; i++)
i32[i] = i;
var f2Main = f2(this, null, i32.buffer);
ok(jsFuns.isAsmJSFunction(f2Main), "f2.main is an asm.js function");
ok(f2Main(4) == 6, "f2.main(4)");
ok(f2Main(100) == 4950, "f2.main(100)");
ok(f2Main(5000) == 4950, "f2.main(5000)");
SimpleTest.waitForExplicitFinish();
</script>
function f3(stdlib, foreign, buffer) {
"use asm";
var i32 = new stdlib.Int32Array(buffer);
function main(n,o) {
n = n|0;
o = o|0;
var i = 0, j = 0, sum = 0;
for (i = 0; (i|0) < (n|0); i=(i+1)|0)
for (j = 0; (j|0) < (o|0); j=(j+1)|0)
sum = (sum + (i32[(j<<2)>>2]|0))|0;
return sum|0;
}
return main;
}
var f3Main = f3(this, null, i32.buffer);
ok(jsFuns.isAsmJSFunction(f3Main), "f3.main is an asm.js function");
ok(f3Main(200000, 1000) == ((4950*200000)|0), "f3.main(200000, 1000)");
var w = new Worker('http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_asmjs.js');
w.onmessage = function(e) {
ok(e.data === "ok", "Worker asm.js tests");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FORCE_STATIC_LIB= 1
ifeq ($(OS_TARGET),WINNT)
VISIBILITY_FLAGS =
endif

View File

@ -51,3 +51,4 @@ LIBRARY_NAME = 'cubeb'
MSVC_ENABLE_PGO = True
FORCE_STATIC_LIB = True

View File

@ -16,9 +16,6 @@ ifeq ($(AS),yasm)
AS_DASH_C_FLAG=
endif
# need static lib for some of the libimg componentry to link properly
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk
jpeg_nbits_table.h: $(srcdir)/genTables.py

Some files were not shown because too many files have changed in this diff Show More