jgrulich / rpms / firefox

Forked from rpms/firefox 4 years ago
Clone
Blob Blame History Raw
changeset:   504680:441b26f2d4f4
parent:      504674:5a55ac856fc4
user:        Martin Stransky <stransky@redhat.com>
date:        Mon Dec 02 12:21:08 2019 +0100
files:       browser/components/shell/nsGNOMEShellSearchProvider.cpp browser/components/shell/nsGNOMEShellSearchProvider.h
description:
Bug 1239694 Use history icons with Gnome shell search provider, r?jhorak

Differential Revision: https://phabricator.services.mozilla.com/D55434


diff --git a/browser/components/shell/nsGNOMEShellSearchProvider.cpp b/browser/components/shell/nsGNOMEShellSearchProvider.cpp
--- a/browser/components/shell/nsGNOMEShellSearchProvider.cpp
+++ b/browser/components/shell/nsGNOMEShellSearchProvider.cpp
@@ -19,21 +19,27 @@
 #include "nsPrintfCString.h"
 #include "nsCOMPtr.h"
 #include "nsGTKToolkit.h"
 #include "nsINavHistoryService.h"
 #include "nsToolkitCompsCID.h"
 #include "nsIFaviconService.h"
 #include "RemoteUtils.h"
 #include "nsIStringBundle.h"
+#include "imgIContainer.h"
+#include "imgITools.h"
+
+#include "mozilla/gfx/DataSurfaceHelpers.h"
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
-#define MAX_SEARCH_RESULTS_NUM 9
+using namespace mozilla;
+using namespace mozilla::gfx;
+
 #define KEYWORD_SEARCH_STRING "special:search"
 #define KEYWORD_SEARCH_STRING_LEN 14
 
 #define DBUS_BUS_NAME "org.mozilla.Firefox.SearchProvider"
 #define DBUS_OBJECT_PATH "/org/mozilla/Firefox/SearchProvider"
 
 static const char* introspect_template =
     "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection "
@@ -81,17 +87,35 @@ DBusHandlerResult nsGNOMEShellSearchProv
                            DBUS_TYPE_INVALID);
 
   dbus_connection_send(mConnection, reply, nullptr);
   dbus_message_unref(reply);
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-nsresult nsGNOMEShellSearchProvider::QueryHistory(const char* aSearchTerm) {
+nsGNOMEShellSearchProvider::nsGNOMEShellSearchProvider()
+    : mConnection(nullptr), mSearchSerial(0) {
+  memset(mHistoryIcons, 0, sizeof(mHistoryIcons));
+}
+
+void nsGNOMEShellSearchProvider::SetHistoryIcon(int aSearchSerial,
+                                                UniquePtr<uint8_t[]> aData,
+                                                int aWidth, int aHeight,
+                                                int aIconIndex) {
+  MOZ_ASSERT(mSearchSerial == aSearchSerial);
+  MOZ_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM);
+  mHistoryIcons[aIconIndex].Set(aSearchSerial, std::move(aData), aWidth,
+                                aHeight);
+}
+
+nsresult nsGNOMEShellSearchProvider::NewHistorySearch(const char* aSearchTerm) {
+  // Initialize new search which invalidates all preview ones
+  mSearchSerial++;
+
   nsresult rv;
   nsCOMPtr<nsINavHistoryQuery> histQuery;
   rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString searchTerm(aSearchTerm);
   rv = histQuery->SetSearchTerms(NS_ConvertUTF8toUTF16(searchTerm));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -165,24 +189,123 @@ void nsGNOMEShellSearchProvider::GetIDKe
 
 int nsGNOMEShellSearchProvider::GetIndexFromIDKey(const char* aIDKey) {
   // ID is NN:URL where NN is index to our current history
   // result container.
   char tmp[] = {aIDKey[0], aIDKey[1], '\0'};
   return atoi(tmp);
 }
 
+class AsyncFaviconDataReady final : public nsIFaviconDataCallback {
+ public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIFAVICONDATACALLBACK
+
+  AsyncFaviconDataReady(nsGNOMEShellSearchProvider* aSearchProvider,
+                        int aIconIndex, int aSearchSerial)
+      : mSearchProvider(aSearchProvider),
+        mIconIndex(aIconIndex),
+        mSearchSerial(aSearchSerial){};
+
+ private:
+  ~AsyncFaviconDataReady() {}
+
+  nsGNOMEShellSearchProvider* mSearchProvider;
+  int mIconIndex;
+  int mSearchSerial;
+};
+
+NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)
+
+// Inspired by SurfaceToPackedBGRA
+static UniquePtr<uint8_t[]> SurfaceToPackedRGBA(DataSourceSurface* aSurface) {
+  IntSize size = aSurface->GetSize();
+  CheckedInt<size_t> bufferSize =
+      CheckedInt<size_t>(size.width * 4) * CheckedInt<size_t>(size.height);
+  if (!bufferSize.isValid()) {
+    return nullptr;
+  }
+  UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow)
+                                       uint8_t[bufferSize.value()]);
+  if (!imageBuffer) {
+    return nullptr;
+  }
+
+  DataSourceSurface::MappedSurface map;
+  if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+    return nullptr;
+  }
+
+  // Convert BGRA to RGBA
+  uint32_t* aSrc = (uint32_t*)map.mData;
+  uint32_t* aDst = (uint32_t*)imageBuffer.get();
+  for (int i = 0; i < size.width * size.height; i++, aDst++, aSrc++) {
+    *aDst = *aSrc & 0xff00ff00;
+    *aDst |= (*aSrc & 0xff) << 16;
+    *aDst |= (*aSrc & 0xff0000) >> 16;
+  }
+
+  aSurface->Unmap();
+
+  return imageBuffer;
+}
+
+NS_IMETHODIMP
+AsyncFaviconDataReady::OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen,
+                                  const uint8_t* aData,
+                                  const nsACString& aMimeType,
+                                  uint16_t aWidth) {
+  // This is a callback from some previous search so we don't want it
+  if (mSearchSerial != mSearchProvider->GetSearchSerial() || !aData ||
+      !aDataLen) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Decode the image from the format it was returned to us in (probably PNG)
+  nsCOMPtr<imgIContainer> container;
+  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
+  nsresult rv = imgtool->DecodeImageFromBuffer(
+      reinterpret_cast<const char*>(aData), aDataLen, aMimeType,
+      getter_AddRefs(container));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  RefPtr<SourceSurface> surface = container->GetFrame(
+      imgIContainer::FRAME_FIRST,
+      imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
+
+  if (!surface || surface->GetFormat() != SurfaceFormat::B8G8R8A8) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Allocate a new buffer that we own.
+  RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
+  UniquePtr<uint8_t[]> data = SurfaceToPackedRGBA(dataSurface);
+  if (!data) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  mSearchProvider->SetHistoryIcon(mSearchSerial, std::move(data),
+                                  surface->GetSize().width,
+                                  surface->GetSize().height, mIconIndex);
+  return NS_OK;
+}
+
 void nsGNOMEShellSearchProvider::ComposeSearchResultReply(
     DBusMessage* reply, const char* aSearchTerm) {
   uint32_t childCount = 0;
   nsresult rv = mHistResultContainer->GetChildCount(&childCount);
   if (NS_FAILED(rv) || childCount == 0) {
     return;
   }
 
+  // Obtain the favicon service and get the favicon for the specified page
+  nsCOMPtr<nsIFaviconService> favIconSvc(
+      do_GetService("@mozilla.org/browser/favicon-service;1"));
+  nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
+
   if (childCount > MAX_SEARCH_RESULTS_NUM) {
     childCount = MAX_SEARCH_RESULTS_NUM;
   }
 
   DBusMessageIter iter;
   dbus_message_iter_init_append(reply, &iter);
   DBusMessageIter iterArray;
   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iterArray);
@@ -195,16 +318,22 @@ void nsGNOMEShellSearchProvider::Compose
     }
     if (!IsHistoryResultNodeURI(child)) {
       continue;
     }
 
     nsAutoCString uri;
     child->GetUri(uri);
 
+    nsCOMPtr<nsIURI> iconIri;
+    ios->NewURI(uri, nullptr, nullptr, getter_AddRefs(iconIri));
+    nsCOMPtr<nsIFaviconDataCallback> callback =
+        new AsyncFaviconDataReady(this, i, mSearchSerial);
+    favIconSvc->GetFaviconDataForPage(iconIri, callback, 0);
+
     nsAutoCString idKey;
     GetIDKeyForURI(i, uri, idKey);
 
     const char* id = idKey.get();
     dbus_message_iter_append_basic(&iterArray, DBUS_TYPE_STRING, &id);
   }
 
   nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING, aSearchTerm);
@@ -221,17 +350,17 @@ DBusHandlerResult nsGNOMEShellSearchProv
   int elements;
 
   if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
                              &stringArray, &elements, DBUS_TYPE_INVALID) ||
       elements == 0) {
     reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument");
   } else {
     reply = dbus_message_new_method_return(aMsg);
-    nsresult rv = QueryHistory(stringArray[0]);
+    nsresult rv = NewHistorySearch(stringArray[0]);
     if (NS_SUCCEEDED(rv)) {
       ComposeSearchResultReply(reply, stringArray[0]);
     }
     dbus_free_string_array(stringArray);
   }
 
   dbus_connection_send(mConnection, reply, nullptr);
   dbus_message_unref(reply);
@@ -249,17 +378,17 @@ DBusHandlerResult nsGNOMEShellSearchProv
   if (!dbus_message_get_args(aMsg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
                              &unusedArray, &unusedNum, DBUS_TYPE_ARRAY,
                              DBUS_TYPE_STRING, &stringArray, &elements,
                              DBUS_TYPE_INVALID) ||
       elements == 0) {
     reply = dbus_message_new_error(aMsg, DBUS_BUS_NAME, "Wrong argument");
   } else {
     reply = dbus_message_new_method_return(aMsg);
-    nsresult rv = QueryHistory(stringArray[0]);
+    nsresult rv = NewHistorySearch(stringArray[0]);
     if (NS_SUCCEEDED(rv)) {
       ComposeSearchResultReply(reply, stringArray[0]);
     }
   }
 
   if (unusedArray) {
     dbus_free_string_array(unusedArray);
   }
@@ -280,45 +409,88 @@ static void appendStringDictionary(DBusM
                                    &iterDict);
   dbus_message_iter_append_basic(&iterDict, DBUS_TYPE_STRING, &aKey);
   dbus_message_iter_open_container(&iterDict, DBUS_TYPE_VARIANT, "s", &iterVar);
   dbus_message_iter_append_basic(&iterVar, DBUS_TYPE_STRING, &aValue);
   dbus_message_iter_close_container(&iterDict, &iterVar);
   dbus_message_iter_close_container(aIter, &iterDict);
 }
 
+/*
+  "icon-data": a tuple of type (iiibiiay) describing a pixbuf with width,
+              height, rowstride, has-alpha,
+              bits-per-sample, channels,
+              image data
+*/
+void GnomeHistoryIcon::AppendIcon(DBusMessageIter* aIter) {
+  DBusMessageIter iterDict, iterVar, iterStruct;
+  dbus_message_iter_open_container(aIter, DBUS_TYPE_DICT_ENTRY, nullptr,
+                                   &iterDict);
+  const char* key = "icon-data";
+  dbus_message_iter_append_basic(&iterDict, DBUS_TYPE_STRING, &key);
+  dbus_message_iter_open_container(&iterDict, DBUS_TYPE_VARIANT, "(iiibiiay)",
+                                   &iterVar);
+  dbus_message_iter_open_container(&iterVar, DBUS_TYPE_STRUCT, nullptr,
+                                   &iterStruct);
+
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_INT32, &mWidth);
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_INT32, &mHeight);
+  int rowstride = mWidth * 4;
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_INT32, &rowstride);
+  int hasAlpha = true;
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_BOOLEAN, &hasAlpha);
+  int bitsPerSample = 8;
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_INT32, &bitsPerSample);
+  int channels = 4;
+  dbus_message_iter_append_basic(&iterStruct, DBUS_TYPE_INT32, &channels);
+
+  DBusMessageIter iterArray;
+  dbus_message_iter_open_container(&iterStruct, DBUS_TYPE_ARRAY, "y",
+                                   &iterArray);
+  unsigned char* array = mData.get();
+  dbus_message_iter_append_fixed_array(&iterArray, DBUS_TYPE_BYTE, &array,
+                                       mWidth * mHeight * 4);
+  dbus_message_iter_close_container(&iterStruct, &iterArray);
+
+  dbus_message_iter_close_container(&iterVar, &iterStruct);
+  dbus_message_iter_close_container(&iterDict, &iterVar);
+  dbus_message_iter_close_container(aIter, &iterDict);
+}
+
 /* We can return those fields at GetResultMetas:
   "id": the result ID
   "name": the display name for the result
   "icon": a serialized GIcon (see g_icon_serialize()), or alternatively,
   "gicon": a textual representation of a GIcon (see g_icon_to_string()),
            or alternativly,
   "icon-data": a tuple of type (iiibiiay) describing a pixbuf with width,
               height, rowstride, has-alpha, bits-per-sample, and image data
   "description": an optional short description (1-2 lines)
 */
 void nsGNOMEShellSearchProvider::AppendResultID(DBusMessageIter* aIter,
                                                 const char* aID) {
+  int index = GetIndexFromIDKey(aID);
   nsCOMPtr<nsINavHistoryResultNode> child;
-  mHistResultContainer->GetChild(GetIndexFromIDKey(aID), getter_AddRefs(child));
+  mHistResultContainer->GetChild(index, getter_AddRefs(child));
   nsAutoCString title;
-  if (NS_FAILED(child->GetTitle(title))) {
-    return;
-  }
+  nsAutoCString uri;
+  child->GetTitle(title);
+  child->GetUri(uri);
 
-  if (title.IsEmpty()) {
-    if (NS_FAILED(child->GetUri(title)) || title.IsEmpty()) {
-      return;
-    }
-  }
+  const char* titleStr = !(title.IsEmpty()) ? title.get() : uri.get();
+  const char* descStr = uri.get();
 
-  const char* titleStr = title.get();
   appendStringDictionary(aIter, "id", aID);
   appendStringDictionary(aIter, "name", titleStr);
-  appendStringDictionary(aIter, "gicon", "text-html");
+  appendStringDictionary(aIter, "description", descStr);
+  if (mHistoryIcons[index].GetSearchSerial() == mSearchSerial) {
+    mHistoryIcons[index].AppendIcon(aIter);
+  } else {
+    appendStringDictionary(aIter, "gicon", "text-html");
+  }
 }
 
 void nsGNOMEShellSearchProvider::AppendSearchID(DBusMessageIter* aIter,
                                                 const char* aID) {
   if (strlen(aID) < KEYWORD_SEARCH_STRING_LEN + 2) {
     return;
   }
   appendStringDictionary(aIter, "id", KEYWORD_SEARCH_STRING);
diff --git a/browser/components/shell/nsGNOMEShellSearchProvider.h b/browser/components/shell/nsGNOMEShellSearchProvider.h
--- a/browser/components/shell/nsGNOMEShellSearchProvider.h
+++ b/browser/components/shell/nsGNOMEShellSearchProvider.h
@@ -7,49 +7,81 @@
 
 #ifndef __nsGNOMEShellSearchProvider_h__
 #define __nsGNOMEShellSearchProvider_h__
 
 #include "mozilla/DBusHelpers.h"
 #include "nsINavHistoryService.h"
 #include "nsUnixRemoteServer.h"
 #include "nsCOMPtr.h"
+#include "mozilla/UniquePtr.h"
+
+#define MAX_SEARCH_RESULTS_NUM 9
+
+class GnomeHistoryIcon {
+ public:
+  GnomeHistoryIcon() : mSearchSerial(-1), mWidth(0), mHeight(0){};
+
+  // From which search is this icon
+  void Set(int aSearchSerial, mozilla::UniquePtr<uint8_t[]> aData, int aWidth,
+           int aHeight) {
+    mSearchSerial = aSearchSerial;
+    mWidth = aWidth;
+    mHeight = aHeight;
+    mData = std::move(aData);
+  }
+
+  int GetSearchSerial() { return mSearchSerial; }
+  void AppendIcon(DBusMessageIter* aIter);
+
+ private:
+  int mSearchSerial;
+  mozilla::UniquePtr<uint8_t[]> mData;
+  int mWidth;
+  int mHeight;
+};
 
 class nsGNOMEShellSearchProvider : public nsUnixRemoteServer {
  public:
-  nsGNOMEShellSearchProvider() : mConnection(nullptr) {}
+  nsGNOMEShellSearchProvider();
   ~nsGNOMEShellSearchProvider() { Shutdown(); }
 
   nsresult Startup();
   void Shutdown();
 
   DBusHandlerResult HandleDBusMessage(DBusConnection* aConnection,
                                       DBusMessage* msg);
   void UnregisterDBusInterface(DBusConnection* aConnection);
 
+  int GetSearchSerial() { return mSearchSerial; }
+  void SetHistoryIcon(int aSearchSerial, mozilla::UniquePtr<uint8_t[]> aData,
+                      int aWidth, int aHeight, int aIconIndex);
+
  private:
   DBusHandlerResult Introspect(DBusMessage* msg);
 
   DBusHandlerResult GetInitialResultSet(DBusMessage* msg);
   DBusHandlerResult GetSubsearchResultSet(DBusMessage* msg);
   DBusHandlerResult GetResultMetas(DBusMessage* msg);
   DBusHandlerResult ActivateResult(DBusMessage* msg);
   DBusHandlerResult LaunchSearch(DBusMessage* msg);
 
-  nsresult QueryHistory(const char* aSearchTerm);
+  nsresult NewHistorySearch(const char* aSearchTerm);
   void GetIDKeyForURI(int aIndex, nsAutoCString& aUri, nsAutoCString& aIDKey);
   int GetIndexFromIDKey(const char* aIDKey);
   bool IsHistoryResultNodeURI(nsINavHistoryResultNode* aHistoryNode);
   void AppendResultID(DBusMessageIter* aIter, const char* aID);
   void AppendSearchID(DBusMessageIter* aIter, const char* aID);
   void ComposeSearchResultReply(DBusMessage* aReply, const char* aSearchTerm);
   void LaunchWithID(const char* aID, uint32_t aTimeStamp);
   void LaunchWithAllResults(uint32_t aTimeStamp);
 
   // The connection is owned by DBus library
   RefPtr<DBusConnection> mConnection;
   nsCOMPtr<nsINavHistoryContainerResultNode> mHistResultContainer;
   nsCOMPtr<nsINavHistoryService> mHistoryService;
   nsAutoCStringN<32> mSearchTerm;
   nsAutoCString mGnomeSearchTitle;
+  int mSearchSerial;
+  GnomeHistoryIcon mHistoryIcons[MAX_SEARCH_RESULTS_NUM];
 };
 
 #endif  // __nsGNOMEShellSearchProvider_h__