|
| 1 | +# Background |
| 2 | +A favicon (favorite icon) is a tiny icon included along with a website, which is displayed in places like the browser's address bar, page tabs and bookmarks menu. Developers would like to have an API which allows them to retrieve the Favicon of a webpage, if it has been set, as well as get an update whenever the favicon has changed. |
| 3 | + |
| 4 | +# Description |
| 5 | +We propose a new Webview2 event which would allow developers to access the current Favicon of a page and be notified when the favicon changes. This means when a page first loads, it would raise the FaviconChanged event since before parsing the HTML document there is no known favicon. DOM or JavaScript may change the Favicon, causing the event to be raised again for the same document. |
| 6 | + |
| 7 | +# Examples |
| 8 | +## Win32 C++ Registering a listener for favicon changes |
| 9 | +```cpp |
| 10 | +Gdiplus::GdiplusStartupInput gdiplusStartupInput; |
| 11 | + |
| 12 | +// Initialize GDI+. |
| 13 | +Gdiplus::GdiplusStartup(&gdiplusToken_, &gdiplusStartupInput, NULL); |
| 14 | +CHECK_FAILURE(m_webView2->add_FaviconChanged( |
| 15 | + Callback<ICoreWebView2FaviconChangedEventHandler>( |
| 16 | + [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { |
| 17 | + wil::unique_cotaskmem_string url; |
| 18 | + |
| 19 | + CHECK_FAILURE(sender->get_FaviconUri(&url)); |
| 20 | + std::wstring strUrl(url.get()); |
| 21 | + if (strUrl.empty()) |
| 22 | + { |
| 23 | + m_favicon.reset(); |
| 24 | + SendMessage(m_appWindow->GetMainWindow(), WM_SETICON, ICON_SMALL, (LPARAM)NULL); |
| 25 | + } |
| 26 | + else |
| 27 | + { |
| 28 | + webview2->GetFavicon( |
| 29 | + COREWEBVIEW2_FAVICON_IMAGE_FORMAT_PNG, |
| 30 | + Callback<ICoreWebView2GetFaviconCompletedHandler>( |
| 31 | + [this](HRESULT errorCode, IStream* iconStream) -> HRESULT |
| 32 | + { |
| 33 | + CHECK_FAILURE(errorCode); |
| 34 | + Gdiplus::Bitmap iconBitmap(iconStream); |
| 35 | + wil::unique_hicon icon; |
| 36 | + if (iconBitmap.GetHICON(&icon) = Gdiplus::Status::Ok) |
| 37 | + { |
| 38 | + m_favicon = std::move(icon); |
| 39 | + } |
| 40 | + else |
| 41 | + { |
| 42 | + m_favicon.reset(); |
| 43 | + } |
| 44 | + |
| 45 | + SendMessage( |
| 46 | + m_appWindow->GetMainWindow(), WM_SETICON, |
| 47 | + ICON_SMALL, (LPARAM)m_favicon.get()); |
| 48 | + return S_OK; |
| 49 | + }).Get()); |
| 50 | + } |
| 51 | + return S_OK; |
| 52 | + }).Get(), &m_faviconChangedToken)); |
| 53 | +} |
| 54 | +``` |
| 55 | +## .NET / WinRT Registering a listener for favicon changes |
| 56 | +```c# |
| 57 | +webView.CoreWebView2.FaviconChanged += (object sender, Object arg) => |
| 58 | +{ |
| 59 | + string value = webView.CoreWebView2.FaviconUri; |
| 60 | + System.IO.Stream stream = await webView.CoreWebView2.GetFaviconAsync( |
| 61 | + CoreWebView2FaviconImageFormat.Png); |
| 62 | + if (stream == null || stream.Length == 0) |
| 63 | + this.Icon = null; |
| 64 | + else |
| 65 | + this.Icon = BitmapFrame.Create(stream); |
| 66 | +}; |
| 67 | +``` |
| 68 | +# API Notes |
| 69 | +Note that even if a web page does not have a Favicon and there was not a previously |
| 70 | +loaded Favicon, the event is not raised. Otherwise if there is not Favicon and the |
| 71 | +previous page did have a Favicon, the FaviconChanged event is raised when the page |
| 72 | +is navigated. The Favicon would be an empty image stream and empty Uri for the lack |
| 73 | +of a favicon. The end developer is expected to handle this scenario. Otherwise, we |
| 74 | +raise the FaviconChanged with an observed change to the Favicon. In that scenario, |
| 75 | +the CoreWebView2 has an updated value for the FaviconUri property, and the |
| 76 | +GetFavicon method to match the updated favicon. Loading the same Favicon twice does |
| 77 | +re-raise the FaviconChanged event. |
| 78 | +See [API Details](#api-details) Section below for API reference |
| 79 | +# API Details |
| 80 | +## Win32 C++ |
| 81 | +```cpp |
| 82 | +/// This interface is a handler for when the `Favicon` is changed. |
| 83 | +/// The sender is the ICoreWebView2 object the top-level document of |
| 84 | +/// which has changed favicon and the eventArgs is nullptr. Use the |
| 85 | +/// FaviconUri property and GetFavicon method to obtain the favicon |
| 86 | +/// data. The second argument is always null. |
| 87 | +/// For more information see `add_FaviconChanged`. |
| 88 | +[uuid(2913DA94-833D-4DE0-8DCA-900FC524A1A4), object, pointer_default(unique)] |
| 89 | +interface ICoreWebView2FaviconChangedEventHandler : IUnknown { |
| 90 | + /// Called to notify the favicon changed. |
| 91 | + HRESULT Invoke( |
| 92 | + [in] ICoreWebView2* sender, |
| 93 | + [in] IUnknown* args); |
| 94 | +} |
| 95 | + |
| 96 | +/// This interface is a handler for the completion of the population of |
| 97 | +/// `imageStream`. |
| 98 | +/// `errorCode` returns S_OK if the API succeeded. |
| 99 | +/// The image is returned in the `faviconStream` object. If there is no image |
| 100 | +/// then no data would be copied into the imageStream. |
| 101 | +/// For more details, see the `GetFavicon` API. |
| 102 | +[uuid(A2508329-7DA8-49D7-8C05-FA125E4AEE8D), object, pointer_default(unique)] |
| 103 | +interface ICoreWebView2GetFaviconCompletedHandler : IUnknown { |
| 104 | + /// Called to notify the favicon has been retrieved. |
| 105 | + HRESULT Invoke( |
| 106 | + [in] HRESULT errorCode, |
| 107 | + [in] IStream* faviconStream); |
| 108 | +} |
| 109 | + |
| 110 | +/// This is the ICoreWebView2 Favicon interface. |
| 111 | +[uuid(DC838C64-F64B-4DC7-98EC-0992108E2157), object, pointer_default(unique)] |
| 112 | +interface ICoreWebView2_10 : ICoreWebView2_9 { |
| 113 | + /// Add an event handler for the `FaviconChanged` event. |
| 114 | + /// The `FaviconChanged` event is raised when the |
| 115 | + /// [favicon](https://developer.mozilla.org/en-US/docs/Glossary/Favicon) |
| 116 | + /// had a different URL then the previous URL. |
| 117 | + /// The FaviconChanged event will be raised for first navigating to a new |
| 118 | + /// document, whether or not a document declares a Favicon in HTML if the |
| 119 | + /// favicon is different from the previous fav icon. The event will |
| 120 | + /// be raised again if a favicon is declared in its HTML or has script |
| 121 | + /// to set its favicon. The favicon information can then be retrieved with |
| 122 | + /// `GetFavicon` and `FaviconUri`. |
| 123 | + HRESULT add_FaviconChanged( |
| 124 | + [in] ICoreWebView2FaviconChangedEventHandler* eventHandler, |
| 125 | + [out] EventRegistrationToken* token); |
| 126 | + |
| 127 | + /// Remove the event handler for `FaviconChanged` event. |
| 128 | + HRESULT remove_FaviconChanged( |
| 129 | + [in] EventRegistrationToken token); |
| 130 | + |
| 131 | + /// Get the current Uri of the favicon as a string. |
| 132 | + /// If the value is null, then the return value is `E_POINTER`, otherwise it is `S_OK`. |
| 133 | + /// If a page has no favicon then the value is an empty string. |
| 134 | + [propget] HRESULT FaviconUri([out, retval] LPWSTR* value); |
| 135 | + |
| 136 | + /// Async function for getting the actual image data of the favicon. |
| 137 | + /// If the `imageStream` is null, the `HRESULT` will be `E_POINTER`, otherwise |
| 138 | + /// it is `S_OK`. |
| 139 | + /// The image is copied to the `imageStream` object. If there is no image then |
| 140 | + /// no data would be copied into the imageStream. |
| 141 | + /// In either scenario the `completedHandler` is executed at the end of the operation. |
| 142 | + HRESULT GetFavicon( |
| 143 | + [in] COREWEBVIEW2_FAVICON_IMAGE_FORMAT format, |
| 144 | + [in] IStream* imageStream, |
| 145 | + [in] ICoreWebView2GetFaviconCompletedHandler* completedHandler); |
| 146 | +} |
| 147 | + |
| 148 | +[v1_enum] |
| 149 | +typedef enum COREWEBVIEW2_FAVICON_IMAGE_FORMAT { |
| 150 | + /// Indicates that CoreWebView2.GetFavicon should return the favicon in PNG format. |
| 151 | + COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG, |
| 152 | + |
| 153 | + /// Indicates that CoreWebView2.GetFavicon should return the favicon in JPG format. |
| 154 | + COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_JPEG, |
| 155 | +} |
| 156 | +``` |
| 157 | + |
| 158 | +## .Net/ WinRT |
| 159 | +```c# |
| 160 | +namespace Microsoft.Web.WebView2.Core |
| 161 | +{ |
| 162 | + enum CoreWebView2FaviconImageFormat |
| 163 | + { |
| 164 | + Png = 0, |
| 165 | + Jpeg = 1, |
| 166 | + }; |
| 167 | + |
| 168 | + runtimeclass CoreWebView2 |
| 169 | + { |
| 170 | + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_10")] |
| 171 | + { |
| 172 | + String FaviconUri { get; }; |
| 173 | + |
| 174 | + event Windows.Foundation.TypedEventHandler<CoreWebView2, Object> FaviconChanged; |
| 175 | + |
| 176 | + Windows.Foundation.IAsyncOperation<Windows.Storage.Streams.IRandomAccessStream> GetFaviconAsync(CoreWebView2FaviconImageFormat format); |
| 177 | + } |
| 178 | + } |
| 179 | +} |
| 180 | +``` |
0 commit comments