1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #pragma once
8 
9 #include "nsIFaviconService.h"
10 #include "nsIChannelEventSink.h"
11 #include "nsIInterfaceRequestor.h"
12 #include "nsIStreamListener.h"
13 #include "mozIPlacesPendingOperation.h"
14 #include "nsThreadUtils.h"
15 #include "nsProxyRelease.h"
16 #include "imgITools.h"
17 #include "imgIContainer.h"
18 #include "imgLoader.h"
19 
20 class nsIPrincipal;
21 
22 #include "Database.h"
23 #include "mozilla/storage.h"
24 
25 #define ICON_STATUS_UNKNOWN 0
26 #define ICON_STATUS_CHANGED 1 << 0
27 #define ICON_STATUS_SAVED 1 << 1
28 #define ICON_STATUS_ASSOCIATED 1 << 2
29 #define ICON_STATUS_CACHED 1 << 3
30 
31 #define TO_CHARBUFFER(_buffer) \
32   reinterpret_cast<char*>(const_cast<uint8_t*>(_buffer))
33 #define TO_INTBUFFER(_string) \
34   reinterpret_cast<uint8_t*>(const_cast<char*>(_string.get()))
35 
36 #define PNG_MIME_TYPE "image/png"
37 #define SVG_MIME_TYPE "image/svg+xml"
38 
39 /**
40  * The maximum time we will keep a favicon around.  We always ask the cache, if
41  * we can, but default to this value if we do not get a time back, or the time
42  * is more in the future than this.
43  * Currently set to one week from now.
44  */
45 #define MAX_FAVICON_EXPIRATION ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC)
46 
47 // Whether there are unsupported payloads to convert yet.
48 #define PREF_CONVERT_PAYLOADS "places.favicons.convertPayloads"
49 
50 namespace mozilla {
51 namespace places {
52 
53 /**
54  * Indicates when a icon should be fetched from network.
55  */
56 enum AsyncFaviconFetchMode { FETCH_NEVER = 0, FETCH_IF_MISSING, FETCH_ALWAYS };
57 
58 /**
59  * Represents one of the payloads (frames) of an icon entry.
60  */
61 struct IconPayload {
IconPayloadIconPayload62   IconPayload() : id(0), width(0) {
63     data.SetIsVoid(true);
64     mimeType.SetIsVoid(true);
65   }
66 
67   int64_t id;
68   uint16_t width;
69   nsCString data;
70   nsCString mimeType;
71 };
72 
73 /**
74  * Represents an icon entry.
75  */
76 struct IconData {
IconDataIconData77   IconData()
78       : expiration(0),
79         fetchMode(FETCH_NEVER),
80         status(ICON_STATUS_UNKNOWN),
81         rootIcon(0) {}
82 
83   nsCString spec;
84   nsCString host;
85   PRTime expiration;
86   enum AsyncFaviconFetchMode fetchMode;
87   uint16_t status;  // This is a bitset, see ICON_STATUS_* defines above.
88   uint8_t rootIcon;
89   nsTArray<IconPayload> payloads;
90 };
91 
92 /**
93  * Data cache for a page entry.
94  */
95 struct PageData {
PageDataPageData96   PageData() : id(0), placeId(0), canAddToHistory(true) {
97     guid.SetIsVoid(true);
98   }
99 
100   int64_t id;       // This is the moz_pages_w_icons id.
101   int64_t placeId;  // This is the moz_places page id.
102   nsCString spec;
103   nsCString host;
104   nsCString bookmarkedSpec;
105   bool canAddToHistory;  // False for disabled history and unsupported schemas.
106   nsCString guid;
107 };
108 
109 /**
110  * Info for a frame.
111  */
112 struct FrameData {
FrameDataFrameData113   FrameData(uint16_t aIndex, uint16_t aWidth) : index(aIndex), width(aWidth) {}
114 
115   uint16_t index;
116   uint16_t width;
117 };
118 
119 /**
120  * Async fetches icon from database or network, associates it with the required
121  * page and finally notifies the change.
122  */
123 class AsyncFetchAndSetIconForPage final : public Runnable,
124                                           public nsIStreamListener,
125                                           public nsIInterfaceRequestor,
126                                           public nsIChannelEventSink,
127                                           public mozIPlacesPendingOperation {
128  public:
129   NS_DECL_NSIRUNNABLE
130   NS_DECL_NSISTREAMLISTENER
131   NS_DECL_NSIINTERFACEREQUESTOR
132   NS_DECL_NSICHANNELEVENTSINK
133   NS_DECL_NSIREQUESTOBSERVER
134   NS_DECL_MOZIPLACESPENDINGOPERATION
135   NS_DECL_ISUPPORTS_INHERITED
136 
137   /**
138    * Constructor.
139    *
140    * @param aIcon
141    *        Icon to be fetched and associated.
142    * @param aPage
143    *        Page to which associate the icon.
144    * @param aFaviconLoadPrivate
145    *        Whether this favicon load is in private browsing.
146    * @param aCallback
147    *        Function to be called when the fetch-and-associate process finishes.
148    * @param aLoadingPrincipal
149    *        LoadingPrincipal of the icon to be fetched.
150    */
151   AsyncFetchAndSetIconForPage(IconData& aIcon, PageData& aPage,
152                               bool aFaviconLoadPrivate,
153                               nsIFaviconDataCallback* aCallback,
154                               nsIPrincipal* aLoadingPrincipal,
155                               uint64_t aRequestContextID);
156 
157  private:
158   nsresult FetchFromNetwork();
~AsyncFetchAndSetIconForPage()159   virtual ~AsyncFetchAndSetIconForPage() {}
160 
161   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
162   IconData mIcon;
163   PageData mPage;
164   const bool mFaviconLoadPrivate;
165   nsMainThreadPtrHandle<nsIPrincipal> mLoadingPrincipal;
166   bool mCanceled;
167   nsCOMPtr<nsIRequest> mRequest;
168   uint64_t mRequestContextID;
169 };
170 
171 /**
172  * Associates the icon to the required page, finally dispatches an event to the
173  * main thread to notify the change to observers.
174  */
175 class AsyncAssociateIconToPage final : public Runnable {
176  public:
177   NS_DECL_NSIRUNNABLE
178 
179   /**
180    * Constructor.
181    *
182    * @param aIcon
183    *        Icon to be associated.
184    * @param aPage
185    *        Page to which associate the icon.
186    * @param aCallback
187    *        Function to be called when the associate process finishes.
188    */
189   AsyncAssociateIconToPage(
190       const IconData& aIcon, const PageData& aPage,
191       const nsMainThreadPtrHandle<nsIFaviconDataCallback>& aCallback);
192 
193  private:
194   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
195   IconData mIcon;
196   PageData mPage;
197 };
198 
199 /**
200  * Asynchronously tries to get the URL of a page's favicon, then notifies the
201  * given observer.
202  */
203 class AsyncGetFaviconURLForPage final : public Runnable {
204  public:
205   NS_DECL_NSIRUNNABLE
206 
207   /**
208    * Constructor.
209    *
210    * @param aPageSpec
211    *        URL of the page whose favicon's URL we're fetching
212    * @param aPageHost
213    *        Host of the page whose favicon's URL we're fetching
214    * @param aCallback
215    *        function to be called once finished
216    * @param aPreferredWidth
217    *        The preferred size for the icon
218    */
219   AsyncGetFaviconURLForPage(const nsACString& aPageSpec,
220                             const nsACString& aPageHost,
221                             uint16_t aPreferredWidth,
222                             nsIFaviconDataCallback* aCallback);
223 
224  private:
225   uint16_t mPreferredWidth;
226   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
227   nsCString mPageSpec;
228   nsCString mPageHost;
229 };
230 
231 /**
232  * Asynchronously tries to get the URL and data of a page's favicon, then
233  * notifies the given observer.
234  */
235 class AsyncGetFaviconDataForPage final : public Runnable {
236  public:
237   NS_DECL_NSIRUNNABLE
238 
239   /**
240    * Constructor.
241    *
242    * @param aPageSpec
243    *        URL of the page whose favicon URL and data we're fetching
244    * @param aPageHost
245    *        Host of the page whose favicon's URL we're fetching
246    * @param aPreferredWidth
247    *        The preferred size of the icon.  We will try to return an icon close
248    *        to this size.
249    * @param aCallback
250    *        function to be called once finished
251    */
252   AsyncGetFaviconDataForPage(const nsACString& aPageSpec,
253                              const nsACString& aPageHost,
254                              uint16_t aPreferredWidth,
255                              nsIFaviconDataCallback* aCallback);
256 
257  private:
258   uint16_t mPreferredWidth;
259   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
260   nsCString mPageSpec;
261   nsCString mPageHost;
262 };
263 
264 class AsyncReplaceFaviconData final : public Runnable {
265  public:
266   NS_DECL_NSIRUNNABLE
267 
268   explicit AsyncReplaceFaviconData(const IconData& aIcon);
269 
270  private:
271   nsresult RemoveIconDataCacheEntry();
272 
273   IconData mIcon;
274 };
275 
276 /**
277  * Notifies the icon change to favicon observers.
278  */
279 class NotifyIconObservers final : public Runnable {
280  public:
281   NS_DECL_NSIRUNNABLE
282 
283   /**
284    * Constructor.
285    *
286    * @param aIcon
287    *        Icon information. Can be empty if no icon is associated to the page.
288    * @param aPage
289    *        Page to which the icon information applies.
290    * @param aCallback
291    *        Function to be notified in all cases.
292    */
293   NotifyIconObservers(
294       const IconData& aIcon, const PageData& aPage,
295       const nsMainThreadPtrHandle<nsIFaviconDataCallback>& aCallback);
296 
297  private:
298   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
299   IconData mIcon;
300   PageData mPage;
301 
302   void SendGlobalNotifications(nsIURI* aIconURI);
303 };
304 
305 /**
306  * Fetches and converts unsupported payloads. This is used during the initial
307  * migration of icons from the old to the new store.
308  */
309 class FetchAndConvertUnsupportedPayloads final : public Runnable {
310  public:
311   NS_DECL_NSIRUNNABLE
312 
313   /**
314    * Constructor.
315    *
316    * @param aDBConn
317    *        The database connection to use.
318    */
319   explicit FetchAndConvertUnsupportedPayloads(mozIStorageConnection* aDBConn);
320 
321  private:
322   nsresult ConvertPayload(int64_t aId, const nsACString& aMimeType,
323                           nsCString& aPayload, int32_t* aWidth);
324   nsresult StorePayload(int64_t aId, int32_t aWidth, const nsCString& aPayload);
325 
326   nsCOMPtr<mozIStorageConnection> mDB;
327 };
328 
329 /**
330  * Copies Favicons from one page to another one.
331  */
332 class AsyncCopyFavicons final : public Runnable {
333  public:
334   NS_DECL_NSIRUNNABLE
335 
336   /**
337    * Constructor.
338    *
339    * @param aFromPage
340    *        The originating page.
341    * @param aToPage
342    *        The destination page.
343    * @param aFaviconLoadPrivate
344    *        Whether this favicon load is in private browsing.
345    * @param aCallback
346    *        An optional callback to invoke when done.
347    */
348   AsyncCopyFavicons(PageData& aFromPage, PageData& aToPage,
349                     nsIFaviconDataCallback* aCallback);
350 
351  private:
352   PageData mFromPage;
353   PageData mToPage;
354   nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
355 };
356 
357 }  // namespace places
358 }  // namespace mozilla
359