Merge backout on this CLOSED TREE

This commit is contained in:
Kyle Huey 2011-06-08 06:24:18 -07:00
Родитель 649ff29eed a61a52bebc
Коммит bf80cb3244
43 изменённых файлов: 1265 добавлений и 940 удалений

Просмотреть файл

@ -864,6 +864,9 @@ pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
// base URL for web-based support pages
pref("app.support.baseURL", "http://support.mozilla.com/1/firefox/%VERSION%/%OS%/%LOCALE%/");
// URL for web-based support page on how to upgrade a graphics driver
pref("app.support.updateGraphicsDriverURL", "http://support.mozilla.com/%LOCALE%/kb/how-do-i-upgrade-my-graphics-drivers");
// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
pref("security.alternate_certificate_error_page", "certerror");

Просмотреть файл

@ -1288,7 +1288,9 @@
<xul:hbox align="center" flex="1">
<xul:image class="panel-promo-icon"/>
<xul:description anonid="promo-message" class="panel-promo-message" flex="1">
placeholder <xul:description anonid="promo-link" class="plain text-link inline-link"/>
placeholder <xul:description anonid="promo-link"
class="plain text-link inline-link"
onclick="document.getBindingParent(this).onLinkClick();"/>
</xul:description>
</xul:hbox>
<xul:toolbarbutton class="panel-promo-closebutton"
@ -1361,6 +1363,14 @@
this.hidden = true;
]]></body>
</method>
<method name="onLinkClick">
<body><![CDATA[
// Open a new selected tab and close the current panel.
gBrowser.loadOneTab(this._promolink.getAttribute("href"),
{ inBackground: false });
this._panel.hidePopup();
]]></body>
</method>
<method name="handleEvent">
<parameter name="event"/>
<body><![CDATA[

Просмотреть файл

@ -58,36 +58,28 @@ function windowObserver(aSubject, aTopic, aData) {
return;
ww.unregisterNotification(windowObserver);
let organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
organizer.addEventListener("load", function onLoad(event) {
organizer.removeEventListener("load", onLoad, false);
executeSoon(function () {
let contentTree = organizer.document.getElementById("placeContent");
isnot(contentTree, null, "Sanity check: placeContent tree should exist");
isnot(organizer.PlacesOrganizer, null, "Sanity check: PlacesOrganizer should exist");
isnot(organizer.gEditItemOverlay, null, "Sanity check: gEditItemOverlay should exist");
waitForFocus(function () {
let contentTree = organizer.document.getElementById("placeContent");
isnot(contentTree, null, "Sanity check: placeContent tree should exist");
isnot(organizer.PlacesOrganizer, null, "Sanity check: PlacesOrganizer should exist");
isnot(organizer.gEditItemOverlay, null, "Sanity check: gEditItemOverlay should exist");
if (!organizer.gEditItemOverlay._initialized){
// The overlay is initialized on focus, we wait for it to be fully operational.
setTimeout(arguments.callee, 10);
return;
}
ok(organizer.gEditItemOverlay._initialized, "gEditItemOverlay is initialized");
isnot(organizer.gEditItemOverlay.itemId, -1, "Editing a bookmark");
isnot(organizer.gEditItemOverlay.itemId, -1, "Editing a bookmark");
// Select History in the left pane.
organizer.PlacesOrganizer.selectLeftPaneQuery('History');
// Select the first history entry.
let selection = contentTree.view.selection;
selection.clearSelection();
selection.rangedSelect(0, 0, true);
// Check the panel is editing the history entry.
is(organizer.gEditItemOverlay.itemId, -1, "Editing an history entry");
// Close Library window.
organizer.close();
// Clean up history.
PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
finish();
});
}, false);
// Select History in the left pane.
organizer.PlacesOrganizer.selectLeftPaneQuery('History');
// Select the first history entry.
let selection = contentTree.view.selection;
selection.clearSelection();
selection.rangedSelect(0, 0, true);
// Check the panel is editing the history entry.
is(organizer.gEditItemOverlay.itemId, -1, "Editing an history entry");
// Close Library window.
organizer.close();
// Clean up history.
waitForClearHistory(finish);
}, organizer);
}
function test() {
@ -105,3 +97,14 @@ function test() {
"chrome,toolbar=yes,dialog=no,resizable",
null);
}
function waitForClearHistory(aCallback) {
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
aCallback(aSubject, aTopic, aData);
}
};
Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
PlacesUtils.bhistory.removeAllPages();
}

Просмотреть файл

@ -63,4 +63,5 @@ externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.

Просмотреть файл

@ -171,6 +171,10 @@ be temporary, and you can try again later.</li>
<!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
<!ENTITY cspFrameAncestorBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
<!ENTITY corruptedContentError.title "Corrupted Content Error">
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
<!ENTITY securityOverride.linkText "Or you can add an exception…">
<!ENTITY securityOverride.getMeOutOfHereButton "Get me out of here!">
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">

Просмотреть файл

@ -3052,19 +3052,13 @@ nsHTMLInputElement::SaveState()
case NS_FORM_INPUT_CHECKBOX:
case NS_FORM_INPUT_RADIO:
{
PRBool checked = GetChecked();
PRBool defaultChecked = PR_FALSE;
GetDefaultChecked(&defaultChecked);
// Only save if checked != defaultChecked (bug 62713)
// (always save if it's a radio button so that the checked
// state of all radio buttons is restored)
if (mType == NS_FORM_INPUT_RADIO || checked != defaultChecked) {
if (GetCheckedChanged()) {
inputState = new nsHTMLInputElementState();
if (!inputState) {
return NS_ERROR_OUT_OF_MEMORY;
}
inputState->SetChecked(checked);
inputState->SetChecked(GetChecked());
}
break;
}

Просмотреть файл

@ -51,6 +51,9 @@ ifdef ENABLE_TESTS
# We can't have index.html in this directory because it would prevent
# running the tests here.
DIRS += bug649134
# For form-related test suite.
DIRS += forms
endif
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mounir Lamouri <mounir.lamouri@mozilla.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = content/html/content/test/forms
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
save_restore_radio_groups.sjs \
test_save_restore_radio_groups.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,44 @@
var pages = [
"<!DOCTYPE html>" +
"<html><body>" +
"<form>" +
"<input name='a' type='radio' checked><input name='a' type='radio'><input name='a' type='radio'>" +
"</form>" +
"</body></html>",
"<!DOCTYPE html>" +
"<html><body>" +
"<form>" +
"<input name='a' type='radio'><input name='a' type='radio' checked><input name='a' type='radio'>" +
"</form>" +
"</body></html>",
];
/**
* This SJS is going to send the same page the two first times it will be called
* and another page the two following times. After that, the response will have
* no content.
* The use case is to have two iframes using this SJS and both being reloaded
* once.
*/
function handleRequest(request, response)
{
var counter = +getState("counter"); // convert to number; +"" === 0
response.setStatusLine(request.httpVersion, 200, "Ok");
response.setHeader("Content-Type", "text/html");
response.setHeader("Cache-Control", "no-cache");
switch (counter) {
case 0:
case 1:
response.write(pages[0]);
break;
case 2:
case 3:
response.write(pages[1]);
break;
}
setState("counter", "" + ++counter);
}

Просмотреть файл

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=350022
-->
<head>
<title>Test for Bug 350022</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<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=350022">Mozilla Bug 350022</a>
<p id="display"></p>
<div id="content"><!-- style="display: none">-->
<iframe src="save_restore_radio_groups.sjs"></iframe>
<iframe src="save_restore_radio_groups.sjs"></iframe>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 350022 **/
function checkRadioGroup(aFrame, aResults)
{
var radios = frames[aFrame].document.getElementsByTagName('input');
is(radios.length, aResults.length,
"Radio group should have " + aResults.length + "elements");
for (var i=0; i<aResults.length; ++i) {
is(radios[i].checked, aResults[i],
"Radio checked state should be " + aResults[i]);
}
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
/**
* We have two iframes each containing one radio button group.
* We are going to change the selected radio button in one group.
* Then, both iframes will be reloaded and the new groups will have another
* radio checked by default.
* For the first group (which had a selection change), nothing should change.
* For the second, the selected radio button should change.
*/
checkRadioGroup(0, [true, false, false]);
checkRadioGroup(1, [true, false, false]);
frames[0].document.getElementsByTagName('input')[2].checked = true;
checkRadioGroup(0, [false, false, true]);
framesElts = document.getElementsByTagName('iframe');
framesElts[0].addEventListener("load", function() {
framesElts[0].removeEventListener("load", arguments.callee, false);
checkRadioGroup(0, [false, false, true]);
framesElts[1].addEventListener("load", function() {
framesElts[1].removeEventListener("load", arguments.callee, false);
checkRadioGroup(1, [false, true, false]);
SimpleTest.finish();
}, false);
frames[1].location.reload();
}, false);
frames[0].location.reload();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -3945,6 +3945,10 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
// Channel refused to load from an unrecognized content type.
error.AssignLiteral("unsafeContentType");
break;
case NS_ERROR_CORRUPTED_CONTENT:
// Broken Content Detected. e.g. Content-MD5 check failure.
error.AssignLiteral("corruptedContentError");
break;
}
}
@ -6124,6 +6128,7 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
//
if (url && NS_FAILED(aStatus)) {
if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
aStatus == NS_ERROR_CORRUPTED_CONTENT ||
aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
DisplayLoadError(aStatus, url, nsnull, aChannel);
return NS_OK;

Просмотреть файл

@ -329,6 +329,7 @@
<h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
<h1 id="et_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.title;</h1>
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
</div>
<div id="errorDescriptionsContainer">
<div id="ed_generic">&generic.longDesc;</div>
@ -353,6 +354,7 @@
<div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
<div id="ed_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
</div>
</div>

Просмотреть файл

@ -62,4 +62,5 @@ externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
remoteXUL=This page uses an unsupported technology that is no longer available by default.

Просмотреть файл

@ -84,6 +84,9 @@
<!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
<!ENTITY cspFrameAncestorBlocked.longDesc "<p>The browser prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
<!ENTITY corruptedContentError.title "Corrupted Content Error">
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
<!ENTITY remoteXUL.title "Remote XUL">
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">

Просмотреть файл

@ -296,6 +296,7 @@ VPATH += \
EXPORTS_NAMESPACES += mozilla
EXPORTS_mozilla = \
RangedPtr.h \
Types.h \
Util.h \
$(NULL)

Просмотреть файл

@ -81,14 +81,14 @@ JSONParser::readString()
* Optimization: if the source contains no escaped characters, create the
* string directly from the source text.
*/
RangeCheckedPointer<const jschar> start = current;
RangedPtr<const jschar> start = current;
for (; current < end; current++) {
if (*current == '"') {
size_t length = current - start;
current++;
JSFlatString *str = (ST == JSONParser::PropertyName)
? js_AtomizeChars(cx, start, length)
: js_NewStringCopyN(cx, start, length);
? js_AtomizeChars(cx, start.get(), length)
: js_NewStringCopyN(cx, start.get(), length);
if (!str)
return token(OOM);
return stringToken(str);
@ -110,7 +110,7 @@ JSONParser::readString()
*/
StringBuffer buffer(cx);
do {
if (start < current && !buffer.append(start, current))
if (start < current && !buffer.append(start.get(), current.get()))
return token(OOM);
if (current >= end)
@ -200,7 +200,7 @@ JSONParser::readNumber()
return token(Error);
}
const RangeCheckedPointer<const jschar> digitStart = current;
const RangedPtr<const jschar> digitStart = current;
/* 0|[1-9][0-9]+ */
if (!JS7_ISDEC(*current)) {
@ -218,7 +218,7 @@ JSONParser::readNumber()
if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
const jschar *dummy;
jsdouble d;
if (!GetPrefixInteger(cx, digitStart, current, 10, &dummy, &d))
if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
return token(OOM);
JS_ASSERT(current == dummy);
return numberToken(negative ? -d : d);
@ -264,7 +264,7 @@ JSONParser::readNumber()
jsdouble d;
const jschar *finish;
if (!js_strtod(cx, digitStart, current, &finish, &d))
if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d))
return token(OOM);
JS_ASSERT(current == finish);
return numberToken(negative ? -d : d);
@ -382,7 +382,7 @@ JSONParser::advanceAfterObjectOpen()
}
static inline void
AssertPastValue(const RangeCheckedPointer<const jschar> current)
AssertPastValue(const RangedPtr<const jschar> current)
{
/*
* We're past an arbitrary JSON value, so the previous character is

Просмотреть файл

@ -41,9 +41,10 @@
#ifndef jsonparser_h___
#define jsonparser_h___
#include "mozilla/RangedPtr.h"
#include "jscntxt.h"
#include "jsstr.h"
#include "jstl.h"
#include "jsvalue.h"
/*
@ -59,8 +60,8 @@ class JSONParser
/* Data members */
JSContext * const cx;
js::RangeCheckedPointer<const jschar> current;
const js::RangeCheckedPointer<const jschar> end;
mozilla::RangedPtr<const jschar> current;
const mozilla::RangedPtr<const jschar> end;
js::Value v;
@ -89,7 +90,7 @@ class JSONParser
ParsingMode parsingMode = StrictJSON,
ErrorHandling errorHandling = RaiseError)
: cx(cx),
current(data, data, length),
current(data, length),
end(data + length, data, length),
parsingMode(parsingMode),
errorHandling(errorHandling)

Просмотреть файл

@ -221,19 +221,6 @@ RoundUpPow2(size_t x)
return result;
}
/*
* Safely subtract two pointers when it is known that end > begin. This avoids
* the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
* set, the unsigned subtraction followed by right shift will produce -1, or
* size_t(-1), instead of the real difference.
*/
template <class T>
JS_ALWAYS_INLINE size_t
PointerRangeSize(T *begin, T *end)
{
return (size_t(end) - size_t(begin)) / sizeof(T);
}
template <class T>
class AlignedPtrAndFlag
{
@ -334,167 +321,6 @@ InitConst(const T &t)
return const_cast<T &>(t);
}
/* Smart pointer, restricted to a range defined at construction. */
template <class T>
class RangeCheckedPointer
{
T *ptr;
#ifdef DEBUG
T * const rangeStart;
T * const rangeEnd;
#endif
void sanityChecks() {
JS_ASSERT(rangeStart <= ptr);
JS_ASSERT(ptr <= rangeEnd);
}
/* Creates a new pointer for |ptr|, restricted to this pointer's range. */
RangeCheckedPointer<T> create(T *ptr) const {
#ifdef DEBUG
return RangeCheckedPointer<T>(ptr, rangeStart, rangeEnd);
#else
return RangeCheckedPointer<T>(ptr, NULL, size_t(0));
#endif
}
public:
RangeCheckedPointer(T *p, T *start, T *end)
: ptr(p)
#ifdef DEBUG
, rangeStart(start), rangeEnd(end)
#endif
{
JS_ASSERT(rangeStart <= rangeEnd);
sanityChecks();
}
RangeCheckedPointer(T *p, T *start, size_t length)
: ptr(p)
#ifdef DEBUG
, rangeStart(start), rangeEnd(start + length)
#endif
{
JS_ASSERT(length <= size_t(-1) / sizeof(T));
JS_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
sanityChecks();
}
RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<T> &other) {
JS_ASSERT(rangeStart == other.rangeStart);
JS_ASSERT(rangeEnd == other.rangeEnd);
ptr = other.ptr;
sanityChecks();
return *this;
}
RangeCheckedPointer<T> operator+(size_t inc) {
JS_ASSERT(inc <= size_t(-1) / sizeof(T));
JS_ASSERT(ptr + inc > ptr);
return create(ptr + inc);
}
RangeCheckedPointer<T> operator-(size_t dec) {
JS_ASSERT(dec <= size_t(-1) / sizeof(T));
JS_ASSERT(ptr - dec < ptr);
return create(ptr - dec);
}
template <class U>
RangeCheckedPointer<T> &operator=(U *p) {
*this = create(p);
return *this;
}
template <class U>
RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<U> &p) {
JS_ASSERT(rangeStart <= p.ptr);
JS_ASSERT(p.ptr <= rangeEnd);
ptr = p.ptr;
sanityChecks();
return *this;
}
RangeCheckedPointer<T> &operator++() {
return (*this += 1);
}
RangeCheckedPointer<T> operator++(int) {
RangeCheckedPointer<T> rcp = *this;
++*this;
return rcp;
}
RangeCheckedPointer<T> &operator--() {
return (*this -= 1);
}
RangeCheckedPointer<T> operator--(int) {
RangeCheckedPointer<T> rcp = *this;
--*this;
return rcp;
}
RangeCheckedPointer<T> &operator+=(size_t inc) {
this->operator=<T>(*this + inc);
return *this;
}
RangeCheckedPointer<T> &operator-=(size_t dec) {
this->operator=<T>(*this - dec);
return *this;
}
T &operator[](int index) const {
JS_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
return *create(ptr + index);
}
T &operator*() const {
return *ptr;
}
operator T*() const {
return ptr;
}
template <class U>
bool operator==(const RangeCheckedPointer<U> &other) const {
return ptr == other.ptr;
}
template <class U>
bool operator!=(const RangeCheckedPointer<U> &other) const {
return !(*this == other);
}
template <class U>
bool operator<(const RangeCheckedPointer<U> &other) const {
return ptr < other.ptr;
}
template <class U>
bool operator<=(const RangeCheckedPointer<U> &other) const {
return ptr <= other.ptr;
}
template <class U>
bool operator>(const RangeCheckedPointer<U> &other) const {
return ptr > other.ptr;
}
template <class U>
bool operator>=(const RangeCheckedPointer<U> &other) const {
return ptr >= other.ptr;
}
size_t operator-(const RangeCheckedPointer<T> &other) const {
JS_ASSERT(ptr >= other.ptr);
return PointerRangeSize(other.ptr, ptr);
}
private:
RangeCheckedPointer();
T *operator&();
};
template <class T, class U>
JS_ALWAYS_INLINE T &
ImplicitCast(U &u)

280
mfbt/RangedPtr.h Normal file
Просмотреть файл

@ -0,0 +1,280 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jeff Walden <jwalden+code@mit.edu> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_RangedPtr_h_
#define mozilla_RangedPtr_h_
#include "mozilla/Util.h"
#ifdef __cplusplus
namespace mozilla {
/*
* RangedPtr is a smart pointer restricted to an address range specified at
* creation. The pointer (and any smart pointers derived from it) must remain
* within the range [start, end] (inclusive of end to facilitate use as
* sentinels). Dereferencing or indexing into the pointer (or pointers derived
* from it) must remain within the range [start, end). All the standard pointer
* operators are defined on it; in debug builds these operations assert that the
* range specified at construction is respected.
*
* In theory passing a smart pointer instance as an argument can be slightly
* slower than passing a T* (due to ABI requirements for passing structs versus
* passing pointers), if the method being called isn't inlined. If you are in
* extremely performance-critical code, you may want to be careful using this
* smart pointer as an argument type.
*
* RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
* explicitly convert to T*. Keep in mind that the raw pointer of course won't
* implement bounds checking in debug builds.
*/
template <typename T>
class RangedPtr
{
T* ptr;
#ifdef DEBUG
T* const rangeStart;
T* const rangeEnd;
#endif
void checkSanity() {
MOZ_ASSERT(rangeStart <= ptr);
MOZ_ASSERT(ptr <= rangeEnd);
}
/* Creates a new pointer for |ptr|, restricted to this pointer's range. */
RangedPtr<T> create(T *ptr) const {
#ifdef DEBUG
return RangedPtr<T>(ptr, rangeStart, rangeEnd);
#else
return RangedPtr<T>(ptr, NULL, size_t(0));
#endif
}
public:
RangedPtr(T* p, T* start, T* end)
: ptr(p)
#ifdef DEBUG
, rangeStart(start), rangeEnd(end)
#endif
{
MOZ_ASSERT(rangeStart <= rangeEnd);
checkSanity();
}
RangedPtr(T* p, T* start, size_t length)
: ptr(p)
#ifdef DEBUG
, rangeStart(start), rangeEnd(start + length)
#endif
{
MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
checkSanity();
}
/* Equivalent to RangedPtr(p, p, length). */
RangedPtr(T* p, size_t length)
: ptr(p)
#ifdef DEBUG
, rangeStart(p), rangeEnd(p + length)
#endif
{
MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
checkSanity();
}
/* Equivalent to RangedPtr(arr, arr, N). */
template<size_t N>
RangedPtr(T arr[N])
: ptr(arr)
#ifdef DEBUG
, rangeStart(arr), rangeEnd(arr + N)
#endif
{
checkSanity();
}
T* get() const {
return ptr;
}
/*
* You can only assign one RangedPtr into another if the two pointers have
* the same valid range:
*
* char arr1[] = "hi";
* char arr2[] = "bye";
* RangedPtr<char> p1(arr1, 2);
* p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
* p1 = RangedPtr<char>(arr2, 3); // asserts
*/
RangedPtr<T>& operator=(const RangedPtr<T>& other) {
MOZ_ASSERT(rangeStart == other.rangeStart);
MOZ_ASSERT(rangeEnd == other.rangeEnd);
ptr = other.ptr;
checkSanity();
return *this;
}
RangedPtr<T> operator+(size_t inc) {
MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
MOZ_ASSERT(ptr + inc > ptr);
return create(ptr + inc);
}
RangedPtr<T> operator-(size_t dec) {
MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
MOZ_ASSERT(ptr - dec < ptr);
return create(ptr - dec);
}
/*
* You can assign a raw pointer into a RangedPtr if the raw pointer is
* within the range specified at creation.
*/
template <typename U>
RangedPtr<T>& operator=(U* p) {
*this = create(p);
return *this;
}
template <typename U>
RangedPtr<T>& operator=(const RangedPtr<U>& p) {
MOZ_ASSERT(rangeStart <= p.ptr);
MOZ_ASSERT(p.ptr <= rangeEnd);
ptr = p.ptr;
checkSanity();
return *this;
}
RangedPtr<T>& operator++() {
return (*this += 1);
}
RangedPtr<T> operator++(int) {
RangedPtr<T> rcp = *this;
++*this;
return rcp;
}
RangedPtr<T>& operator--() {
return (*this -= 1);
}
RangedPtr<T> operator--(int) {
RangedPtr<T> rcp = *this;
--*this;
return rcp;
}
RangedPtr<T>& operator+=(size_t inc) {
this->operator=<T>(*this + inc);
return *this;
}
RangedPtr<T>& operator-=(size_t dec) {
this->operator=<T>(*this - dec);
return *this;
}
T& operator[](int index) const {
MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
return *create(ptr + index);
}
T& operator*() const {
return *ptr;
}
template <typename U>
bool operator==(const RangedPtr<U>& other) const {
return ptr == other.ptr;
}
template <typename U>
bool operator!=(const RangedPtr<U>& other) const {
return !(*this == other);
}
template<typename U>
bool operator==(const U* u) const {
return ptr == u;
}
template<typename U>
bool operator!=(const U* u) const {
return !(*this == u);
}
template <typename U>
bool operator<(const RangedPtr<U>& other) const {
return ptr < other.ptr;
}
template <typename U>
bool operator<=(const RangedPtr<U>& other) const {
return ptr <= other.ptr;
}
template <typename U>
bool operator>(const RangedPtr<U>& other) const {
return ptr > other.ptr;
}
template <typename U>
bool operator>=(const RangedPtr<U>& other) const {
return ptr >= other.ptr;
}
size_t operator-(const RangedPtr<T>& other) const {
MOZ_ASSERT(ptr >= other.ptr);
return PointerRangeSize(other.ptr, ptr);
}
private:
RangedPtr();
T* operator&();
operator T*() const;
};
} /* namespace mozilla */
#endif /* __cplusplus */
#endif /* mozilla_RangedPtr_h_ */

Просмотреть файл

@ -18,7 +18,7 @@
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyrigght (C) 2011
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):

Просмотреть файл

@ -18,7 +18,7 @@
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyrigght (C) 2011
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -79,6 +79,59 @@ MOZ_END_EXTERN_C
#endif /* DEBUG */
/*
* MOZ_INLINE is a macro which expands to tell the compiler that the method
* decorated with it should be inlined. This macro is usable from C and C++
* code, even though C89 does not support the |inline| keyword. The compiler
* may ignore this directive if it chooses.
*/
#ifndef MOZ_INLINE
# if defined __cplusplus
# define MOZ_INLINE inline
# elif defined _MSC_VER
# define MOZ_INLINE __inline
# elif defined __GNUC__
# define MOZ_INLINE __inline__
# else
# define MOZ_INLINE inline
# endif
#endif
/*
* MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must be inlined, even if the compiler thinks
* otherwise. This is only a (much) stronger version of the MOZ_INLINE hint:
* compilers are not guaranteed to respect it (although they're much more likely
* to do so).
*/
#ifndef MOZ_ALWAYS_INLINE
# if defined DEBUG
# define MOZ_ALWAYS_INLINE MOZ_INLINE
# elif defined _MSC_VER
# define MOZ_ALWAYS_INLINE __forceinline
# elif defined __GNUC__
# define MOZ_ALWAYS_INLINE __attribute__((always_inline)) MOZ_INLINE
# else
# define MOZ_ALWAYS_INLINE MOZ_INLINE
# endif
#endif
/*
* MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must never be inlined, even if the compiler would
* otherwise choose to inline the method. Compilers aren't absolutely
* guaranteed to support this, but most do.
*/
#ifndef MOZ_NEVER_INLINE
# if defined _MSC_VER
# define MOZ_NEVER_INLINE __declspec(noinline)
# elif defined __GNUC__
# define MOZ_NEVER_INLINE __attribute__((noinline))
# else
# define MOZ_NEVER_INLINE
# endif
#endif
#ifdef __cplusplus
namespace mozilla {
@ -250,6 +303,20 @@ class Maybe
}
};
/*
* Safely subtract two pointers when it is known that end >= begin. This avoids
* the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
* set, the unsigned subtraction followed by right shift will produce -1, or
* size_t(-1), instead of the real difference.
*/
template <class T>
MOZ_ALWAYS_INLINE size_t
PointerRangeSize(T* begin, T* end)
{
MOZ_ASSERT(end >= begin);
return (size_t(end) - size_t(begin)) / sizeof(T);
}
} /* namespace mozilla */
#endif /* __cplusplus */

Просмотреть файл

@ -215,6 +215,9 @@ pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LO
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
/* preference for the locale picker */
pref("extensions.getLocales.get.url", "");
/* blocklist preferences */
pref("extensions.blocklist.enabled", true);
pref("extensions.blocklist.interval", 86400);
@ -643,6 +646,9 @@ pref("urlclassifier.updatecachemax", 4194304);
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
#endif
// prevent focus to show/hide the virtual keyboard if the action is not
// True if this is the first time we are showing about:firstrun
pref("browser.firstrun.show.uidiscovery", true);
pref("browser.firstrun.show.localepicker", false);
// initiated by a user
pref("content.ime.strict_policy", true);

Просмотреть файл

@ -1156,6 +1156,20 @@ var ConsoleAPIObserver = {
let consoleMsg = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError);
consoleMsg.init(joinedArguments, null, null, 0, 0, flag, "content javascript");
Services.console.logMessage(consoleMsg);
} else if (aMessage.level == "trace") {
let bundle = Services.strings.createBundle("chrome://global/locale/headsUpDisplay.properties");
let args = aMessage.arguments;
let filename = this.abbreviateSourceURL(args[0].filename);
let functionName = args[0].functionName || bundle.GetStringFromName("stacktrace.anonymousFunction");
let lineNumber = args[0].lineNumber;
let body = bundle.formatStringFromName("stacktrace.outputMessage", [filename, functionName, lineNumber], 3);
body += "\n";
args.forEach(function(aFrame) {
body += aFrame.filename + " :: " + aFrame.functionName + " :: " + aFrame.lineNumber + "\n";
});
Services.console.logStringMessage(body);
} else {
Services.console.logStringMessage(joinedArguments);
}
@ -1197,6 +1211,24 @@ var ConsoleAPIObserver = {
}
return output;
},
abbreviateSourceURL: function abbreviateSourceURL(aSourceURL) {
// Remove any query parameters.
let hookIndex = aSourceURL.indexOf("?");
if (hookIndex > -1)
aSourceURL = aSourceURL.substring(0, hookIndex);
// Remove a trailing "/".
if (aSourceURL[aSourceURL.length - 1] == "/")
aSourceURL = aSourceURL.substring(0, aSourceURL.length - 1);
// Remove all but the last path component.
let slashIndex = aSourceURL.lastIndexOf("/");
if (slashIndex > -1)
aSourceURL = aSourceURL.substring(slashIndex + 1);
return aSourceURL;
}
};

Просмотреть файл

@ -63,4 +63,5 @@ externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.

Просмотреть файл

@ -166,6 +166,9 @@ be temporary, and you can try again later.</li>
<!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
<!ENTITY cspFrameAncestorBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
<!ENTITY corruptedContentError.title "Corrupted Content Error">
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
<!ENTITY securityOverride.linkText "Or you can add an exception…">
<!ENTITY securityOverride.getMeOutOfHereButton "Get me out of here!">
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">

Просмотреть файл

@ -745,3 +745,9 @@ dialog {
padding: @padding_xlarge@ 0px;
}
}
/* because the buttons can wrap, we need to use the margin to create inter-button
spacing and a bottom margin for the notification */
notification > button {
margin-bottom: @margin_normal@;
}

Просмотреть файл

@ -28,5 +28,6 @@ notification .outset {
}
notification .buttons {
padding: @padding_normal@;
display: block; /* allow the buttons to wrap */
padding: @padding_normal@ @padding_normal@ 0 @padding_normal@;
}

Просмотреть файл

@ -755,3 +755,9 @@ dialog {
padding: @padding_xlarge@ 0px;
}
}
/* because the buttons can wrap, we need to use the margin to create inter-button
spacing and a bottom margin for the notification */
notification > button {
margin-bottom: @margin_normal@;
}

Просмотреть файл

@ -37,6 +37,9 @@
* ***** END LICENSE BLOCK ***** */
#include <string.h>
#include "mozilla/RangedPtr.h"
#include "nsURLParsers.h"
#include "nsURLHelper.h"
#include "nsIURI.h"
@ -45,13 +48,16 @@
#include "nsCRT.h"
#include "netCore.h"
using namespace mozilla;
//----------------------------------------------------------------------------
static PRUint32
CountConsecutiveSlashes(const char *str, PRInt32 len)
{
RangedPtr<const char> p(str, len);
PRUint32 count = 0;
while (len-- && *str++ == '/') ++count;
while (len-- && *p++ == '/') ++count;
return count;
}

Просмотреть файл

@ -477,7 +477,23 @@ namespace places {
// The page is already in the database, and we can fetch current
// params from the database.
nsCOMPtr<mozIStorageStatement> getPageInfo =
history->GetStatementByStoragePool(DB_PAGE_INFO_FOR_FRECENCY);
history->GetStatementByStoragePool(
"SELECT typed, hidden, visit_count, "
"(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), "
"EXISTS ( "
"SELECT 1 FROM moz_bookmarks "
"WHERE fk = :page_id "
"AND NOT EXISTS( "
"SELECT 1 "
"FROM moz_items_annos a "
"JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
"WHERE n.name = :anno_name "
"AND a.item_id = parent "
") "
"), "
"(url > 'place:' AND url < 'place;') "
"FROM moz_places "
"WHERE id = :page_id ");
NS_ENSURE_STATE(getPageInfo);
mozStorageStatementScoper infoScoper(getPageInfo);
@ -504,20 +520,40 @@ namespace places {
rv = getPageInfo->GetInt32(5, &isQuery);
NS_ENSURE_SUCCESS(rv, rv);
// NOTE: This is not limited to visits with "visit_type NOT IN (0,4,7,8)"
// because otherwise it would not return any visit for those transitions
// causing an incorrect frecency, see CalculateFrecencyInternal().
// In case of a temporary or permanent redirect, calculate the frecency
// as if the original page was visited.
nsCAutoString visitsForFrecencySQL(NS_LITERAL_CSTRING(
"/* do not warn (bug 659740 - SQLite may ignore index if few visits exist) */"
"SELECT "
"ROUND((strftime('%s','now','localtime','utc') - v.visit_date/1000000)/86400), "
"IFNULL(r.visit_type, v.visit_type), "
"v.visit_date "
"FROM moz_historyvisits v "
"LEFT JOIN moz_historyvisits r ON r.id = v.from_visit AND v.visit_type BETWEEN "
) + nsPrintfCString("%d AND %d ", nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
NS_LITERAL_CSTRING("WHERE v.place_id = :page_id "
"ORDER BY v.visit_date DESC ")
);
// Get a sample of the last visits to the page, to calculate its weight.
nsCOMPtr<mozIStorageStatement> getVisits =
history->GetStatementByStoragePool(DB_VISITS_FOR_FRECENCY);
history->GetStatementByStoragePool(visitsForFrecencySQL);
NS_ENSURE_STATE(getVisits);
mozStorageStatementScoper visitsScoper(getVisits);
rv = getVisits->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
NS_ENSURE_SUCCESS(rv, rv);
// Fetch only a limited number of recent visits.
PRInt32 numSampledVisits = 0;
// The visits query is already limited to the last N visits.
while (NS_SUCCEEDED(getVisits->ExecuteStep(&hasResult)) && hasResult) {
numSampledVisits++;
for (PRInt32 maxVisits = history->GetNumVisitsForFrecency();
numSampledVisits < maxVisits &&
NS_SUCCEEDED(getVisits->ExecuteStep(&hasResult)) && hasResult;
numSampledVisits++) {
PRInt32 visitType;
rv = getVisits->GetInt32(1, &visitType);
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -373,6 +373,8 @@ PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavHistory, gHistoryService)
nsNavHistory::nsNavHistory()
: mBatchLevel(0)
, mBatchDBTransaction(nsnull)
, mAsyncThreadStatements(mDBConn)
, mStatements(mDBConn)
, mDBPageSize(0)
, mCurrentJournalMode(JOURNAL_DELETE)
, mCachedNow(0)
@ -908,16 +910,6 @@ nsNavHistory::InitAdditionalDBItems()
nsresult rv = InitTriggers();
NS_ENSURE_SUCCESS(rv, rv);
// These statements are used by frecency calculation. Since frecency runs in
// the storage async thread, it needs to access them through a const history
// object, for thread-safety. Due to const correctness it's not possible for
// the statements getter to lazily initialize them on first use, thus they
// are initialized here.
(void*)GetStatement(mDBPageInfoForFrecency);
(void*)GetStatement(mDBAsyncThreadPageInfoForFrecency);
(void*)GetStatement(mDBVisitsForFrecency);
(void*)GetStatement(mDBAsyncThreadVisitsForFrecency);
return NS_OK;
}
@ -1289,34 +1281,6 @@ nsNavHistory::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
"WHERE url = :page_url "
));
// NOTE: This is not limited to visits with "visit_type NOT IN (0,4,7,8)"
// because otherwise mDBVisitsForFrecency would return no visits
// for places with only embed (or undefined) visits. That would
// cause an incorrect frecency, see CalculateFrecencyInternal().
// In such a case a place with only EMBED visits would result in a non-zero
// frecency.
// In case of a temporary or permanent redirect, calculate the frecency as if
// the original page was visited.
nsCAutoString visitsForFrecencySQL(NS_LITERAL_CSTRING(
"SELECT "
"ROUND((strftime('%s','now','localtime','utc') - v.visit_date/1000000)/86400), "
"COALESCE( "
"(SELECT r.visit_type FROM moz_historyvisits r WHERE v.visit_type IN ") +
nsPrintfCString("(%d,%d) ", TRANSITION_REDIRECT_PERMANENT,
TRANSITION_REDIRECT_TEMPORARY) +
NS_LITERAL_CSTRING(" AND r.id = v.from_visit), "
"visit_type), "
"visit_date "
"FROM moz_historyvisits v "
"WHERE v.place_id = :page_id "
"ORDER BY visit_date DESC LIMIT ") +
nsPrintfCString("%d", mNumVisitsForFrecency)
);
RETURN_IF_STMT(mDBVisitsForFrecency, visitsForFrecencySQL);
RETURN_IF_STMT(mDBAsyncThreadVisitsForFrecency, visitsForFrecencySQL);
RETURN_IF_STMT(mDBUpdateFrecency, NS_LITERAL_CSTRING(
"UPDATE moz_places "
"SET frecency = CALCULATE_FRECENCY(:page_id) "
@ -1329,34 +1293,6 @@ nsNavHistory::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
"WHERE id = :page_id AND frecency <> 0"
));
RETURN_IF_STMT(mDBGetPlaceVisitStats, NS_LITERAL_CSTRING(
"SELECT typed, hidden, frecency "
"FROM moz_places "
"WHERE id = :page_id "
));
// When calculating frecency, we need special information for the page.
nsCAutoString pageInfoForFrecencySQL(NS_LITERAL_CSTRING(
"SELECT typed, hidden, visit_count, "
"(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), "
"(SELECT id FROM moz_bookmarks "
"WHERE fk = :page_id "
"AND parent NOT IN ("
"SELECT a.item_id "
"FROM moz_items_annos a "
"JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
"WHERE n.name = :anno_name"
") "
"LIMIT 1), "
"(url > 'place:' AND url < 'place;') "
"FROM moz_places "
"WHERE id = :page_id "
));
RETURN_IF_STMT(mDBPageInfoForFrecency, pageInfoForFrecencySQL);
RETURN_IF_STMT(mDBAsyncThreadPageInfoForFrecency, pageInfoForFrecencySQL);
#ifdef MOZ_XUL
RETURN_IF_STMT(mDBFeedbackIncrease, NS_LITERAL_CSTRING(
// Leverage the PRIMARY KEY (place_id, input) to insert/update entries.
@ -2511,16 +2447,14 @@ nsNavHistory::FixInvalidFrecenciesForExcludedPlaces()
"SET frecency = 0 WHERE id IN ("
"SELECT h.id FROM moz_places h "
"WHERE h.url >= 'place:' AND h.url < 'place;' "
"UNION "
"UNION ALL "
// Unvisited child of a livemark
"SELECT b.fk FROM moz_bookmarks b "
"JOIN moz_places h ON b.fk = h.id AND visit_count = 0 AND frecency < 0 "
"JOIN moz_bookmarks bp ON bp.id = b.parent "
"JOIN moz_items_annos a ON a.item_id = bp.id "
"JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
"WHERE n.name = :anno_name "
"AND b.fk IN( "
"SELECT id FROM moz_places WHERE visit_count = 0 AND frecency < 0 "
") "
")"),
getter_AddRefs(dbUpdateStatement));
NS_ENSURE_SUCCESS(rv, rv);
@ -7266,13 +7200,8 @@ nsNavHistory::FinalizeStatements() {
mDBVisitToVisitResult,
mDBBookmarkToUrlResult,
mDBUrlToUrlResult,
mDBVisitsForFrecency,
mDBUpdateFrecency,
mDBUpdateHiddenOnFrecency,
mDBGetPlaceVisitStats,
mDBPageInfoForFrecency,
mDBAsyncThreadPageInfoForFrecency,
mDBAsyncThreadVisitsForFrecency,
};
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(stmts); i++) {
@ -7280,6 +7209,17 @@ nsNavHistory::FinalizeStatements() {
NS_ENSURE_SUCCESS(rv, rv);
}
// Finalize the statementCaches on the correct threads.
mStatements.FinalizeStatements();
nsRefPtr<FinalizeStatementCacheProxy<mozIStorageStatement> > event =
new FinalizeStatementCacheProxy<mozIStorageStatement>(
mAsyncThreadStatements, NS_ISUPPORTS_CAST(nsINavHistoryService*, this));
nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

Просмотреть файл

@ -72,6 +72,7 @@
#include "nsNavHistoryQuery.h"
#include "mozilla/storage.h"
#include "mozilla/storage/StatementCache.h"
#define QUERYUPDATE_TIME 0
#define QUERYUPDATE_SIMPLE 1
@ -137,8 +138,6 @@ namespace places {
, DB_ADD_NEW_PAGE
, DB_GET_URL_PAGE_INFO
, DB_SET_PLACE_TITLE
, DB_PAGE_INFO_FOR_FRECENCY
, DB_VISITS_FOR_FRECENCY
};
enum JournalMode {
@ -493,31 +492,32 @@ public:
return GetStatement(mDBGetURLPageInfo);
case DB_SET_PLACE_TITLE:
return GetStatement(mDBSetPlaceTitle);
case DB_PAGE_INFO_FOR_FRECENCY:
return GetStatement(mDBPageInfoForFrecency);
case DB_VISITS_FOR_FRECENCY:
return GetStatement(mDBVisitsForFrecency);
}
return nsnull;
}
mozIStorageStatement* GetStatementByStoragePool(
enum mozilla::places::HistoryStatementId aStatementId
) const
{
using namespace mozilla::places;
/**
* This cache should be used only for background thread statements.
*
* @pre must be running on the background thread of mDBConn.
*/
mutable mozilla::storage::StatementCache<mozIStorageStatement> mAsyncThreadStatements;
mutable mozilla::storage::StatementCache<mozIStorageStatement> mStatements;
switch(aStatementId) {
case DB_PAGE_INFO_FOR_FRECENCY:
return NS_IsMainThread() ? mDBPageInfoForFrecency
: mDBAsyncThreadPageInfoForFrecency;
case DB_VISITS_FOR_FRECENCY:
return NS_IsMainThread() ? mDBVisitsForFrecency
: mDBAsyncThreadVisitsForFrecency;
default:
NS_NOTREACHED("Trying to handle an unknown statement");
}
return nsnull;
template<int N>
already_AddRefed<mozIStorageStatement>
GetStatementByStoragePool(const char (&aQuery)[N]) const
{
nsDependentCString query(aQuery, N - 1);
return GetStatementByStoragePool(query);
}
already_AddRefed<mozIStorageStatement>
GetStatementByStoragePool(const nsACString& aQuery) const
{
return NS_IsMainThread()
? mStatements.GetCachedStatement(aQuery)
: mAsyncThreadStatements.GetCachedStatement(aQuery);
}
PRInt32 GetFrecencyAgedWeight(PRInt32 aAgeInDays) const
@ -580,6 +580,11 @@ public:
}
}
PRInt32 GetNumVisitsForFrecency() const
{
return mNumVisitsForFrecency;
}
PRInt64 GetNewSessionID();
/**
@ -647,14 +652,6 @@ protected:
nsCOMPtr<mozIStorageStatement> mDBUrlToUrlResult; // kGetInfoIndex_* results
nsCOMPtr<mozIStorageStatement> mDBUpdateFrecency;
nsCOMPtr<mozIStorageStatement> mDBUpdateHiddenOnFrecency;
nsCOMPtr<mozIStorageStatement> mDBGetPlaceVisitStats;
// Cached statements used in frecency calculation. Since it could happen on
// both main thread or storage async thread, we keep two versions of them
// for thread-safety.
mutable nsCOMPtr<mozIStorageStatement> mDBVisitsForFrecency;
mutable nsCOMPtr<mozIStorageStatement> mDBPageInfoForFrecency;
mutable nsCOMPtr<mozIStorageStatement> mDBAsyncThreadVisitsForFrecency;
mutable nsCOMPtr<mozIStorageStatement> mDBAsyncThreadPageInfoForFrecency;
#ifdef MOZ_XUL
// AutoComplete stuff
nsCOMPtr<mozIStorageStatement> mDBFeedbackIncrease;

Просмотреть файл

@ -46,28 +46,22 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
// This is just a helper for the next constant.
function book_tag_sql_fragment(aName, aColumn, aForTag)
{
return ["(",
"SELECT ", aColumn, " ",
"FROM moz_bookmarks b ",
"JOIN moz_bookmarks t ",
"ON t.id = b.parent ",
"AND t.parent ", (aForTag ? "" : "!"), "= :parent ",
"WHERE b.fk = h.id ",
(aForTag ? "" : "ORDER BY b.lastModified DESC LIMIT 1"),
") AS ", aName].join("");
}
// This SQL query fragment provides the following:
// - the parent folder for bookmarked entries (kQueryIndexParent)
// - whether the entry is bookmarked (kQueryIndexBookmarked)
// - the bookmark title, if it is a bookmark (kQueryIndexBookmarkTitle)
// - the tags associated with a bookmarked entry (kQueryIndexTags)
const kBookTagSQLFragment =
book_tag_sql_fragment("parent", "b.parent", false) + ", " +
book_tag_sql_fragment("bookmark", "b.title", false) + ", " +
book_tag_sql_fragment("tags", "GROUP_CONCAT(t.title, ',')", true);
"EXISTS(SELECT 1 FROM moz_bookmarks WHERE fk = h.id) AS bookmarked, "
+ "( "
+ "SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL "
+ "ORDER BY lastModified DESC LIMIT 1 "
+ ") AS btitle, "
+ "( "
+ "SELECT GROUP_CONCAT(t.title, ',') "
+ "FROM moz_bookmarks b "
+ "JOIN moz_bookmarks t ON t.id = b.parent AND t.parent = :parent "
+ "WHERE b.fk = h.id "
+ ") AS tags";
// observer topics
const kTopicShutdown = "places-shutdown";
@ -85,7 +79,7 @@ const MATCH_BEGINNING = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING;
const kQueryIndexURL = 0;
const kQueryIndexTitle = 1;
const kQueryIndexFaviconURL = 2;
const kQueryIndexParentId = 3;
const kQueryIndexBookmarked = 3;
const kQueryIndexBookmarkTitle = 4;
const kQueryIndexTags = 5;
const kQueryIndexVisitCount = 6;
@ -235,9 +229,9 @@ function nsPlacesAutoComplete()
+ "LEFT JOIN moz_openpages_temp t ON t.url = h.url "
+ "WHERE h.frecency <> 0 "
+ "AND AUTOCOMPLETE_MATCH(:searchString, h.url, "
+ "IFNULL(bookmark, h.title), tags, "
+ "h.visit_count, h.typed, parent, "
+ "t.open_count, "
+ "IFNULL(btitle, h.title), tags, "
+ "h.visit_count, h.typed, "
+ "bookmarked, t.open_count, "
+ ":matchBehavior, :searchBehavior) "
+ "{ADDITIONAL_CONDITIONS} "
+ "ORDER BY h.frecency DESC, h.id DESC "
@ -297,7 +291,7 @@ function nsPlacesAutoComplete()
});
XPCOMUtils.defineLazyGetter(this, "_bookmarkQuery", function() {
let replacementText = "AND bookmark IS NOT NULL";
let replacementText = "AND bookmarked";
return this._db.createAsyncStatement(
SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
);
@ -333,31 +327,24 @@ function nsPlacesAutoComplete()
});
XPCOMUtils.defineLazyGetter(this, "_adaptiveQuery", function() {
// In this query, we are taking kBookTagSQLFragment only for h.id because it
// uses data from the moz_bookmarks table and we sync tables on bookmark
// insert. So, most likely, h.id will always be populated when we have any
// bookmark.
return this._db.createAsyncStatement(
"/* do not warn (bug 487789) */ "
+ "SELECT h.url, h.title, f.url, " + kBookTagSQLFragment + ", "
+ "h.visit_count, h.typed, h.id, :query_type, t.open_count, rank "
+ "h.visit_count, h.typed, h.id, :query_type, t.open_count "
+ "FROM ( "
+ "SELECT ROUND( "
+ "MAX(((i.input = :search_string) + "
+ "(SUBSTR(i.input, 1, LENGTH(:search_string)) = :search_string) "
+ ") * i.use_count "
+ ") , 1 " // Round at first decimal.
+ "SELECT ROUND( "
+ "MAX(use_count) * (1 + (input = :search_string)), 1 "
+ ") AS rank, place_id "
+ "FROM moz_inputhistory i "
+ "GROUP BY i.place_id "
+ "HAVING rank > 0 "
+ "FROM moz_inputhistory "
+ "WHERE input BETWEEN :search_string AND :search_string || X'FFFF' "
+ "GROUP BY place_id "
+ ") AS i "
+ "JOIN moz_places h ON h.id = i.place_id "
+ "LEFT JOIN moz_favicons f ON f.id = h.favicon_id "
+ "LEFT JOIN moz_openpages_temp t ON t.url = h.url "
+ "WHERE AUTOCOMPLETE_MATCH(NULL, h.url, "
+ "IFNULL(bookmark, h.title), tags, "
+ "h.visit_count, h.typed, parent, "
+ "IFNULL(btitle, h.title), tags, "
+ "h.visit_count, h.typed, bookmarked, "
+ "t.open_count, "
+ ":matchBehavior, :searchBehavior) "
+ "ORDER BY rank DESC, h.frecency DESC "
@ -376,7 +363,7 @@ function nsPlacesAutoComplete()
+ "WHERE rev_host = (SELECT rev_host FROM moz_places WHERE id = b.fk) "
+ "ORDER BY frecency DESC "
+ "LIMIT 1) "
+ "), b.parent, b.title, NULL, h.visit_count, h.typed, IFNULL(h.id, b.fk), "
+ "), 1, b.title, NULL, h.visit_count, h.typed, IFNULL(h.id, b.fk), "
+ ":query_type, t.open_count "
+ "FROM moz_keywords k "
+ "JOIN moz_bookmarks b ON b.keyword_id = k.id "
@ -1012,8 +999,8 @@ nsPlacesAutoComplete.prototype = {
let entryTitle = aRow.getResultByIndex(kQueryIndexTitle) || "";
let entryFavicon = aRow.getResultByIndex(kQueryIndexFaviconURL) || "";
let entryParentId = aRow.getResultByIndex(kQueryIndexParentId);
let entryBookmarkTitle = entryParentId ?
let entryBookmarked = aRow.getResultByIndex(kQueryIndexBookmarked);
let entryBookmarkTitle = entryBookmarked ?
aRow.getResultByIndex(kQueryIndexBookmarkTitle) : null;
let entryTags = aRow.getResultByIndex(kQueryIndexTags) || "";
@ -1056,7 +1043,7 @@ nsPlacesAutoComplete.prototype = {
// haven't already done so.
if (showTags)
style = "tag";
else if (entryParentId)
else if (entryBookmarked)
style = "bookmark";
else
style = "favicon";

Просмотреть файл

@ -44,194 +44,170 @@
* https://bugzilla.mozilla.org/show_bug.cgi?id=412132
*/
const bmServ = PlacesUtils.bookmarks;
const histServ = PlacesUtils.history;
const lmServ = PlacesUtils.livemarks;
let tests = [
add_test(function unvisited_bookmarked_livemarkItem()
{
desc: ["Frecency of unvisited, separately bookmarked livemark item's URI ",
"should be zero after bookmark's URI changed."].join(""),
run: function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0.");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Frecency of unvisited, separately bookmarked livemark item's " +
"URI should be zero after bookmark's URI changed.");
bmServ.changeBookmarkURI(aItemId, uri("http://example.com/new-uri"));
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
print("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
do_log_info("Bookmarked => frecency of URI should be != 0.");
do_check_neq(frecencyForUrl(TEST_URI), 0);
PlacesUtils.bookmarks.changeBookmarkURI(id, NetUtil.newURI("http://example.com/new-uri"));
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function visited_bookmarked_livemarkItem()
{
desc: ["Frecency of visited, separately bookmarked livemark item's URI ",
"should not be zero after bookmark's URI changed."].join(""),
run: function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Frecency of visited, separately bookmarked livemark item's " +
"URI should not be zero after bookmark's URI changed.");
visit(uri(aUrl));
bmServ.changeBookmarkURI(aItemId, uri("http://example.com/new-uri"));
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
print("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
visit(TEST_URI);
PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/new-uri"));
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function changeuri_unvisited_bookmark()
{
desc: ["After changing URI of bookmark, frecency of bookmark's original URI ",
"should be zero if original URI is unvisited and no longer ",
"bookmarked."].join(""),
run: function ()
do_log_info("After changing URI of bookmark, frecency of bookmark's " +
"original URI should be zero if original URI is unvisited and " +
"no longer bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let url = "http://example.com/1";
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(url),
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(url, function(aFrecency) aFrecency > 0,
this.check1, this, [url, bmId]);
},
check1: function (aUrl, aItemId) {
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.changeBookmarkURI(aItemId, uri("http://example.com/2"));
PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/2"));
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
waitForAsyncUpdates(function ()
{
do_log_info("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function changeuri_visited_bookmark()
{
desc: ["After changing URI of bookmark, frecency of bookmark's original URI ",
"should not be zero if original URI is visited."].join(""),
run: function ()
do_log_info("After changing URI of bookmark, frecency of bookmark's " +
"original URI should not be zero if original URI is visited.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(bmURL),
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
visit(uri(aUrl));
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl, aItemId]);
},
check2: function (aUrl, aItemId)
{
bmServ.changeBookmarkURI(aItemId, uri("http://example.com/2"));
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check3, this, [aUrl]);
},
check3: function (aUrl)
{
print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
visit(TEST_URI);
waitForAsyncUpdates(function ()
{
PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/2"));
waitForAsyncUpdates(function ()
{
do_log_info("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
});
add_test(function changeuri_bookmark_still_bookmarked()
{
desc: ["After changing URI of bookmark, frecency of bookmark's original URI ",
"should not be zero if original URI is still bookmarked."].join(""),
run: function ()
do_log_info("After changing URI of bookmark, frecency of bookmark's " +
"original URI should not be zero if original URI is still " +
"bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 1 title");
let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bm1Id = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(bmURL),
bmServ.DEFAULT_INDEX,
"bookmark 1 title");
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
let bm2Id = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(bmURL),
bmServ.DEFAULT_INDEX,
"bookmark 2 title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL, bm1Id]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
PlacesUtils.bookmarks.changeBookmarkURI(id1, uri("http://example.com/2"));
waitForAsyncUpdates(function ()
{
do_log_info("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.changeBookmarkURI(aItemId, uri("http://example.com/2"));
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function changeuri_nonexistent_bookmark()
{
desc: "Changing the URI of a nonexistent bookmark should fail.",
run: function ()
{
do_log_info("Changing the URI of a nonexistent bookmark should fail.");
function tryChange(itemId)
{
try {
bmServ.changeBookmarkURI(itemId + 1, uri("http://example.com/2"));
PlacesUtils.bookmarks.changeBookmarkURI(itemId + 1, uri("http://example.com/2"));
do_throw("Nonexistent bookmark should throw.");
}
catch (exc) {}
catch (ex) {}
}
// First try a straight-up bogus item ID, one greater than the current max
@ -243,62 +219,54 @@ let tests = [
tryChange(maxId + 1);
// Now add a bookmark, delete it, and check.
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri("http://example.com/"),
bmServ.DEFAULT_INDEX,
"bookmark title");
bmServ.removeItem(bmId);
tryChange(bmId);
run_next_test();
}
},
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
uri("http://example.com/"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
PlacesUtils.bookmarks.removeItem(id);
tryChange(id);
];
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
/******************************************************************************/
///////////////////////////////////////////////////////////////////////////////
function createLivemark(lmItemURI)
/**
* Creates a livemark with a single child item.
*
* @param aChildURI
* the URI of the livemark's single child item
* @return the item ID of the single child item
*/
function createLivemark(aChildURI)
{
let lmId = lmServ.createLivemarkFolderOnly(bmServ.unfiledBookmarksFolder,
"livemark title",
uri("http://www.mozilla.org/"),
uri("http://www.mozilla.org/news.rdf"),
-1);
return bmServ.insertBookmark(lmId,
lmItemURI,
bmServ.DEFAULT_INDEX,
"livemark item title");
let livemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly(
PlacesUtils.unfiledBookmarksFolderId, "livemark title",
uri("http://example.com/"), uri("http://example.com/rdf"), -1
);
return PlacesUtils.bookmarks.insertBookmark(livemarkId,
aChildURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"livemark item title");
}
function visit(uri)
/**
* Adds a visit for aURI.
*
* @param aURI
* the URI of the Place for which to add a visit
*/
function visit(aURI)
{
histServ.addVisit(uri,
Date.now() * 1000,
null,
histServ.TRANSITION_BOOKMARK,
false,
0);
PlacesUtils.history.addVisit(aURI, Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_BOOKMARK,
false, 0);
}
/******************************************************************************/
///////////////////////////////////////////////////////////////////////////////
function run_test()
{
do_test_pending();
run_next_test();
}
function run_next_test()
{
if (tests.length) {
let test = tests.shift();
print("\n ***Test: " + test.desc);
remove_all_bookmarks();
waitForClearHistory(function() {
test.run.call(test);
});
}
else {
do_test_finished();
}
}

Просмотреть файл

@ -45,376 +45,325 @@
* bookmark is deleted.
*/
const bmServ = PlacesUtils.bookmarks;
const histServ = PlacesUtils.history;
const lmServ = PlacesUtils.livemarks;
let tests = [
add_test(function unvisited_bookmarked_livemarkItem()
{
desc: ["Frecency of unvisited, separately bookmarked livemark item's URI ",
"should be zero after bookmark removed."].join(""),
run: function ()
do_log_info("Frecency of unvisited, separately bookmarked livemark item's " +
"URI should be zero after bookmark removed.");
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeItem(aItemId);
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
PlacesUtils.bookmarks.removeItem(id);
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function visited_bookmarked_livemarkItem()
{
desc: ["Frecency of visited, separately bookmarked livemark item's URI ",
"should not be zero after bookmark removed."].join(""),
run: function ()
do_log_info("Frecency of visited, separately bookmarked livemark item's " +
"URI should not be zero after bookmark removed.");
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
visit(uri(aUrl));
bmServ.removeItem(aItemId);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
visit(TEST_URI);
PlacesUtils.bookmarks.removeItem(id);
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function removed_bookmark()
{
desc: ["After removing bookmark, frecency of bookmark's URI should be zero ",
"if URI is unvisited and no longer bookmarked."].join(""),
run: function ()
do_log_info("After removing bookmark, frecency of bookmark's URI should be " +
"zero if URI is unvisited and no longer bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let url = "http://example.com/1";
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(url),
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(url, function(aFrecency) aFrecency > 0,
this.check1, this, [url, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeItem(aItemId);
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
PlacesUtils.bookmarks.removeItem(id);
waitForAsyncUpdates(function ()
{
do_log_info("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function removed_but_visited_bookmark()
{
desc: ["After removing bookmark, frecency of bookmark's URI should not be ",
"zero if URI is visited."].join(""),
run: function ()
do_log_info("After removing bookmark, frecency of bookmark's URI should " +
"not be zero if URI is visited.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bmURI = uri(bmURL);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
let bmId = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL, bmId]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
visit(TEST_URI);
PlacesUtils.bookmarks.removeItem(id);
visit(uri(aUrl));
bmServ.removeItem(aItemId);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
waitForAsyncUpdates(function ()
{
do_log_info("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function remove_bookmark_still_bookmarked()
{
desc: ["After removing bookmark, frecency of bookmark's URI should not be ",
"zero if URI is still bookmarked."].join(""),
run: function ()
do_log_info("After removing bookmark, frecency of bookmark's URI should ",
"not be zero if URI is still bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 1 title");
let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bmURI = uri(bmURL);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
let bm1Id = bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark 1 title");
PlacesUtils.bookmarks.removeItem(id1);
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark 2 title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL, bm1Id]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
waitForAsyncUpdates(function ()
{
do_log_info("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeItem(aItemId);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI still bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function cleared_parent_of_unvisited_bookmark_to_livemarkItem()
{
desc: ["Frecency of unvisited, separately bookmarked livemark item's URI ",
"should be zero after all children removed from bookmark's ",
"parent."].join(""),
run: function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
do_log_info("Frecency of unvisited, separately bookmarked livemark item's " +
"URI should be zero after all children removed from bookmark's " +
"parent.");
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL]);
},
check1: function (aUrl)
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeFolderChildren(bmServ.unfiledBookmarksFolder);
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function cleared_parent_of_visited_bookmark_to_livemarkItem()
{
desc: ["Frecency of visited, separately bookmarked livemark item's URI ",
"should not be zero after all children removed from bookmark's ",
"parent."].join(""),
run: function ()
do_log_info("Frecency of visited, separately bookmarked livemark item's " +
"URI should not be zero after all children removed from " +
"bookmark's parent.");
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
const TEST_URI = NetUtil.newURI("http://example.com/livemark-item");
createLivemark(TEST_URI);
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
// Add livemark and bookmark. Bookmark's URI is the URI of the livemark's
// only item.
let lmItemURL = "http://example.com/livemark-item";
let lmItemURI = uri(lmItemURL);
createLivemark(lmItemURI);
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
lmItemURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(lmItemURL, function(aFrecency) aFrecency > 0,
this.check1, this, [lmItemURL]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
visit(uri(aUrl));
bmServ.removeFolderChildren(bmServ.unfiledBookmarksFolder);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
visit(TEST_URI);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
waitForAsyncUpdates(function ()
{
do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function cleared_parent_of_unvisited_unbookmarked_livemarkItem()
{
desc: ["After removing all children from bookmark's parent, frecency of ",
"bookmark's URI should be zero if URI is unvisited and no longer ",
"bookmarked."].join(""),
run: function ()
do_log_info("After removing all children from bookmark's parent, frecency " +
"of bookmark's URI should be zero if URI is unvisited and no " +
"longer bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let url = "http://example.com/1";
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
uri(url),
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(url, function(aFrecency) aFrecency > 0,
this.check1, this, [url]);
},
check1: function (aUrl, aItemId)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeFolderChildren(bmServ.unfiledBookmarksFolder);
waitForFrecency(aUrl, function(aFrecency) aFrecency == 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
waitForAsyncUpdates(function ()
{
do_log_info("Unvisited URI no longer bookmarked => frecency should = 0");
do_check_eq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function cleared_parent_of_visited_bookmark()
{
desc: ["After removing all children from bookmark's parent, frecency of ",
"bookmark's URI should not be zero if URI is visited."].join(""),
run: function ()
do_log_info("After removing all children from bookmark's parent, frecency " +
"of bookmark's URI should not be zero if URI is visited.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bmURI = uri(bmURL);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL]);
},
check1: function (aUrl)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
visit(TEST_URI);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
visit(uri(aUrl));
bmServ.removeFolderChildren(bmServ.unfiledBookmarksFolder);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
print("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
waitForAsyncUpdates(function ()
{
do_log_info("*Visited* URI no longer bookmarked => frecency should != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
add_test(function cleared_parent_of_bookmark_still_bookmarked()
{
desc: ["After removing all children from bookmark's parent, frecency of ",
"bookmark's URI should not be zero if URI is still ",
"bookmarked."].join(""),
run: function ()
do_log_info("After removing all children from bookmark's parent, frecency " +
"of bookmark's URI should not be zero if URI is still " +
"bookmarked.");
const TEST_URI = NetUtil.newURI("http://example.com/1");
let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.toolbarFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 1 title");
let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
TEST_URI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark 2 title");
waitForAsyncUpdates(function ()
{
let bmURL = "http://example.com/1";
let bmURI = uri(bmURL);
do_log_info("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.insertBookmark(bmServ.toolbarFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark 1 title");
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
bmServ.insertBookmark(bmServ.unfiledBookmarksFolder,
bmURI,
bmServ.DEFAULT_INDEX,
"bookmark 2 title");
waitForFrecency(bmURL, function(aFrecency) aFrecency > 0,
this.check1, this, [bmURL]);
},
check1: function (aUrl)
{
print("Bookmarked => frecency of URI should be != 0");
do_check_neq(frecencyForUrl(aUrl), 0);
waitForAsyncUpdates(function ()
{
// URI still bookmarked => frecency should != 0.
do_check_neq(frecencyForUrl(TEST_URI), 0);
bmServ.removeFolderChildren(bmServ.unfiledBookmarksFolder);
waitForFrecency(aUrl, function(aFrecency) aFrecency > 0,
this.check2, this, [aUrl]);
},
check2: function (aUrl)
{
// URI still bookmarked => frecency should != 0.
do_check_neq(frecencyForUrl(aUrl), 0);
run_next_test();
}
},
];
remove_all_bookmarks();
waitForClearHistory(run_next_test);
});
});
});
///////////////////////////////////////////////////////////////////////////////
/**
* Creates a livemark with a single child item.
*
* @param aLmChildItemURI
* @param aChildURI
* the URI of the livemark's single child item
* @return the item ID of the single child item
*/
function createLivemark(aLmChildItemURI) {
let lmItemId = lmServ.createLivemarkFolderOnly(bmServ.unfiledBookmarksFolder,
"livemark title",
uri("http://example.com/"),
uri("http://example.com/rdf"),
-1);
return bmServ.insertBookmark(lmItemId,
aLmChildItemURI,
bmServ.DEFAULT_INDEX,
"livemark item title");
function createLivemark(aChildURI)
{
let livemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly(
PlacesUtils.unfiledBookmarksFolderId, "livemark title",
uri("http://example.com/"), uri("http://example.com/rdf"), -1
);
return PlacesUtils.bookmarks.insertBookmark(livemarkId,
aChildURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"livemark item title");
}
/**
@ -423,32 +372,16 @@ function createLivemark(aLmChildItemURI) {
* @param aURI
* the URI of the Place for which to add a visit
*/
function visit(aURI) {
let visitId = histServ.addVisit(aURI,
Date.now() * 1000,
null,
histServ.TRANSITION_BOOKMARK,
false,
0);
function visit(aURI)
{
PlacesUtils.history.addVisit(aURI, Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_BOOKMARK,
false, 0);
}
///////////////////////////////////////////////////////////////////////////////
function run_test() {
do_test_pending();
function run_test()
{
run_next_test();
}
function run_next_test() {
if (tests.length) {
let test = tests.shift();
print("\n ***Test: " + test.desc);
remove_all_bookmarks();
waitForClearHistory(function() {
test.run.call(test);
});
}
else {
do_test_finished();
}
}

Просмотреть файл

@ -197,7 +197,7 @@ function populateGraphicsSection() {
suggestedDriverVersion = gfxInfo.getFeatureSuggestedDriverVersion(feature);
} catch(e) {}
if (suggestedDriverVersion)
errorMessage = bundle.formatStringFromName("tryNewerDriver", [suggestedDriverVersion], 1);
errorMessage = bundle.formatStringFromName("tryNewerDriver2", [suggestedDriverVersion], 1);
else
errorMessage = bundle.GetStringFromName("blockedDriver");
break;
@ -342,6 +342,17 @@ function populateGraphicsSection() {
createElement("td", msg),
])
]);
let urlFormatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Ci.nsIURLFormatter);
let supportUrl = urlFormatter.formatURLPref("app.support.updateGraphicsDriverURL");
if (supportUrl != "about:blank") {
let links = graphics_tbody.querySelectorAll(".supportLink-graphicsDriver");
for (let i = 0; i < links.length; i++) {
links[i].href = supportUrl;
links[i].target = "_blank";
}
}
}
function getPrefValue(aName) {
@ -406,9 +417,9 @@ function createParentElement(tagName, childElems) {
return elem;
}
function createElement(tagName, textContent, opt_class) {
function createElement(tagName, content, opt_class) {
let elem = document.createElement(tagName);
elem.textContent = textContent;
elem.innerHTML = content;
elem.className = opt_class || "";
return elem;
}

Просмотреть файл

@ -919,6 +919,17 @@
event.preventDefault();
]]>
</handler>
<handler event="MozMousePixelScroll" phase="capturing">
<![CDATA[
if (event.axis == event.HORIZONTAL_AXIS)
return;
// shouldn't be scrolled by pixel scrolling events before a line/page
// scrolling event.
event.preventDefault();
]]>
</handler>
</handlers>
</binding>

Просмотреть файл

@ -12,7 +12,8 @@ acceleratedWindows = GPU Accelerated Windows
blockedDriver = Blocked for your graphics driver version.
# LOCALIZATION NOTE The %S here is a placeholder, leave unchanged, it will get replaced by the driver version string.
tryNewerDriver = Blocked for your graphics driver version. Try updating your graphics driver to version %S or newer.
# Don't translate <a class="supportLink-graphicsDriver"> - it is used to link to a support article.
tryNewerDriver2 = Blocked for your graphics driver version. Try <a class="supportLink-graphicsDriver">updating your graphics driver</a> to version %S or newer.
# LOCALIZATION NOTE The verb "blocked" here refers to a graphics feature such as "Direct2D" or "OpenGL layers".
blockedGfxCard = Blocked for your graphics card because of unresolved driver issues.

Просмотреть файл

@ -82,13 +82,16 @@ function pfs_loaded() {
info("PFS loaded");
var docEle = gPFS.document.documentElement;
docEle.addEventListener("pageshow", page_shown, false);
docEle.addEventListener("wizardfinish", function onwizardfinish() {
var onwizardfinish = function () {
info("wizardfinish event");
}, false);
docEle.addEventListener("wizardnext", function onwizardnext() {
};
var onwizardnext = function () {
info("wizardnext event");
}, false);
};
docEle.addEventListener("pageshow", page_shown, false);
docEle.addEventListener("wizardfinish", onwizardfinish, false);
docEle.addEventListener("wizardnext", onwizardnext, false);
gPFS.addEventListener("unload", function() {
info("unload event");

Просмотреть файл

@ -158,8 +158,10 @@ Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *jenv, jcl
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack)
{
#ifdef MOZ_CRASHREPORTER
nsJNIString javaStack(stack);
CrashReporter::AppendAppNotesToCrashReport(
NS_ConvertUTF16toUTF8(javaStack));
#endif
abort();
}

Просмотреть файл

@ -258,11 +258,11 @@
* Deprecated declarations.
*/
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define NS_DEPRECATED __attribute__((deprecated))
# define MOZ_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
# define NS_DEPRECATED __declspec(deprecated)
# define MOZ_DEPRECATED __declspec(deprecated)
#else
# define NS_DEPRECATED
# define MOZ_DEPRECATED
#endif
/**

Просмотреть файл

@ -345,7 +345,7 @@ def write_interface(iface, fd):
if iface.attributes.scriptable:
fd.write("NS_SCRIPTABLE ")
if iface.attributes.deprecated:
fd.write("NS_DEPRECATED ")
fd.write("MOZ_DEPRECATED ")
fd.write(iface.name)
if iface.base:
fd.write(" : public %s" % iface.base)

Просмотреть файл

@ -245,7 +245,7 @@ interface(TreeState *state)
"class %s%s%s%s",
(keepvtable ? "" : "NS_NO_VTABLE "),
(scriptable ? "NS_SCRIPTABLE " : ""),
(deprecated ? "NS_DEPRECATED " : ""),
(deprecated ? "MOZ_DEPRECATED " : ""),
className);
if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
@ -792,7 +792,7 @@ write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
if (mode == AS_DECL) {
if (IDL_tree_property_get(ident, "deprecated"))
fputs("NS_DEPRECATED ", outfile);
fputs("MOZ_DEPRECATED ", outfile);
if (is_method_scriptable(attr_tree, ident))
fputs("NS_SCRIPTABLE ", outfile);
@ -1046,7 +1046,7 @@ write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
if (mode == AS_DECL) {
if (IDL_tree_property_get(op->ident, "deprecated"))
fputs("NS_DEPRECATED ", outfile);
fputs("MOZ_DEPRECATED ", outfile);
if (is_method_scriptable(method_tree, op->ident))
fputs("NS_SCRIPTABLE ", outfile);