/// <summary> /// Get top-left location to start drawing the image at depending on background-position value. /// </summary> /// <param name="backgroundPosition">the background-position value</param> /// <param name="rectangle">the rectangle to position image in</param> /// <param name="imgSize">the size of the image</param> /// <returns>the top-left location</returns> private static RPoint GetLocation(string backgroundPosition, RRect rectangle, RSize imgSize) { double left = rectangle.Left; if (backgroundPosition.IndexOf("left", StringComparison.OrdinalIgnoreCase) > -1) { left = (rectangle.Left + .5f); } else if (backgroundPosition.IndexOf("right", StringComparison.OrdinalIgnoreCase) > -1) { left = rectangle.Right - imgSize.Width; } else if (backgroundPosition.IndexOf("0", StringComparison.OrdinalIgnoreCase) < 0) { left = (rectangle.Left + (rectangle.Width - imgSize.Width) / 2 + .5f); } double top = rectangle.Top; if (backgroundPosition.IndexOf("top", StringComparison.OrdinalIgnoreCase) > -1) { top = rectangle.Top; } else if (backgroundPosition.IndexOf("bottom", StringComparison.OrdinalIgnoreCase) > -1) { top = rectangle.Bottom - imgSize.Height; } else if (backgroundPosition.IndexOf("0", StringComparison.OrdinalIgnoreCase) < 0) { top = (rectangle.Top + (rectangle.Height - imgSize.Height) / 2 + .5f); } return new RPoint(left, top); }
/// <summary> /// Init. /// </summary> protected RGraphics(RAdapter adapter, RRect initialClip) { ArgChecker.AssertArgNotNull(adapter, "global"); _adapter = adapter; _clipStack.Push(initialClip); }
/// <summary> /// Draws all the border of the box with respect to style, width, etc. /// </summary> /// <param name="g">the device to draw into</param> /// <param name="box">the box to draw borders for</param> /// <param name="rect">the bounding rectangle to draw in</param> /// <param name="isFirst">is it the first rectangle of the element</param> /// <param name="isLast">is it the last rectangle of the element</param> public static void DrawBoxBorders(RGraphics g, CssBox box, RRect rect, bool isFirst, bool isLast) { if (rect.Width > 0 && rect.Height > 0) { if (!(string.IsNullOrEmpty(box.BorderTopStyle) || box.BorderTopStyle == CssConstants.None || box.BorderTopStyle == CssConstants.Hidden) && box.ActualBorderTopWidth > 0) { DrawBorder(Border.Top, box, g, rect, isFirst, isLast); } if (isFirst && !(string.IsNullOrEmpty(box.BorderLeftStyle) || box.BorderLeftStyle == CssConstants.None || box.BorderLeftStyle == CssConstants.Hidden) && box.ActualBorderLeftWidth > 0) { DrawBorder(Border.Left, box, g, rect, true, isLast); } if (!(string.IsNullOrEmpty(box.BorderBottomStyle) || box.BorderBottomStyle == CssConstants.None || box.BorderBottomStyle == CssConstants.Hidden) && box.ActualBorderBottomWidth > 0) { DrawBorder(Border.Bottom, box, g, rect, isFirst, isLast); } if (isLast && !(string.IsNullOrEmpty(box.BorderRightStyle) || box.BorderRightStyle == CssConstants.None || box.BorderRightStyle == CssConstants.Hidden) && box.ActualBorderRightWidth > 0) { DrawBorder(Border.Right, box, g, rect, isFirst, true); } } }
/// <summary> /// Draw the background image of the given box in the given rectangle.<br/> /// Handle background-repeat and background-position values. /// </summary> /// <param name="g">the device to draw into</param> /// <param name="box">the box to draw its background image</param> /// <param name="imageLoadHandler">the handler that loads image to draw</param> /// <param name="rectangle">the rectangle to draw image in</param> public static void DrawBackgroundImage(RGraphics g, CssBox box, ImageLoadHandler imageLoadHandler, RRect rectangle) { // image size depends if specific rectangle given in image loader var imgSize = new RSize(imageLoadHandler.Rectangle == RRect.Empty ? imageLoadHandler.Image.Width : imageLoadHandler.Rectangle.Width, imageLoadHandler.Rectangle == RRect.Empty ? imageLoadHandler.Image.Height : imageLoadHandler.Rectangle.Height); // get the location by BackgroundPosition value var location = GetLocation(box.BackgroundPosition, rectangle, imgSize); var srcRect = imageLoadHandler.Rectangle == RRect.Empty ? new RRect(0, 0, imgSize.Width, imgSize.Height) : new RRect(imageLoadHandler.Rectangle.Left, imageLoadHandler.Rectangle.Top, imgSize.Width, imgSize.Height); // initial image destination rectangle var destRect = new RRect(location, imgSize); // need to clip so repeated image will be cut on rectangle var lRectangle = rectangle; lRectangle.Intersect(g.GetClip()); g.PushClip(lRectangle); switch (box.BackgroundRepeat) { case "no-repeat": g.DrawImage(imageLoadHandler.Image, destRect, srcRect); break; case "repeat-x": DrawRepeatX(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize); break; case "repeat-y": DrawRepeatY(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize); break; default: DrawRepeat(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize); break; } g.PopClip(); }
/// <summary> /// Set the image using callback from load image event, use the given data. /// </summary> /// <param name="path">the path to the image to load (file path or uri)</param> /// <param name="image">the image to load</param> /// <param name="imageRectangle">optional: limit to specific rectangle of the image and not all of it</param> private void OnHtmlImageLoadEventCallback(string path, object image, RRect imageRectangle) { if (!_disposed) { _imageRectangle = imageRectangle; if (image != null) { _image = _htmlContainer.Adapter.ConvertImage(image); ImageLoadComplete(_asyncCallback); } else if (!string.IsNullOrEmpty(path)) { SetImageFromPath(path); } else { ImageLoadComplete(_asyncCallback); } } }
/// <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); } } } } }
/// <summary> /// Get linear gradient color brush from <paramref name="color1"/> to <paramref name="color2"/>. /// </summary> /// <param name="rect">the rectangle to get the brush for</param> /// <param name="color1">the start color of the gradient</param> /// <param name="color2">the end color of the gradient</param> /// <param name="angle">the angle to move the gradient from start color to end color in the rectangle</param> /// <returns>linear gradient color brush instance</returns> public RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor color2, double angle) { return _adapter.GetLinearGradientBrush(rect, color1, color2, angle); }
/// <summary> /// Paints the background of the box /// </summary> /// <param name="g">the device to draw into</param> /// <param name="rect">the bounding rectangle to draw in</param> /// <param name="isFirst">is it the first rectangle of the element</param> /// <param name="isLast">is it the last rectangle of the element</param> protected void PaintBackground(RGraphics g, RRect rect, bool isFirst, bool isLast) { if (rect.Width > 0 && rect.Height > 0) { RBrush brush = null; if (BackgroundGradient != CssConstants.None) { brush = g.GetLinearGradientBrush(rect, ActualBackgroundColor, ActualBackgroundGradient, ActualBackgroundGradientAngle); } else if (RenderUtils.IsColorVisible(ActualBackgroundColor)) { brush = g.GetSolidBrush(ActualBackgroundColor); } if (brush != null) { // TODO:a handle it correctly (tables background) // if (isLast) // rectangle.Width -= ActualWordSpacing + CssUtils.GetWordEndWhitespace(ActualFont); RGraphicsPath roundrect = null; if (IsRounded) { roundrect = RenderUtils.GetRoundRect(g, rect, ActualCornerNw, ActualCornerNe, ActualCornerSe, ActualCornerSw); } Object prevMode = null; if (HtmlContainer != null && !HtmlContainer.AvoidGeometryAntialias && IsRounded) { prevMode = g.SetAntiAliasSmoothingMode(); } if (roundrect != null) { g.DrawPath(brush, roundrect); } else { g.DrawRectangle(brush, Math.Ceiling(rect.X), Math.Ceiling(rect.Y), rect.Width, rect.Height); } g.ReturnPreviousSmoothingMode(prevMode); if (roundrect != null) roundrect.Dispose(); brush.Dispose(); } if (_imageLoadHandler != null && _imageLoadHandler.Image != null && isFirst) { BackgroundImageDrawHandler.DrawBackgroundImage(g, this, _imageLoadHandler, rect); } } }
/// <summary> /// Draws the specified Image at the specified location and with the specified size. /// </summary> /// <param name="image">Image to draw. </param> /// <param name="destRect">Rectangle structure that specifies the location and size of the drawn image. </param> public abstract void DrawImage(RImage image, RRect destRect);
/// <summary> /// Replaces this <see cref="RRect" /> structure with the intersection of itself and the specified /// <see /// cref="RRect" /> /// structure. /// </summary> /// <param name="rect">The rectangle to intersect. </param> public void Intersect(RRect rect) { RRect rectangleF = Intersect(rect, this); X = rectangleF.X; Y = rectangleF.Y; Width = rectangleF.Width; Height = rectangleF.Height; }
/// <summary> /// Determines if this rectangle intersects with <paramref name="rect" />. /// </summary> /// <returns> /// This method returns true if there is any intersection. /// </returns> /// <param name="rect">The rectangle to test. </param> public bool IntersectsWith(RRect rect) { if (rect.X < X + Width && X < rect.X + rect.Width && rect.Y < Y + Height) return Y < rect.Y + rect.Height; else return false; }
/// <summary> /// Paints the text decoration (underline/strike-through/over-line) /// </summary> /// <param name="g">the device to draw into</param> /// <param name="rectangle"> </param> /// <param name="isFirst"> </param> /// <param name="isLast"> </param> protected void PaintDecoration(RGraphics g, RRect rectangle, bool isFirst, bool isLast) { if (string.IsNullOrEmpty(TextDecoration) || TextDecoration == CssConstants.None) return; double y = 0f; if (TextDecoration == CssConstants.Underline) { y = Math.Round(rectangle.Top + ActualFont.UnderlineOffset); } else if (TextDecoration == CssConstants.LineThrough) { y = rectangle.Top + rectangle.Height / 2f; } else if (TextDecoration == CssConstants.Overline) { y = rectangle.Top; } y -= ActualPaddingBottom - ActualBorderBottomWidth; double x1 = rectangle.X; if (isFirst) x1 += ActualPaddingLeft + ActualBorderLeftWidth; double x2 = rectangle.Right; if (isLast) x2 -= ActualPaddingRight + ActualBorderRightWidth; var pen = g.GetPen(ActualColor); pen.Width = 1; pen.DashStyle = RDashStyle.Solid; g.DrawLine(pen, x1, y, x2, y); }
/// <summary> /// Determines if the rectangular region represented by <paramref name="rect" /> is entirely contained within this /// <see cref="RRect" /> /// structure. /// </summary> /// <returns> /// This method returns true if the rectangular region represented by <paramref name="rect" /> is entirely contained within the rectangular region represented by this /// <see cref="RRect" /> /// ; otherwise false. /// </returns> /// <param name="rect"> /// The <see cref="RRect" /> to test. /// </param> public bool Contains(RRect rect) { if (X <= rect.X && rect.X + rect.Width <= X + Width && Y <= rect.Y) return rect.Y + rect.Height <= Y + Height; else return false; }
/// <summary> /// Makes a border path for rounded borders.<br/> /// To support rounded dotted/dashed borders we need to use arc in the border path.<br/> /// Return null if the border is not rounded.<br/> /// </summary> /// <param name="g">the device to draw into</param> /// <param name="border">Desired border</param> /// <param name="b">Box which the border corresponds</param> /// <param name="r">the rectangle the border is enclosing</param> /// <returns>Beveled border path, null if there is no rounded corners</returns> private static RGraphicsPath GetRoundedBorderPath(RGraphics g, Border border, CssBox b, RRect r) { RGraphicsPath path = null; switch (border) { case Border.Top: if (b.ActualCornerNw > 0 || b.ActualCornerNe > 0) { path = g.GetGraphicsPath(); path.Start(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNw); if (b.ActualCornerNw > 0) path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerNw, r.Top + b.ActualBorderTopWidth / 2, b.ActualCornerNw, RGraphicsPath.Corner.TopLeft); path.LineTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerNe, r.Top + b.ActualBorderTopWidth / 2); if (b.ActualCornerNe > 0) path.ArcTo(r.Right - b.ActualBorderRightWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNe, b.ActualCornerNe, RGraphicsPath.Corner.TopRight); } break; case Border.Bottom: if (b.ActualCornerSw > 0 || b.ActualCornerSe > 0) { path = g.GetGraphicsPath(); path.Start(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSe); if (b.ActualCornerSe > 0) path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerSe, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualCornerSe, RGraphicsPath.Corner.BottomRight); path.LineTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerSw, r.Bottom - b.ActualBorderBottomWidth / 2); if (b.ActualCornerSw > 0) path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSw, b.ActualCornerSw, RGraphicsPath.Corner.BottomLeft); } break; case Border.Right: if (b.ActualCornerNe > 0 || b.ActualCornerSe > 0) { path = g.GetGraphicsPath(); bool noTop = b.BorderTopStyle == CssConstants.None || b.BorderTopStyle == CssConstants.Hidden; bool noBottom = b.BorderBottomStyle == CssConstants.None || b.BorderBottomStyle == CssConstants.Hidden; path.Start(r.Right - b.ActualBorderRightWidth / 2 - (noTop ? b.ActualCornerNe : 0), r.Top + b.ActualBorderTopWidth / 2 + (noTop ? 0 : b.ActualCornerNe)); if (b.ActualCornerNe > 0 && noTop) path.ArcTo(r.Right - b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNe, b.ActualCornerNe, RGraphicsPath.Corner.TopRight); path.LineTo(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSe); if (b.ActualCornerSe > 0 && noBottom) path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerSe, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualCornerSe, RGraphicsPath.Corner.BottomRight); } break; case Border.Left: if (b.ActualCornerNw > 0 || b.ActualCornerSw > 0) { path = g.GetGraphicsPath(); bool noTop = b.BorderTopStyle == CssConstants.None || b.BorderTopStyle == CssConstants.Hidden; bool noBottom = b.BorderBottomStyle == CssConstants.None || b.BorderBottomStyle == CssConstants.Hidden; path.Start(r.Left + b.ActualBorderLeftWidth / 2 + (noBottom ? b.ActualCornerSw : 0), r.Bottom - b.ActualBorderBottomWidth / 2 - (noBottom ? 0 : b.ActualCornerSw)); if (b.ActualCornerSw > 0 && noBottom) path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSw, b.ActualCornerSw, RGraphicsPath.Corner.BottomLeft); path.LineTo(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNw); if (b.ActualCornerNw > 0 && noTop) path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerNw, r.Top + b.ActualBorderTopWidth / 2, b.ActualCornerNw, RGraphicsPath.Corner.TopLeft); } break; } return path; }
/// <summary> /// Draw the background image at the required location repeating it over the X and Y axis.<br/> /// Adjust location to left-top if starting location doesn't include all the range (adjusted to center or bottom/right). /// </summary> private static void DrawRepeat(RGraphics g, ImageLoadHandler imageLoadHandler, RRect rectangle, RRect srcRect, RRect destRect, RSize imgSize) { while (destRect.X > rectangle.X) destRect.X -= imgSize.Width; while (destRect.Y > rectangle.Y) destRect.Y -= imgSize.Height; using (var brush = g.GetTextureBrush(imageLoadHandler.Image, srcRect, destRect.Location)) { g.DrawRectangle(brush, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); } }
/// <summary> /// Set rectangle for inset/outset border as it need diagonal connection to other borders. /// </summary> /// <param name="border">Desired border</param> /// <param name="b">Box which the border corresponds</param> /// <param name="r">the rectangle the border is enclosing</param> /// <param name="isLineStart">Specifies if the border is for a starting line (no bevel on left)</param> /// <param name="isLineEnd">Specifies if the border is for an ending line (no bevel on right)</param> /// <returns>Beveled border path, null if there is no rounded corners</returns> private static void SetInOutsetRectanglePoints(Border border, CssBox b, RRect r, bool isLineStart, bool isLineEnd) { switch (border) { case Border.Top: _borderPts[0] = new RPoint(r.Left, r.Top); _borderPts[1] = new RPoint(r.Right, r.Top); _borderPts[2] = new RPoint(r.Right, r.Top + b.ActualBorderTopWidth); _borderPts[3] = new RPoint(r.Left, r.Top + b.ActualBorderTopWidth); if (isLineEnd) _borderPts[2].X -= b.ActualBorderRightWidth; if (isLineStart) _borderPts[3].X += b.ActualBorderLeftWidth; break; case Border.Right: _borderPts[0] = new RPoint(r.Right - b.ActualBorderRightWidth, r.Top + b.ActualBorderTopWidth); _borderPts[1] = new RPoint(r.Right, r.Top); _borderPts[2] = new RPoint(r.Right, r.Bottom); _borderPts[3] = new RPoint(r.Right - b.ActualBorderRightWidth, r.Bottom - b.ActualBorderBottomWidth); break; case Border.Bottom: _borderPts[0] = new RPoint(r.Left, r.Bottom - b.ActualBorderBottomWidth); _borderPts[1] = new RPoint(r.Right, r.Bottom - b.ActualBorderBottomWidth); _borderPts[2] = new RPoint(r.Right, r.Bottom); _borderPts[3] = new RPoint(r.Left, r.Bottom); if (isLineStart) _borderPts[0].X += b.ActualBorderLeftWidth; if (isLineEnd) _borderPts[1].X -= b.ActualBorderRightWidth; break; case Border.Left: _borderPts[0] = new RPoint(r.Left, r.Top); _borderPts[1] = new RPoint(r.Left + b.ActualBorderLeftWidth, r.Top + b.ActualBorderTopWidth); _borderPts[2] = new RPoint(r.Left + b.ActualBorderLeftWidth, r.Bottom - b.ActualBorderBottomWidth); _borderPts[3] = new RPoint(r.Left, r.Bottom); break; } }
/// <summary> /// On image load process is complete with image or without update the image box. /// </summary> /// <param name="image">the image loaded or null if failed</param> /// <param name="rectangle">the source rectangle to draw in the image (empty - draw everything)</param> /// <param name="async">is the callback was called async to load image call</param> private void OnLoadImageComplete(RImage image, RRect rectangle, bool async) { _imageWord.Image = image; _imageWord.ImageRectangle = rectangle; _imageLoadingComplete = true; _wordsSizeMeasured = false; if (_imageLoadingComplete && image == null) { SetErrorBorder(); } if (!HtmlContainer.AvoidImagesLateLoading || async) { var width = new CssLength(Width); var height = new CssLength(Height); var layout = (width.Number <= 0 || width.Unit != CssUnit.Pixels) || (height.Number <= 0 || height.Unit != CssUnit.Pixels); HtmlContainer.RequestRefresh(layout); } }
/// <summary> /// Sets the baseline of the words of the specified box to certain height /// </summary> /// <param name="g">Device info</param> /// <param name="b">box to check words</param> /// <param name="baseline">baseline</param> internal void SetBaseLine(RGraphics g, CssBox b, double baseline) { //TODO: Aqui me quede, checar poniendo "by the" con un font-size de 3em List<CssRect> ws = WordsOf(b); if (!Rectangles.ContainsKey(b)) return; RRect r = Rectangles[b]; //Save top of words related to the top of rectangle double gap = 0f; if (ws.Count > 0) { gap = ws[0].Top - r.Top; } else { CssRect firstw = b.FirstWordOccourence(b, this); if (firstw != null) { gap = firstw.Top - r.Top; } } //New top that words will have //float newtop = baseline - (Height - OwnerBox.FontDescent - 3); //OLD double newtop = baseline; // -GetBaseLineHeight(b, g); //OLD if (b.ParentBox != null && b.ParentBox.Rectangles.ContainsKey(this) && r.Height < b.ParentBox.Rectangles[this].Height) { //Do this only if rectangle is shorter than parent's double recttop = newtop - gap; RRect newr = new RRect(r.X, recttop, r.Width, r.Height); Rectangles[b] = newr; b.OffsetRectangle(this, gap); } foreach (var word in ws) { if (!word.IsImage) word.Top = newtop; } }
/// <summary> /// On image load process complete with image request refresh for it to be painted. /// </summary> /// <param name="image">the image loaded or null if failed</param> /// <param name="rectangle">the source rectangle to draw in the image (empty - draw everything)</param> /// <param name="async">is the callback was called async to load image call</param> private void OnImageLoadComplete(RImage image, RRect rectangle, bool async) { if (image != null && async) HtmlContainer.RequestRefresh(false); }
/// <summary> /// Offsets the rectangle of the specified linebox by the specified gap, /// and goes deep for rectangles of children in that linebox. /// </summary> /// <param name="lineBox"></param> /// <param name="gap"></param> internal void OffsetRectangle(CssLineBox lineBox, double gap) { if (Rectangles.ContainsKey(lineBox)) { var r = Rectangles[lineBox]; Rectangles[lineBox] = new RRect(r.X, r.Y + gap, r.Width, r.Height); } }
/// <summary> /// Draw simple border. /// </summary> /// <param name="border">Desired border</param> /// <param name="g">the device to draw to</param> /// <param name="box">Box which the border corresponds</param> /// <param name="brush">the brush to use</param> /// <param name="rectangle">the bounding rectangle to draw in</param> /// <returns>Beveled border path, null if there is no rounded corners</returns> public static void DrawBorder(Border border, RGraphics g, CssBox box, RBrush brush, RRect rectangle) { SetInOutsetRectanglePoints(border, box, rectangle, true, true); g.DrawPolygon(brush, _borderPts); }
/// <summary> /// Draw specific border (top/bottom/left/right) with the box data (style/width/rounded).<br/> /// </summary> /// <param name="border">desired border to draw</param> /// <param name="box">the box to draw its borders, contain the borders data</param> /// <param name="g">the device to draw into</param> /// <param name="rect">the rectangle the border is enclosing</param> /// <param name="isLineStart">Specifies if the border is for a starting line (no bevel on left)</param> /// <param name="isLineEnd">Specifies if the border is for an ending line (no bevel on right)</param> private static void DrawBorder(Border border, CssBox box, RGraphics g, RRect rect, bool isLineStart, bool isLineEnd) { var style = GetStyle(border, box); var color = GetColor(border, box, style); var borderPath = GetRoundedBorderPath(g, border, box, rect); if (borderPath != null) { // rounded border need special path Object prevMode = null; if (box.HtmlContainer != null && !box.HtmlContainer.AvoidGeometryAntialias && box.IsRounded) prevMode = g.SetAntiAliasSmoothingMode(); var pen = GetPen(g, style, color, GetWidth(border, box)); using (borderPath) g.DrawPath(pen, borderPath); g.ReturnPreviousSmoothingMode(prevMode); } else { // non rounded border if (style == CssConstants.Inset || style == CssConstants.Outset) { // inset/outset border needs special rectangle SetInOutsetRectanglePoints(border, box, rect, isLineStart, isLineEnd); g.DrawPolygon(g.GetSolidBrush(color), _borderPts); } else { // solid/dotted/dashed border draw as simple line var pen = GetPen(g, style, color, GetWidth(border, box)); switch (border) { case Border.Top: g.DrawLine(pen, Math.Ceiling(rect.Left), rect.Top + box.ActualBorderTopWidth / 2, rect.Right - 1, rect.Top + box.ActualBorderTopWidth / 2); break; case Border.Left: g.DrawLine(pen, rect.Left + box.ActualBorderLeftWidth / 2, Math.Ceiling(rect.Top), rect.Left + box.ActualBorderLeftWidth / 2, Math.Floor(rect.Bottom)); break; case Border.Bottom: g.DrawLine(pen, Math.Ceiling(rect.Left), rect.Bottom - box.ActualBorderBottomWidth / 2, rect.Right - 1, rect.Bottom - box.ActualBorderBottomWidth / 2); break; case Border.Right: g.DrawLine(pen, rect.Right - box.ActualBorderRightWidth / 2, Math.Ceiling(rect.Top), rect.Right - box.ActualBorderRightWidth / 2, Math.Floor(rect.Bottom)); break; } } } }
/// <summary> /// Paints the fragment /// </summary> /// <param name="g">the device to draw to</param> protected override void PaintImp(RGraphics g) { var offset = HtmlContainer != null ? HtmlContainer.ScrollOffset : RPoint.Empty; var rect = new RRect(Bounds.X + offset.X, Bounds.Y + offset.Y, Bounds.Width, Bounds.Height); if (rect.Height > 2 && RenderUtils.IsColorVisible(ActualBackgroundColor)) { g.DrawRectangle(g.GetSolidBrush(ActualBackgroundColor), rect.X, rect.Y, rect.Width, rect.Height); } var b1 = g.GetSolidBrush(ActualBorderTopColor); BordersDrawHandler.DrawBorder(Border.Top, g, this, b1, rect); if (rect.Height > 1) { var b2 = g.GetSolidBrush(ActualBorderLeftColor); BordersDrawHandler.DrawBorder(Border.Left, g, this, b2, rect); var b3 = g.GetSolidBrush(ActualBorderRightColor); BordersDrawHandler.DrawBorder(Border.Right, g, this, b3, rect); var b4 = g.GetSolidBrush(ActualBorderBottomColor); BordersDrawHandler.DrawBorder(Border.Bottom, g, this, b4, rect); } }
/// <summary> /// Push the clipping region of this Graphics to interception of current clipping rectangle and the given rectangle. /// </summary> /// <param name="rect">Rectangle to clip to.</param> public abstract void PushClip(RRect rect);
/// <summary> /// Creates and returns an inflated copy of the specified <see cref="RRect" /> structure. The copy is inflated by the specified amount. The original rectangle remains unmodified. /// </summary> /// <returns> /// The inflated <see cref="RRect" />. /// </returns> /// <param name="rect"> /// The <see cref="RRect" /> to be copied. This rectangle is not modified. /// </param> /// <param name="x">The amount to inflate the copy of the rectangle horizontally. </param> /// <param name="y">The amount to inflate the copy of the rectangle vertically. </param> public static RRect Inflate(RRect rect, double x, double y) { RRect rectangleF = rect; rectangleF.Inflate(x, y); return rectangleF; }
/// <summary> /// Push the clipping region of this Graphics to exclude the given rectangle from the current clipping rectangle. /// </summary> /// <param name="rect">Rectangle to exclude clipping in.</param> public abstract void PushClipExclude(RRect rect);
/// <summary> /// Returns a <see cref="RRect" /> structure that represents the intersection of two rectangles. If there is no intersection, and empty /// <see /// cref="RRect" /> /// is returned. /// </summary> /// <returns> /// A third <see cref="RRect" /> structure the size of which represents the overlapped area of the two specified rectangles. /// </returns> /// <param name="a">A rectangle to intersect. </param> /// <param name="b">A rectangle to intersect. </param> public static RRect Intersect(RRect a, RRect b) { double x = Math.Max(a.X, b.X); double num1 = Math.Min(a.X + a.Width, b.X + b.Width); double y = Math.Max(a.Y, b.Y); double num2 = Math.Min(a.Y + a.Height, b.Y + b.Height); if (num1 >= x && num2 >= y) return new RRect(x, y, num1 - x, num2 - y); else return Empty; }
/// <summary> /// Get TextureBrush object that uses the specified image and bounding rectangle. /// </summary> /// <param name="image">The Image object with which this TextureBrush object fills interiors.</param> /// <param name="dstRect">A Rectangle structure that represents the bounding rectangle for this TextureBrush object.</param> /// <param name="translateTransformLocation">The dimension by which to translate the transformation</param> public abstract RBrush GetTextureBrush(RImage image, RRect dstRect, RPoint translateTransformLocation);
/// <summary> /// Creates the smallest possible third rectangle that can contain both of two rectangles that form a union. /// </summary> /// <returns> /// A third <see cref="RRect" /> structure that contains both of the two rectangles that form the union. /// </returns> /// <param name="a">A rectangle to union. </param> /// <param name="b">A rectangle to union. </param> public static RRect Union(RRect a, RRect b) { double x = Math.Min(a.X, b.X); double num1 = Math.Max(a.X + a.Width, b.X + b.Width); double y = Math.Min(a.Y, b.Y); double num2 = Math.Max(a.Y + a.Height, b.Y + b.Height); return new RRect(x, y, num1 - x, num2 - y); }
/// <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); }