/// <summary> /// Convert from WPF point to core point. /// </summary> public static Point[] Convert(RPoint[] points) { Point[] myPoints = new Point[points.Length]; for (int i = 0; i < points.Length; i++) myPoints[i] = Convert(points[i]); return myPoints; }
public override void ArcTo(double x, double y, double size, Corner corner) { float left = (float)(Math.Min(x, _lastPoint.X) - (corner == Corner.TopRight || corner == Corner.BottomRight ? size : 0)); float top = (float)(Math.Min(y, _lastPoint.Y) - (corner == Corner.BottomLeft || corner == Corner.BottomRight ? size : 0)); _graphicsPath.AddArc(left, top, (float)size * 2, (float)size * 2, GetStartAngle(corner), 90); _lastPoint = new RPoint(x, y); }
/// <summary> /// Initializes a new instance of the <see cref="RRect" /> class with the specified location and size. /// </summary> /// <param name="location">A <see cref="RPoint" /> that represents the upper-left corner of the rectangular region.</param> /// <param name="size">A <see cref="RSize" /> that represents the width and height of the rectangular region.</param> public RRect(RPoint location, RSize size) { _x = location.X; _y = location.Y; _width = size.Width; _height = size.Height; }
/// <summary> /// Check if the given location is inside the given box deep.<br/> /// Check inner boxes and all lines that the given box spans to. /// </summary> /// <param name="box">the box to check</param> /// <param name="location">the location to check</param> /// <returns>true - location inside the box, false - otherwise</returns> public static bool IsInBox(CssBox box, RPoint location) { foreach (var line in box.Rectangles) { if (line.Value.Contains(location)) return true; } foreach (var childBox in box.Boxes) { if (IsInBox(childBox, location)) return true; } return false; }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// </summary> /// <param name="g">Device context to use</param> protected override void PerformLayoutImp(RGraphics g) { if (Display == CssConstants.None) return; RectanglesReset(); var prevSibling = DomUtils.GetPreviousSibling(this); double left = ContainingBlock.Location.X + ContainingBlock.ActualPaddingLeft + ActualMarginLeft + ContainingBlock.ActualBorderLeftWidth; double top = (prevSibling == null && ParentBox != null ? ParentBox.ClientTop : ParentBox == null ? Location.Y : 0) + MarginTopCollapse(prevSibling) + (prevSibling != null ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth : 0); Location = new RPoint(left, top); ActualBottom = top; //width at 100% (or auto) double minwidth = GetMinimumWidth(); double width = ContainingBlock.Size.Width - ContainingBlock.ActualPaddingLeft - ContainingBlock.ActualPaddingRight - ContainingBlock.ActualBorderLeftWidth - ContainingBlock.ActualBorderRightWidth - ActualMarginLeft - ActualMarginRight - ActualBorderLeftWidth - ActualBorderRightWidth; //Check width if not auto if (Width != CssConstants.Auto && !string.IsNullOrEmpty(Width)) { width = CssValueParser.ParseLength(Width, width, this); } if (width < minwidth || width >= 9999) width = minwidth; double height = ActualHeight; if (height < 1) { height = Size.Height + ActualBorderTopWidth + ActualBorderBottomWidth; } if (height < 1) { height = 2; } if (height <= 2 && ActualBorderTopWidth < 1 && ActualBorderBottomWidth < 1) { BorderTopStyle = BorderBottomStyle = CssConstants.Solid; BorderTopWidth = "1px"; BorderBottomWidth = "1px"; } Size = new RSize(width, height); ActualBottom = Location.Y + ActualPaddingTop + ActualPaddingBottom + height; }
/// <summary> /// Handle mouse double click to select word under the mouse. /// </summary> /// <param name="parent">the control hosting the html to set cursor and invalidate</param> /// <param name="location">the location of the mouse</param> public void HandleMouseDoubleClick(RControl parent, RPoint location) { ArgChecker.AssertArgNotNull(parent, "parent"); try { if (_selectionHandler != null && IsMouseInContainer(location)) _selectionHandler.SelectWord(parent, OffsetByScroll(location)); } catch (Exception ex) { ReportError(HtmlRenderErrorType.KeyboardMouse, "Failed mouse double click handle", ex); } }
/// <summary> /// Paint all the words in the box. /// </summary> /// <param name="g">the device to draw into</param> /// <param name="offset">the current scroll offset to offset the words</param> private void PaintWords(RGraphics g, RPoint offset) { if (Width.Length > 0) { var isRtl = Direction == CssConstants.Rtl; foreach (var word in Words) { if (!word.IsLineBreak) { var wordPoint = new RPoint(word.Left + offset.X, word.Top + offset.Y); if (word.Selected) { // handle paint selected word background and with partial word selection var wordLine = DomUtils.GetCssLineBoxByWord(word); var left = word.SelectedStartOffset > -1 ? word.SelectedStartOffset : (wordLine.Words[0] != word && word.HasSpaceBefore ? -ActualWordSpacing : 0); var padWordRight = word.HasSpaceAfter && !wordLine.IsLastSelectedWord(word); var width = word.SelectedEndOffset > -1 ? word.SelectedEndOffset : word.Width + (padWordRight ? ActualWordSpacing : 0); var rect = new RRect(word.Left + offset.X + left, word.Top + offset.Y, width - left, wordLine.LineHeight); g.DrawRectangle(GetSelectionBackBrush(g, false), rect.X, rect.Y, rect.Width, rect.Height); if (HtmlContainer.SelectionForeColor != RColor.Empty && (word.SelectedStartOffset > 0 || word.SelectedEndIndexOffset > -1)) { g.PushClipExclude(rect); g.DrawString(word.Text, ActualFont, ActualColor, wordPoint, new RSize(word.Width, word.Height), isRtl); g.PopClip(); g.PushClip(rect); g.DrawString(word.Text, ActualFont, GetSelectionForeBrush(), wordPoint, new RSize(word.Width, word.Height), isRtl); g.PopClip(); } else { g.DrawString(word.Text, ActualFont, GetSelectionForeBrush(), wordPoint, new RSize(word.Width, word.Height), isRtl); } } else { // g.DrawRectangle(HtmlContainer.Adapter.GetPen(RColor.Black), wordPoint.X, wordPoint.Y, word.Width - 1, word.Height - 1); g.DrawString(word.Text, ActualFont, ActualColor, wordPoint, new RSize(word.Width, word.Height), isRtl); } } } } }
public override void DrawPolygon(RBrush brush, RPoint[] points) { if (points != null && points.Length > 0) { var g = new StreamGeometry(); using (var context = g.Open()) { context.BeginFigure(Util.Convert(points[0]), true); for (int i = 1; i < points.Length; i++) context.LineTo(Util.Convert(points[i])); context.EndFigure(false); } _g.DrawGeometry(((BrushAdapter)brush).Brush, null, g); } }
public override void DrawString(string str, RFont font, RColor color, RPoint point, RSize size, bool rtl) { var text = GetText(str, font); text.Constraint = Util.Convert(size); _g.DrawText(new SolidColorBrush(Util.Convert(color)), Util.Convert(point), text); }
/// <summary> /// Check if the current selection is non empty, has some selection data. /// </summary> /// <param name="loc"></param> /// <param name="allowPartialSelect">true - partial word selection allowed, false - only full words selection</param> /// <returns>true - is non empty selection, false - empty selection</returns> private bool CheckNonEmptySelection(RPoint loc, bool allowPartialSelect) { // full word selection is never empty if (!allowPartialSelect) return true; // if end selection location is near starting location then the selection is empty if (Math.Abs(_selectionStartPoint.X - loc.X) <= 1 && Math.Abs(_selectionStartPoint.Y - loc.Y) < 5) return false; // selection is empty if on same word and same index return _selectionStart != _selectionEnd || _selectionStartIndex != _selectionEndIndex; }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// If the location is below the word line then set the selection to the end.<br/> /// If the location is to the right of the word then set the selection to the end.<br/> /// If the offset is to the left of the word set the selection to the beginning.<br/> /// Otherwise calculate the width of each substring to find the char the location is on. /// </summary> /// <param name="control">used to create graphics to measure string</param> /// <param name="word">the word to calculate its index and offset</param> /// <param name="loc">the location to calculate for</param> /// <param name="inclusive">is to include the first character in the calculation</param> /// <param name="selectionIndex">return the index of the char under the location</param> /// <param name="selectionOffset">return the offset of the char under the location</param> private static void CalculateWordCharIndexAndOffset(RControl control, CssRect word, RPoint loc, bool inclusive, out int selectionIndex, out double selectionOffset) { selectionIndex = 0; selectionOffset = 0f; var offset = loc.X - word.Left; if (word.Text == null) { // not a text word - set full selection selectionIndex = -1; selectionOffset = -1; } else if (offset > word.Width - word.OwnerBox.ActualWordSpacing || loc.Y > DomUtils.GetCssLineBoxByWord(word).LineBottom) { // mouse under the line, to the right of the word - set to the end of the word selectionIndex = word.Text.Length; selectionOffset = word.Width; } else if (offset > 0) { // calculate partial word selection int charFit; double charFitWidth; var maxWidth = offset + (inclusive ? 0 : 1.5f * word.LeftGlyphPadding); control.MeasureString(word.Text, word.OwnerBox.ActualFont, maxWidth, out charFit, out charFitWidth); selectionIndex = charFit; selectionOffset = charFitWidth; } }
/// <summary> /// Handle mouse move to handle hover cursor and text selection. /// </summary> /// <param name="parent">the control hosting the html to set cursor and invalidate</param> /// <param name="loc">the location of the mouse on the html</param> public void HandleMouseMove(RControl parent, RPoint loc) { if (_root.HtmlContainer.IsSelectionEnabled && _mouseDownInControl && parent.LeftMouseButton) { if (_mouseDownOnSelectedWord) { // make sure not to start drag-drop on click but when it actually moves as it f***s mouse-up if ((DateTime.Now - _lastMouseDown).TotalMilliseconds > 200) StartDragDrop(parent); } else { HandleSelection(parent, loc, !_isDoubleClickSelect); _inSelection = _selectionStart != null && _selectionEnd != null && (_selectionStart != _selectionEnd || _selectionStartIndex != _selectionEndIndex); } } else { // Handle mouse hover over the html to change the cursor depending if hovering word, link of other. var link = DomUtils.GetLinkBox(_root, loc); if (link != null) { _cursorChanged = true; parent.SetCursorHand(); if (link != _lastLink) { _root.HtmlContainer.HandleLinkHover(parent, loc, link); _lastLink = link; } } else if (_root.HtmlContainer.IsSelectionEnabled) { var word = DomUtils.GetCssBoxWord(_root, loc); _cursorChanged = word != null && !word.IsImage && !(word.Selected && (word.SelectedStartIndex < 0 || word.Left + word.SelectedStartOffset <= loc.X) && (word.SelectedEndOffset < 0 || word.Left + word.SelectedEndOffset >= loc.X)); if (_cursorChanged) parent.SetCursorIBeam(); else parent.SetCursorDefault(); _lastLink = null; } else if (_cursorChanged) { parent.SetCursorDefault(); _lastLink = null; } } }
/// <summary> /// Clear the current selection. /// </summary> public void ClearSelection() { // clear drag and drop _dragDropData = null; ClearSelection(_root); _selectionStartOffset = -1; _selectionStartIndex = -1; _selectionEndOffset = -1; _selectionEndIndex = -1; _selectionStartPoint = RPoint.Empty; _selectionStart = null; _selectionEnd = null; }
/// <summary> /// Handle mouse move to handle hover cursor and text selection. /// </summary> /// <param name="parent">the control hosting the html to set cursor and invalidate</param> /// <param name="location">the location of the mouse</param> public void HandleMouseMove(RControl parent, RPoint location) { ArgChecker.AssertArgNotNull(parent, "parent"); try { var loc = OffsetByScroll(location); if (_selectionHandler != null && IsMouseInContainer(location)) _selectionHandler.HandleMouseMove(parent, loc); /* if( _hoverBoxes != null ) { bool refresh = false; foreach(var hoverBox in _hoverBoxes) { foreach(var rect in hoverBox.Item1.Rectangles.Values) { if( rect.Contains(loc) ) { //hoverBox.Item1.Color = "gold"; refresh = true; } } } if(refresh) RequestRefresh(true); } */ } catch (Exception ex) { ReportError(HtmlRenderErrorType.KeyboardMouse, "Failed mouse move handle", ex); } }
/// <summary> /// Adjusts the location of this rectangle by the specified amount. /// </summary> /// <param name="pos">The amount to offset the location. </param> public void Offset(RPoint pos) { Offset(pos.X, pos.Y); }
/// <summary> /// Determines if the specified point is contained within this <see cref="RRect" /> structure. /// </summary> /// <returns> /// This method returns true if the point represented by the <paramref name="pt" /> parameter is contained within this /// <see cref="RRect" /> /// structure; otherwise false. /// </returns> /// <param name="pt">The <see cref="RPoint" /> to test.</param> public bool Contains(RPoint pt) { return(Contains(pt.X, pt.Y)); }
/// <summary> /// Translates a <see cref="RPoint" /> by the negative of a specified size. /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to subtract from the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Subtract(RPoint pt, RSize sz) { return(new RPoint(pt.X - sz.Width, pt.Y - sz.Height)); }
/// <summary> /// Translates a given <see cref="RPoint" /> by a specified /// <see /// cref="T:System.Drawing.SizeF" /> /// . /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to add to the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Add(RPoint pt, RSize sz) { return(new RPoint(pt.X + sz.Width, pt.Y + sz.Height)); }
/// <summary> /// Initializes a new instance of the <see cref="RSize" /> structure from the specified <see cref="RPoint" /> structure. /// </summary> /// <param name="pt">The <see cref="RPoint" /> structure from which to initialize this <see cref="RSize" /> structure.</param> public RSize(RPoint pt) { _width = pt.X; _height = pt.Y; }
/// <summary> /// Handle link clicked going over <see cref="LinkClicked"/> event and using <see cref="Process.Start()"/> if not canceled. /// </summary> /// <param name="parent">the control hosting the html to invalidate</param> /// <param name="location">the location of the mouse</param> /// <param name="link">the link that was clicked</param> internal void HandleLinkClicked(RControl parent, RPoint location, CssBox link) { EventHandler<HtmlLinkClickedEventArgs> clickHandler = LinkClicked; if (clickHandler != null) { var args = new HtmlLinkClickedEventArgs(link.HrefLink, link.HtmlTag.Attributes); try { clickHandler(this, args); } catch (Exception ex) { throw new HtmlLinkClickedException("Error in link clicked intercept", ex); } if (args.Handled) return; } if (!string.IsNullOrEmpty(link.HrefLink)) { if (link.HrefLink.StartsWith("#") && link.HrefLink.Length > 1) { EventHandler<HtmlScrollEventArgs> scrollHandler = ScrollChange; if (scrollHandler != null) { var rect = GetElementRectangle(link.HrefLink.Substring(1)); if (rect.HasValue) { scrollHandler(this, new HtmlScrollEventArgs(rect.Value.Location)); HandleMouseMove(parent, location); } } } else { var nfo = new ProcessStartInfo(link.HrefLink); nfo.UseShellExecute = true; Process.Start(nfo); } } }
/// <summary> /// Draw the given string using the given font and foreground color at given location. /// </summary> /// <param name="str">the string to draw</param> /// <param name="font">the font to use to draw the string</param> /// <param name="color">the text color to set</param> /// <param name="point">the location to start string draw (top-left)</param> /// <param name="size">used to know the size of the rendered text for transparent text support</param> /// <param name="rtl">is to render the string right-to-left (true - RTL, false - LTR)</param> public abstract void DrawString(String str, RFont font, RColor color, RPoint point, RSize size, bool rtl);
/// <summary> /// Handle mouse down to handle selection. /// </summary> /// <param name="parent">the control hosting the html to invalidate</param> /// <param name="loc">the location of the mouse on the html</param> /// <param name="isMouseInContainer"> </param> public void HandleMouseDown(RControl parent, RPoint loc, bool isMouseInContainer) { bool clear = !isMouseInContainer; if (isMouseInContainer) { _mouseDownInControl = true; _isDoubleClickSelect = (DateTime.Now - _lastMouseDown).TotalMilliseconds < 400; _lastMouseDown = DateTime.Now; _mouseDownOnSelectedWord = false; if (_root.HtmlContainer.IsSelectionEnabled && parent.LeftMouseButton) { var word = DomUtils.GetCssBoxWord(_root, loc); if (word != null && word.Selected) { _mouseDownOnSelectedWord = true; } else { clear = true; } } else if (parent.RightMouseButton) { var rect = DomUtils.GetCssBoxWord(_root, loc); var link = DomUtils.GetLinkBox(_root, loc); if (_root.HtmlContainer.IsContextMenuEnabled) { _contextMenuHandler.ShowContextMenu(parent, rect, link); } clear = rect == null || !rect.Selected; } } if (clear) { ClearSelection(); parent.Invalidate(); } }
/// <summary> /// Fills the interior of a polygon defined by an array of points specified by Point structures. /// </summary> /// <param name="brush">Brush that determines the characteristics of the fill. </param> /// <param name="points">Array of Point structures that represent the vertices of the polygon to fill. </param> public abstract void DrawPolygon(RBrush brush, RPoint[] points);
/// <summary> /// Select the word at the given location if found. /// </summary> /// <param name="control">the control hosting the html to invalidate</param> /// <param name="loc">the location to select word at</param> public void SelectWord(RControl control, RPoint loc) { if (_root.HtmlContainer.IsSelectionEnabled) { var word = DomUtils.GetCssBoxWord(_root, loc); if (word != null) { word.Selection = this; _selectionStartPoint = loc; _selectionStart = _selectionEnd = word; control.Invalidate(); } } }
/// <summary> /// Draw video image over the iframe if found. /// </summary> private void DrawImage(RGraphics g, RPoint offset, RRect rect) { if (_imageWord.Image != null) { if (rect.Width > 0 && rect.Height > 0) { if (_imageWord.ImageRectangle == RRect.Empty) g.DrawImage(_imageWord.Image, rect); else g.DrawImage(_imageWord.Image, rect, _imageWord.ImageRectangle); if (_imageWord.Selected) { g.DrawRectangle(GetSelectionBackBrush(g, true), _imageWord.Left + offset.X, _imageWord.Top + offset.Y, _imageWord.Width + 2, DomUtils.GetCssLineBoxByWord(_imageWord).LineHeight); } } } else if (_isVideo && !_imageLoadingComplete) { RenderUtils.DrawImageLoadingIcon(g, HtmlContainer, rect); if (rect.Width > 19 && rect.Height > 19) { g.DrawRectangle(g.GetPen(RColor.LightGray), rect.X, rect.Y, rect.Width, rect.Height); } } }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// <seealso cref="CalculateWordCharIndexAndOffset(RControl,HtmlRenderer.Core.Dom.CssRect,RPoint,bool)"/>. /// </summary> /// <param name="control">used to create graphics to measure string</param> /// <param name="word">the word to calculate its index and offset</param> /// <param name="loc">the location to calculate for</param> /// <param name="selectionStart">to set the starting or ending char and offset data</param> private void CalculateWordCharIndexAndOffset(RControl control, CssRect word, RPoint loc, bool selectionStart) { int selectionIndex; double selectionOffset; CalculateWordCharIndexAndOffset(control, word, loc, selectionStart, out selectionIndex, out selectionOffset); if (selectionStart) { _selectionStartIndex = selectionIndex; _selectionStartOffset = selectionOffset; } else { _selectionEndIndex = selectionIndex; _selectionEndOffset = selectionOffset; } }
/// <summary> /// Adjust the offset of the given location by the current scroll offset. /// </summary> /// <param name="location">the location to adjust</param> /// <returns>the adjusted location</returns> private RPoint OffsetByScroll(RPoint location) { return new RPoint(location.X - ScrollOffset.X, location.Y - ScrollOffset.Y); }
/// <summary> /// Handle html text selection by mouse move over the html with left mouse button pressed.<br/> /// Calculate the words in the selected range and set their selected property. /// </summary> /// <param name="control">the control hosting the html to invalidate</param> /// <param name="loc">the mouse location</param> /// <param name="allowPartialSelect">true - partial word selection allowed, false - only full words selection</param> private void HandleSelection(RControl control, RPoint loc, bool allowPartialSelect) { // get the line under the mouse or nearest from the top var lineBox = DomUtils.GetCssLineBox(_root, loc); if (lineBox != null) { // get the word under the mouse var word = DomUtils.GetCssBoxWord(lineBox, loc); // if no word found under the mouse use the last or the first word in the line if (word == null && lineBox.Words.Count > 0) { if (loc.Y > lineBox.LineBottom) { // under the line word = lineBox.Words[lineBox.Words.Count - 1]; } else if (loc.X < lineBox.Words[0].Left) { // before the line word = lineBox.Words[0]; } else if (loc.X > lineBox.Words[lineBox.Words.Count - 1].Right) { // at the end of the line word = lineBox.Words[lineBox.Words.Count - 1]; } } // if there is matching word if (word != null) { if (_selectionStart == null) { // on start set the selection start word _selectionStartPoint = loc; _selectionStart = word; if (allowPartialSelect) CalculateWordCharIndexAndOffset(control, word, loc, true); } // always set selection end word _selectionEnd = word; if (allowPartialSelect) CalculateWordCharIndexAndOffset(control, word, loc, false); ClearSelection(_root); if (CheckNonEmptySelection(loc, allowPartialSelect)) { CheckSelectionDirection(); SelectWordsInRange(_root, _backwardSelection ? _selectionEnd : _selectionStart, _backwardSelection ? _selectionStart : _selectionEnd); } else { _selectionEnd = null; } _cursorChanged = true; control.SetCursorIBeam(); control.Invalidate(); } } }
/// <summary> /// Check if the mouse is currently on the html container.<br/> /// Relevant if the html container is not filled in the hosted control (location is not zero and the size is not the full size of the control). /// </summary> private bool IsMouseInContainer(RPoint location) { return location.X >= _location.X && location.X <= _location.X + _actualSize.Width && location.Y >= _location.Y + ScrollOffset.Y && location.Y <= _location.Y + ScrollOffset.Y + _actualSize.Height; }
public override RBrush GetTextureBrush(RImage image, RRect dstRect, RPoint translateTransformLocation) { //TODO: Implement texture brush return PerspexAdapter.Instance.GetSolidBrush(Util.Convert(Colors.Magenta)); //var brush = new ImageBrush(((ImageAdapter)image).Image); //brush.Stretch = Stretch.None; //brush.TileMode = TileMode.Tile; //brush.Viewport = Utils.Convert(dstRect); //brush.ViewportUnits = BrushMappingMode.Absolute; //brush.Transform = new TranslateTransform(translateTransformLocation.X, translateTransformLocation.Y); //brush.Freeze(); //return new BrushAdapter(brush); }
/// <summary> /// Get attribute value of element at the given x,y location by given key.<br/> /// If more than one element exist with the attribute at the location the inner most is returned. /// </summary> /// <param name="location">the location to find the attribute at</param> /// <param name="attribute">the attribute key to get value by</param> /// <returns>found attribute value or null if not found</returns> public string GetAttributeAt(RPoint location, string attribute) { ArgChecker.AssertArgNotNullOrEmpty(attribute, "attribute"); var cssBox = DomUtils.GetCssBox(_root, OffsetByScroll(location)); return cssBox != null ? DomUtils.GetAttribute(cssBox, attribute) : null; }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions.<br/> /// </summary> /// <param name="g">Device context to use</param> protected virtual void PerformLayoutImp(RGraphics g) { if (Display != CssConstants.None) { RectanglesReset(); MeasureWordsSize(g); } if (IsBlock || Display == CssConstants.ListItem || Display == CssConstants.Table || Display == CssConstants.InlineTable || Display == CssConstants.TableCell) { // Because their width and height are set by CssTable if (Display != CssConstants.TableCell && Display != CssConstants.Table) { double width = ContainingBlock.Size.Width - ContainingBlock.ActualPaddingLeft - ContainingBlock.ActualPaddingRight - ContainingBlock.ActualBorderLeftWidth - ContainingBlock.ActualBorderRightWidth; if (Width != CssConstants.Auto && !string.IsNullOrEmpty(Width)) { width = CssValueParser.ParseLength(Width, width, this); } Size = new RSize(width, Size.Height); // must be separate because the margin can be calculated by percentage of the width Size = new RSize(width - ActualMarginLeft - ActualMarginRight, Size.Height); } if (Display != CssConstants.TableCell) { var prevSibling = DomUtils.GetPreviousSibling(this); double left = ContainingBlock.Location.X + ContainingBlock.ActualPaddingLeft + ActualMarginLeft + ContainingBlock.ActualBorderLeftWidth; double top = (prevSibling == null && ParentBox != null ? ParentBox.ClientTop : ParentBox == null ? Location.Y : 0) + MarginTopCollapse(prevSibling) + (prevSibling != null ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth : 0); Location = new RPoint(left, top); ActualBottom = top; } //If we're talking about a table here.. if (Display == CssConstants.Table || Display == CssConstants.InlineTable) { CssLayoutEngineTable.PerformLayout(g, this); } else { //If there's just inline boxes, create LineBoxes if (DomUtils.ContainsInlinesOnly(this)) { ActualBottom = Location.Y; CssLayoutEngine.CreateLineBoxes(g, this); //This will automatically set the bottom of this block } else if (_boxes.Count > 0) { foreach (var childBox in Boxes) { childBox.PerformLayout(g); } ActualRight = CalculateActualRight(); ActualBottom = MarginBottomCollapse(); } } } else { var prevSibling = DomUtils.GetPreviousSibling(this); if (prevSibling != null) { if (Location == RPoint.Empty) Location = prevSibling.Location; ActualBottom = prevSibling.ActualBottom; } } ActualBottom = Math.Max(ActualBottom, Location.Y + ActualHeight); CreateListItemBox(g); var actualWidth = Math.Max(GetMinimumWidth() + GetWidthMarginDeep(this), Size.Width < 90999 ? ActualRight - HtmlContainer.Root.Location.X : 0); HtmlContainer.ActualSize = CommonUtils.Max(HtmlContainer.ActualSize, new RSize(actualWidth, ActualBottom - HtmlContainer.Root.Location.Y)); }
/// <summary> /// Get css link href at the given x,y location. /// </summary> /// <param name="location">the location to find the link at</param> /// <returns>css link href if exists or null</returns> public string GetLinkAt(RPoint location) { var link = DomUtils.GetLinkBox(_root, OffsetByScroll(location)); return link != null ? link.HrefLink : null; }
/// <summary> /// Deeply offsets the top of the box and its contents /// </summary> /// <param name="amount"></param> internal void OffsetTop(double amount) { List<CssLineBox> lines = new List<CssLineBox>(); foreach (CssLineBox line in Rectangles.Keys) lines.Add(line); foreach (CssLineBox line in lines) { RRect r = Rectangles[line]; Rectangles[line] = new RRect(r.X, r.Y + amount, r.Width, r.Height); } foreach (CssRect word in Words) { word.Top += amount; } foreach (CssBox b in Boxes) { b.OffsetTop(amount); } if (_listItemBox != null) _listItemBox.OffsetTop(amount); Location = new RPoint(Location.X, Location.Y + amount); }
/// <summary> /// Handle mouse up to handle selection and link click. /// </summary> /// <param name="parent">the control hosting the html to invalidate</param> /// <param name="location">the location of the mouse</param> /// <param name="e">the mouse event data</param> public void HandleMouseUp(RControl parent, RPoint location, RMouseEvent e) { ArgChecker.AssertArgNotNull(parent, "parent"); try { if (_selectionHandler != null && IsMouseInContainer(location)) { var ignore = _selectionHandler.HandleMouseUp(parent, e.LeftButton); if (!ignore && e.LeftButton) { var loc = OffsetByScroll(location); var link = DomUtils.GetLinkBox(_root, loc); if (link != null) { HandleLinkClicked(parent, location, link); } } } } catch (HtmlLinkClickedException) { throw; } catch (Exception ex) { ReportError(HtmlRenderErrorType.KeyboardMouse, "Failed mouse up handle", ex); } }