/// <summary> /// Extracts source from anchor. /// </summary> /// <param name="htmlNode"></param> /// <param name="element"></param> private static void ExtractHref(HtmlNode htmlNode, ref Elements.BaseElement element) { if (htmlNode.Attributes.Contains("href")) { ((Elements.Text)element).Href = htmlNode.Attributes["href"].Value; } }
/// <summary> /// Extracts identifier from nodes (for table of contents linkng). /// </summary> /// <param name="htmlNode"></param> /// <param name="element"></param> private static void ExtractId(HtmlNode htmlNode, ref Elements.BaseElement element) { if (htmlNode.Attributes.Contains("id")) { element.Identifiers.Add(htmlNode.Attributes["id"].Value); } // we have to also extract id's from parents if (htmlNode.ParentNode != null) { ExtractId(htmlNode.ParentNode, ref element); } }
private void Navigate(string src) { // extract href / id string itemHref, id; if (src.StartsWith("#", StringComparison.OrdinalIgnoreCase)) { itemHref = String.Empty; id = src.Substring(1); } else if (src.Contains('#')) { itemHref = src.Substring(0, src.IndexOf('#')); id = src.Substring(src.IndexOf('#') + 1); } else { itemHref = src; id = String.Empty; } // remove directiories from href itemHref = GetFileName(itemHref); // find location int loc = 0; for (int i = 0; i < Book.ItemElementsContainers.Count; i++) { ItemElementsContainer iec = Book.ItemElementsContainers[i]; for (int j = 0; j < iec.Elements.Count; j++) { Elements.BaseElement element = iec.Elements[j]; if ( (String.IsNullOrEmpty(itemHref) || GetFileName(iec.Item.Href).Equals(itemHref, StringComparison.OrdinalIgnoreCase)) && (String.IsNullOrEmpty(id) || (!String.IsNullOrEmpty(id) && element.Identifiers.Contains(id))) ) { // change state (from TOC view) State = EPubReader.State.Normal; // set location CurrentLocation = loc + j; // exit return; } } loc += iec.Elements.Count; } }
/// <summary> /// Render item elements container /// </summary> /// <param name="iec"></param> internal void Render(ItemElementsContainer iec) { #if DEBUG Stopwatch sw = new Stopwatch(); sw.Start(); #endif int currentLocation = iec.StartLocation; Page page = CreatePage(currentLocation); double top = 0; for (int i = 0; i < iec.Elements.Count; i++) { Elements.BaseElement element = iec.Elements[i]; if (element is Elements.Break) { RenderBreak(iec, currentLocation, ref page, ref top); } else if (element is Elements.Image) { RenderImage(iec, currentLocation, ref page, ref top, element); } else if (element is Elements.Line) { RenderLine(iec, currentLocation, ref page, ref top); } else if (element is Elements.Text) { RenderText(iec, currentLocation, ref page, ref top, element); } if (i < iec.Elements.Count - 1) { currentLocation++; } } // we push page even doesnt have any content page.EndLocation = currentLocation; // add page to list iec.Pages.Add(page); #if DEBUG sw.Stop(); Debug.WriteLine(String.Format(CultureInfo.InvariantCulture, "Information: EPubReader.Renderer.Render(\"{1}\") - Executed in {0} ms", sw.ElapsedMilliseconds.ToString(CultureInfo.InvariantCulture), iec.Item.Href)); #endif }
private void RenderText(ItemElementsContainer iec, int currentLocation, ref Page page, ref double top, Elements.BaseElement element) { Elements.Text textElement = (Elements.Text)element; string value = " " + textElement.Value; TextBlock tb = ExtractTextBlock(ref page, top); double prevTextBlockActualHeight = tb.ActualHeight; tb.Inlines.Add(CreateRun(textElement, value)); double textBlockActualHeight = tb.ActualHeight - prevTextBlockActualHeight; // check if fits (in most cases it will pass, because of short paragraphs) if (top + textBlockActualHeight > page.Content.Height) { // remove inline tb.Inlines.RemoveAt(tb.Inlines.Count - 1); int idx = 1; string[] parts = value.Split(' '); while (true) { string text = StringJoin(' ', parts, idx); prevTextBlockActualHeight = tb.ActualHeight; tb.Inlines.Add(CreateRun(textElement, text)); textBlockActualHeight = tb.ActualHeight - prevTextBlockActualHeight; if (top + textBlockActualHeight > page.Content.Height) { // remove inline tb.Inlines.RemoveAt(tb.Inlines.Count - 1); // push prev text // it could be empty if nothing fits string prevText = null; if (idx > 1) { prevText = StringJoin(' ', parts, idx - 1); tb.Inlines.Add(CreateRun(textElement, prevText)); } PushPage(iec, ref page, currentLocation, ref top); // render rest of text if (idx > 1) { textElement.Value = value.Substring(prevText.Length); } else { textElement.Value = value; } RenderText(iec, currentLocation, ref page, ref top, element); break; } else { // remove inline tb.Inlines.RemoveAt(tb.Inlines.Count - 1); } idx++; } } else { // create anchor rect if href isn't null if (!String.IsNullOrEmpty(textElement.Href)) { AnchorRect anchorRect = new AnchorRect(); anchorRect.Href = textElement.Href; anchorRect.Rect = new Rect( _ePubViewer.ContentMargin.Left, (textBlockActualHeight == 0) ? top - _ePubViewer.LineHeight : top, _ePubViewer.ContentSize.Width, (textBlockActualHeight == 0) ? _ePubViewer.LineHeight : textBlockActualHeight); page.AnchorRects.Add(anchorRect); } top += textBlockActualHeight; } }
private void RenderImage(ItemElementsContainer iec, int currentLocation, ref Page page, ref double top, Elements.BaseElement element) { Elements.Image imageElement = (Elements.Image)element; // create UI element Image image = new Image(); image.Tag = imageElement; Binding binding = new Binding("Tag"); binding.RelativeSource = new RelativeSource(RelativeSourceMode.Self); binding.Converter = new Converters.IsolatedStorageFileToImageSourceConverter(); binding.ConverterParameter = _ePubViewer.Book; BindingOperations.SetBinding(image, Image.SourceProperty, binding); // check size of image (it it's larger then entire space) if (imageElement.Width + image.Margin.Left + image.Margin.Right > page.Content.Width || imageElement.Height + image.Margin.Top + image.Margin.Bottom > page.Content.Height) { // image bigger then size of control if (page.Content.Children.Count > 0) { PushPage(iec, ref page, currentLocation, ref top); } // count new width / height double widthRatio = (double)imageElement.Width / page.Content.Width; double heightRatio = (double)imageElement.Height / page.Content.Height; double ratio = Math.Max(widthRatio, heightRatio); image.Width = (int)((double)imageElement.Width / ratio); image.Height = (int)((double)imageElement.Height / ratio); image.Stretch = Stretch.Uniform; image.SetValue(Canvas.TopProperty, top); page.Content.Children.Add(image); } else { // image smaller then size of control // try fit current page if (top + imageElement.Height + image.Margin.Top + image.Margin.Bottom > page.Content.Height) { PushPage(iec, ref page, currentLocation, ref top); } image.Width = imageElement.Width; image.Height = imageElement.Height; image.Stretch = Stretch.None; image.SetValue(Canvas.TopProperty, top); page.Content.Children.Add(image); } top += image.Height + image.Margin.Top + image.Margin.Bottom; }