Пример #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
        /// <param name="src">the source of the element to load the stylesheet by</param>
        /// <param name="attributes">the attributes of the link element</param>
        public static string LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            try
            {
                var args = new HtmlStylesheetLoadEventArgs(src, attributes);
                htmlContainer.RaiseHtmlStylesheetLoadEvent(args);

                if (args.SetStyleSheet != null)
                {
                    return(args.SetStyleSheet);
                }
                else if (args.SetSrc != null)
                {
                    return(LoadStylesheet(htmlContainer, args.SetSrc));
                }
                else
                {
                    return(LoadStylesheet(htmlContainer, src));
                }
            }
            catch (Exception ex)
            {
                htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex);
                return(string.Empty);
            }
        }
Пример #2
0
        /// <summary>
        /// Load Vimeo video data (title, image, link) by calling Vimeo API.
        /// </summary>
        private void LoadVimeoDataAsync(Uri uri)
        {
            ThreadPool.QueueUserWorkItem(state =>
            {
                try
                {
                    var apiUri =
                        new Uri(string.Format(
                                    "http://vimeo.com/api/v2/video/{0}.json", uri.Segments[2]));

                    var client      = new WebClient();
                    client.Encoding = Encoding.UTF8;
                    client.DownloadStringCompleted += OnDownloadVimeoApiCompleted;
                    client.DownloadStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    _imageLoadingComplete = true;
                    SetErrorBorder();
                    HtmlContainer.ReportError(HtmlRenderErrorType.Iframe,
                                              "Failed to get vimeo video data: " + uri,
                                              ex);
                    HtmlContainer.RequestRefresh(false);
                }
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
        /// <param name="src">the source of the element to load the stylesheet by</param>
        /// <param name="attributes">the attributes of the link element</param>
        public static string LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary<string, string> attributes)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            try
            {
                var args = new HtmlStylesheetLoadEventArgs(src, attributes);
                htmlContainer.RaiseHtmlStylesheetLoadEvent(args);

                if(args.SetStyleSheet != null)
                {
                    return args.SetStyleSheet;
                }
                else if(args.SetSrc != null)
                {
                    return LoadStylesheet(htmlContainer, args.SetSrc);
                }
                else
                {
                    return LoadStylesheet(htmlContainer, src);
                }
            }
            catch (Exception ex)
            {
                htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex);
                return string.Empty;
            }
        }
Пример #4
0
        /// <summary>
        /// Load YouTube video data (title, image, link) by calling YouTube API.
        /// </summary>
        private void LoadYoutubeDataAsync(Uri uri)
        {
            ThreadPool.QueueUserWorkItem(state =>
            {
                try
                {
                    var apiUri =
                        new Uri(
                            string.Format(
                                "http://gdata.youtube.com/feeds/api/videos/{0}?v=2&alt=json",
                                uri.Segments[2]));

                    var client      = new WebClient();
                    client.Encoding = Encoding.UTF8;
                    client.DownloadStringCompleted += OnDownloadYoutubeApiCompleted;
                    client.DownloadStringAsync(apiUri);
                }
                catch (Exception ex)
                {
                    HtmlContainer.ReportError(HtmlRenderErrorType.Iframe,
                                              "Failed to get youtube video data: " +
                                              uri, ex);
                    HtmlContainer.RequestRefresh(false);
                }
            });
        }
        /// <summary>
        /// Load stylesheet data from the given source.<br/>
        /// The source can be local file or web URI.<br/>
        /// First raise <see cref="HtmlStylesheetLoadEventArgs"/> event to allow the client to overwrite the stylesheet loading.<br/>
        /// If the stylesheet is downloaded from URI we will try to correct local URIs to absolute.<br/>
        /// </summary>
        /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
        /// <param name="src">the source of the element to load the stylesheet by</param>
        /// <param name="attributes">the attributes of the link element</param>
        /// <param name="stylesheet">return the stylesheet string that has been loaded (null if failed or <paramref name="stylesheetData"/> is given)</param>
        /// <param name="stylesheetData">return stylesheet data object that was provided by overwrite (null if failed or <paramref name="stylesheet"/> is given)</param>
        public static void LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes, out string stylesheet, out CssData stylesheetData)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            stylesheet     = null;
            stylesheetData = null;
            try
            {
                var args = new HtmlStylesheetLoadEventArgs(src, attributes);
                htmlContainer.RaiseHtmlStylesheetLoadEvent(args);

                if (!string.IsNullOrEmpty(args.SetStyleSheet))
                {
                    stylesheet = args.SetStyleSheet;
                }
                else if (args.SetStyleSheetData != null)
                {
                    stylesheetData = args.SetStyleSheetData;
                }
                else if (args.SetSrc != null)
                {
                    stylesheet = LoadStylesheet(htmlContainer, args.SetSrc);
                }
                else
                {
                    stylesheet = LoadStylesheet(htmlContainer, src);
                }
            }
            catch (Exception ex)
            {
                htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex);
            }
        }
Пример #6
0
        /// <summary>
        /// Set image of this image box by analyzing the src attribute.<br/>
        /// Load the image from inline base64 encoded string.<br/>
        /// Or from calling property/method on the bridge object that returns image or url to image.<br/>
        /// Or from file path<br/>
        /// Or from URI.
        /// </summary>
        /// <remarks>
        /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/>
        /// on the main thread and not threadpool.
        /// </remarks>
        /// <param name="htmlContainer">the container of the html to handle load image for</param>
        /// <param name="src">the source of the image to load</param>
        /// <param name="attributes">the collection of attributes on the element to use in event</param>
        /// <returns>the image object (null if failed)</returns>
        public void LoadImage(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            _htmlContainer = htmlContainer;

            try
            {
                var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback);
                _htmlContainer.RaiseHtmlImageLoadEvent(args);

                if (!args.Handled)
                {
                    if (!string.IsNullOrEmpty(src))
                    {
                        if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase))
                        {
                            _image = GetImageFromData(src);
                            if (_image == null)
                            {
                                _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data");
                            }
                            _releaseImageObject = true;
                            ImageLoadComplete(false);
                        }
                        else
                        {
                            SetImageFromPath(src);
                        }
                    }
                    else
                    {
                        ImageLoadComplete(false);
                    }
                }
            }
            catch (Exception ex)
            {
                _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex);
                ImageLoadComplete(false);
            }
        }
Пример #7
0
        /// <summary>
        /// Set image of this image box by analyzing the src attribute.<br/>
        /// Load the image from inline base64 encoded string.<br/>
        /// Or from calling property/method on the bridge object that returns image or URL to image.<br/>
        /// Or from file path<br/>
        /// Or from URI.
        /// </summary>
        /// <remarks>
        /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/>
        /// on the main thread and not thread-pool.
        /// </remarks>
        /// <param name="src">the source of the image to load</param>
        /// <param name="attributes">the collection of attributes on the element to use in event</param>
        /// <returns>the image object (null if failed)</returns>
        public void LoadImage(string src, Dictionary <string, string> attributes)
        {
            try
            {
                var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback);
                _htmlContainer.RaiseHtmlImageLoadEvent(args);
                _asyncCallback = !_htmlContainer.AvoidAsyncImagesLoading;

                if (!args.Handled)
                {
                    if (!string.IsNullOrEmpty(src))
                    {
                        if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase))
                        {
                            SetFromInlineData(src);
                        }
                        else
                        {
                            SetImageFromPath(src);
                        }
                    }
                    else
                    {
                        ImageLoadComplete(false);
                    }
                }
            }
            catch (Exception ex)
            {
                _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex);
                ImageLoadComplete(false);
            }
        }
Пример #8
0
        /// <summary>
        /// Handle error occurred during video data load to handle if the video was not found.
        /// </summary>
        /// <param name="ex">the exception that occurred during data load web request</param>
        /// <param name="source">the name of the video source (YouTube/Vimeo/Etc.)</param>
        private void HandleDataLoadFailure(Exception ex, string source)
        {
            var webResponse = ex is WebException webError ? webError.Response as HttpWebResponse : null;

            if (webResponse != null && webResponse.StatusCode == HttpStatusCode.NotFound)
            {
                _videoTitle = "The video is not found, possibly removed by the user.";
            }
            else
            {
                HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to load " + source + " video data", ex);
            }
        }
Пример #9
0
        /// <summary>
        /// Load the stylesheet from local file by given path.
        /// </summary>
        /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
        /// <param name="path">the stylesheet file to load</param>
        /// <returns>the loaded stylesheet string</returns>
        private static string LoadStylesheetFromFile(HtmlContainer htmlContainer, string path)
        {
            var fileInfo = CommonUtils.TryGetFileInfo(path);

            if (fileInfo != null)
            {
                if (fileInfo.Exists)
                {
                    using (var sr = new StreamReader(fileInfo.FullName))
                    {
                        return(sr.ReadToEnd());
                    }
                }
                else
                {
                    htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "No stylesheet found by path: " + path);
                }
            }
            else
            {
                htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Failed load image, invalid source: " + path);
            }
            return(string.Empty);
        }
Пример #10
0
 /// <summary>
 /// Load the image from inline base64 encoded string data.
 /// </summary>
 /// <param name="src">the source that has the base64 encoded image</param>
 private void SetFromInlineData(string src)
 {
     _image = GetImageFromData(src);
     if (_image == null)
     {
         _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data");
     }
     _releaseImageObject = true;
     ImageLoadComplete(false);
 }
 /// <summary>
 /// Load the stylesheet from uri by downloading the string.
 /// </summary>
 /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
 /// <param name="uri">the uri to download from</param>
 /// <returns>the loaded stylesheet string</returns>
 private static string LoadStylesheetFromUri(HtmlContainer htmlContainer, Uri uri)
 {
     using (var client = new WebClient())
     {
         var stylesheet = client.DownloadString(uri);
         try
         {
             stylesheet = CorrectRelativeUrls(stylesheet, uri);
         }
         catch (Exception ex)
         {
             htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Error in correcting relative URL in loaded stylesheet", ex);
         }
         return(stylesheet);
     }
 }
Пример #12
0
 /// <summary>
 /// Handle link click.
 /// </summary>
 private void OnOpenLinkClick(object sender, EventArgs eventArgs)
 {
     try
     {
         Point mp = _parentControl.PointToClient(Control.MousePosition);
         _currentLink.HtmlContainer.HandleLinkClicked(_parentControl,
                                                      new MouseEventArgs(MouseButtons.None, 0, mp.X, mp.Y, 0),
                                                      _currentLink);
     }
     catch (HtmlLinkClickedException)
     {
         throw;
     }
     catch (Exception ex)
     {
         _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to open link", ex);
     }
     finally
     {
         DisposeContextMenu();
     }
 }
Пример #13
0
        /// <summary>
        /// Load image from path of image file or uri.
        /// </summary>
        /// <param name="path">the file path or uri to load image from</param>
        public void SetImageFromPath(string path)
        {
            var uri = CommonUtils.TryGetUri(path);

            if (uri != null && uri.Scheme != "file")
            {
                SetImageFromUri(uri);
            }
            else
            {
                var fileInfo = CommonUtils.TryGetFileInfo(uri != null ? uri.AbsolutePath : path);
                if (fileInfo != null)
                {
                    SetImageFromFile(fileInfo);
                }
                else
                {
                    _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed load image, invalid source: " + path);
                    ImageLoadComplete(false);
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Parse Vimeo API response to get video data (title, image, link).
        /// </summary>
        private void OnDownloadVimeoApiCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (!e.Cancelled)
                {
                    if (e.Error == null)
                    {
                        var idx = e.Result.IndexOf("\"title\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            idx = e.Result.IndexOf('"', idx + 7);
                            if (idx > -1)
                            {
                                var endIdx = e.Result.IndexOf('"', idx + 1);
                                while (e.Result[endIdx - 1] == '\\')
                                {
                                    endIdx = e.Result.IndexOf('"', endIdx + 1);
                                }
                                if (endIdx > -1)
                                {
                                    _videoTitle = e.Result.Substring(idx + 1, endIdx - idx - 1).Replace("\\\"", "\"");
                                }
                            }
                        }

                        idx = e.Result.IndexOf("\"thumbnail_large\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            if (string.IsNullOrEmpty(Width))
                            {
                                Width = "640";
                            }
                            if (string.IsNullOrEmpty(Height))
                            {
                                Height = "360";
                            }
                        }
                        else
                        {
                            idx = e.Result.IndexOf("thumbnail_medium", idx);
                            if (idx > -1)
                            {
                                if (string.IsNullOrEmpty(Width))
                                {
                                    Width = "200";
                                }
                                if (string.IsNullOrEmpty(Height))
                                {
                                    Height = "150";
                                }
                            }
                            else
                            {
                                idx = e.Result.IndexOf("thumbnail_small", idx);
                                if (string.IsNullOrEmpty(Width))
                                {
                                    Width = "100";
                                }
                                if (string.IsNullOrEmpty(Height))
                                {
                                    Height = "75";
                                }
                            }
                        }
                        if (idx > -1)
                        {
                            idx = e.Result.IndexOf("http:", idx);
                            if (idx > -1)
                            {
                                var endIdx = e.Result.IndexOf('"', idx);
                                if (endIdx > -1)
                                {
                                    _videoImageUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", "");
                                }
                            }
                        }

                        idx = e.Result.IndexOf("\"url\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            idx = e.Result.IndexOf("http:", idx);
                            if (idx > -1)
                            {
                                var endIdx = e.Result.IndexOf('"', idx);
                                if (endIdx > -1)
                                {
                                    _videoLinkUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", "");
                                }
                            }
                        }
                    }
                    else
                    {
                        HandleDataLoadFailure(e.Error, "Vimeo");
                    }
                }
            }
            catch (Exception ex)
            {
                HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to parse Vimeo video response", ex);
            }

            HandlePostApiCall(sender);
        }
Пример #15
0
        /// <summary>
        /// Parse YouTube API response to get video data (title, image, link).
        /// </summary>
        private void OnDownloadYoutubeApiCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (!e.Cancelled)
                {
                    if (e.Error == null)
                    {
                        var idx = e.Result.IndexOf("\"media$title\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            idx = e.Result.IndexOf("\"$t\"", idx);
                            if (idx > -1)
                            {
                                idx = e.Result.IndexOf('"', idx + 4);
                                if (idx > -1)
                                {
                                    var endIdx = e.Result.IndexOf('"', idx + 1);
                                    while (e.Result[endIdx - 1] == '\\')
                                    {
                                        endIdx = e.Result.IndexOf('"', endIdx + 1);
                                    }
                                    if (endIdx > -1)
                                    {
                                        _videoTitle = e.Result.Substring(idx + 1, endIdx - idx - 1).Replace("\\\"", "\"");
                                    }
                                }
                            }
                        }

                        idx = e.Result.IndexOf("\"media$thumbnail\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            var iidx = e.Result.IndexOf("sddefault", idx);
                            if (iidx > -1)
                            {
                                if (string.IsNullOrEmpty(Width))
                                {
                                    Width = "640px";
                                }
                                if (string.IsNullOrEmpty(Height))
                                {
                                    Height = "480px";
                                }
                            }
                            else
                            {
                                iidx = e.Result.IndexOf("hqdefault", idx);
                                if (iidx > -1)
                                {
                                    if (string.IsNullOrEmpty(Width))
                                    {
                                        Width = "480px";
                                    }
                                    if (string.IsNullOrEmpty(Height))
                                    {
                                        Height = "360px";
                                    }
                                }
                                else
                                {
                                    iidx = e.Result.IndexOf("mqdefault", idx);
                                    if (iidx > -1)
                                    {
                                        if (string.IsNullOrEmpty(Width))
                                        {
                                            Width = "320px";
                                        }
                                        if (string.IsNullOrEmpty(Height))
                                        {
                                            Height = "180px";
                                        }
                                    }
                                    else
                                    {
                                        iidx = e.Result.IndexOf("default", idx);
                                        if (string.IsNullOrEmpty(Width))
                                        {
                                            Width = "120px";
                                        }
                                        if (string.IsNullOrEmpty(Height))
                                        {
                                            Height = "90px";
                                        }
                                    }
                                }
                            }

                            iidx = e.Result.LastIndexOf("http:", iidx, StringComparison.Ordinal);
                            if (iidx > -1)
                            {
                                var endIdx = e.Result.IndexOf('"', iidx);
                                if (endIdx > -1)
                                {
                                    _videoImageUrl = e.Result.Substring(iidx, endIdx - iidx).Replace("\\\"", "\"").Replace("\\", "");
                                }
                            }
                        }

                        idx = e.Result.IndexOf("\"link\"", StringComparison.Ordinal);
                        if (idx > -1)
                        {
                            idx = e.Result.IndexOf("http:", idx);
                            if (idx > -1)
                            {
                                var endIdx = e.Result.IndexOf('"', idx);
                                if (endIdx > -1)
                                {
                                    _videoLinkUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", "");
                                }
                            }
                        }
                    }
                    else
                    {
                        HandleDataLoadFailure(e.Error, "YouTube");
                    }
                }
            }
            catch (Exception ex)
            {
                HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to parse YouTube video response", ex);
            }

            HandlePostApiCall(sender);
        }
 /// <summary>
 /// Load the stylesheet from local file by given path.
 /// </summary>
 /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
 /// <param name="path">the stylesheet file to load</param>
 /// <returns>the loaded stylesheet string</returns>
 private static string LoadStylesheetFromFile(HtmlContainer htmlContainer, string path)
 {
     var fileInfo = CommonUtils.TryGetFileInfo(path);
     if (fileInfo != null)
     {
         if (fileInfo.Exists)
         {
             using (var sr = new StreamReader(fileInfo.FullName))
             {
                 return sr.ReadToEnd();
             }
         }
         else
         {
             htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "No stylesheet found by path: " + path);
         }
     }
     else
     {
         htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Failed load image, invalid source: " + path);
     }
     return string.Empty;
 }
Пример #17
0
        /// <summary>
        /// Show context menu clicked on given rectangle.
        /// </summary>
        /// <param name="parent">the parent control to show the context menu on</param>
        /// <param name="rect">the rectangle that was clicked to show context menu</param>
        /// <param name="link">the link that was clicked to show context menu on</param>
        public void ShowContextMenu(Control parent, CssRect rect, CssBox link)
        {
            try
            {
                DisposeContextMenu();

                _parentControl = parent;
                _currentRect   = rect;
                _currentLink   = link;
                _contextMenu   = new ContextMenuStrip();
                _contextMenu.ShowImageMargin = false;

                if (rect != null)
                {
                    bool isVideo = false;
                    if (link != null)
                    {
                        isVideo = link is CssBoxFrame && ((CssBoxFrame)link).IsVideo;
                        var openLink = _contextMenu.Items.Add(isVideo ? _openVideo : _openLink, null, OnOpenLinkClick);
                        if (_htmlContainer.IsSelectionEnabled)
                        {
                            var copyLink = _contextMenu.Items.Add(isVideo ? _copyVideoUrl : _copyLink, null, OnCopyLinkClick);
                            copyLink.Enabled = !string.IsNullOrEmpty(link.HrefLink);
                        }
                        openLink.Enabled = !string.IsNullOrEmpty(link.HrefLink);
                        _contextMenu.Items.Add("-");
                    }

                    if (rect.IsImage && !isVideo)
                    {
                        var saveImage = _contextMenu.Items.Add(_saveImage, null, OnSaveImageClick);
                        if (_htmlContainer.IsSelectionEnabled)
                        {
                            var copyImageUrl = _contextMenu.Items.Add(_copyImageLink, null, OnCopyImageLinkClick);
                            var copyImage    = _contextMenu.Items.Add(_copyImage, null, OnCopyImageClick);
                            copyImageUrl.Enabled = !string.IsNullOrEmpty(_currentRect.OwnerBox.GetAttribute("src"));
                            copyImage.Enabled    = rect.Image != null;
                        }
                        saveImage.Enabled = rect.Image != null;
                        _contextMenu.Items.Add("-");
                    }

                    if (_htmlContainer.IsSelectionEnabled)
                    {
                        var copy = _contextMenu.Items.Add(_copy, null, OnCopyClick);
                        copy.Enabled = rect.Selected;
                    }
                }

                if (_htmlContainer.IsSelectionEnabled)
                {
                    _contextMenu.Items.Add(_selectAll, null, OnSelectAllClick);
                }

                if (_contextMenu.Items.Count > 0)
                {
                    if (_contextMenu.Items[_contextMenu.Items.Count - 1].Text == string.Empty)
                    {
                        _contextMenu.Items.RemoveAt(_contextMenu.Items.Count - 1);
                    }
                    _contextMenu.Show(parent, parent.PointToClient(Control.MousePosition));
                }
            }
            catch (Exception ex)
            {
                _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to show context menu", ex);
            }
        }
Пример #18
0
        /// <summary>
        /// Set image of this image box by analyzing the src attribute.<br/>
        /// Load the image from inline base64 encoded string.<br/>
        /// Or from calling property/method on the bridge object that returns image or url to image.<br/>
        /// Or from file path<br/>
        /// Or from URI.
        /// </summary>
        /// <remarks>
        /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/>
        /// on the main thread and not thread-pool.
        /// </remarks>
        /// <param name="htmlContainer">the container of the html to handle load image for</param>
        /// <param name="src">the source of the image to load</param>
        /// <param name="attributes">the collection of attributes on the element to use in event</param>
        /// <returns>the image object (null if failed)</returns>
        public void LoadImage(HtmlContainer htmlContainer, string src, Dictionary<string, string> attributes)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            _htmlContainer = htmlContainer;

            try
            {
                var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback);
                _htmlContainer.RaiseHtmlImageLoadEvent(args);
                _asyncCallback = true;

                if (!args.Handled)
                {
                    if (!string.IsNullOrEmpty(src))
                    {
                        if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase))
                        {
                            _image = GetImageFromData(src);
                            if (_image == null)
                                _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data");
                            _releaseImageObject = true;
                            ImageLoadComplete(false);
                        }
                        else
                        {
                            SetImageFromPath(src);
                        }
                    }
                    else
                    {
                        ImageLoadComplete(false);
                    }
                }
            }
            catch (Exception ex)
            {
                _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex);
                ImageLoadComplete(false);
            }
        }