/// <summary>Sets up this renderer so that it's ready to start packing child elements of /// a given element into lines.</summary> /// <param name="renderable">The parent render data whose children will be packed.</param> public LineBoxMeta BeginLines(RenderableData renderable, VirtualElements virts, LayoutBox box, bool autoWidth) { // Get CS: ComputedStyle cs = renderable.computedStyle; LineBoxMeta lineZone; InfiniText.FontFace face = box.FontFace; // Update line height: // Line height: Css.Value lineHeightValue = cs.LineHeightX; float cssLineHeight; if (lineHeightValue.IsType(typeof(Css.Keywords.Normal))) { // Get from the metrics font now: cssLineHeight = box.FontFace.BaselineToBaseline * box.FontSize; } else if ( lineHeightValue.Type != Css.ValueType.RelativeNumber && lineHeightValue.GetType() != typeof(Css.Units.DecimalUnit) ) { // E.g. line-height:14px, but not line-height:1. It's just as-is: cssLineHeight = lineHeightValue.GetRawDecimal(); } else { // Some multiple of the font size: cssLineHeight = lineHeightValue.GetRawDecimal() * box.FontSize; } // Check if it's a block context: if (box.DisplayMode == DisplayMode.Inline && LastBlockBox != null) { // Anything else uses the nearest parent block element as the max. lineZone = new InlineBoxMeta(LastBlockBox, TopOfStackSafe, box, renderable); // Put up the 'strut': lineZone.LineHeight = cssLineHeight; box.Baseline = box.FontSize * face.Descender; } else { lineZone = LastBlockBox = new BlockBoxMeta(TopOfStackSafe, box, renderable); lineZone.MaxX = box.InnerWidth; if (virts != null && virts.Has(ComputedStyle.VerticalScrollPriority)) { lineZone.MaxX -= 14; if (lineZone.MaxX < 0) { lineZone.MaxX = 0; } } bool left = (cs.DrawDirectionX == DirectionMode.RTL); lineZone.GoingLeftwards = left; // H-align: int hAlign = cs.HorizontalAlignX; if (hAlign == HorizontalAlignMode.Auto) { if (left) { hAlign = HorizontalAlignMode.Right; } else { hAlign = HorizontalAlignMode.Left; } } if (hAlign == HorizontalAlignMode.Left) { // Ok how it is (left by default). hAlign = 0; } lineZone.HorizontalAlign = hAlign; } // Apply whitespace mode: lineZone.WhiteSpace = cs.WhiteSpaceX; // Apply line height: lineZone.CssLineHeight = cssLineHeight; // Update vertical-align: Css.Value vAlign = cs.Resolve(Css.Properties.VerticalAlign.GlobalProperty); // Get the complete value: float vAlignValue = vAlign.GetDecimal(renderable, Css.Properties.VerticalAlign.GlobalProperty); // If it's a keyword.. if (vAlign is Css.CssKeyword) { // It's a mode: lineZone.VerticalAlign = (int)vAlignValue; lineZone.VerticalAlignOffset = 0f; } else { // It's a baseline offset: lineZone.VerticalAlign = VerticalAlignMode.Baseline; lineZone.VerticalAlignOffset = vAlignValue; } box.ContentWidth = 0; box.ContentHeight = 0; return(lineZone); }
/// <summary>Runs before reflow.</summary> public override void UpdateCss(Renderman renderer) { // Clear the blocks: FirstBox = null; LastBox = null; // Get the text renderer (or create it): Css.TextRenderingProperty text = RequireTextProperty(); // Get computed style: ComputedStyle cs = computedStyle; // Get the first box as it contains the fontface/ size: LayoutBox box = cs.FirstBox; // Colour too: Color fontColour = cs.Resolve(Css.Properties.ColorProperty.GlobalProperty).GetColour(this, Css.Properties.ColorProperty.GlobalProperty); // Colour: text.BaseColour = fontColour; // Font size update: float fontSize = box.FontSize; text.FontSize = fontSize; // Spacing: float wordSpacing = cs.ResolveDecimal(Css.Properties.WordSpacing.GlobalProperty); float letterSpacing = cs.ResolveDecimal(Css.Properties.LetterSpacing.GlobalProperty); // If word spacing is not 'normal', remove 1em from it (Note that letter spacing is always additive): if (wordSpacing == -1f) { wordSpacing = 0f; } else { wordSpacing -= fontSize; } text.WordSpacing = wordSpacing; text.LetterSpacing = letterSpacing; // Decoration: int decoration = cs.ResolveInt(Css.Properties.TextDecorationLine.GlobalProperty); if (decoration == 0) { // Remove a line if we have one: text.TextLine = null; } else { // Got a line! if (text.TextLine == null) { text.TextLine = new TextDecorationInfo(decoration); } // Get the colour: Css.Value lineColour = cs.Resolve(Css.Properties.TextDecorationColor.GlobalProperty); if (lineColour == null || lineColour.IsType(typeof(Css.Keywords.CurrentColor))) { // No override: text.TextLine.ColourOverride = false; } else { // Set the colour: text.TextLine.SetColour(lineColour.GetColour(this, Css.Properties.TextDecorationColor.GlobalProperty)); } } // Get the font face: text.FontToDraw = box.FontFace; // Overflow-wrap mode (only active for 'break-word' which is just '1'): text.OverflowWrapActive = (cs.ResolveInt(Css.Properties.OverflowWrap.GlobalProperty) == 1); // Check if the text is 'dirty'. // If it is, that means we'll need to rebuild the TextRenderingProperty's Glyph array. if (text.Dirty) { // Setup text now: // (Resets text.Characters based on all the text related CSS properties like variant etc). text.LoadCharacters((Node as RenderableTextNode).characterData_, this); } if (text.Characters == null || text.AllEmpty) { text.FontSize = 0f; return; } }