Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2014-07-02 17:24:00 -07:00
commit c778b21cc9
21 changed files with 175 additions and 565 deletions

View File

@ -1910,7 +1910,6 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup) {
}
function getShortcutOrURIAndPostData(aURL, aCallback) {
let mayInheritPrincipal = false;
let postData = null;
let shortcutURL = null;
let keyword = aURL;
@ -1926,8 +1925,7 @@ function getShortcutOrURIAndPostData(aURL, aCallback) {
if (engine) {
let submission = engine.getSubmission(param);
postData = submission.postData;
aCallback({ postData: submission.postData, url: submission.uri.spec,
mayInheritPrincipal: mayInheritPrincipal });
aCallback({ postData: submission.postData, url: submission.uri.spec });
return;
}
@ -1935,8 +1933,7 @@ function getShortcutOrURIAndPostData(aURL, aCallback) {
PlacesUtils.getURLAndPostDataForKeyword(keyword);
if (!shortcutURL) {
aCallback({ postData: postData, url: aURL,
mayInheritPrincipal: mayInheritPrincipal });
aCallback({ postData: postData, url: aURL });
return;
}
@ -1968,12 +1965,7 @@ function getShortcutOrURIAndPostData(aURL, aCallback) {
postData = getPostDataStream(escapedPostData, param, encodedParam,
"application/x-www-form-urlencoded");
// This URL came from a bookmark, so it's safe to let it inherit the current
// document's principal.
mayInheritPrincipal = true;
aCallback({ postData: postData, url: shortcutURL,
mayInheritPrincipal: mayInheritPrincipal });
aCallback({ postData: postData, url: shortcutURL });
}
if (matches) {
@ -1996,15 +1988,9 @@ function getShortcutOrURIAndPostData(aURL, aCallback) {
// the original URL.
postData = null;
aCallback({ postData: postData, url: aURL,
mayInheritPrincipal: mayInheritPrincipal });
aCallback({ postData: postData, url: aURL });
} else {
// This URL came from a bookmark, so it's safe to let it inherit the current
// document's principal.
mayInheritPrincipal = true;
aCallback({ postData: postData, url: shortcutURL,
mayInheritPrincipal: mayInheritPrincipal });
aCallback({ postData: postData, url: shortcutURL });
}
}
@ -5151,6 +5137,8 @@ function middleMousePaste(event) {
// bar's behavior (stripsurroundingwhitespace)
clipboard = clipboard.replace(/\s*\n\s*/g, "");
clipboard = stripUnsafeProtocolOnPaste(clipboard);
// if it's not the current tab, we don't need to do anything because the
// browser doesn't exist.
let where = whereToOpenLink(event, true, false);
@ -5178,14 +5166,32 @@ function middleMousePaste(event) {
if (where != "current" ||
lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
openUILink(data.url, event,
{ ignoreButton: true,
disallowInheritPrincipal: !data.mayInheritPrincipal });
{ ignoreButton: true });
}
});
event.stopPropagation();
}
function stripUnsafeProtocolOnPaste(pasteData) {
// Don't allow pasting in full URIs which inherit the security context.
const URI_INHERITS_SECURITY_CONTEXT = Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT;
let pastedURI;
pasteData = pasteData.trim();
do {
if (pastedURI) {
pasteData = pastedURI.path.trim();
}
try {
pastedURI = makeURI(pasteData);
} catch (ex) {
break;
}
} while (Services.netutil.URIChainHasFlags(pastedURI, URI_INHERITS_SECURITY_CONTEXT));
return pasteData;
}
function handleDroppedLink(event, url, name)
{
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;

View File

@ -309,11 +309,9 @@ skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.conten
skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
[browser_locationBarCommand.js]
skip-if = os == "linux" || e10s # Linux: Intermittent failures, bug 917535; e10s: Bug ?????? - Focus issues (There should be no focused element - Got [object XULElement], expected null)
[browser_locationBarExternalLoad.js]
skip-if = e10s # Bug ?????? - URL bar issues ("There should be no focused element - Got [object XULElement], expected null")
[browser_menuButtonFitts.js]
skip-if = os != "win" || e10s # The Fitts Law menu button is only supported on Windows (bug 969376); # Bug ?????? - URL bar issues ("There should be no focused element - Got [object XULElement], expected null")
[browser_middleMouse_inherit.js]
[browser_middleMouse_noJSPaste.js]
skip-if = e10s # Bug 921952 - Content:Click event issues
[browser_minimize.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: gBrowser.docShell is null)
@ -347,6 +345,7 @@ skip-if = e10s # Bug ?????? - timeout after logging "Error: Channel closing: too
[browser_relatedTabs.js]
[browser_removeTabsToTheEnd.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_removeUnsafeProtocolsFromURLBarPaste.js]
[browser_sanitize-download-history.js]
skip-if = true # bug 432425
[browser_sanitize-passwordDisabledHosts.js]

View File

@ -11,10 +11,9 @@ function getPostDataString(aIS) {
return dataLines[dataLines.length-1];
}
function keywordResult(aURL, aPostData, aIsUnsafe) {
function keywordResult(aURL, aPostData) {
this.url = aURL;
this.postData = aPostData;
this.isUnsafe = aIsUnsafe;
}
function keyWordData() {}
@ -53,20 +52,20 @@ var testData = [
new keywordResult("http://bmget-nosearch/", null)],
[new searchKeywordData("searchget", "http://searchget/?search={searchTerms}", null, "foo4"),
new keywordResult("http://searchget/?search=foo4", null, true)],
new keywordResult("http://searchget/?search=foo4", null)],
[new searchKeywordData("searchpost", "http://searchpost/", "search={searchTerms}", "foo5"),
new keywordResult("http://searchpost/", "search=foo5", true)],
new keywordResult("http://searchpost/", "search=foo5")],
[new searchKeywordData("searchpostget", "http://searchpostget/?search1={searchTerms}", "search2={searchTerms}", "foo6"),
new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6", true)],
new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6")],
// Bookmark keywords that don't take parameters should not be activated if a
// parameter is passed (bug 420328).
[new bmKeywordData("bmget-noparam", "http://bmget-noparam/", null, "foo7"),
new keywordResult(null, null, true)],
new keywordResult(null, null)],
[new bmKeywordData("bmpost-noparam", "http://bmpost-noparam/", "not_a=param", "foo8"),
new keywordResult(null, null, true)],
new keywordResult(null, null)],
// Test escaping (%s = escaped, %S = raw)
// UTF-8 default
@ -88,7 +87,7 @@ var testData = [
// getShortcutOrURIAndPostData for non-keywords (setupKeywords only adds keywords for
// bmKeywordData objects)
[{keyword: "http://gavinsharp.com"},
new keywordResult(null, null, true)]
new keywordResult(null, null)]
];
function test() {
@ -109,7 +108,6 @@ function test() {
let expected = result.url || query;
is(returnedData.url, expected, "got correct URL for " + data.keyword);
is(getPostDataString(returnedData.postData), result.postData, "got correct postData for " + data.keyword);
is(returnedData.mayInheritPrincipal, !result.isUnsafe, "got correct mayInheritPrincipal for " + data.keyword);
}
cleanupKeywords();
}).then(finish);

View File

@ -1,65 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
nextTest();
}
let urls = [
"javascript:'foopy';",
"data:text/html,<body>hi"
];
function urlEnter(url) {
gURLBar.value = url;
gURLBar.focus();
EventUtils.synthesizeKey("VK_RETURN", {});
}
function urlClick(url) {
gURLBar.value = url;
gURLBar.focus();
let goButton = document.getElementById("urlbar-go-button");
EventUtils.synthesizeMouseAtCenter(goButton, {});
}
function nextTest() {
let url = urls.shift();
if (url) {
testURL(url, urlEnter, function () {
testURL(url, urlClick, nextTest);
});
}
else
finish();
}
function testURL(url, loadFunc, endFunc) {
let tab = gBrowser.selectedTab = gBrowser.addTab();
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
});
addPageShowListener(function () {
let pagePrincipal = gBrowser.contentPrincipal;
loadFunc(url);
addPageShowListener(function () {
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
is(fm.focusedElement, null, "should be no focused element");
is(fm.focusedWindow, gBrowser.contentWindow, "content window should be focused");
ok(!gBrowser.contentPrincipal.equals(pagePrincipal),
"load of " + url + " by " + loadFunc.name + " should produce a page with a different principal");
endFunc();
});
});
}
function addPageShowListener(func) {
gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
func();
});
}

View File

@ -20,7 +20,7 @@ function test() {
let pagePrincipal = gBrowser.contentPrincipal;
// copy javascript URI to the clipboard
let url = "javascript:1+1";
let url = "javascript:http://www.example.com/";
waitForClipboard(url,
function() {
Components.classes["@mozilla.org/widget/clipboardhelper;1"]
@ -39,9 +39,7 @@ function test() {
);
addPageShowListener(function () {
is(gBrowser.currentURI.spec, url, "url loaded by middle click");
ok(!gBrowser.contentPrincipal.equals(pagePrincipal),
"middle click load of " + url + " should produce a page with a different principal");
is(gBrowser.currentURI.spec, url.replace(/^javascript:/, ""), "url loaded by middle click doesn't include JS");
finish();
});
});

View File

@ -0,0 +1,49 @@
function test() {
waitForExplicitFinish();
testNext();
}
let pairs = [
["javascript:", ""],
["javascript:1+1", "1+1"],
["javascript:document.domain", "document.domain"],
["data:text/html,<body>hi</body>", "text/html,<body>hi</body>"],
// Nested things get confusing because some things don't parse as URIs:
["javascript:javascript:alert('hi!')", "alert('hi!')"],
["data:data:text/html,<body>hi</body>", "text/html,<body>hi</body>"],
["javascript:data:javascript:alert('hi!')", "data:javascript:alert('hi!')"],
["javascript:data:text/html,javascript:alert('hi!')", "text/html,javascript:alert('hi!')"],
["data:data:text/html,javascript:alert('hi!')", "text/html,javascript:alert('hi!')"],
];
let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
function paste(input, cb) {
waitForClipboard(input, function() {
clipboardHelper.copyString(input);
}, function() {
document.commandDispatcher.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
cb();
}, function() {
ok(false, "Failed to copy string '" + input + "' to clipboard");
cb();
});
}
function testNext() {
gURLBar.value = '';
if (!pairs.length) {
finish();
return;
}
let [inputValue, expectedURL] = pairs.shift();
gURLBar.focus();
paste(inputValue, function() {
is(gURLBar.value, expectedURL, "entering '" + inputValue + "' strips relevant bits.");
setTimeout(testNext, 0);
});
}

View File

@ -62,6 +62,7 @@
this._ignoreNextSelect = false;
this.inputField.controllers.insertControllerAt(0, this._copyCutController);
this.inputField.addEventListener("paste", this, false);
this.inputField.addEventListener("mousedown", this, false);
this.inputField.addEventListener("mousemove", this, false);
this.inputField.addEventListener("mouseout", this, false);
@ -111,6 +112,7 @@
this._prefs.removeObserver("", this);
this._prefs = null;
this.inputField.controllers.removeController(this._copyCutController);
this.inputField.removeEventListener("paste", this, false);
this.inputField.removeEventListener("mousedown", this, false);
this.inputField.removeEventListener("mousemove", this, false);
this.inputField.removeEventListener("mouseout", this, false);
@ -263,7 +265,6 @@
return; // Do nothing for right clicks
var url = this.value;
var mayInheritPrincipal = false;
var postData = null;
var action = this._parseActionUrl(url);
@ -286,7 +287,7 @@
}
else {
this._canonizeURL(aTriggeringEvent, response => {
[url, postData, mayInheritPrincipal] = response;
[url, postData] = response;
if (url) {
matchLastLocationChange = (lastLocationChange ==
gBrowser.selectedBrowser.lastLocationChange);
@ -311,12 +312,6 @@
let webnav = Ci.nsIWebNavigation;
let flags = webnav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
webnav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
// Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
// inheriting the currently loaded document's principal, unless this
// URL is marked as safe to inherit (e.g. came from a bookmark
// keyword).
if (!mayInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
gBrowser.loadURIWithFlags(url, flags, null, null, postData);
}
@ -427,7 +422,7 @@
}
getShortcutOrURIAndPostData(url, data => {
aCallback([data.url, data.postData, data.mayInheritPrincipal]);
aCallback([data.url, data.postData]);
});
]]></body>
</method>
@ -624,6 +619,36 @@
<parameter name="aEvent"/>
<body><![CDATA[
switch (aEvent.type) {
case "paste":
let originalPasteData = aEvent.clipboardData.getData("text/plain");
if (!originalPasteData) {
return;
}
let oldValue = this.inputField.value;
let oldStart = oldValue.substring(0, this.inputField.selectionStart);
// If there is already non-whitespace content in the URL bar
// preceding the pasted content, it's not necessary to check
// protocols used by the pasted content:
if (oldStart.trim()) {
return;
}
let oldEnd = oldValue.substring(this.inputField.selectionEnd);
let pasteData = stripUnsafeProtocolOnPaste(originalPasteData);
if (originalPasteData != pasteData) {
// Unfortunately we're not allowed to set the bits being pasted
// so cancel this event:
aEvent.preventDefault();
aEvent.stopPropagation();
this.inputField.value = oldStart + pasteData + oldEnd;
// Fix up cursor/selection:
let newCursorPos = oldStart.length + pasteData.length;
this.inputField.selectionStart = newCursorPos;
this.inputField.selectionEnd = newCursorPos;
}
break;
case "mousedown":
if (this.doubleClickSelectsAll &&
aEvent.button == 0 && aEvent.detail == 2) {

View File

@ -155,7 +155,8 @@ AutocompletePopup.prototype = {
* Check if the autocomplete popup is open.
*/
get isOpen() {
return this._panel.state == "open" || this._panel.state == "showing";
return this._panel &&
(this._panel.state == "open" || this._panel.state == "showing");
},
/**

View File

@ -257,7 +257,9 @@ Tooltip.prototype = {
},
isShown: function() {
return this.panel.state !== "closed" && this.panel.state !== "hiding";
return this.panel &&
this.panel.state !== "closed" &&
this.panel.state !== "hiding";
},
setSize: function(width, height) {

View File

@ -167,7 +167,7 @@ ElementStyle.prototype = {
dummyElement.parentNode.removeChild(dummyElement);
}
this.dummyElementPromise = null;
});
}, console.error);
},
/**
@ -511,7 +511,7 @@ Rule.prototype = {
this._originalSourceStrings = sourceStrings;
return sourceStrings;
});
}, console.error);
},
/**
@ -1395,6 +1395,7 @@ CssRuleView.prototype = {
},
destroy: function() {
this.isDestroyed = true;
this.clear();
gDummyPromise = null;
@ -1405,9 +1406,9 @@ CssRuleView.prototype = {
this._prefObserver.destroy();
this.element.removeEventListener("copy", this._onCopy);
delete this._onCopy;
this._onCopy = null;
delete this._outputParser;
this._outputParser = null;
// Remove context menu
if (this._contextmenu) {
@ -1858,7 +1859,7 @@ RuleEditor.prototype = {
this.rule.getOriginalSourceStrings().then((strings) => {
sourceLabel.setAttribute("value", strings.short);
sourceLabel.setAttribute("tooltiptext", strings.full);
})
}, console.error);
}
},
@ -2319,6 +2320,10 @@ TextPropertyEditor.prototype = {
* Populate the span based on changes to the TextProperty.
*/
update: function() {
if (this.ruleEditor.ruleView.isDestroyed) {
return;
}
if (this.prop.enabled) {
this.enable.style.removeProperty("visibility");
this.enable.setAttribute("checked", "");

View File

@ -23,18 +23,22 @@ let test = asyncTest(function*() {
});
function createDocument() {
content.document.body.innerHTML = '<div id="test" style="' +
'margin-top:0px;' +
'padding-top: 0px;' +
'color:#000000;' +
'background-color: #000000;" >'+
'</div>';
content.document.body.innerHTML = '' +
'<style>' +
' #test {' +
' margin-top:0px;' +
' padding-top: 0px;' +
' color:#000000;' +
' background-color: #000000;' +
' }' +
'</style>' +
'<div id="test"></div>';
}
function* testMarginIncrements(view) {
info("Testing keyboard increments on the margin property");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
yield runIncrementTest(marginPropEditor, view, {
@ -52,7 +56,7 @@ function* testMarginIncrements(view) {
function* testVariousUnitIncrements(view) {
info("Testing keyboard increments on values with various units");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
yield runIncrementTest(paddingPropEditor, view, {
@ -71,7 +75,7 @@ function* testVariousUnitIncrements(view) {
function* testHexIncrements(view) {
info("Testing keyboard increments with hex colors");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
yield runIncrementTest(hexColorPropEditor, view, {
@ -87,7 +91,7 @@ function* testHexIncrements(view) {
function* testRgbIncrements(view) {
info("Testing keyboard increments with rgb colors");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor;
yield runIncrementTest(rgbColorPropEditor, view, {
@ -103,7 +107,7 @@ function* testRgbIncrements(view) {
function* testShorthandIncrements(view) {
info("Testing keyboard increments within shorthand values");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
yield runIncrementTest(paddingPropEditor, view, {
@ -119,7 +123,7 @@ function* testShorthandIncrements(view) {
function* testOddCases(view) {
info("Testing some more odd cases");
let idRuleEditor = getRuleViewRuleEditor(view, 0);
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
yield runIncrementTest(marginPropEditor, view, {
@ -144,14 +148,11 @@ function* runIncrementTest(propertyEditor, view, tests) {
let editor = yield focusEditableField(propertyEditor.valueSpan);
for(let test in tests) {
yield testIncrement(editor, tests[test], view);
yield testIncrement(editor, tests[test], view, propertyEditor);
}
// Once properties have been set, wait for the inspector to update
yield view.inspector.once("inspector-updated");
}
function* testIncrement(editor, options, view) {
function* testIncrement(editor, options, view, {ruleEditor}) {
editor.input.value = options.start;
let input = editor.input;
@ -163,14 +164,15 @@ function* testIncrement(editor, options, view) {
is(input.value, options.start, "Value initialized at " + options.start);
let onModifications = ruleEditor.rule._applyingModifications;
let onKeyUp = once(input, "keyup");
let key;
key = options.down ? "VK_DOWN" : "VK_UP";
key = options.pageDown ? "VK_PAGE_DOWN" : options.pageUp ? "VK_PAGE_UP" : key;
EventUtils.synthesizeKey(key, {altKey: options.alt, shiftKey: options.shift}, view.doc.defaultView);
EventUtils.synthesizeKey(key, {altKey: options.alt, shiftKey: options.shift},
view.doc.defaultView);
yield onKeyUp;
input = editor.input;
is(input.value, options.end, "Value changed to " + options.end);
yield onModifications;
is(editor.input.value, options.end, "Value changed to " + options.end);
}

View File

@ -147,8 +147,9 @@ body {
margin: 0 5px;
}
.devtools-toolbar {
#root .devtools-toolbar {
width: 100%;
border-bottom-width: 0;
}
.link {

View File

@ -14,8 +14,9 @@
.devtools-sidebar-tabs > tabs {
-moz-appearance: none;
padding: 0;
border-width: 0;
border-bottom-width: 1px;
border-bottom-style: solid;
border-style: solid;
height: 24px;
line-height: 24px;
box-sizing: border-box;
@ -33,6 +34,9 @@
margin: 0;
padding: 0;
}
.devtools-toolbar checkbox .checkbox-label-box {
border: none !important; /* overrides .checkbox-label-box from checkbox.css */
}
.devtools-toolbar checkbox .checkbox-label-box .checkbox-label {
margin: 0 6px !important; /* overrides .checkbox-label from checkbox.css */
padding: 0;

View File

@ -33,9 +33,6 @@ public class BrowserContract {
public static final String READING_LIST_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.readinglist";
public static final Uri READING_LIST_AUTHORITY_URI = Uri.parse("content://" + READING_LIST_AUTHORITY);
public static final String SEARCH_HISTORY_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.searchhistory";
public static final Uri SEARCH_HISTORY_AUTHORITY_URI = Uri.parse("content://" + SEARCH_HISTORY_AUTHORITY);
public static final String PARAM_PROFILE = "profile";
public static final String PARAM_PROFILE_PATH = "profilePath";
public static final String PARAM_LIMIT = "limit";
@ -436,17 +433,6 @@ public class BrowserContract {
public static final String TYPE = "type";
}
@RobocopTarget
public static final class SearchHistory implements CommonColumns, HistoryColumns {
private SearchHistory() {}
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/searchhistory";
public static final String QUERY = "query";
public static final String TABLE_NAME = "searchhistory";
public static final Uri CONTENT_URI = Uri.withAppendedPath(SEARCH_HISTORY_AUTHORITY_URI, "searchhistory");
}
@RobocopTarget
public static final class SuggestedSites implements CommonColumns, URLColumns {
private SuggestedSites() {}

View File

@ -16,7 +16,6 @@ import org.mozilla.gecko.db.BrowserContract.Favicons;
import org.mozilla.gecko.db.BrowserContract.History;
import org.mozilla.gecko.db.BrowserContract.Obsolete;
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.sync.Utils;
@ -35,7 +34,7 @@ import android.util.Log;
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
private static final String LOGTAG = "GeckoBrowserDBHelper";
public static final int DATABASE_VERSION = 19;
public static final int DATABASE_VERSION = 18;
public static final String DATABASE_NAME = "browser.db";
final protected Context mContext;
@ -750,20 +749,6 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
createOrUpdateAllSpecialFolders(db);
createReadingListTable(db);
createSearchHistoryTable(db);
}
private void createSearchHistoryTable(SQLiteDatabase db) {
debug("Creating " + SearchHistory.TABLE_NAME + " table");
db.execSQL("CREATE TABLE " + SearchHistory.TABLE_NAME + "(" +
SearchHistory._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
SearchHistory.QUERY + " TEXT UNIQUE NOT NULL, " +
SearchHistory.DATE_LAST_VISITED + " INTEGER, " +
SearchHistory.VISITS + " INTEGER ) ");
db.execSQL("CREATE INDEX idx_search_history_last_visited ON " +
SearchHistory.TABLE_NAME + "(" + SearchHistory.DATE_LAST_VISITED + ")");
}
private void createReadingListTable(SQLiteDatabase db) {
@ -1393,10 +1378,6 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
}
}
private void upgradeDatabaseFrom18to19(SQLiteDatabase db) {
createSearchHistoryTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
debug("Upgrading browser.db: " + db.getPath() + " from " +
@ -1473,10 +1454,6 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
case 18:
upgradeDatabaseFrom17to18(db);
break;
case 19:
upgradeDatabaseFrom18to19(db);
break;
}
}
@ -1589,4 +1566,4 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
bookmark.remove("folder");
}
}
}
}

View File

@ -1,112 +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/. */
package org.mozilla.gecko.db;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
public class SearchHistoryProvider extends SharedBrowserDatabaseProvider {
/**
* Collapse whitespace.
*/
private String stripWhitespace(String query) {
if (TextUtils.isEmpty(query)) {
return "";
}
// Collapse whitespace
return query.trim().replaceAll("\\s+", " ");
}
@Override
public Uri insertInTransaction(Uri uri, ContentValues cv) {
final String query = stripWhitespace(cv.getAsString(SearchHistory.QUERY));
// We don't support inserting empty search queries.
if (TextUtils.isEmpty(query)) {
return null;
}
final SQLiteDatabase db = getWritableDatabase(uri);
/*
* FIRST: Try incrementing the VISITS counter and updating the DATE_LAST_VISITED.
*/
final String sql = "UPDATE " + SearchHistory.TABLE_NAME + " SET " +
SearchHistory.VISITS + " = " + SearchHistory.VISITS + " + 1, " +
SearchHistory.DATE_LAST_VISITED + " = " + System.currentTimeMillis() +
" WHERE " + SearchHistory.QUERY + " = ?";
final Cursor c = db.rawQuery(sql, new String[] { query });
try {
if (c.getCount() > 1) {
// There is a UNIQUE constraint on the QUERY column,
// so there should only be one match.
return null;
}
if (c.moveToFirst()) {
return ContentUris
.withAppendedId(uri, c.getInt(c.getColumnIndex(SearchHistory._ID)));
}
} finally {
c.close();
}
/*
* SECOND: If the update failed, then insert a new record.
*/
cv.put(SearchHistory.QUERY, query);
cv.put(SearchHistory.VISITS, 1);
cv.put(SearchHistory.DATE_LAST_VISITED, System.currentTimeMillis());
long id = db.insert(SearchHistory.TABLE_NAME, null, cv);
if (id < 0) {
return null;
}
return ContentUris.withAppendedId(uri, id);
}
@Override
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
return getWritableDatabase(uri)
.delete(SearchHistory.TABLE_NAME, selection, selectionArgs);
}
/**
* Since we are managing counts and the full-text db, an update
* could mangle the internal state. So we disable it.
*/
@Override
public int updateInTransaction(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException(
"This content provider does not support updating items");
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
String groupBy = null;
String having = null;
return getReadableDatabase(uri)
.query(SearchHistory.TABLE_NAME, projection, selection, selectionArgs,
groupBy, having, sortOrder);
}
@Override
public String getType(Uri uri) {
return SearchHistory.CONTENT_TYPE;
}
}

View File

@ -150,7 +150,6 @@ gbjar.sources += [
'db/PerProfileDatabaseProvider.java',
'db/PerProfileDatabases.java',
'db/ReadingListProvider.java',
'db/SearchHistoryProvider.java',
'db/SharedBrowserDatabaseProvider.java',
'db/SQLiteBridgeContentProvider.java',
'db/SuggestedSites.java',

View File

@ -59,7 +59,7 @@ skip-if = android_version == "10" || processor == "x86"
# [testMasterPassword] disabled for being finicky, see bug 1033013
# disabled on 2.3; bug 979603
# disabled on 4.0; bug 1006242
skip-if = android_version == "10" || android_version == "15"
# skip-if = android_version == "10" || android_version == "15"
[testNewTab]
# disabled on 2.3; bug 995696
skip-if = android_version == "10"
@ -80,7 +80,6 @@ skip-if = processor == "x86"
skip-if = processor == "x86"
# [testReaderMode] # see bug 913254, 936224
[testReadingListProvider]
[testSearchHistoryProvider]
[testSearchSuggestions]
# disabled on x86; bug 907768
skip-if = processor == "x86"

View File

@ -1,269 +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/. */
package org.mozilla.gecko.tests;
import java.util.concurrent.Callable;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.gecko.db.SearchHistoryProvider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
public class testSearchHistoryProvider extends ContentProviderTest {
// Translations of "United Kingdom" in several different languages
private static final String[] testStrings = {"An Ríocht Aontaithe", // Irish
"Angli", // Albanian
"Britanniarum Regnum", // Latin
"Britio", // Esperanto
"Büyük Britanya", // Turkish
"Egyesült Királyság", // Hungarian
"Erresuma Batua", // Basque
"Inggris Raya", // Indonesian
"Ir-Renju Unit", // Maltese
"Iso-Britannia", // Finnish
"Jungtinė Karalystė", // Lithuanian
"Lielbritānija", // Latvian
"Regatul Unit", // Romanian
"Regne Unit", // Catalan, Valencian
"Regno Unito", // Italian
"Royaume-Uni", // French
"Spojené království", // Czech
"Spojené kráľovstvo", // Slovak
"Storbritannia", // Norwegian
"Storbritannien", // Danish
"Suurbritannia", // Estonian
"Ujedinjeno Kraljevstvo", // Bosnian
"United Alaeze", // Igbo
"United Kingdom", // English
"Vereinigtes Königreich", // German
"Verenigd Koninkrijk", // Dutch
"Verenigde Koninkryk", // Afrikaans
"Vương quốc Anh", // Vietnamese
"Wayòm Ini", // Haitian, Haitian Creole
"Y Deyrnas Unedig", // Welsh
"Združeno kraljestvo", // Slovene
"Zjednoczone Królestwo", // Polish
"Ηνωμένο Βασίλειο", // Greek (modern)
"Великобритания", // Russian
"Нэгдсэн Вант Улс", // Mongolian
"Обединетото Кралство", // Macedonian
"Уједињено Краљевство", // Serbian
"Միացյալ Թագավորություն", // Armenian
"בריטניה", // Hebrew (modern)
"פֿאַראייניקטע מלכות", // Yiddish
"المملكة المتحدة", // Arabic
"برطانیہ", // Urdu
"پادشاهی متحده", // Persian (Farsi)
"यूनाइटेड किंगडम", // Hindi
"संयुक्त राज्य", // Nepali
"যুক্তরাজ্য", // Bengali, Bangla
"યુનાઇટેડ કિંગડમ", // Gujarati
"ஐக்கிய ராஜ்யம்", // Tamil
"สหราชอาณาจักร", // Thai
"ສະ​ຫະ​ປະ​ຊາ​ຊະ​ອາ​ນາ​ຈັກ", // Lao
"გაერთიანებული სამეფო", // Georgian
"イギリス", // Japanese
"联合王国" // Chinese
};
private static final String DB_NAME = "searchhistory.db";
/**
* Boilerplate alert.
* <p/>
* Make sure this method is present and that it returns a new
* instance of your class.
*/
private static Callable<ContentProvider> sProviderFactory =
new Callable<ContentProvider>() {
@Override
public ContentProvider call() {
return new SearchHistoryProvider();
}
};
@Override
public void setUp() throws Exception {
super.setUp(sProviderFactory, BrowserContract.SEARCH_HISTORY_AUTHORITY, DB_NAME);
mTests.add(new TestInsert());
mTests.add(new TestUnicodeQuery());
mTests.add(new TestTimestamp());
mTests.add(new TestDelete());
mTests.add(new TestIncrement());
}
public void testSearchHistory() throws Exception {
for (Runnable test : mTests) {
String testName = test.getClass().getSimpleName();
setTestName(testName);
mAsserter.dumpLog(
"testBrowserProvider: Database empty - Starting " + testName + ".");
// Clear the db
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
test.run();
}
}
/**
* Verify that we can insert values into the DB, including unicode.
*/
private class TestInsert extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv;
for (int i = 0; i < testStrings.length; i++) {
cv = new ContentValues();
cv.put(SearchHistory.QUERY, testStrings[i]);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
}
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), testStrings.length,
"Should have one row for each insert");
c.close();
}
}
/**
* Verify that we can insert values into the DB, including unicode.
*/
private class TestUnicodeQuery extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv;
Cursor c = null;
String selection = SearchHistory.QUERY + " = ?";
for (int i = 0; i < testStrings.length; i++) {
cv = new ContentValues();
cv.put(SearchHistory.QUERY, testStrings[i]);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, selection,
new String[]{ testStrings[i] }, null);
mAsserter.is(c.getCount(), 1,
"Should have one row for insert of " + testStrings[i]);
}
if (c != null) {
c.close();
}
}
}
/**
* Verify that timestamps are updated on insert.
*/
private class TestTimestamp extends TestCase {
@Override
public void test() throws Exception {
String insertedTerm = "Courtside Seats";
long insertStart;
long insertFinish;
long t1Db;
long t2Db;
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
// First check that the DB has a value that is close to the
// system time.
insertStart = System.currentTimeMillis();
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
t1Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
c.close();
insertFinish = System.currentTimeMillis();
mAsserter.ok(t1Db >= insertStart, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t1Db <= insertFinish, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
insertStart = System.currentTimeMillis();
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
t2Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
c.close();
insertFinish = System.currentTimeMillis();
mAsserter.ok(t2Db >= insertStart, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t2Db <= insertFinish, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t2Db > t1Db, "DATE_LAST_VISITED",
"Date last visited should be updated on key increment.");
}
}
/**
* Verify that sending a delete command empties the database.
*/
private class TestDelete extends TestCase {
@Override
public void test() throws Exception {
String insertedTerm = "Courtside Seats";
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 1, "Should have one value");
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
c.close();
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 0, "Should be empty");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c.close();
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 1, "Should have one value");
c.close();
}
}
/**
* Ensure that we only increment when the case matches.
*/
private class TestIncrement extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, "omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
cv = new ContentValues();
cv.put(SearchHistory.QUERY, "omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
mAsserter.is(c.getCount(), 1, "Should have one result");
mAsserter.is(c.getInt(c.getColumnIndex(SearchHistory.VISITS)), 2,
"Counter should be 2");
c.close();
cv = new ContentValues();
cv.put(SearchHistory.QUERY, "Omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 2, "Should have two results");
c.close();
}
}
}

View File

@ -2776,6 +2776,10 @@ function nodeDocument(node) {
* See TreeWalker documentation for explanations of the methods.
*/
function DocumentWalker(aNode, aRootWin, aShow, aFilter, aExpandEntityReferences) {
if (!aRootWin.location) {
throw new Error("Got an invalid root window in DocumentWalker");
}
let doc = nodeDocument(aNode);
this.layoutHelpers = new LayoutHelpers(aRootWin);
this.walker = doc.createTreeWalker(doc,

View File

@ -61,6 +61,7 @@ let initTable = [
["io", "@mozilla.org/network/io-service;1", "nsIIOService2"],
["locale", "@mozilla.org/intl/nslocaleservice;1", "nsILocaleService"],
["logins", "@mozilla.org/login-manager;1", "nsILoginManager"],
["netutil", "@mozilla.org/network/util;1", "nsINetUtil"],
["obs", "@mozilla.org/observer-service;1", "nsIObserverService"],
["perms", "@mozilla.org/permissionmanager;1", "nsIPermissionManager"],
["prompt", "@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService"],