/// <summary> /// Static constructor and initialization /// </summary> static CssBox() { #region Initialize _properties, _inheritables and _defaults Dictionaries _properties = new Dictionary<string, PropertyInfo>(); _defaults = new Dictionary<string, string>(); _inheritables = new List<PropertyInfo>(); _cssproperties = new List<PropertyInfo>(); PropertyInfo[] props = typeof(CssBox).GetProperties(); for (int i = 0; i < props.Length; i++) { CssPropertyAttribute att = Attribute.GetCustomAttribute(props[i], typeof(CssPropertyAttribute)) as CssPropertyAttribute; if (att != null) { _properties.Add(att.Name, props[i]); _defaults.Add(att.Name, GetDefaultValue(props[i])); _cssproperties.Add(props[i]); CssPropertyInheritedAttribute inh = Attribute.GetCustomAttribute(props[i], typeof(CssPropertyInheritedAttribute)) as CssPropertyInheritedAttribute; if (inh != null) { _inheritables.Add(props[i]); } } } #endregion Empty = new CssBox(); }
/// <summary> /// Parses a length. Lengths are followed by an unit identifier (e.g. 10px, 3.1em) /// </summary> /// <param name="length">Specified length</param> /// <param name="hundredPercent">Equivalent to 100 percent when length is percentage</param> /// <param name="box"></param> /// <param name="useParentsEm"></param> /// <param name="returnPoints">Allows the return float to be in points. If false, result will be pixels</param> /// <returns></returns> public static float ParseLength(string length, float hundredPercent, CssBox box, float emFactor, bool returnPoints) { //Return zero if no length specified, zero specified if (string.IsNullOrEmpty(length) || length == "0") return 0f; //If percentage, use ParseNumber if (length.EndsWith("%")) return ParseNumber(length, hundredPercent); //If no units, return zero if (length.Length < 3) return 0f; //Get units of the length string unit = length.Substring(length.Length - 2, 2); //Factor will depend on the unit float factor = 1f; //Number of the length string number = length.Substring(0, length.Length - 2); //TODO: Units behave different in paper and in screen! switch (unit) { case CssConstants.Em: factor = emFactor; break; case CssConstants.Px: factor = 1f; break; case CssConstants.Mm: factor = 3f; //3 pixels per millimeter break; case CssConstants.Cm: factor = 37f; //37 pixels per centimeter break; case CssConstants.In: factor = 96f; //96 pixels per inch break; case CssConstants.Pt: factor = 96f / 72f; // 1 point = 1/72 of inch if (returnPoints) { return ParseNumber(number, hundredPercent); } break; case CssConstants.Pc: factor = 96f / 72f * 12f; // 1 pica = 12 points break; default: factor = 0f; break; } return factor * ParseNumber(number, hundredPercent); }
/// <summary> /// Creates a new LineBox /// </summary> public CssLineBox(CssBox ownerBox) { _rects = new Dictionary<CssBox, RectangleF>(); _relatedBoxes = new List<CssBox>(); _words = new List<CssBoxWord>(); _ownerBox = ownerBox; _ownerBox.LineBoxes.Add(this); }
public SpacingBox(CssBox tableBox, ref CssBox extendedBox, int startRow) : base(tableBox, new HtmlTag("<none colspan=" + extendedBox.GetAttribute("colspan", "1") + ">")) { ExtendedBox = extendedBox; Display = CssConstants.None; _startRow = startRow; _endRow = startRow + int.Parse(extendedBox.GetAttribute("rowspan", "1")) - 1; }
public CssTable(CssBox tableBox, Graphics g) :this() { if (!(tableBox.Display == CssConstants.Table || tableBox.Display == CssConstants.InlineTable)) throw new ArgumentException("Box is not a table", "tableBox"); _tableBox = tableBox; MeasureWords(tableBox, g); Analyze(g); }
public CssAnonymousBlockBox(CssBox parent, CssBox insertBefore) : this(parent) { int index = parent.Boxes.IndexOf(insertBefore); if (index < 0) { throw new Exception("insertBefore box doesn't exist on parent"); } parent.Boxes.Remove(this); parent.Boxes.Insert(index, this); }
/// <summary> /// Creates line boxes for the specified blockbox /// </summary> /// <param name="g"></param> /// <param name="blockBox"></param> public static void CreateLineBoxes(Graphics g, CssBox blockBox) { blockBox.LineBoxes.Clear(); float maxRight = blockBox.ActualRight - blockBox.ActualPaddingRight - blockBox.ActualBorderRightWidth; //Get the start x and y of the blockBox float startx = blockBox.Location.X + blockBox.ActualPaddingLeft - 0 + blockBox.ActualBorderLeftWidth; //TODO: Check for floats float starty = blockBox.Location.Y + blockBox.ActualPaddingTop - 0 + blockBox.ActualBorderTopWidth; float curx = startx + blockBox.ActualTextIndent; float cury = starty; //Reminds the maximum bottom reached float maxBottom = starty; //Extra amount of spacing that should be applied to lines when breaking them. float lineSpacing = 0f; //First line box CssLineBox line = new CssLineBox(blockBox); //Flow words and boxes FlowBox(g, blockBox, blockBox, maxRight, lineSpacing, startx,ref line, ref curx, ref cury, ref maxBottom); //Gets the rectangles foreach linebox foreach (CssLineBox linebox in blockBox.LineBoxes) { BubbleRectangles(blockBox, linebox); linebox.AssignRectanglesToBoxes(); ApplyAlignment(g, linebox); if (blockBox.Direction == CssConstants.Rtl) ApplyRightToLeft(linebox); //linebox.DrawRectangles(g); } blockBox.ActualBottom = maxBottom + blockBox.ActualPaddingBottom + blockBox.ActualBorderBottomWidth; }
/// <summary> /// Gets the cell column index checking its position and other cells colspans /// </summary> /// <param name="row"></param> /// <param name="cell"></param> /// <returns></returns> private int GetCellRealColumnIndex(CssBox row, CssBox cell) { int i = 0; foreach (CssBox b in row.Boxes) { if (b.Equals(cell)) break; i += GetColSpan(b); } return i; }
/// <summary> /// Gets the spanned width of a cell /// (With of all columns it spans minus one) /// </summary> /// <param name="row"></param> /// <param name="cell"></param> /// <param name="realcolindex"></param> /// <param name="colspan"></param> /// <returns></returns> private float GetSpannedMinWidth(CssBox row, CssBox cell, int realcolindex, int colspan) { float w = 0f; for (int i = realcolindex; i < row.Boxes.Count || i < realcolindex + colspan - 1; i++) { w += ColumnMinWidths[i]; } return w; }
/// <summary> /// Analyzes the Table and assigns values to this CssTable object. /// To be called from the constructor /// </summary> private void Analyze(Graphics g) { float availSpace = GetAvailableWidth(); float availCellSpace = float.NaN; //Will be set later #region Assign box kinds foreach (CssBox b in TableBox.Boxes) { b.RemoveAnonymousSpaces(); switch (b.Display) { case CssConstants.TableCaption: _caption = b; break; case CssConstants.TableColumn: for (int i = 0; i < GetSpan(b); i++) { Columns.Add(CreateColumn(b)); } break; case CssConstants.TableColumnGroup: if (b.Boxes.Count == 0) { int gspan = GetSpan(b); for (int i = 0; i < gspan; i++) { Columns.Add(CreateColumn(b)); } } else { foreach (CssBox bb in b.Boxes) { int bbspan = GetSpan(bb); for (int i = 0; i < bbspan; i++) { Columns.Add(CreateColumn(bb)); } } } break; case CssConstants.TableFooterGroup: if (FooterBox != null) BodyRows.Add(b); else _footerBox = b; break; case CssConstants.TableHeaderGroup: if (HeaderBox != null) BodyRows.Add(b); else _headerBox = b; break; case CssConstants.TableRow: BodyRows.Add(b); break; case CssConstants.TableRowGroup: foreach (CssBox bb in b.Boxes) if (b.Display == CssConstants.TableRow) BodyRows.Add(b); break; default: break; } } #endregion #region Gather AllRows if (HeaderBox != null) _allRows.AddRange(HeaderBox.Boxes); _allRows.AddRange(BodyRows); if (FooterBox != null) _allRows.AddRange(FooterBox.Boxes); #endregion #region Insert EmptyBoxes for vertical cell spanning if (!TableBox.TableFixed) { int currow = 0; int curcol = 0; List<CssBox> rows = BodyRows; foreach (CssBox row in rows) { row.RemoveAnonymousSpaces(); curcol = 0; for(int k = 0; k < row.Boxes.Count ; k++) { CssBox cell = row.Boxes[k]; int rowspan = GetRowSpan(cell); int realcol = GetCellRealColumnIndex(row, cell); //Real column of the cell for (int i = currow + 1; i < currow + rowspan; i++) { int colcount = 0; for (int j = 0; j <= rows[i].Boxes.Count; j++) { if (colcount == realcol) { rows[i].Boxes.Insert(colcount, new SpacingBox(TableBox, ref cell, currow)); break; } colcount++; realcol -= GetColSpan(rows[i].Boxes[j]) - 1; } } // End for (int i = currow + 1; i < currow + rowspan; i++) curcol++; } /// End foreach (Box cell in row.Boxes) currow++; } /// End foreach (Box row in rows) TableBox.TableFixed = true; } /// End if (!TableBox.TableFixed) #endregion #region Determine Row and Column Count, and ColumnWidths //Rows _rowCount = BodyRows.Count + (HeaderBox != null ? HeaderBox.Boxes.Count : 0) + (FooterBox != null ? FooterBox.Boxes.Count : 0); //Columns if (Columns.Count > 0) _columnCount = Columns.Count; else foreach (CssBox b in AllRows) //Check trhough rows _columnCount = Math.Max(_columnCount, b.Boxes.Count); //Initialize column widths array _columnWidths = new float[_columnCount]; //Fill them with NaNs for (int i = 0; i < _columnWidths.Length; i++) _columnWidths[i] = float.NaN; availCellSpace = GetAvailableCellWidth(); if (Columns.Count > 0) { #region Fill ColumnWidths array by scanning column widths for (int i = 0; i < Columns.Count; i++) { CssLength len = new CssLength(Columns[i].Width); //Get specified width if (len.Number > 0) //If some width specified { if (len.IsPercentage)//Get width as a percentage { ColumnWidths[i] = CssValue.ParseNumber(Columns[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { ColumnWidths[i] = len.Number; //Get width as an absolute-pixel value } } } #endregion } else { #region Fill ColumnWidths array by scanning width in table-cell definitions foreach (CssBox row in AllRows) { //Check for column width in table-cell definitions for (int i = 0; i < _columnCount; i++) { if (float.IsNaN(ColumnWidths[i]) && //Check if no width specified for column i < row.Boxes.Count && //And there's a box to check row.Boxes[i].Display == CssConstants.TableCell)//And the box is a table-cell { CssLength len = new CssLength(row.Boxes[i].Width); //Get specified width if (len.Number > 0) //If some width specified { int colspan = GetColSpan(row.Boxes[i]); float flen = 0f; if (len.IsPercentage)//Get width as a percentage { flen = CssValue.ParseNumber(row.Boxes[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { flen = len.Number; //Get width as an absolute-pixel value } flen /= Convert.ToSingle(colspan); for (int j = i; j < i + colspan; j++) { ColumnWidths[j] = flen; } } } } } #endregion } #endregion #region Determine missing Column widths if (WidthSpecified) //If a width was specified, { //Assign NaNs equally with space left after gathering not-NaNs int numberOfNans = 0; float occupedSpace = 0f; //Calculate number of NaNs and occuped space for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) numberOfNans++; else occupedSpace += ColumnWidths[i]; //Determine width that will be assigned to un asigned widths float nanWidth = (availCellSpace - occupedSpace) / Convert.ToSingle(numberOfNans); for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) ColumnWidths[i] = nanWidth; } else { //Assign NaNs using full width float[] _maxFullWidths = new float[ColumnWidths.Length]; //Get the maximum full length of NaN boxes foreach (CssBox row in AllRows) { for (int i = 0; i < row.Boxes.Count; i++) { int col = GetCellRealColumnIndex(row, row.Boxes[i]); if (float.IsNaN(ColumnWidths[col]) && i < row.Boxes.Count && GetColSpan(row.Boxes[i]) == 1) { _maxFullWidths[col] = Math.Max(_maxFullWidths[col], row.Boxes[i].GetFullWidth(g)); } } } for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) ColumnWidths[i] = _maxFullWidths[i]; } #endregion #region Reduce widths if necessary int curCol = 0; float reduceAmount = 1f; //While table width is larger than it should, and width is reductable while (GetWidthSum() > GetAvailableWidth() && CanReduceWidth()) { while (!CanReduceWidth(curCol)) curCol++; ColumnWidths[curCol] -= reduceAmount; curCol++; if (curCol >= ColumnWidths.Length) curCol = 0; } #endregion #region Check for minimum sizes (increment widths if necessary) foreach (CssBox row in AllRows) { foreach (CssBox cell in row.Boxes) { int colspan = GetColSpan(cell); int col = GetCellRealColumnIndex(row, cell); int affectcol = col + colspan - 1; if (ColumnWidths[col] < ColumnMinWidths[col]) { float diff = ColumnMinWidths[col] - ColumnWidths[col]; ColumnWidths[affectcol] = ColumnMinWidths[affectcol]; if (col < ColumnWidths.Length - 1) { ColumnWidths[col + 1] -= diff; } } } } #endregion #region Set table padding TableBox.Padding = "0"; //Ensure there's no padding #endregion #region Layout cells //Actually layout cells! float startx = TableBox.ClientLeft + HorizontalSpacing; float starty = TableBox.ClientTop + VerticalSpacing; float curx = startx; float cury = starty; float maxRight = startx; float maxBottom = 0f; int currentrow = 0; foreach (CssBox row in AllRows) { if (row is CssAnonymousSpaceBlockBox || row is CssAnonymousSpaceBox) continue; curx = startx; curCol = 0; foreach (CssBox cell in row.Boxes) { if (curCol >= ColumnWidths.Length) break; int rowspan = GetRowSpan(cell); float width = GetCellWidth(GetCellRealColumnIndex(row, cell), cell); cell.Location = new PointF(curx, cury); cell.Size = new SizeF(width, 0f); cell.MeasureBounds(g); //That will automatically set the bottom of the cell //Alter max bottom only if row is cell's row + cell's rowspan - 1 SpacingBox sb = cell as SpacingBox; if (sb != null) { if (sb.EndRow == currentrow) { maxBottom = Math.Max(maxBottom, sb.ExtendedBox.ActualBottom); } } else if(rowspan == 1) { maxBottom = Math.Max(maxBottom, cell.ActualBottom); } maxRight = Math.Max(maxRight, cell.ActualRight); curCol++; curx = cell.ActualRight + HorizontalSpacing; } foreach (CssBox cell in row.Boxes) { SpacingBox spacer = cell as SpacingBox; if (spacer == null && GetRowSpan(cell) == 1) { cell.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, cell); } else if(spacer != null && spacer.EndRow == currentrow) { spacer.ExtendedBox.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, spacer.ExtendedBox); } } cury = maxBottom + VerticalSpacing; currentrow++; } TableBox.ActualRight = maxRight + HorizontalSpacing + TableBox.ActualBorderRightWidth; TableBox.ActualBottom = maxBottom + VerticalSpacing + TableBox.ActualBorderBottomWidth; #endregion }
/// <summary> /// Applies style to all boxes in the tree /// </summary> private void CascadeStyles(CssBox startBox) { bool someBlock = false; foreach (CssBox b in startBox.Boxes) { b.InheritStyle(); if (b.HtmlTag != null) { //Check if tag name matches with a defined class if (MediaBlocks["all"].ContainsKey(b.HtmlTag.TagName)) { MediaBlocks["all"][b.HtmlTag.TagName].AssignTo(b); } //Check if class="" attribute matches with a defined style if (b.HtmlTag.HasAttribute("class") && MediaBlocks["all"].ContainsKey("." + b.HtmlTag.Attributes["class"])) { MediaBlocks["all"]["." + b.HtmlTag.Attributes["class"]].AssignTo(b); } b.HtmlTag.TranslateAttributes(b); //Check for the style="" attribute if (b.HtmlTag.HasAttribute("style")) { CssBlock block = new CssBlock(b.HtmlTag.Attributes["style"]); block.AssignTo(b); } //Check for the <style> tag if (b.HtmlTag.TagName.Equals("style", StringComparison.CurrentCultureIgnoreCase) && b.Boxes.Count == 1) { FeedStyleSheet(b.Boxes[0].Text); } //Check for the <link rel=stylesheet> tag if (b.HtmlTag.TagName.Equals("link", StringComparison.CurrentCultureIgnoreCase) && b.GetAttribute("rel", string.Empty).Equals("stylesheet", StringComparison.CurrentCultureIgnoreCase)) { FeedStyleSheet(CssValue.GetStyleSheet(b.GetAttribute("href", string.Empty))); } } CascadeStyles(b); } if (someBlock) { foreach (CssBox box in startBox.Boxes) { box.Display = CssConstants.Block; } } }
/// <summary> /// Scans the boxes (non-deeply) of the box, and returns groups of contiguous inline boxes. /// </summary> /// <param name="b"></param> /// <returns></returns> private List<List<CssBox>> BlockCorrection_GetInlineGroups(CssBox box) { List<List<CssBox>> result = new List<List<CssBox>>(); List<CssBox> current = null; //Scan boxes for (int i = 0; i < box.Boxes.Count; i++) { CssBox b = box.Boxes[i]; //If inline, add it to the current group if (b.Display == CssConstants.Inline) { if (current == null) { current = new List<CssBox>(); result.Add(current); } current.Add(b); } else { current = null; } } //If last list contains nothing, erase it if (result.Count > 0 && result[result.Count - 1].Count == 0) { result.RemoveAt(result.Count - 1); } return result; }
/// <summary> /// Recursively measures words inside the box /// </summary> /// <param name="b"></param> /// <param name="g"></param> private void MeasureWords(CssBox b, Graphics g) { if (b == null) return; foreach (CssBox bb in b.Boxes) { bb.MeasureWordsSize(g); MeasureWords(bb, g); } }
/// <summary> /// Gets the rowspan of the specified box /// </summary> /// <param name="b"></param> private int GetRowSpan(CssBox b) { string att = b.GetAttribute("rowspan", "1"); int rowspan; if (!int.TryParse(att, out rowspan)) { return 1; } return rowspan; }
/// <summary> /// Rounds the specified point /// </summary> /// <param name="p"></param> /// <param name="b"></param> /// <returns></returns> private static PointF RoundP(PointF p, CssBox b) { //HACK: Don't round if in printing mode //return Point.Round(p); return p; }
/// <summary> /// Creates the corner to place with the borders /// </summary> /// <param name="outer"></param> /// <param name="inner"></param> /// <param name="startAngle"></param> /// <param name="sweepAngle"></param> /// <returns></returns> private static GraphicsPath CreateCorner(CssBox b, RectangleF r, int cornerIndex) { GraphicsPath corner = new GraphicsPath(); RectangleF outer = RectangleF.Empty; RectangleF inner = RectangleF.Empty; float start1 = 0; float start2 = 0; switch (cornerIndex) { case 1: outer = new RectangleF(r.Left, r.Top, b.ActualCornerNW, b.ActualCornerNW); inner = RectangleF.FromLTRB(outer.Left + b.ActualBorderLeftWidth, outer.Top + b.ActualBorderTopWidth, outer.Right, outer.Bottom); start1 = 180; start2 = 270; break; case 2: outer = new RectangleF(r.Right - b.ActualCornerNE, r.Top, b.ActualCornerNE, b.ActualCornerNE); inner = RectangleF.FromLTRB(outer.Left, outer.Top + b.ActualBorderTopWidth, outer.Right - b.ActualBorderRightWidth, outer.Bottom); outer.X -= outer.Width; inner.X -= inner.Width; start1 = -90; start2 = 0; break; case 3: outer = RectangleF.FromLTRB(r.Right - b.ActualCornerSE, r.Bottom - b.ActualCornerSE, r.Right, r.Bottom); inner = new RectangleF(outer.Left, outer.Top, outer.Width - b.ActualBorderRightWidth, outer.Height - b.ActualBorderBottomWidth); outer.X -= outer.Width; outer.Y -= outer.Height; inner.X -= inner.Width; inner.Y -= inner.Height; start1 = 0; start2 = 90; break; case 4: outer = new RectangleF(r.Left, r.Bottom - b.ActualCornerSW, b.ActualCornerSW, b.ActualCornerSW); inner = RectangleF.FromLTRB( r.Left + b.ActualBorderLeftWidth , outer.Top , outer.Right, outer.Bottom - b.ActualBorderBottomWidth); start1 = 90; start2 = 180; outer.Y -= outer.Height; inner.Y -= inner.Height; break; } if (outer.Width <= 0f) outer.Width = 1f; if (outer.Height <= 0f) outer.Height = 1f; if (inner.Width <= 0f) inner.Width = 1f; if (inner.Height <= 0f) inner.Height = 1f; outer.Width *= 2; outer.Height *= 2; inner.Width *= 2; inner.Height *= 2; outer = RoundR(outer, b); inner = RoundR(inner, b); corner.AddArc(outer, start1, 90); corner.AddArc(inner, start2, -90); corner.CloseFigure(); return corner; }
public CssAnonymousSpaceBlockBox(CssBox parent, CssBox insertBefore) : base(parent, insertBefore) { Display = CssConstants.None; }
public CssAnonymousSpaceBlockBox(CssBox parent) : base(parent) { Display = CssConstants.None; }
public CssAnonymousBlockBox(CssBox parent) : base(parent) { Display = CssConstants.Block; }
/// <summary> /// Gets the cells width, taking colspan and being in the specified column /// </summary> /// <param name="column"></param> /// <param name="b"></param> /// <returns></returns> private float GetCellWidth(int column, CssBox b) { float colspan = Convert.ToSingle(GetColSpan(b)); float sum = 0f; for (int i = column; i < column + colspan; i++) { if (column >= ColumnWidths.Length) break; if (ColumnWidths.Length <= i) break; sum += ColumnWidths[i]; } sum += (colspan - 1) * HorizontalSpacing; return sum; ;// -b.ActualBorderLeftWidth - b.ActualBorderRightWidth - b.ActualPaddingRight - b.ActualPaddingLeft; }
/// <summary> /// Gets the colspan of the specified box /// </summary> /// <param name="b"></param> private int GetColSpan(CssBox b) { string att = b.GetAttribute("colspan", "1"); int colspan; if (!int.TryParse(att, out colspan)) { return 1; } return colspan; }
/// <summary> /// Gets the span attribute of the tag of the specified box /// </summary> /// <param name="b"></param> private int GetSpan(CssBox b) { float f = CssValue.ParseNumber(b.GetAttribute("span"), 1); return Math.Max(1, Convert.ToInt32(f)); }
/// <summary> /// Recursively measures the specified box /// </summary> /// <param name="b"></param> /// <param name="g"></param> private void Measure(CssBox b, Graphics g) { if (b == null) return; foreach (CssBox bb in b.Boxes) { bb.MeasureBounds(g); Measure(bb, g); } }
internal CssBoxWord(CssBox owner) { _ownerBox = owner; _word = string.Empty; }
/// <summary> /// Rounds the specified rectangle /// </summary> /// <param name="p"></param> /// <param name="b"></param> /// <returns></returns> private static RectangleF RoundR(RectangleF r, CssBox b) { //HACK: Don't round if in printing mode return Rectangle.Round(r); }
/// <summary> /// Makes block boxes be among only block boxes. /// Inline boxes should live in a pool of Inline boxes only. /// </summary> /// <param name="startBox"></param> private void BlockCorrection(CssBox startBox) { bool inlinesonly = startBox.ContainsInlinesOnly(); if (!inlinesonly) { List<List<CssBox>> inlinegroups = BlockCorrection_GetInlineGroups(startBox); foreach (List<CssBox> group in inlinegroups) { if (group.Count == 0) continue; if (group.Count == 1 && group[0] is CssAnonymousSpaceBox) { CssAnonymousSpaceBlockBox sbox = new CssAnonymousSpaceBlockBox(startBox, group[0]); group[0].ParentBox = sbox; } else { CssAnonymousBlockBox newbox = new CssAnonymousBlockBox(startBox, group[0]); foreach (CssBox inline in group) { inline.ParentBox = newbox; } } } } foreach (CssBox b in startBox.Boxes) { BlockCorrection(b); } }
/// <summary> /// Creates the column with the specified width /// </summary> /// <param name="width"></param> /// <returns></returns> private CssBox CreateColumn(CssBox modelBox) { return modelBox; //Box b = new Box(null, new HtmlTag(string.Format("<COL style=\"width:{0}\" >", width))); //b.Width = width; //return b; }
/// <summary> /// Makes a border path /// </summary> /// <param name="border">Desired border</param> /// <param name="b">Box wich the border corresponds</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</returns> public static GraphicsPath GetBorderPath(Border border, CssBox b, RectangleF r, bool isLineStart, bool isLineEnd) { PointF[] pts = new PointF[4]; float bwidth = 0; GraphicsPath corner = null; switch (border) { case Border.Top: bwidth = b.ActualBorderTopWidth; pts[0] = RoundP(new PointF(r.Left + b.ActualCornerNW, r.Top), b); pts[1] = RoundP(new PointF(r.Right - b.ActualCornerNE, r.Top), b); pts[2] = RoundP(new PointF(r.Right - b.ActualCornerNE, r.Top + bwidth), b); pts[3] = RoundP(new PointF(r.Left + b.ActualCornerNW, r.Top + bwidth), b); if (isLineEnd && b.ActualCornerNE == 0f) pts[2].X -= b.ActualBorderRightWidth; if (isLineStart && b.ActualCornerNW == 0f) pts[3].X += b.ActualBorderLeftWidth; if (b.ActualCornerNW > 0f) corner = CreateCorner(b, r, 1); break; case Border.Right: bwidth = b.ActualBorderRightWidth; pts[0] = RoundP(new PointF(r.Right - bwidth, r.Top + b.ActualCornerNE), b); pts[1] = RoundP(new PointF(r.Right, r.Top + b.ActualCornerNE), b); pts[2] = RoundP(new PointF(r.Right, r.Bottom - b.ActualCornerSE), b); pts[3] = RoundP(new PointF(r.Right - bwidth, r.Bottom - b.ActualCornerSE), b); if (b.ActualCornerNE == 0f) pts[0].Y += b.ActualBorderTopWidth; if (b.ActualCornerSE == 0f) pts[3].Y -= b.ActualBorderBottomWidth; if (b.ActualCornerNE > 0f) corner = CreateCorner(b, r, 2); break; case Border.Bottom: bwidth = b.ActualBorderBottomWidth; pts[0] = RoundP(new PointF(r.Left + b.ActualCornerSW, r.Bottom - bwidth), b); pts[1] = RoundP(new PointF(r.Right - b.ActualCornerSE, r.Bottom - bwidth), b); pts[2] = RoundP(new PointF(r.Right - b.ActualCornerSE, r.Bottom), b); pts[3] = RoundP(new PointF(r.Left + b.ActualCornerSW, r.Bottom), b); if (isLineStart && b.ActualCornerSW == 0f) pts[0].X += b.ActualBorderLeftWidth; if (isLineEnd && b.ActualCornerSE == 0f) pts[1].X -= b.ActualBorderRightWidth; if (b.ActualCornerSE > 0f) corner = CreateCorner(b, r, 3); break; case Border.Left: bwidth = b.ActualBorderLeftWidth; pts[0] = RoundP(new PointF(r.Left, r.Top + b.ActualCornerNW), b); pts[1] = RoundP(new PointF(r.Left + bwidth, r.Top + b.ActualCornerNW), b); pts[2] = RoundP(new PointF(r.Left + bwidth, r.Bottom - b.ActualCornerSW), b); pts[3] = RoundP(new PointF(r.Left, r.Bottom - b.ActualCornerSW), b); if (b.ActualCornerNW == 0f) pts[1].Y += b.ActualBorderTopWidth; if (b.ActualCornerSW == 0f) pts[2].Y -= b.ActualBorderBottomWidth; if (b.ActualCornerSW > 0f) corner = CreateCorner(b, r, 4); break; } GraphicsPath path = new GraphicsPath(pts, new byte[] { (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line }); if (corner != null) { path.AddPath(corner, true); } return path; }
/// <summary> /// Creates a new BoxWord which represents an image /// </summary> /// <param name="owner"></param> /// <param name="image"></param> public CssBoxWord(CssBox owner, Image image) : this(owner) { Image = image; }
/// <summary> /// Asigns the style on this block o the specified box /// </summary> /// <param name="b"></param> public void AssignTo(CssBox b) { foreach (PropertyInfo prop in PropertyValues.Keys) { string value = PropertyValues[prop]; if (value == CssConstants.Inherit && b.ParentBox != null) { value = Convert.ToString(prop.GetValue(b.ParentBox, null)); } prop.SetValue(b, value, null); } }