public static float Calculate (Rule rule, DOMElement element) { try { // Cut unnecessary parts string value = rule.Value.Split(new[] { "calc(" }, StringSplitOptions.None)[1]; value = value.ToLower(); if (value[value.Length - 1] != ')') return -1f; else value = value.Substring(0, value.Length - 1); if (value.Length < 2) return -1f; // Cut pixel unit value = Compute(rule, element, value, Unit.Px, false); foreach (Unit unit in CSSUnits.allUnits) value = Compute(rule, element, value, unit); if (value == null) { Console.WriteLine("Calc function isn't correct!"); return -1f; } else { return float.Parse(new DataTable().Compute(value, "").ToString().Replace(',', '.'), CultureInfo.InvariantCulture.NumberFormat); } } catch (Exception exception) { Console.WriteLine(exception.Message); return -1f; } }
/// <summary> // Calculates x times the size of the current font /// </summary> public static float EmToPx(Rule rule, DOMElement element) { float fontSize = (element.Parent != null) ? element.Parent.Style.Font.Size : 16; // 16 - Document font-size if (element.Style.Font != null) { fontSize = element.Style.Font.Size; } return(fontSize * rule.ComputedValue.Value); }
/// <summary> /// Calculates pixels from percent /// </summary> public static float PercentToPx(Rule rule, DOMElement element) { if (rule.Property == "width") { float parentWidth = (element.Parent != null) ? element.Parent.ComputedStyle.Size.Width : LayoutEngine.htmlDocument.Width; return((rule.ComputedValue.ValueBeforeComputing / 100) * parentWidth); } else if (rule.Property == "height") { float parentHeight = (element.Parent != null) ? element.Parent.Style.Size.Height : LayoutEngine.htmlDocument.Height; return((rule.ComputedValue.ValueBeforeComputing / 100) * parentHeight); } return(0f); }
public static CSSValue ParseValue(Rule rule, DOMElement element) { CSSValue cssValue = new CSSValue(); if (rule.Value.StartsWith("calc(")) { cssValue.Unit = Unit.CalcFunc; rule.ComputedValue = cssValue; return(cssValue); } else { List <string> array = Regex.Split(rule.Value, @"[^0-9\.]+").Where(c => c != "." && c.Trim() != "").ToList(); if (array.Count > 0 && rule.Value.Length > 2) { float value = float.Parse(array[0], CultureInfo.InvariantCulture.NumberFormat); int startIndex = value.ToString().Length; string unitType = rule.Value.Substring(startIndex, rule.Value.Length - startIndex).ToLower(); cssValue.Value = value; foreach (Unit unit in allUnits) { string abbreviation = GetUnitAbbreviation(unit); if (unitType == abbreviation) { cssValue.Unit = unit; } } rule.ComputedValue = cssValue; cssValue.Value = ConvertAnyUnitToPixels(rule, element); cssValue.ValueBeforeComputing = value; return(cssValue); } } return(null); }
public static float ConvertAnyUnitToPixels(Rule rule, DOMElement element) { CSSValue cssValue = rule.ComputedValue; if (cssValue.Unit == Unit.Px) { return(cssValue.Value); } else if (cssValue.Unit == Unit.Cm) { return(CSSUnitsConverter.CmToPX(cssValue.Value)); } else if (cssValue.Unit == Unit.Mm) { return(CSSUnitsConverter.MmToPX(cssValue.Value)); } else if (cssValue.Unit == Unit.In) { return(CSSUnitsConverter.InToPX(cssValue.Value)); } else if (cssValue.Unit == Unit.Percent) { return(CSSUnitsConverter.PercentToPx(rule, element)); } else if (cssValue.Unit == Unit.Pt) { return(CSSUnitsConverter.PtToPX(cssValue.Value)); } else if (cssValue.Unit == Unit.Em) { return(CSSUnitsConverter.EmToPx(rule, element)); } else if (cssValue.Unit == Unit.Vh) { return(CSSUnitsConverter.VhToPx(rule, element)); } else if (cssValue.Unit == Unit.Vw) { return(CSSUnitsConverter.VwToPx(rule, element)); } return(-1f); }
private static string Compute (Rule rule, DOMElement element, string calcString, Unit unitType, bool convert = true) { while (true) { string unit = CSSUnits.GetUnitAbbreviation(unitType); int unitStartIndex = calcString.IndexOf(unit); int unitEndIndex = unitStartIndex + unit.Length; // If there is no unit if (unitStartIndex == -1) break; // Get starting value index int valueStartIndex = GetStartIndex(calcString, unitStartIndex); if (valueStartIndex == unitStartIndex) return null; // Get and parse value string value = calcString.Substring(valueStartIndex, unitStartIndex - valueStartIndex); float parsedValue = float.Parse(value, CultureInfo.InvariantCulture.NumberFormat); // Compute the value if (convert) { rule.ComputedValue.Unit = unitType; rule.ComputedValue.ValueBeforeComputing = parsedValue; rule.ComputedValue.Value = parsedValue; } float computedValue = (convert) ? CSSUnits.ConvertAnyUnitToPixels(rule, element) : parsedValue; // Replace string with computed value StringBuilder stringBuilder = new StringBuilder(calcString); stringBuilder.Remove(valueStartIndex, unitStartIndex - valueStartIndex + unit.Length); stringBuilder.Insert(valueStartIndex, computedValue.ToString().Replace(',', '.')); calcString = stringBuilder.ToString(); } return calcString; }
private static void SetPositions(List <DOMElement> elements) { foreach (DOMElement element in elements) { if (elements.IndexOf(element) > 0) { DOMElement prevElement = elements[elements.IndexOf(element) - 1]; if (element.Style.Display == Display.InlineBlock || element.Style.Display == Display.TableCell) { element.ComputedStyle.Position.Y = prevElement.ComputedStyle.Position.Y + element.ComputedStyle.Padding.Top; element.ComputedStyle.Position.X = 0; if (prevElement.Style.Display == element.Style.Display) { element.ComputedStyle.Position.X += prevElement.ComputedStyle.Position.X + prevElement.ComputedStyle.Size.Width; } else { element.ComputedStyle.Position.Y += prevElement.ComputedStyle.Size.Height + prevElement.Style.Margin.Bottom + element.Style.Margin.Top; } element.ComputedStyle.Position.X += (prevElement.Style.Margin.Right >= element.Style.Margin.Left) ? prevElement.Style.Margin.Right : element.Style.Margin.Left; } else if (element.Style.Display == Display.Block || element.Style.Display == Display.TableRow || element.Style.Display == Display.Table) { element.ComputedStyle.Position.Y = prevElement.ComputedStyle.Position.Y + prevElement.ComputedStyle.Size.Height; if (element.Parent != null) { element.ComputedStyle.Position.X = element.Parent.ComputedStyle.Position.X + element.ComputedStyle.Padding.Left; } element.ComputedStyle.Position.Y += (prevElement.Style.Margin.Bottom >= element.Style.Margin.Top) ? prevElement.Style.Margin.Bottom : element.Style.Margin.Top; element.ComputedStyle.Position.X += (prevElement.Style.Margin.Right >= element.Style.Margin.Left) ? prevElement.Style.Margin.Right : element.Style.Margin.Left; } if (prevElement.Style.Display == Display.None) { element.ComputedStyle.Position.X = prevElement.ComputedStyle.Position.X; element.ComputedStyle.Position.Y = prevElement.ComputedStyle.Position.Y; } } else { element.ComputedStyle.Position.Y = element.Style.Margin.Top; element.ComputedStyle.Position.X = element.Style.Margin.Left; if (element.Parent != null) { element.ComputedStyle.Position.Y += element.Parent.ComputedStyle.Position.Y; element.ComputedStyle.Position.X += element.Parent.ComputedStyle.Position.X; } element.ComputedStyle.Position.Y += element.ComputedStyle.Padding.Top; element.ComputedStyle.Position.X += element.ComputedStyle.Padding.Left; } if (element.Children.Count > 0) { SetPositions(element.Children); } } }
private static List <DOMElement> GetDOMTree(List <Element> elements) { List <DOMElement> domElements = new List <DOMElement>(); List <DOMElement> domTree = new List <DOMElement>(); for (int x = 0; x < elements.Count; x++) { // Initialize an DOMElement. DOMElement domElement = new DOMElement() { Level = elements[x].Level }; if (elements[x].Type == ElementType.Text) { domElement.Content = elements[x].Content; domElement.Type = DOMElementType.Text; } else if (elements[x].Type == ElementType.Tag) { domElement.Type = DOMElementType.Normal; domElement.Tag = elements[x].Tag; } bool canBeProcessed = false; if (elements[x].Type == ElementType.Text) { canBeProcessed = true; } else if (elements[x].Type == ElementType.Tag) { canBeProcessed = elements[x].Tag.Type == TagType.Opening || elements[x].Tag.Type == TagType.SelfClosing; } if (elements[x].Level != 0) { if (canBeProcessed) { DOMElement parent = null; // Get parent of current DOMElement. for (int y = domElements.Count - 1; y >= 0; y--) { if (domElements[y].Level == domElement.Level - 1) { parent = domElements[y]; break; } } if (parent != null) { // Set parent of current DOMElement. domElement.Parent = parent; // Add current DOMElement to parent's children list. parent.Children.Add(domElement); } } } else { if (canBeProcessed) { // Add DOMElements to domTree that have only level 0. domTree.Add(domElement); } } domElements.Add(domElement); } return(domTree); }
/// <summary> // Calculates x percent of viewport width /// </summary> public static float VwToPx(Rule rule, DOMElement element) { return(rule.ComputedValue.Value / 100 * LayoutEngine.htmlDocument.getViewport().Width); }