コード例 #1
0
        /// <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(HtmlContainerInt 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);
            }
        }
コード例 #2
0
        /// <summary>
        /// Generate css tree by parsing the given html and applying the given css style data on it.
        /// </summary>
        /// <param name="html">the html to parse</param>
        /// <param name="htmlContainer">the html container to use for reference resolve</param>
        /// <param name="cssData">the css data to use</param>
        /// <returns>the root of the generated tree</returns>
        public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref CssData cssData)
        {
            var root = HtmlParser.ParseDocument(html);
            if (root != null)
            {
                root.HtmlContainer = htmlContainer;

                bool cssDataChanged = false;
                CascadeParseStyles(root, htmlContainer, ref cssData, ref cssDataChanged);

                CascadeApplyStyles(root, cssData);

                SetTextSelectionStyle(htmlContainer, cssData);

                CorrectTextBoxes(root);

                CorrectImgBoxes(root);

                bool followingBlock = true;
                CorrectLineBreaksBlocks(root, ref followingBlock);

                CorrectInlineBoxesParent(root);

                CorrectBlockInsideInline(root);

                CorrectInlineBoxesParent(root);
            }
            return root;
        }
コード例 #3
0
        /// <summary>
        /// Measure the size of the html by performing layout under the given restrictions.
        /// </summary>
        /// <param name="g">the graphics to use</param>
        /// <param name="htmlContainer">the html to calculate the layout for</param>
        /// <param name="minSize">the minimal size of the rendered html (zero - not limit the width/height)</param>
        /// <param name="maxSize">the maximum size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height)</param>
        /// <returns>return: the size of the html to be rendered within the min/max limits</returns>
        public static RSize MeasureHtmlByRestrictions(RGraphics g, HtmlContainerInt htmlContainer, RSize minSize, RSize maxSize)
        {
            // first layout without size restriction to know html actual size
            htmlContainer.PerformLayout(g);

            if (maxSize.Width > 0 && maxSize.Width < htmlContainer.ActualSize.Width)
            {
                // to allow the actual size be smaller than max we need to set max size only if it is really larger
                htmlContainer.MaxSize = new RSize(maxSize.Width, 0);
                htmlContainer.PerformLayout(g);
            }

            // restrict the final size by min/max
            var finalWidth = Math.Max(maxSize.Width > 0 ? Math.Min(maxSize.Width, (int)htmlContainer.ActualSize.Width) : (int)htmlContainer.ActualSize.Width, minSize.Width);

            // if the final width is larger than the actual we need to re-layout so the html can take the full given width.
            if (finalWidth > htmlContainer.ActualSize.Width)
            {
                htmlContainer.MaxSize = new RSize(finalWidth, 0);
                htmlContainer.PerformLayout(g);
            }

            var finalHeight = Math.Max(maxSize.Height > 0 ? Math.Min(maxSize.Height, (int)htmlContainer.ActualSize.Height) : (int)htmlContainer.ActualSize.Height, minSize.Height);

            return new RSize(finalWidth, finalHeight);
        }
コード例 #4
0
 /// <summary>
 /// Load stylesheet string from given source (file path or uri).
 /// </summary>
 /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param>
 /// <param name="src">the file path or uri to load the stylesheet from</param>
 /// <returns>the stylesheet string</returns>
 private static string LoadStylesheet(HtmlContainerInt htmlContainer, string src)
 {
     var uri = CommonUtils.TryGetUri(src);
     if (uri == null || uri.Scheme == "file")
     {
         return LoadStylesheetFromFile(htmlContainer, uri != null ? uri.AbsolutePath : src);
     }
     else
     {
         return LoadStylesheetFromUri(htmlContainer, uri);
     }
 }
コード例 #5
0
        /// <summary>
        /// Perform the layout of the html container by given size restrictions returning the final size.<br/>
        /// The layout can be effected by the HTML content in the <paramref name="htmlContainer"/> if <paramref name="autoSize"/> or
        /// <paramref name="autoSizeHeightOnly"/> is set to true.<br/>
        /// Handle minimum and maximum size restrictions.<br/>
        /// Handle auto size and auto size for height only. if <paramref name="autoSize"/> is true <paramref name="autoSizeHeightOnly"/>
        /// is ignored.<br/>
        /// </summary>
        /// <param name="g">the graphics used for layout</param>
        /// <param name="htmlContainer">the html container to layout</param>
        /// <param name="size">the current size</param>
        /// <param name="minSize">the min size restriction - can be empty for no restriction</param>
        /// <param name="maxSize">the max size restriction - can be empty for no restriction</param>
        /// <param name="autoSize">if to modify the size (width and height) by html content layout</param>
        /// <param name="autoSizeHeightOnly">if to modify the height by html content layout</param>
        public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize size, RSize minSize, RSize maxSize, bool autoSize, bool autoSizeHeightOnly)
        {
            if (autoSize)
                htmlContainer.MaxSize = new RSize(0, 0);
            else if (autoSizeHeightOnly)
                htmlContainer.MaxSize = new RSize(size.Width, 0);
            else
                htmlContainer.MaxSize = size;

            htmlContainer.PerformLayout(g);

            RSize newSize = size;
            if (autoSize || autoSizeHeightOnly)
            {
                if (autoSize)
                {
                    if (maxSize.Width > 0 && maxSize.Width < htmlContainer.ActualSize.Width)
                    {
                        // to allow the actual size be smaller than max we need to set max size only if it is really larger
                        htmlContainer.MaxSize = maxSize;
                        htmlContainer.PerformLayout(g);
                    }
                    else if (minSize.Width > 0 && minSize.Width > htmlContainer.ActualSize.Width)
                    {
                        // if min size is larger than the actual we need to re-layout so all 100% layouts will be correct
                        htmlContainer.MaxSize = new RSize(minSize.Width, 0);
                        htmlContainer.PerformLayout(g);
                    }
                    newSize = htmlContainer.ActualSize;
                }
                else if (Math.Abs(size.Height - htmlContainer.ActualSize.Height) > 0.01)
                {
                    var prevWidth = size.Width;

                    // make sure the height is not lower than min if given
                    newSize.Height = minSize.Height > 0 && minSize.Height > htmlContainer.ActualSize.Height
                        ? minSize.Height
                        : htmlContainer.ActualSize.Height;

                    // handle if changing the height of the label affects the desired width and those require re-layout
                    if (Math.Abs(prevWidth - size.Width) > 0.01)
                        return Layout(g, htmlContainer, size, minSize, maxSize, false, true);
                }
            }

            return newSize;
        }
コード例 #6
0
        /// <summary>
        /// Read styles defined inside the dom structure in links and style elements.<br/>
        /// If the html tag is "style" tag parse it content and add to the css data for all future tags parsing.<br/>
        /// If the html tag is "link" that point to style data parse it content and add to the css data for all future tags parsing.<br/>
        /// </summary>
        /// <param name="box">the box to parse style data in</param>
        /// <param name="htmlContainer">the html container to use for reference resolve</param>
        /// <param name="cssData">the style data to fill with found styles</param>
        /// <param name="cssDataChanged">check if the css data has been modified by the handled html not to change the base css data</param>
        private void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref CssData cssData, ref bool cssDataChanged)
        {
            if (box.HtmlTag != null)
            {
                // Check for the <link rel=stylesheet> tag
                if (box.HtmlTag.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase) &&
                    box.GetAttribute("rel", string.Empty).Equals("stylesheet", StringComparison.CurrentCultureIgnoreCase))
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    string stylesheet;
                    CssData stylesheetData;
                    StylesheetLoadHandler.LoadStylesheet(htmlContainer, box.GetAttribute("href", string.Empty), box.HtmlTag.Attributes, out stylesheet, out stylesheetData);
                    if (stylesheet != null)
                        _cssParser.ParseStyleSheet(cssData, stylesheet);
                    else if (stylesheetData != null)
                        cssData.Combine(stylesheetData);
                }

                // Check for the <style> tag
                if (box.HtmlTag.Name.Equals("style", StringComparison.CurrentCultureIgnoreCase) && box.Boxes.Count > 0)
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    foreach (var child in box.Boxes)
                        _cssParser.ParseStyleSheet(cssData, child.Text.CutSubstring());
                }
            }

            foreach (var childBox in box.Boxes)
            {
                CascadeParseStyles(childBox, htmlContainer, ref cssData, ref cssDataChanged);
            }
        }
コード例 #7
0
        /// <summary>
        /// Set the selected text style (selection text color and background color).
        /// </summary>
        /// <param name="htmlContainer"> </param>
        /// <param name="cssData">the style data</param>
        private void SetTextSelectionStyle(HtmlContainerInt htmlContainer, CssData cssData)
        {
            htmlContainer.SelectionForeColor = RColor.Empty;
            htmlContainer.SelectionBackColor = RColor.Empty;

            if (cssData.ContainsCssBlock("::selection"))
            {
                var blocks = cssData.GetCssBlock("::selection");
                foreach (var block in blocks)
                {
                    if (block.Properties.ContainsKey("color"))
                        htmlContainer.SelectionForeColor = _cssParser.ParseColor(block.Properties["color"]);
                    if (block.Properties.ContainsKey("background-color"))
                        htmlContainer.SelectionBackColor = _cssParser.ParseColor(block.Properties["background-color"]);
                }
            }
        }
コード例 #8
0
 /// <summary>
 /// Draw image failed to load icon.
 /// </summary>
 /// <param name="g">the device to draw into</param>
 /// <param name="htmlContainer"></param>
 /// <param name="r">the rectangle to draw icon in</param>
 public static void DrawImageErrorIcon(RGraphics g, HtmlContainerInt htmlContainer, RRect r)
 {
     g.DrawRectangle(g.GetPen(RColor.LightGray), r.Left + 2, r.Top + 2, 15, 15);
     var image = htmlContainer.Adapter.GetLoadingFailedImage();
     g.DrawImage(image, new RRect(r.Left + 3, r.Top + 3, image.Width, image.Height));
 }
コード例 #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(HtmlContainerInt 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 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(HtmlContainerInt 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;
     }
 }
コード例 #11
0
        /// <summary>
        /// Init.
        /// </summary>
        /// <param name="htmlContainer">the container of the html to handle load image for</param>
        /// <param name="loadCompleteCallback">callback raised when image load process is complete with image or without</param>
        public ImageLoadHandler(HtmlContainerInt htmlContainer, ActionInt<RImage, RRect, bool> loadCompleteCallback)
        {
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");
            ArgChecker.AssertArgNotNull(loadCompleteCallback, "loadCompleteCallback");

            _htmlContainer = htmlContainer;
            _loadCompleteCallback = loadCompleteCallback;
        }
コード例 #12
0
        /// <summary>
        /// Init.
        /// </summary>
        /// <param name="selectionHandler">the selection handler linked to the context menu handler</param>
        /// <param name="htmlContainer">the html container the handler is on</param>
        public ContextMenuHandler(SelectionHandler selectionHandler, HtmlContainerInt htmlContainer)
        {
            ArgChecker.AssertArgNotNull(selectionHandler, "selectionHandler");
            ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");

            _selectionHandler = selectionHandler;
            _htmlContainer = htmlContainer;
        }