mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 834539 - Replace getPageTitle with an async API. r=mak. sr=gavin.
This commit is contained in:
parent
01296b90c1
commit
82717d4434
@ -300,7 +300,7 @@ GenerateGUID(nsCString& _guid)
|
||||
}
|
||||
|
||||
bool
|
||||
IsValidGUID(const nsCString& aGUID)
|
||||
IsValidGUID(const nsACString& aGUID)
|
||||
{
|
||||
nsCString::size_type len = aGUID.Length();
|
||||
if (len != GUID_LENGTH) {
|
||||
|
@ -137,7 +137,7 @@ nsresult GenerateGUID(nsCString& _guid);
|
||||
* The guid to test.
|
||||
* @return true if it is a valid guid, false otherwise.
|
||||
*/
|
||||
bool IsValidGUID(const nsCString& aGUID);
|
||||
bool IsValidGUID(const nsACString& aGUID);
|
||||
|
||||
/**
|
||||
* Truncates the title if it's longer than TITLE_LENGTH_MAX.
|
||||
|
@ -212,6 +212,67 @@ class PlaceHashKey : public nsCStringHashKey
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Convert the given js value to a js array.
|
||||
*
|
||||
* @param [in] aValue
|
||||
* the JS value to convert.
|
||||
* @param [in] aCtx
|
||||
* The JSContext for aValue.
|
||||
* @param [out] _array
|
||||
* the JS array.
|
||||
* @param [out] _arrayLength
|
||||
* _array's length.
|
||||
*/
|
||||
nsresult
|
||||
GetJSArrayFromJSValue(const JS::Value& aValue,
|
||||
JSContext* aCtx,
|
||||
JSObject** _array,
|
||||
uint32_t* _arrayLength) {
|
||||
JS::Rooted<JSObject*> val(aCtx, aValue.toObjectOrNull());
|
||||
if (JS_IsArrayObject(aCtx, val)) {
|
||||
*_array = val;
|
||||
(void)JS_GetArrayLength(aCtx, *_array, _arrayLength);
|
||||
NS_ENSURE_ARG(*_arrayLength > 0);
|
||||
}
|
||||
else {
|
||||
// Build a temporary array to store this one item so the code below can
|
||||
// just loop.
|
||||
*_arrayLength = 1;
|
||||
*_array = JS_NewArrayObject(aCtx, 0, nullptr);
|
||||
NS_ENSURE_TRUE(*_array, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JSBool rc = JS_DefineElement(aCtx, *_array, 0, aValue, nullptr, nullptr, 0);
|
||||
NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attemps to convert a given js value to a nsIURI object.
|
||||
* @param aCtx
|
||||
* The JSContext for aValue.
|
||||
* @param aValue
|
||||
* The JS value to convert.
|
||||
* @return the nsIURI object, or null if aValue is not a nsIURI object.
|
||||
*/
|
||||
already_AddRefed<nsIURI>
|
||||
GetJSValueAsURI(JSContext* aCtx,
|
||||
const JS::Value& aValue) {
|
||||
if (!JSVAL_IS_PRIMITIVE(aValue)) {
|
||||
nsCOMPtr<nsIXPConnect> xpc = mozilla::services::GetXPConnect();
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(aCtx, JSVAL_TO_OBJECT(aValue),
|
||||
getter_AddRefs(wrappedObj));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsCOMPtr<nsIURI> uri = do_QueryWrappedNative(wrappedObj);
|
||||
return uri.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an nsIURI from the "uri" property of a JSObject.
|
||||
*
|
||||
@ -231,18 +292,41 @@ GetURIFromJSObject(JSContext* aCtx,
|
||||
JS::Rooted<JS::Value> uriVal(aCtx);
|
||||
JSBool rc = JS_GetProperty(aCtx, aObject, aProperty, uriVal.address());
|
||||
NS_ENSURE_TRUE(rc, nullptr);
|
||||
return GetJSValueAsURI(aCtx, uriVal);
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(uriVal)) {
|
||||
nsCOMPtr<nsIXPConnect> xpc = mozilla::services::GetXPConnect();
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(aCtx, JSVAL_TO_OBJECT(uriVal),
|
||||
getter_AddRefs(wrappedObj));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsCOMPtr<nsIURI> uri = do_QueryWrappedNative(wrappedObj);
|
||||
return uri.forget();
|
||||
/**
|
||||
* Attemps to convert a JS value to a string.
|
||||
* @param aCtx
|
||||
* The JSContext for aObject.
|
||||
* @param aValue
|
||||
* The JS value to convert.
|
||||
* @param _string
|
||||
* The string to populate with the value, or set it to void.
|
||||
*/
|
||||
void
|
||||
GetJSValueAsString(JSContext* aCtx,
|
||||
const JS::Value& aValue,
|
||||
nsString& _string) {
|
||||
if (JSVAL_IS_VOID(aValue) ||
|
||||
!(JSVAL_IS_NULL(aValue) || JSVAL_IS_STRING(aValue))) {
|
||||
_string.SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
// |null| in JS maps to the empty string.
|
||||
if (JSVAL_IS_NULL(aValue)) {
|
||||
_string.Truncate();
|
||||
return;
|
||||
}
|
||||
size_t length;
|
||||
const jschar* chars =
|
||||
JS_GetStringCharsZAndLength(aCtx, JSVAL_TO_STRING(aValue), &length);
|
||||
if (!chars) {
|
||||
_string.SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
_string.Assign(static_cast<const PRUnichar*>(chars), length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,24 +349,13 @@ GetStringFromJSObject(JSContext* aCtx,
|
||||
{
|
||||
JS::Rooted<JS::Value> val(aCtx);
|
||||
JSBool rc = JS_GetProperty(aCtx, aObject, aProperty, val.address());
|
||||
if (!rc || JSVAL_IS_VOID(val) ||
|
||||
!(JSVAL_IS_NULL(val) || JSVAL_IS_STRING(val))) {
|
||||
if (!rc) {
|
||||
_string.SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
// |null| in JS maps to the empty string.
|
||||
if (JSVAL_IS_NULL(val)) {
|
||||
_string.Truncate();
|
||||
return;
|
||||
else {
|
||||
GetJSValueAsString(aCtx, val, _string);
|
||||
}
|
||||
size_t length;
|
||||
const jschar* chars =
|
||||
JS_GetStringCharsZAndLength(aCtx, JSVAL_TO_STRING(val), &length);
|
||||
if (!chars) {
|
||||
_string.SetIsVoid(true);
|
||||
return;
|
||||
}
|
||||
_string.Assign(static_cast<const PRUnichar*>(chars), length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -492,8 +565,8 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
|
||||
// We are in the main thread, no need to lock.
|
||||
if (mHistory->IsShuttingDown()) {
|
||||
// If we are shutting down, we cannot notify the observers.
|
||||
@ -563,8 +636,7 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
|
||||
nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(navHistory, NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -581,44 +653,57 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Notifies a callback object when a visit has been handled.
|
||||
* Helper class for methods which notify their callers through the
|
||||
* mozIVisitInfoCallback interface.
|
||||
*/
|
||||
class NotifyVisitInfoCallback : public nsRunnable
|
||||
class NotifyPlaceInfoCallback : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NotifyVisitInfoCallback(mozIVisitInfoCallback* aCallback,
|
||||
NotifyPlaceInfoCallback(mozIVisitInfoCallback* aCallback,
|
||||
const VisitData& aPlace,
|
||||
bool aIsSingleVisit,
|
||||
nsresult aResult)
|
||||
: mCallback(aCallback)
|
||||
, mPlace(aPlace)
|
||||
, mResult(aResult)
|
||||
, mIsSingleVisit(aIsSingleVisit)
|
||||
{
|
||||
NS_PRECONDITION(aCallback, "Must pass a non-null callback!");
|
||||
MOZ_ASSERT(aCallback, "Must pass a non-null callback!");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
|
||||
nsCOMPtr<nsIURI> referrerURI;
|
||||
if (!mPlace.referrerSpec.IsEmpty()) {
|
||||
(void)NS_NewURI(getter_AddRefs(referrerURI), mPlace.referrerSpec);
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIVisitInfo> visit =
|
||||
new VisitInfo(mPlace.visitId, mPlace.visitTime, mPlace.transitionType,
|
||||
referrerURI.forget());
|
||||
PlaceInfo::VisitsArray visits;
|
||||
(void)visits.AppendElement(visit);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
(void)NS_NewURI(getter_AddRefs(uri), mPlace.spec);
|
||||
|
||||
// We do not notify about the frecency of the place.
|
||||
nsCOMPtr<mozIPlaceInfo> place =
|
||||
new PlaceInfo(mPlace.placeId, mPlace.guid, uri.forget(), mPlace.title,
|
||||
-1, visits);
|
||||
nsCOMPtr<mozIPlaceInfo> place;
|
||||
if (mIsSingleVisit) {
|
||||
nsCOMPtr<mozIVisitInfo> visit =
|
||||
new VisitInfo(mPlace.visitId, mPlace.visitTime, mPlace.transitionType,
|
||||
referrerURI.forget());
|
||||
PlaceInfo::VisitsArray visits;
|
||||
(void)visits.AppendElement(visit);
|
||||
|
||||
// The frecency isn't exposed because it may not reflect the updated value
|
||||
// in the case of InsertVisitedURIs.
|
||||
place =
|
||||
new PlaceInfo(mPlace.placeId, mPlace.guid, uri.forget(), mPlace.title,
|
||||
-1, visits);
|
||||
}
|
||||
else {
|
||||
// Same as above.
|
||||
place =
|
||||
new PlaceInfo(mPlace.placeId, mPlace.guid, uri.forget(), mPlace.title,
|
||||
-1);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(mResult)) {
|
||||
(void)mCallback->HandleResult(place);
|
||||
}
|
||||
@ -638,6 +723,7 @@ private:
|
||||
mozIVisitInfoCallback* mCallback;
|
||||
VisitData mPlace;
|
||||
const nsresult mResult;
|
||||
bool mIsSingleVisit;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -649,7 +735,7 @@ public:
|
||||
NotifyCompletion(mozIVisitInfoCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
{
|
||||
NS_PRECONDITION(aCallback, "Must pass a non-null callback!");
|
||||
MOZ_ASSERT(aCallback, "Must pass a non-null callback!");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
@ -706,7 +792,7 @@ CanAddURI(nsIURI* aURI,
|
||||
|
||||
// We cannot add the URI. Notify the callback, if we were given one.
|
||||
if (aCallback) {
|
||||
// NotifyVisitInfoCallback does not hold a strong reference to the callback, so we
|
||||
// NotifyPlaceInfoCallback does not hold a strong reference to the callback, so we
|
||||
// have to manage it by AddRefing now and then releasing it after the event
|
||||
// has run.
|
||||
NS_ADDREF(aCallback);
|
||||
@ -714,11 +800,11 @@ CanAddURI(nsIURI* aURI,
|
||||
VisitData place(aURI);
|
||||
place.guid = aGUID;
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyVisitInfoCallback(aCallback, place, NS_ERROR_INVALID_ARG);
|
||||
new NotifyPlaceInfoCallback(aCallback, place, true, NS_ERROR_INVALID_ARG);
|
||||
(void)NS_DispatchToMainThread(event);
|
||||
|
||||
// Also dispatch an event to release our reference to the callback after
|
||||
// NotifyVisitInfoCallback has run.
|
||||
// NotifyPlaceInfoCallback has run.
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
(void)NS_ProxyRelease(mainThread, aCallback, true);
|
||||
}
|
||||
@ -746,9 +832,8 @@ public:
|
||||
nsTArray<VisitData>& aPlaces,
|
||||
mozIVisitInfoCallback* aCallback = NULL)
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
NS_PRECONDITION(aPlaces.Length() > 0, "Must pass a non-empty array!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
MOZ_ASSERT(aPlaces.Length() > 0, "Must pass a non-empty array!");
|
||||
|
||||
nsRefPtr<InsertVisitedURIs> event =
|
||||
new InsertVisitedURIs(aConnection, aPlaces, aCallback);
|
||||
@ -764,8 +849,7 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_PRECONDITION(!NS_IsMainThread(),
|
||||
"This should not be called on the main thread");
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "This should not be called on the main thread");
|
||||
|
||||
// Prevent the main thread from shutting down while this is running.
|
||||
MutexAutoLock lockedScope(mHistory->GetShutdownMutex());
|
||||
@ -784,15 +868,22 @@ public:
|
||||
|
||||
// We can avoid a database lookup if it's the same place as the last
|
||||
// visit we added.
|
||||
bool known = (lastPlace && lastPlace->IsSamePlaceAs(place)) ||
|
||||
mHistory->FetchPageInfo(place);
|
||||
bool known = lastPlace && lastPlace->IsSamePlaceAs(place);
|
||||
if (!known) {
|
||||
nsresult rv = mHistory->FetchPageInfo(place, &known);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
|
||||
return NS_DispatchToMainThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
FetchReferrerInfo(referrer, place);
|
||||
|
||||
nsresult rv = DoDatabaseInserts(known, place, referrer);
|
||||
if (mCallback) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyVisitInfoCallback(mCallback, place, rv);
|
||||
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
|
||||
nsresult rv2 = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv2, rv2);
|
||||
}
|
||||
@ -825,8 +916,7 @@ private:
|
||||
, mCallback(aCallback)
|
||||
, mHistory(History::GetService())
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
|
||||
(void)mPlaces.SwapElements(aPlaces);
|
||||
(void)mReferrers.SetLength(mPlaces.Length());
|
||||
@ -844,9 +934,6 @@ private:
|
||||
"Passed a VisitData with a URI we cannot add to history!");
|
||||
#endif
|
||||
}
|
||||
|
||||
// We AddRef on the main thread, and release it when we are destroyed.
|
||||
NS_IF_ADDREF(mCallback);
|
||||
}
|
||||
|
||||
virtual ~InsertVisitedURIs()
|
||||
@ -873,8 +960,7 @@ private:
|
||||
VisitData& aPlace,
|
||||
VisitData& aReferrer)
|
||||
{
|
||||
NS_PRECONDITION(!NS_IsMainThread(),
|
||||
"This should not be called on the main thread");
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "This should not be called on the main thread");
|
||||
|
||||
// If the page was in moz_places, we need to update the entry.
|
||||
nsresult rv;
|
||||
@ -891,7 +977,10 @@ private:
|
||||
// have a callback or when the GUID isn't known. No point in doing the
|
||||
// disk I/O if we do not need it.
|
||||
if (mCallback || aPlace.guid.IsEmpty()) {
|
||||
bool exists = mHistory->FetchPageInfo(aPlace);
|
||||
bool exists;
|
||||
rv = mHistory->FetchPageInfo(aPlace, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!exists) {
|
||||
NS_NOTREACHED("should have an entry in moz_places");
|
||||
}
|
||||
@ -1145,12 +1234,7 @@ private:
|
||||
nsTArray<VisitData> mPlaces;
|
||||
nsTArray<VisitData> mReferrers;
|
||||
|
||||
/**
|
||||
* We own a strong reference to this, but in an indirect way. We call AddRef
|
||||
* in our constructor, which happens on the main thread, and proxy the relase
|
||||
* of the object to the main thread in our destructor.
|
||||
*/
|
||||
mozIVisitInfoCallback* mCallback;
|
||||
nsCOMPtr<mozIVisitInfoCallback> mCallback;
|
||||
|
||||
/**
|
||||
* Strong reference to the History object because we do not want it to
|
||||
@ -1159,6 +1243,69 @@ private:
|
||||
nsRefPtr<History> mHistory;
|
||||
};
|
||||
|
||||
class GetPlaceInfo MOZ_FINAL : public nsRunnable {
|
||||
public:
|
||||
/**
|
||||
* Get the place info for a given place (by GUID or URI) asynchronously.
|
||||
*/
|
||||
static nsresult Start(mozIStorageConnection* aConnection,
|
||||
VisitData& aPlace,
|
||||
mozIVisitInfoCallback* aCallback) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
|
||||
nsRefPtr<GetPlaceInfo> event = new GetPlaceInfo(aPlace, aCallback);
|
||||
|
||||
// Get the target thread, and then start the work!
|
||||
nsCOMPtr<nsIEventTarget> target = do_GetInterface(aConnection);
|
||||
NS_ENSURE_TRUE(target, NS_ERROR_UNEXPECTED);
|
||||
nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "This should not be called on the main thread");
|
||||
|
||||
bool exists;
|
||||
nsresult rv = mHistory->FetchPageInfo(mPlace, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!exists)
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyPlaceInfoCallback(mCallback, mPlace, false, rv);
|
||||
|
||||
rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
GetPlaceInfo(VisitData& aPlace,
|
||||
mozIVisitInfoCallback* aCallback)
|
||||
: mPlace(aPlace)
|
||||
, mCallback(aCallback)
|
||||
, mHistory(History::GetService())
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
}
|
||||
|
||||
virtual ~GetPlaceInfo()
|
||||
{
|
||||
if (mCallback) {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
(void)NS_ProxyRelease(mainThread, mCallback, true);
|
||||
}
|
||||
}
|
||||
|
||||
VisitData mPlace;
|
||||
nsCOMPtr<mozIVisitInfoCallback> mCallback;
|
||||
nsRefPtr<History> mHistory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the page title for a page in moz_places (if necessary).
|
||||
*/
|
||||
@ -1179,9 +1326,8 @@ public:
|
||||
nsIURI* aURI,
|
||||
const nsAString& aTitle)
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(),
|
||||
"This should be called on the main thread");
|
||||
NS_PRECONDITION(aURI, "Must pass a non-null URI object!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
|
||||
MOZ_ASSERT(aURI, "Must pass a non-null URI object!");
|
||||
|
||||
nsCString spec;
|
||||
nsresult rv = aURI->GetSpec(spec);
|
||||
@ -1200,11 +1346,13 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_PRECONDITION(!NS_IsMainThread(),
|
||||
"This should not be called on the main thread");
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "This should not be called on the main thread");
|
||||
|
||||
// First, see if the page exists in the database (we'll need its id later).
|
||||
bool exists = mHistory->FetchPageInfo(mPlace);
|
||||
bool exists;
|
||||
nsresult rv = mHistory->FetchPageInfo(mPlace, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!exists || !mPlace.titleChanged) {
|
||||
// We have no record of this page, or we have no title change, so there
|
||||
// is no need to do any further work.
|
||||
@ -1225,8 +1373,7 @@ public:
|
||||
|
||||
{
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"),
|
||||
mPlace.placeId);
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), mPlace.placeId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Empty strings should clear the title, just like
|
||||
// nsNavHistory::SetPageTitle.
|
||||
@ -1244,7 +1391,7 @@ public:
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyTitleObservers(mPlace.spec, mPlace.title, mPlace.guid);
|
||||
nsresult rv = NS_DispatchToMainThread(event);
|
||||
rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -1716,9 +1863,9 @@ void
|
||||
StoreAndNotifyEmbedVisit(VisitData& aPlace,
|
||||
mozIVisitInfoCallback* aCallback = NULL)
|
||||
{
|
||||
NS_PRECONDITION(aPlace.transitionType == nsINavHistoryService::TRANSITION_EMBED,
|
||||
"Must only pass TRANSITION_EMBED visits to this!");
|
||||
NS_PRECONDITION(NS_IsMainThread(), "Must be called on the main thread!");
|
||||
MOZ_ASSERT(aPlace.transitionType == nsINavHistoryService::TRANSITION_EMBED,
|
||||
"Must only pass TRANSITION_EMBED visits to this!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread!");
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
(void)NS_NewURI(getter_AddRefs(uri), aPlace.spec);
|
||||
@ -1731,16 +1878,16 @@ StoreAndNotifyEmbedVisit(VisitData& aPlace,
|
||||
navHistory->registerEmbedVisit(uri, aPlace.visitTime);
|
||||
|
||||
if (aCallback) {
|
||||
// NotifyVisitInfoCallback does not hold a strong reference to the callback,
|
||||
// NotifyPlaceInfoCallback does not hold a strong reference to the callback,
|
||||
// so we have to manage it by AddRefing now and then releasing it after the
|
||||
// event has run.
|
||||
NS_ADDREF(aCallback);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyVisitInfoCallback(aCallback, aPlace, NS_OK);
|
||||
new NotifyPlaceInfoCallback(aCallback, aPlace, true, NS_OK);
|
||||
(void)NS_DispatchToMainThread(event);
|
||||
|
||||
// Also dispatch an event to release our reference to the callback after
|
||||
// NotifyVisitInfoCallback has run.
|
||||
// NotifyPlaceInfoCallback has run.
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
(void)NS_ProxyRelease(mainThread, aCallback, true);
|
||||
}
|
||||
@ -1972,37 +2119,65 @@ History::UpdatePlace(const VisitData& aPlace)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
History::FetchPageInfo(VisitData& _place)
|
||||
nsresult
|
||||
History::FetchPageInfo(VisitData& _place, bool* _exists)
|
||||
{
|
||||
NS_PRECONDITION(!_place.spec.IsEmpty(), "must have a non-empty spec!");
|
||||
NS_PRECONDITION(!_place.spec.IsEmpty() || !_place.guid.IsEmpty(), "must have either a non-empty spec or guid!");
|
||||
NS_PRECONDITION(!NS_IsMainThread(), "must be called off of the main thread!");
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
|
||||
"SELECT id, title, hidden, typed, guid "
|
||||
nsresult rv;
|
||||
|
||||
// URI takes precedence.
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
bool selectByURI = !_place.spec.IsEmpty();
|
||||
if (selectByURI) {
|
||||
stmt = GetStatement(
|
||||
"SELECT guid, id, title, hidden, typed, frecency "
|
||||
"FROM moz_places "
|
||||
"WHERE url = :page_url "
|
||||
);
|
||||
NS_ENSURE_TRUE(stmt, false);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
|
||||
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
|
||||
_place.spec);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
bool hasResult;
|
||||
rv = stmt->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
if (!hasResult) {
|
||||
return false;
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), _place.spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
stmt = GetStatement(
|
||||
"SELECT url, id, title, hidden, typed, frecency "
|
||||
"FROM moz_places "
|
||||
"WHERE guid = :guid "
|
||||
);
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), _place.guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = stmt->GetInt64(0, &_place.placeId);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_TRUE(stmt, rv);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
|
||||
rv = stmt->ExecuteStep(_exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!*_exists) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (selectByURI) {
|
||||
if (_place.guid.IsEmpty()) {
|
||||
rv = stmt->GetUTF8String(0, _place.guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsAutoCString spec;
|
||||
rv = stmt->GetUTF8String(0, spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.spec = spec;
|
||||
}
|
||||
|
||||
rv = stmt->GetInt64(1, &_place.placeId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString title;
|
||||
rv = stmt->GetString(1, title);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
rv = stmt->GetString(2, title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If the title we were given was void, that means we did not bother to set
|
||||
// it to anything. As a result, ignore the fact that we may have changed the
|
||||
@ -2022,26 +2197,23 @@ History::FetchPageInfo(VisitData& _place)
|
||||
// Any one visible transition makes this location visible. If database
|
||||
// has location as visible, reflect that in our data structure.
|
||||
int32_t hidden;
|
||||
rv = stmt->GetInt32(2, &hidden);
|
||||
rv = stmt->GetInt32(3, &hidden);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.hidden = !!hidden;
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
}
|
||||
|
||||
if (!_place.typed) {
|
||||
// If this transition wasn't typed, others might have been. If database
|
||||
// has location as typed, reflect that in our data structure.
|
||||
int32_t typed;
|
||||
rv = stmt->GetInt32(3, &typed);
|
||||
rv = stmt->GetInt32(4, &typed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
_place.typed = !!typed;
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
}
|
||||
|
||||
if (_place.guid.IsVoid()) {
|
||||
rv = stmt->GetUTF8String(4, _place.guid);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
rv = stmt->GetInt32(5, &_place.frecency);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
@ -2500,6 +2672,74 @@ History::RemoveAllDownloads()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIAsyncHistory
|
||||
|
||||
NS_IMETHODIMP
|
||||
History::GetPlacesInfo(const JS::Value& aPlaceIdentifiers,
|
||||
mozIVisitInfoCallback* aCallback,
|
||||
JSContext* aCtx) {
|
||||
nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
|
||||
NS_ABORT_IF_FALSE(navHistory, "Could not get nsNavHistory?!");
|
||||
|
||||
uint32_t placesIndentifiersLength;
|
||||
JS::Rooted<JSObject*> placesIndentifiers(aCtx);
|
||||
nsresult rv = GetJSArrayFromJSValue(aPlaceIdentifiers, aCtx,
|
||||
placesIndentifiers.address(),
|
||||
&placesIndentifiersLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsTArray<VisitData> placesInfo;
|
||||
placesInfo.SetCapacity(placesIndentifiersLength);
|
||||
for (uint32_t i = 0; i < placesIndentifiersLength; i++) {
|
||||
JS::Value placeIdentifier;
|
||||
JSBool rc = JS_GetElement(aCtx, placesIndentifiers, i, &placeIdentifier);
|
||||
NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// GUID
|
||||
nsAutoString fatGUID;
|
||||
GetJSValueAsString(aCtx, placeIdentifier, fatGUID);
|
||||
if (!fatGUID.IsVoid()) {
|
||||
NS_ConvertUTF16toUTF8 guid(fatGUID);
|
||||
if (!IsValidGUID(guid))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
VisitData& placeInfo = *placesInfo.AppendElement(VisitData());
|
||||
placeInfo.guid = guid;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIURI> uri = GetJSValueAsURI(aCtx, placeIdentifier);
|
||||
if (!uri)
|
||||
return NS_ERROR_INVALID_ARG; // neither a guid, nor a uri.
|
||||
*placesInfo.AppendElement(VisitData(uri));
|
||||
}
|
||||
}
|
||||
|
||||
mozIStorageConnection* dbConn = GetDBConn();
|
||||
NS_ENSURE_STATE(dbConn);
|
||||
|
||||
for (nsTArray<VisitData>::size_type i = 0; i < placesInfo.Length(); i++) {
|
||||
nsresult rv = GetPlaceInfo::Start(dbConn, placesInfo.ElementAt(i), aCallback);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Be sure to notify that all of our operations are complete. This
|
||||
// is dispatched to the background thread first and redirected to the
|
||||
// main thread from there to make sure that all database notifications
|
||||
// and all embed or canAddURI notifications have finished.
|
||||
if (aCallback) {
|
||||
// NotifyCompletion does not hold a strong reference to the callback,
|
||||
// so we have to manage it by AddRefing now. NotifyCompletion will
|
||||
// release it for us once it has dispatched the callback to the main
|
||||
// thread.
|
||||
NS_ADDREF(aCallback);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> backgroundThread = do_GetInterface(dbConn);
|
||||
NS_ENSURE_TRUE(backgroundThread, NS_ERROR_UNEXPECTED);
|
||||
nsCOMPtr<nsIRunnable> event = new NotifyCompletion(aCallback);
|
||||
return backgroundThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
History::UpdatePlaces(const JS::Value& aPlaceInfos,
|
||||
mozIVisitInfoCallback* aCallback,
|
||||
@ -2508,22 +2748,10 @@ History::UpdatePlaces(const JS::Value& aPlaceInfos,
|
||||
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(aPlaceInfos), NS_ERROR_INVALID_ARG);
|
||||
|
||||
uint32_t infosLength = 1;
|
||||
uint32_t infosLength;
|
||||
JS::Rooted<JSObject*> infos(aCtx);
|
||||
if (JS_IsArrayObject(aCtx, aPlaceInfos.toObjectOrNull())) {
|
||||
infos = aPlaceInfos.toObjectOrNull();
|
||||
(void)JS_GetArrayLength(aCtx, infos, &infosLength);
|
||||
NS_ENSURE_ARG(infosLength > 0);
|
||||
}
|
||||
else {
|
||||
// Build a temporary array to store this one item so the code below can
|
||||
// just loop.
|
||||
infos = JS_NewArrayObject(aCtx, 0, NULL);
|
||||
NS_ENSURE_TRUE(infos, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JSBool rc = JS_DefineElement(aCtx, infos, 0, aPlaceInfos, NULL, NULL, 0);
|
||||
NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
nsresult rv = GetJSArrayFromJSValue(aPlaceInfos, aCtx, infos.address(), &infosLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsTArray<VisitData> visitData;
|
||||
for (uint32_t i = 0; i < infosLength; i++) {
|
||||
@ -2643,7 +2871,7 @@ History::UpdatePlaces(const JS::Value& aPlaceInfos,
|
||||
nsCOMPtr<nsIEventTarget> backgroundThread = do_GetInterface(dbConn);
|
||||
NS_ENSURE_TRUE(backgroundThread, NS_ERROR_UNEXPECTED);
|
||||
nsCOMPtr<nsIRunnable> event = new NotifyCompletion(aCallback);
|
||||
(void)backgroundThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
return backgroundThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -73,9 +73,10 @@ public:
|
||||
*
|
||||
* @param _place
|
||||
* The VisitData for the place we need to know information about.
|
||||
* @return true if the page was recorded in moz_places, false otherwise.
|
||||
* @param [out] _exists
|
||||
* Whether or the page was recorded in moz_places, false otherwise.
|
||||
*/
|
||||
bool FetchPageInfo(VisitData& _place);
|
||||
nsresult FetchPageInfo(VisitData& _place, bool* _exists);
|
||||
|
||||
/**
|
||||
* Get the number of bytes of memory this History object is using,
|
||||
|
@ -15,6 +15,21 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// PlaceInfo
|
||||
|
||||
PlaceInfo::PlaceInfo(int64_t aId,
|
||||
const nsCString& aGUID,
|
||||
already_AddRefed<nsIURI> aURI,
|
||||
const nsString& aTitle,
|
||||
int64_t aFrecency)
|
||||
: mId(aId)
|
||||
, mGUID(aGUID)
|
||||
, mURI(aURI)
|
||||
, mTitle(aTitle)
|
||||
, mFrecency(aFrecency)
|
||||
, mVisitsAvailable(false)
|
||||
{
|
||||
NS_PRECONDITION(mURI, "Must provide a non-null uri!");
|
||||
}
|
||||
|
||||
PlaceInfo::PlaceInfo(int64_t aId,
|
||||
const nsCString& aGUID,
|
||||
already_AddRefed<nsIURI> aURI,
|
||||
@ -27,6 +42,7 @@ PlaceInfo::PlaceInfo(int64_t aId,
|
||||
, mTitle(aTitle)
|
||||
, mFrecency(aFrecency)
|
||||
, mVisits(aVisits)
|
||||
, mVisitsAvailable(true)
|
||||
{
|
||||
NS_PRECONDITION(mURI, "Must provide a non-null uri!");
|
||||
}
|
||||
@ -73,6 +89,14 @@ NS_IMETHODIMP
|
||||
PlaceInfo::GetVisits(JSContext* aContext,
|
||||
JS::Value* _visits)
|
||||
{
|
||||
// If the visits data was not provided, return null rather
|
||||
// than an empty array to distinguish this case from the case
|
||||
// of a place without any visit.
|
||||
if (!mVisitsAvailable) {
|
||||
*_visits = JSVAL_NULL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// TODO bug 625913 when we use this in situations that have more than one
|
||||
// visit here, we will likely want to make this cache the value.
|
||||
JS::Rooted<JSObject*> visits(aContext, JS_NewArrayObject(aContext, 0, NULL));
|
||||
|
@ -26,6 +26,8 @@ public:
|
||||
|
||||
typedef nsTArray< nsCOMPtr<mozIVisitInfo> > VisitsArray;
|
||||
|
||||
PlaceInfo(int64_t aId, const nsCString& aGUID, already_AddRefed<nsIURI> aURI,
|
||||
const nsString& aTitle, int64_t aFrecency);
|
||||
PlaceInfo(int64_t aId, const nsCString& aGUID, already_AddRefed<nsIURI> aURI,
|
||||
const nsString& aTitle, int64_t aFrecency,
|
||||
const VisitsArray& aVisits);
|
||||
@ -37,6 +39,7 @@ private:
|
||||
const nsString mTitle;
|
||||
const int64_t mFrecency;
|
||||
const VisitsArray mVisits;
|
||||
bool mVisitsAvailable;
|
||||
};
|
||||
|
||||
} // namespace places
|
||||
|
@ -1754,6 +1754,56 @@ this.PlacesUtils = {
|
||||
deferred.resolve(charset);
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Promised wrapper for mozIAsyncHistory::updatePlaces for a single place.
|
||||
*
|
||||
* @param aPlaces
|
||||
* a single mozIPlaceInfo object
|
||||
* @resolves {Promise}
|
||||
*/
|
||||
promiseUpdatePlace: function PU_promiseUpdatePlaces(aPlace) {
|
||||
let deferred = Promise.defer();
|
||||
PlacesUtils.asyncHistory.updatePlaces(aPlace, {
|
||||
_placeInfo: null,
|
||||
handleResult: function handleResult(aPlaceInfo) {
|
||||
this._placeInfo = aPlaceInfo;
|
||||
},
|
||||
handleError: function handleError(aResultCode, aPlaceInfo) {
|
||||
deferred.reject(new Components.Exception("Error", aResultCode));
|
||||
},
|
||||
handleCompletion: function() {
|
||||
deferred.resolve(this._placeInfo);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Promised wrapper for mozIAsyncHistory::getPlacesInfo for a single place.
|
||||
*
|
||||
* @param aPlaceIdentifier
|
||||
* either an nsIURI or a GUID (@see getPlacesInfo)
|
||||
* @resolves to the place info object handed to handleResult.
|
||||
*/
|
||||
promisePlaceInfo: function PU_promisePlaceInfo(aPlaceIdentifier) {
|
||||
let deferred = Promise.defer();
|
||||
PlacesUtils.asyncHistory.getPlacesInfo(aPlaceIdentifier, {
|
||||
_placeInfo: null,
|
||||
handleResult: function handleResult(aPlaceInfo) {
|
||||
this._placeInfo = aPlaceInfo;
|
||||
},
|
||||
handleError: function handleError(aResultCode, aPlaceInfo) {
|
||||
deferred.reject(new Components.Exception("Error", aResultCode));
|
||||
},
|
||||
handleCompletion: function() {
|
||||
deferred.resolve(this._placeInfo);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
@ -73,34 +73,34 @@ interface mozIPlaceInfo : nsISupports
|
||||
readonly attribute jsval visits;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared Callback interface for mozIAsyncHistory methods. The semantics
|
||||
* for each method are detailed in mozIAsyncHistory.
|
||||
*/
|
||||
[scriptable, uuid(1f266877-2859-418b-a11b-ec3ae4f4f93d)]
|
||||
interface mozIVisitInfoCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when the given mozIPlaceInfo object could not be processed.
|
||||
* Called when the given place could not be processed.
|
||||
*
|
||||
* @param aResultCode
|
||||
* nsresult indicating the failure reason.
|
||||
* @param aPlaceInfo
|
||||
* The information that was being entered into the database.
|
||||
* The information that was given to the caller for the place.
|
||||
*/
|
||||
void handleError(in nsresult aResultCode,
|
||||
in mozIPlaceInfo aPlaceInfo);
|
||||
|
||||
/**
|
||||
* Called for each visit added, title change, or guid change when passed to
|
||||
* mozIAsyncHistory::updatePlaces. If more than one operation is done for
|
||||
* a given visit, only one callback will be given (i.e. title change and
|
||||
* add visit).
|
||||
* Called for each place processed successfully.
|
||||
*
|
||||
* @param aPlaceInfo
|
||||
* The information that was being entered into the database.
|
||||
* The current info stored for the place.
|
||||
*/
|
||||
void handleResult(in mozIPlaceInfo aPlaceInfo);
|
||||
|
||||
/**
|
||||
* Called when the mozIAsyncHistory::updatePlaces has finished processing
|
||||
* all mozIPlaceInfo records.
|
||||
* Called when all records were processed.
|
||||
*/
|
||||
void handleCompletion();
|
||||
|
||||
@ -121,13 +121,43 @@ interface mozIVisitedStatusCallback : nsISupports
|
||||
in boolean aVisitedStatus);
|
||||
};
|
||||
|
||||
[scriptable, uuid(b7edc16e-9f3c-4bf5-981b-4e8000b02d89)]
|
||||
[scriptable, uuid(1643EFD2-A329-4733-A39D-17069C8D3B2D)]
|
||||
interface mozIAsyncHistory : nsISupports
|
||||
{
|
||||
/**
|
||||
* Gets the available information for the given array of places, each
|
||||
* identified by either nsIURI or places GUID (string).
|
||||
*
|
||||
* The retrieved places info objects DO NOT include the visits data (the
|
||||
* |visits| attribute is set to null).
|
||||
*
|
||||
* If a given place does not exist in the database, aCallback.handleError is
|
||||
* called for it with NS_ERROR_NOT_AVAILABLE result code.
|
||||
*
|
||||
* @param aPlaceIdentifiers
|
||||
* The place[s] for which to retrieve information, identified by either
|
||||
* a single place GUID, a single URI, or a JS array of URIs and/or GUIDs.
|
||||
* @param aCallback
|
||||
* A mozIVisitInfoCallback object which consists of callbacks to be
|
||||
* notified for successful or failed retrievals.
|
||||
* If there's no information available for a given place, aCallback
|
||||
* is called with a stub place info object, containing just the provided
|
||||
* data (GUID or URI).
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG
|
||||
* - Passing in NULL for aPlaceIdentifiers or aCallback.
|
||||
* - Not providing at least one valid GUID or URI.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void getPlacesInfo(in jsval aPlaceIdentifiers,
|
||||
in mozIVisitInfoCallback aCallback);
|
||||
|
||||
/**
|
||||
* Adds a set of visits for one or more mozIPlaceInfo objects, and updates
|
||||
* each mozIPlaceInfo's title or guid.
|
||||
*
|
||||
* aCallback.handleResult is called for each visit added.
|
||||
*
|
||||
* @param aPlaceInfo
|
||||
* The mozIPlaceInfo object[s] containing the information to store or
|
||||
* update. This can be a single object, or an array of objects.
|
||||
|
@ -1241,6 +1241,7 @@ interface nsINavHistoryService : nsISupports
|
||||
|
||||
/**
|
||||
* Gets the original title of the page.
|
||||
* @deprecated use mozIAsyncHistory.getPlacesInfo instead.
|
||||
*/
|
||||
AString getPageTitle(in nsIURI aURI);
|
||||
|
||||
|
@ -2828,6 +2828,8 @@ nsNavHistory::GetCharsetForURI(nsIURI* aURI,
|
||||
NS_IMETHODIMP
|
||||
nsNavHistory::GetPageTitle(nsIURI* aURI, nsAString& aTitle)
|
||||
{
|
||||
PLACES_WARN_DEPRECATED();
|
||||
|
||||
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
|
||||
NS_ENSURE_ARG(aURI);
|
||||
|
||||
|
116
toolkit/components/places/tests/unit/test_getPlacesInfo.js
Normal file
116
toolkit/components/places/tests/unit/test_getPlacesInfo.js
Normal file
@ -0,0 +1,116 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function promiseGetPlacesInfo(aPlacesIdentifiers) {
|
||||
let deferred = Promise.defer();
|
||||
PlacesUtils.asyncHistory.getPlacesInfo(aPlacesIdentifiers, {
|
||||
_results: [],
|
||||
_errors: [],
|
||||
|
||||
handleResult: function handleResult(aPlaceInfo) {
|
||||
this._results.push(aPlaceInfo);
|
||||
},
|
||||
handleError: function handleError(aResultCode, aPlaceInfo) {
|
||||
this._errors.push({ resultCode: aResultCode, info: aPlaceInfo });
|
||||
},
|
||||
handleCompletion: function handleCompletion() {
|
||||
deferred.resolve({ errors: this._errors, results: this._results });
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function ensurePlacesInfoObjectsAreEqual(a, b) {
|
||||
do_check_true(a.uri.equals(b.uri));
|
||||
do_check_eq(a.title, b.title);
|
||||
do_check_eq(a.guid, b.guid);
|
||||
do_check_eq(a.placeId, b.placeId);
|
||||
}
|
||||
|
||||
function test_getPlacesInfoExistentPlace() {
|
||||
let testURI = NetUtil.newURI("http://www.example.tld");
|
||||
yield promiseAddVisits(testURI);
|
||||
|
||||
let getPlacesInfoResult = yield promiseGetPlacesInfo([testURI]);
|
||||
do_check_eq(getPlacesInfoResult.results.length, 1);
|
||||
do_check_eq(getPlacesInfoResult.errors.length, 0);
|
||||
|
||||
let placeInfo = getPlacesInfoResult.results[0];
|
||||
do_check_true(placeInfo instanceof Ci.mozIPlaceInfo);
|
||||
|
||||
do_check_true(placeInfo.uri.equals(testURI));
|
||||
do_check_eq(placeInfo.title, "test visit for " + testURI.spec);
|
||||
do_check_true(placeInfo.guid.length > 0);
|
||||
do_check_eq(placeInfo.visits, null);
|
||||
}
|
||||
add_task(test_getPlacesInfoExistentPlace);
|
||||
|
||||
function test_getPlacesInfoNonExistentPlace() {
|
||||
let testURI = NetUtil.newURI("http://www.example_non_existent.tld");
|
||||
let getPlacesInfoResult = yield promiseGetPlacesInfo(testURI);
|
||||
do_check_eq(getPlacesInfoResult.results.length, 0);
|
||||
do_check_eq(getPlacesInfoResult.errors.length, 1);
|
||||
}
|
||||
add_task(test_getPlacesInfoNonExistentPlace);
|
||||
|
||||
function test_promisedHelper() {
|
||||
let (uri = NetUtil.newURI("http://www.helper_existent_example.tld")) {
|
||||
yield promiseAddVisits(uri);
|
||||
let placeInfo = yield PlacesUtils.promisePlaceInfo(uri);
|
||||
do_check_true(placeInfo instanceof Ci.mozIPlaceInfo);
|
||||
};
|
||||
|
||||
let (uri = NetUtil.newURI("http://www.helper_non_existent_example.tld")) {
|
||||
try {
|
||||
let placeInfo = yield PlacesUtils.promisePlaceInfo(uri);
|
||||
do_throw("PlacesUtils.promisePlaceInfo should have rejected the promise");
|
||||
}
|
||||
catch(ex) { }
|
||||
};
|
||||
}
|
||||
add_task(test_promisedHelper);
|
||||
|
||||
function test_infoByGUID() {
|
||||
let testURI = NetUtil.newURI("http://www.guid_example.tld");
|
||||
yield promiseAddVisits(testURI);
|
||||
|
||||
let placeInfoByURI = yield PlacesUtils.promisePlaceInfo(testURI);
|
||||
let placeInfoByGUID = yield PlacesUtils.promisePlaceInfo(placeInfoByURI.guid);
|
||||
ensurePlacesInfoObjectsAreEqual(placeInfoByURI, placeInfoByGUID);
|
||||
}
|
||||
add_task(test_infoByGUID);
|
||||
|
||||
function test_invalid_guid() {
|
||||
try {
|
||||
let placeInfoByGUID = yield PlacesUtils.promisePlaceInfo("###");
|
||||
do_throw("getPlacesInfo should fail for invalid guids")
|
||||
}
|
||||
catch(ex) { }
|
||||
}
|
||||
add_task(test_invalid_guid);
|
||||
|
||||
function test_mixed_selection() {
|
||||
let placeInfo1, placeInfo2;
|
||||
let (uri = NetUtil.newURI("http://www.mixed_selection_test_1.tld")) {
|
||||
yield promiseAddVisits(uri);
|
||||
placeInfo1 = yield PlacesUtils.promisePlaceInfo(uri);
|
||||
};
|
||||
|
||||
let (uri = NetUtil.newURI("http://www.mixed_selection_test_2.tld")) {
|
||||
yield promiseAddVisits(uri);
|
||||
placeInfo2 = yield PlacesUtils.promisePlaceInfo(uri);
|
||||
};
|
||||
|
||||
let getPlacesInfoResult = yield promiseGetPlacesInfo([placeInfo1.uri, placeInfo2.guid]);
|
||||
do_check_eq(getPlacesInfoResult.results.length, 2);
|
||||
do_check_eq(getPlacesInfoResult.errors.length, 0);
|
||||
|
||||
do_check_eq(getPlacesInfoResult.results[0].uri.spec, placeInfo1.uri.spec);
|
||||
do_check_eq(getPlacesInfoResult.results[1].guid, placeInfo2.guid);
|
||||
}
|
||||
add_task(test_mixed_selection);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
@ -123,3 +123,4 @@ skip-if = os == "android"
|
||||
[test_PlacesUtils_lazyobservers.js]
|
||||
[test_placesTxn.js]
|
||||
[test_telemetry.js]
|
||||
[test_getPlacesInfo.js]
|
||||
|
Loading…
Reference in New Issue
Block a user