tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsGNOMEShellSearchProvider.cpp (19233B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:expandtab:shiftwidth=2:tabstop=2:
      3 */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "nsGNOMEShellSearchProvider.h"
      9 
     10 #include "nsToolkitCompsCID.h"
     11 #include "base/message_loop.h"  // for MessageLoop
     12 #include "base/task.h"          // for NewRunnableMethod, etc
     13 #include "mozilla/gfx/2D.h"
     14 #include "nsComponentManagerUtils.h"
     15 #include "nsIIOService.h"
     16 #include "nsIURI.h"
     17 #include "nsNetCID.h"
     18 #include "nsPrintfCString.h"
     19 #include "nsServiceManagerUtils.h"
     20 #include "mozilla/GUniquePtr.h"
     21 #include "nsImportModule.h"
     22 #include "nsIOpenTabsProvider.h"
     23 #include "imgIContainer.h"
     24 #include "imgITools.h"
     25 #include "mozilla/places/nsFaviconService.h"
     26 
     27 using namespace mozilla;
     28 using namespace mozilla::gfx;
     29 
     30 // Mozilla has old GIO version in build roots
     31 #define G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE GBusNameOwnerFlags(1 << 2)
     32 
     33 static const char* introspect_template =
     34    "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection "
     35    "1.0//EN\"\n"
     36    "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
     37    "<node>\n"
     38    " <interface name=\"org.gnome.Shell.SearchProvider2\">\n"
     39    "   <method name=\"GetInitialResultSet\">\n"
     40    "     <arg type=\"as\" name=\"terms\" direction=\"in\" />\n"
     41    "     <arg type=\"as\" name=\"results\" direction=\"out\" />\n"
     42    "   </method>\n"
     43    "   <method name=\"GetSubsearchResultSet\">\n"
     44    "     <arg type=\"as\" name=\"previous_results\" direction=\"in\" />\n"
     45    "     <arg type=\"as\" name=\"terms\" direction=\"in\" />\n"
     46    "     <arg type=\"as\" name=\"results\" direction=\"out\" />\n"
     47    "   </method>\n"
     48    "   <method name=\"GetResultMetas\">\n"
     49    "     <arg type=\"as\" name=\"identifiers\" direction=\"in\" />\n"
     50    "     <arg type=\"aa{sv}\" name=\"metas\" direction=\"out\" />\n"
     51    "   </method>\n"
     52    "   <method name=\"ActivateResult\">\n"
     53    "     <arg type=\"s\" name=\"identifier\" direction=\"in\" />\n"
     54    "     <arg type=\"as\" name=\"terms\" direction=\"in\" />\n"
     55    "     <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n"
     56    "   </method>\n"
     57    "   <method name=\"LaunchSearch\">\n"
     58    "     <arg type=\"as\" name=\"terms\" direction=\"in\" />\n"
     59    "     <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n"
     60    "   </method>\n"
     61    "</interface>\n"
     62    "</node>\n";
     63 
     64 // Inspired by SurfaceToPackedBGRA
     65 static UniquePtr<uint8_t[]> SurfaceToPackedRGBA(DataSourceSurface* aSurface) {
     66  IntSize size = aSurface->GetSize();
     67  CheckedInt<size_t> bufferSize =
     68      CheckedInt<size_t>(size.width * 4) * CheckedInt<size_t>(size.height);
     69  if (!bufferSize.isValid()) {
     70    return nullptr;
     71  }
     72  UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow)
     73                                       uint8_t[bufferSize.value()]);
     74  if (!imageBuffer) {
     75    return nullptr;
     76  }
     77 
     78  DataSourceSurface::MappedSurface map;
     79  if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     80    return nullptr;
     81  }
     82 
     83  // Convert BGRA to RGBA
     84  uint32_t* aSrc = (uint32_t*)map.mData;
     85  uint32_t* aDst = (uint32_t*)imageBuffer.get();
     86  for (int i = 0; i < size.width * size.height; i++, aDst++, aSrc++) {
     87    *aDst = *aSrc & 0xff00ff00;
     88    *aDst |= (*aSrc & 0xff) << 16;
     89    *aDst |= (*aSrc & 0xff0000) >> 16;
     90  }
     91 
     92  aSurface->Unmap();
     93 
     94  return imageBuffer;
     95 }
     96 
     97 static nsresult UpdateHistoryIcon(
     98    const places::FaviconPromise::ResolveOrRejectValue& aPromiseResult,
     99    const RefPtr<nsGNOMEShellHistorySearchResult>& aSearchResult,
    100    int aIconIndex, int aTimeStamp) {
    101  // This is a callback from some previous search so we don't want it
    102  if (aTimeStamp != aSearchResult->GetTimeStamp()) {
    103    return NS_ERROR_FAILURE;
    104  }
    105 
    106  nsCOMPtr<nsIFavicon> favicon =
    107      aPromiseResult.IsResolve() ? aPromiseResult.ResolveValue() : nullptr;
    108  if (!favicon) {
    109    return NS_ERROR_FAILURE;
    110  }
    111 
    112  // Get favicon content.
    113  nsTArray<uint8_t> rawData;
    114  nsresult rv = favicon->GetRawData(rawData);
    115  NS_ENSURE_SUCCESS(rv, rv);
    116  nsAutoCString mimeType;
    117  rv = favicon->GetMimeType(mimeType);
    118  NS_ENSURE_SUCCESS(rv, rv);
    119 
    120  // Decode the image from the format it was returned to us in (probably PNG)
    121  nsCOMPtr<imgIContainer> container;
    122  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
    123  rv = imgtool->DecodeImageFromBuffer(
    124      reinterpret_cast<const char*>(rawData.Elements()), rawData.Length(),
    125      mimeType, getter_AddRefs(container));
    126  NS_ENSURE_SUCCESS(rv, rv);
    127 
    128  RefPtr<SourceSurface> surface = container->GetFrame(
    129      imgIContainer::FRAME_FIRST,
    130      imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
    131 
    132  if (!surface || surface->GetFormat() != SurfaceFormat::B8G8R8A8) {
    133    return NS_ERROR_FAILURE;
    134  }
    135 
    136  // Allocate a new buffer that we own.
    137  RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
    138  UniquePtr<uint8_t[]> data = SurfaceToPackedRGBA(dataSurface);
    139  if (!data) {
    140    return NS_ERROR_OUT_OF_MEMORY;
    141  }
    142 
    143  aSearchResult->SetHistoryIcon(aTimeStamp, std::move(data),
    144                                surface->GetSize().width,
    145                                surface->GetSize().height, aIconIndex);
    146  return NS_OK;
    147 }
    148 
    149 void nsGNOMEShellSearchProvider::HandleSearchResultSet(
    150    GVariant* aParameters, GDBusMethodInvocation* aInvocation,
    151    bool aInitialSearch) {
    152  // Discard any existing search results.
    153  mSearchResult = nullptr;
    154 
    155  RefPtr<nsGNOMEShellHistorySearchResult> newSearch =
    156      new nsGNOMEShellHistorySearchResult(this, mConnection,
    157                                          mSearchResultTimeStamp);
    158  mSearchResultTimeStamp++;
    159  newSearch->SetTimeStamp(mSearchResultTimeStamp);
    160 
    161  // Send the search request over DBus. We'll get reply over DBus it will be
    162  // set to mSearchResult by nsGNOMEShellSearchProvider::SetSearchResult().
    163  DBusHandleResultSet(newSearch.forget(), aParameters, aInitialSearch,
    164                      aInvocation);
    165 }
    166 
    167 void nsGNOMEShellSearchProvider::HandleResultMetas(
    168    GVariant* aParameters, GDBusMethodInvocation* aInvocation) {
    169  if (mSearchResult) {
    170    DBusHandleResultMetas(mSearchResult, aParameters, aInvocation);
    171  }
    172 }
    173 
    174 void nsGNOMEShellSearchProvider::ActivateResult(
    175    GVariant* aParameters, GDBusMethodInvocation* aInvocation) {
    176  if (mSearchResult) {
    177    DBusActivateResult(mSearchResult, aParameters, aInvocation);
    178  }
    179 }
    180 
    181 void nsGNOMEShellSearchProvider::LaunchSearch(
    182    GVariant* aParameters, GDBusMethodInvocation* aInvocation) {
    183  if (mSearchResult) {
    184    DBusLaunchSearch(mSearchResult, aParameters, aInvocation);
    185  }
    186 }
    187 
    188 static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender,
    189                             const gchar* aObjectPath,
    190                             const gchar* aInterfaceName,
    191                             const gchar* aMethodName, GVariant* aParameters,
    192                             GDBusMethodInvocation* aInvocation,
    193                             gpointer aUserData) {
    194  MOZ_ASSERT(aUserData);
    195  MOZ_ASSERT(NS_IsMainThread());
    196 
    197  if (strcmp("org.gnome.Shell.SearchProvider2", aInterfaceName) == 0) {
    198    if (strcmp("GetInitialResultSet", aMethodName) == 0) {
    199      static_cast<nsGNOMEShellSearchProvider*>(aUserData)
    200          ->HandleSearchResultSet(aParameters, aInvocation,
    201                                  /* aInitialSearch */ true);
    202    } else if (strcmp("GetSubsearchResultSet", aMethodName) == 0) {
    203      static_cast<nsGNOMEShellSearchProvider*>(aUserData)
    204          ->HandleSearchResultSet(aParameters, aInvocation,
    205                                  /* aInitialSearch */ false);
    206    } else if (strcmp("GetResultMetas", aMethodName) == 0) {
    207      static_cast<nsGNOMEShellSearchProvider*>(aUserData)->HandleResultMetas(
    208          aParameters, aInvocation);
    209    } else if (strcmp("ActivateResult", aMethodName) == 0) {
    210      static_cast<nsGNOMEShellSearchProvider*>(aUserData)->ActivateResult(
    211          aParameters, aInvocation);
    212    } else if (strcmp("LaunchSearch", aMethodName) == 0) {
    213      static_cast<nsGNOMEShellSearchProvider*>(aUserData)->LaunchSearch(
    214          aParameters, aInvocation);
    215    } else {
    216      g_warning(
    217          "nsGNOMEShellSearchProvider: HandleMethodCall() wrong method %s",
    218          aMethodName);
    219    }
    220  }
    221 }
    222 
    223 static GVariant* HandleGetProperty(GDBusConnection* aConnection,
    224                                   const gchar* aSender,
    225                                   const gchar* aObjectPath,
    226                                   const gchar* aInterfaceName,
    227                                   const gchar* aPropertyName, GError** aError,
    228                                   gpointer aUserData) {
    229  MOZ_ASSERT(aUserData);
    230  MOZ_ASSERT(NS_IsMainThread());
    231  g_set_error(aError, G_IO_ERROR, G_IO_ERROR_FAILED,
    232              "%s:%s setting is not supported", aInterfaceName, aPropertyName);
    233  return nullptr;
    234 }
    235 
    236 static gboolean HandleSetProperty(GDBusConnection* aConnection,
    237                                  const gchar* aSender,
    238                                  const gchar* aObjectPath,
    239                                  const gchar* aInterfaceName,
    240                                  const gchar* aPropertyName, GVariant* aValue,
    241                                  GError** aError, gpointer aUserData) {
    242  MOZ_ASSERT(aUserData);
    243  MOZ_ASSERT(NS_IsMainThread());
    244  g_set_error(aError, G_IO_ERROR, G_IO_ERROR_FAILED,
    245              "%s:%s setting is not supported", aInterfaceName, aPropertyName);
    246  return false;
    247 }
    248 
    249 static const GDBusInterfaceVTable gInterfaceVTable = {
    250    HandleMethodCall, HandleGetProperty, HandleSetProperty};
    251 
    252 void nsGNOMEShellSearchProvider::OnBusAcquired(GDBusConnection* aConnection) {
    253  GUniquePtr<GError> error;
    254  mIntrospectionData = dont_AddRef(g_dbus_node_info_new_for_xml(
    255      introspect_template, getter_Transfers(error)));
    256  if (!mIntrospectionData) {
    257    g_warning(
    258        "nsGNOMEShellSearchProvider: g_dbus_node_info_new_for_xml() failed! %s",
    259        error->message);
    260    return;
    261  }
    262 
    263  mRegistrationId = g_dbus_connection_register_object(
    264      aConnection, GetDBusObjectPath(), mIntrospectionData->interfaces[0],
    265      &gInterfaceVTable, this,  /* user_data */
    266      nullptr,                  /* user_data_free_func */
    267      getter_Transfers(error)); /* GError** */
    268 
    269  if (mRegistrationId == 0) {
    270    g_warning(
    271        "nsGNOMEShellSearchProvider: g_dbus_connection_register_object() "
    272        "failed! %s",
    273        error->message);
    274    return;
    275  }
    276 }
    277 
    278 void nsGNOMEShellSearchProvider::OnNameAcquired(GDBusConnection* aConnection) {
    279  mConnection = aConnection;
    280 }
    281 
    282 void nsGNOMEShellSearchProvider::OnNameLost(GDBusConnection* aConnection) {
    283  mConnection = nullptr;
    284  if (!mRegistrationId) {
    285    return;
    286  }
    287  if (g_dbus_connection_unregister_object(aConnection, mRegistrationId)) {
    288    mRegistrationId = 0;
    289  }
    290 }
    291 
    292 nsresult nsGNOMEShellSearchProvider::Startup() {
    293  if (mDBusID) {
    294    // We're already connected so we don't need to reconnect
    295    return NS_ERROR_ALREADY_INITIALIZED;
    296  }
    297 
    298  mDBusID = g_bus_own_name(
    299      G_BUS_TYPE_SESSION, GetDBusBusName(), G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE,
    300      [](GDBusConnection* aConnection, const gchar*,
    301         gpointer aUserData) -> void {
    302        static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnBusAcquired(
    303            aConnection);
    304      },
    305      [](GDBusConnection* aConnection, const gchar*,
    306         gpointer aUserData) -> void {
    307        static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameAcquired(
    308            aConnection);
    309      },
    310      [](GDBusConnection* aConnection, const gchar*,
    311         gpointer aUserData) -> void {
    312        static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameLost(
    313            aConnection);
    314      },
    315      this, nullptr);
    316 
    317  if (!mDBusID) {
    318    g_warning("nsGNOMEShellSearchProvider: g_bus_own_name() failed!");
    319    return NS_ERROR_FAILURE;
    320  }
    321 
    322  mSearchResultTimeStamp = 0;
    323  return NS_OK;
    324 }
    325 
    326 void nsGNOMEShellSearchProvider::Shutdown() {
    327  OnNameLost(mConnection);
    328  if (mDBusID) {
    329    g_bus_unown_name(mDBusID);
    330    mDBusID = 0;
    331  }
    332  mIntrospectionData = nullptr;
    333 }
    334 
    335 bool nsGNOMEShellSearchProvider::SetSearchResult(
    336    RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) {
    337  MOZ_ASSERT(!mSearchResult);
    338 
    339  if (mSearchResultTimeStamp != aSearchResult->GetTimeStamp()) {
    340    NS_WARNING("Time stamp mismatch.");
    341    return false;
    342  }
    343  mSearchResult = aSearchResult;
    344  return true;
    345 }
    346 
    347 static void DispatchSearchResults(
    348    RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult,
    349    nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) {
    350  aSearchResult->ReceiveSearchResultContainer(aHistResultContainer);
    351 }
    352 
    353 nsresult nsGNOMEShellHistoryService::QueryHistory(
    354    RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) {
    355  if (!mHistoryService) {
    356    mHistoryService = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
    357    if (!mHistoryService) {
    358      return NS_ERROR_FAILURE;
    359    }
    360  }
    361 
    362  nsresult rv;
    363  nsCOMPtr<nsINavHistoryQuery> histQuery;
    364  rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery));
    365  NS_ENSURE_SUCCESS(rv, rv);
    366 
    367  rv = histQuery->SetSearchTerms(
    368      NS_ConvertUTF8toUTF16(aSearchResult->GetSearchTerm()));
    369  NS_ENSURE_SUCCESS(rv, rv);
    370 
    371  nsCOMPtr<nsINavHistoryQueryOptions> histQueryOpts;
    372  rv = mHistoryService->GetNewQueryOptions(getter_AddRefs(histQueryOpts));
    373  NS_ENSURE_SUCCESS(rv, rv);
    374 
    375  rv = histQueryOpts->SetSortingMode(
    376      nsINavHistoryQueryOptions::SORT_BY_FRECENCY_DESCENDING);
    377  NS_ENSURE_SUCCESS(rv, rv);
    378 
    379  rv = histQueryOpts->SetMaxResults(MAX_SEARCH_RESULTS_NUM);
    380  NS_ENSURE_SUCCESS(rv, rv);
    381 
    382  nsCOMPtr<nsINavHistoryResult> histResult;
    383  rv = mHistoryService->ExecuteQuery(histQuery, histQueryOpts,
    384                                     getter_AddRefs(histResult));
    385  NS_ENSURE_SUCCESS(rv, rv);
    386 
    387  nsCOMPtr<nsINavHistoryContainerResultNode> resultContainer;
    388 
    389  rv = histResult->GetRoot(getter_AddRefs(resultContainer));
    390  NS_ENSURE_SUCCESS(rv, rv);
    391 
    392  rv = resultContainer->SetContainerOpen(true);
    393  NS_ENSURE_SUCCESS(rv, rv);
    394 
    395  // Simulate async searching by delayed reply. This search API will
    396  // likely become async in the future and we want to be sure to not rely on
    397  // its current synchronous behavior.
    398  MOZ_ASSERT(MessageLoop::current());
    399  MessageLoop::current()->PostTask(
    400      NewRunnableFunction("Gnome shell search results", &DispatchSearchResults,
    401                          aSearchResult, resultContainer));
    402 
    403  return NS_OK;
    404 }
    405 
    406 static void DBusGetIDKeyForURI(int aIndex, bool aIsOpen, nsAutoCString& aUri,
    407                               nsAutoCString& aIDKey) {
    408  // Compose ID as NN:S:URL where NN is index to our current history
    409  // result container and S is the state, which can be 'o'pen or 'h'istory
    410  aIDKey =
    411      nsPrintfCString("%.2d:%c:%s", aIndex, aIsOpen ? 'o' : 'h', aUri.get());
    412 }
    413 
    414 // Send (as) rearch result reply
    415 void nsGNOMEShellHistorySearchResult::HandleSearchResultReply() {
    416  MOZ_ASSERT(mReply);
    417  MOZ_ASSERT(mHistResultContainer);
    418 
    419  GVariantBuilder b;
    420  g_variant_builder_init(&b, G_VARIANT_TYPE("as"));
    421 
    422  uint32_t childCount = 0;
    423  nsresult rv = mHistResultContainer->GetChildCount(&childCount);
    424  if (NS_SUCCEEDED(rv) && childCount > 0) {
    425    // Obtain the favicon service and get the favicon for the specified page
    426    auto* favIconSvc = nsFaviconService::GetFaviconService();
    427    nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
    428 
    429    if (childCount > MAX_SEARCH_RESULTS_NUM) {
    430      childCount = MAX_SEARCH_RESULTS_NUM;
    431    }
    432 
    433    for (uint32_t i = 0; i < childCount; i++) {
    434      nsCOMPtr<nsINavHistoryResultNode> child;
    435      rv = mHistResultContainer->GetChild(i, getter_AddRefs(child));
    436      if (NS_WARN_IF(NS_FAILED(rv))) {
    437        continue;
    438      }
    439      if (!IsHistoryResultNodeURI(child)) {
    440        continue;
    441      }
    442 
    443      nsAutoCString uri;
    444      child->GetUri(uri);
    445 
    446      RefPtr<nsGNOMEShellHistorySearchResult> self = this;
    447      nsCOMPtr<nsIURI> iconIri;
    448      ios->NewURI(uri, nullptr, nullptr, getter_AddRefs(iconIri));
    449      favIconSvc->AsyncGetFaviconForPage(iconIri)->Then(
    450          GetMainThreadSerialEventTarget(), __func__,
    451          [self, iconIndex = i, timeStamp = mTimeStamp](
    452              const places::FaviconPromise::ResolveOrRejectValue& aResult) {
    453            UpdateHistoryIcon(aResult, self, iconIndex, timeStamp);
    454          });
    455 
    456      bool isOpen = false;
    457      for (const auto& openuri : mOpenTabs) {
    458        if (openuri.Equals(uri)) {
    459          isOpen = true;
    460          break;
    461        }
    462      }
    463      nsAutoCString idKey;
    464      DBusGetIDKeyForURI(i, isOpen, uri, idKey);
    465 
    466      g_variant_builder_add(&b, "s", idKey.get());
    467    }
    468  }
    469 
    470  nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING,
    471                               mSearchTerm.get());
    472  g_variant_builder_add(&b, "s", searchString.get());
    473 
    474  GVariant* v = g_variant_builder_end(&b);
    475  g_dbus_method_invocation_return_value(mReply, g_variant_new_tuple(&v, 1));
    476  mReply = nullptr;
    477 }
    478 
    479 void nsGNOMEShellHistorySearchResult::ReceiveSearchResultContainer(
    480    nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) {
    481  // Propagate search results to nsGNOMEShellSearchProvider.
    482  // SetSearchResult() checks this is up-to-date search (our time stamp matches
    483  // latest requested search timestamp).
    484  if (!mSearchProvider->SetSearchResult(this)) {
    485    return;
    486  }
    487 
    488  mHistResultContainer = aHistResultContainer;
    489 
    490  // Getting the currently open tabs to mark them accordingly
    491  nsresult rv;
    492  nsCOMPtr<nsIOpenTabsProvider> provider = do_ImportESModule(
    493      "moz-src:///browser/components/shell/OpenTabsProvider.sys.mjs", &rv);
    494  if (NS_FAILED(rv)) {
    495    // Don't fail, just log an error message
    496    NS_WARNING("Failed to determine currently open tabs. Using history only.");
    497  }
    498 
    499  nsTArray<nsCString> openTabs;
    500  if (provider) {
    501    rv = provider->GetOpenTabs(openTabs);
    502    if (NS_FAILED(rv)) {
    503      // Don't fail, just log an error message
    504      NS_WARNING(
    505          "Failed to determine currently open tabs. Using history only.");
    506    }
    507  }
    508  // In case of error, we just clear out mOpenTabs with an empty new array
    509  mOpenTabs = std::move(openTabs);
    510 
    511  HandleSearchResultReply();
    512 }
    513 
    514 void nsGNOMEShellHistorySearchResult::SetHistoryIcon(int aTimeStamp,
    515                                                     UniquePtr<uint8_t[]> aData,
    516                                                     int aWidth, int aHeight,
    517                                                     int aIconIndex) {
    518  MOZ_ASSERT(mTimeStamp == aTimeStamp);
    519  MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM);
    520  mHistoryIcons[aIconIndex].Set(mTimeStamp, std::move(aData), aWidth, aHeight);
    521 }
    522 
    523 GnomeHistoryIcon* nsGNOMEShellHistorySearchResult::GetHistoryIcon(
    524    int aIconIndex) {
    525  MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM);
    526  if (mHistoryIcons[aIconIndex].GetTimeStamp() == mTimeStamp &&
    527      mHistoryIcons[aIconIndex].IsLoaded()) {
    528    return mHistoryIcons + aIconIndex;
    529  }
    530  return nullptr;
    531 }
    532 
    533 nsGNOMEShellHistoryService* GetGNOMEShellHistoryService() {
    534  static nsGNOMEShellHistoryService gGNOMEShellHistoryService;
    535  return &gGNOMEShellHistoryService;
    536 }