/// <summary> /// Applies right alignment to the text on the linebox /// </summary> private static void ApplyRightAlignment(Graphics g, CssLineBox line) { if (line.Words.Count == 0) { return; } CssBoxWord lastWord = line.Words[line.Words.Count - 1]; float right = line.OwnerBox.ActualRight - line.OwnerBox.ActualPaddingRight - line.OwnerBox.ActualBorderRightWidth; float diff = right - lastWord.Right - lastWord.LastMeasureOffset.X - lastWord.OwnerBox.ActualBorderRightWidth - lastWord.OwnerBox.ActualPaddingRight; if (diff <= 0) { return; } //if (line.OwnerBox.Direction == CssConstants.Rtl) //{ //} foreach (CssBoxWord word in line.Words) { word.Left += diff; } foreach (CssBox b in line.Rectangles.Keys) { RectangleF r = b.Rectangles[line]; b.Rectangles[line] = new RectangleF(r.X + diff, r.Y, r.Width, r.Height); } }
private void CutWord() { if (_curword.Text.Length > 0) { Words.Add(_curword); } _curword = new CssBoxWord(Box); }
/// <summary> /// Lets the linebox add the word an its box to their lists if necessary. /// </summary> /// <param name="word"></param> internal void ReportExistanceOf(CssBoxWord word) { if (!Words.Contains(word)) { Words.Add(word); } if (!RelatedBoxes.Contains(word.OwnerBox)) { RelatedBoxes.Add(word.OwnerBox); } }
/// <summary> /// Splits the text on words using rules of the specified box /// </summary> /// <param name="text"></param> /// <returns></returns> public void SplitWords() { if (string.IsNullOrEmpty(Text)) { return; } _curword = new CssBoxWord(Box); bool onspace = IsSpace(Text[0]); for (int i = 0; i < Text.Length; i++) { if (IsSpace(Text[i])) { if (!onspace) { CutWord(); } if (IsLineBreak(Text[i])) { _curword.AppendChar('\n'); CutWord(); } else if (IsTab(Text[i])) { _curword.AppendChar('\t'); CutWord(); } else { _curword.AppendChar(' '); } onspace = true; } else { if (onspace) { CutWord(); } _curword.AppendChar(Text[i]); onspace = false; } } CutWord(); }
/// <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(Graphics g, CssBox b, float baseline) { //TODO: Aqui me quede, checar poniendo "by the" con un font-size de 3em List <CssBoxWord> ws = WordsOf(b); if (!Rectangles.ContainsKey(b)) { return; } RectangleF r = Rectangles[b]; //Save top of words related to the top of rectangle float gap = 0f; if (ws.Count > 0) { gap = ws[0].Top - r.Top; } else { CssBoxWord 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 float 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 float recttop = newtop - gap; RectangleF newr = new RectangleF(r.X, recttop, r.Width, r.Height); Rectangles[b] = newr; b.OffsetRectangle(this, gap); } foreach (CssBoxWord w in ws) { if (!w.IsImage) { w.Top = newtop; } } }
private CssBoxWordSplitter() { _words = new List <CssBoxWord>(); _curword = null; }
/// <summary> /// Assigns words its width and height /// </summary> /// <param name="g"></param> internal void MeasureWordsSize(Graphics g) { if (_wordsSizeMeasured) return; //Measure white space if not yet done if (float.IsNaN(_actualWordSpacing)) MeasureWordSpacing(g); if (HtmlTag != null && HtmlTag.TagName.Equals("img", StringComparison.CurrentCultureIgnoreCase)) { #region Measure image CssBoxWord word = new CssBoxWord(this, CssValue.GetImage(GetAttribute("src"))); Words.Clear(); Words.Add(word); #endregion } else { #region Measure text words bool lastWasSpace = false; foreach (CssBoxWord b in Words) { bool collapse = CssBoxWordSplitter.CollapsesWhiteSpaces(this); if (CssBoxWordSplitter.EliminatesLineBreaks(this)) b.ReplaceLineBreaksAndTabs(); if (b.IsSpaces) { b.Height = FontLineSpacing; if (b.IsTab) { b.Width = ActualWordSpacing * 4; //TODO: Configure tab size } else if (b.IsLineBreak) { b.Width = 0; } else { if (!(lastWasSpace && collapse)) { b.Width = ActualWordSpacing * (collapse ? 1 : b.Text.Length); } } lastWasSpace = true; } else { string word = b.Text; CharacterRange[] measurable = { new CharacterRange(0, word.Length) }; StringFormat sf = new StringFormat(); sf.SetMeasurableCharacterRanges(measurable); Region[] regions = g.MeasureCharacterRanges(word, ActualFont, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf); SizeF s = regions[0].GetBounds(g).Size; PointF p = regions[0].GetBounds(g).Location; b.LastMeasureOffset = new PointF(p.X, p.Y); b.Width = s.Width;// +p.X; b.Height = s.Height;// +p.Y; lastWasSpace = false; } } #endregion } _wordsSizeMeasured = true; }
/// <summary> /// Gets the longest word (in width) inside the box, deeply. /// </summary> /// <param name="b"></param> /// <returns></returns> private void GetMinimumWidth_LongestWord(CssBox b, ref float maxw, ref CssBoxWord word) { if (b.Words.Count > 0) { foreach (CssBoxWord w in b.Words) { if (w.FullWidth > maxw) { maxw = w.FullWidth; word = w; } } } else { foreach(CssBox bb in b.Boxes) GetMinimumWidth_LongestWord(bb, ref maxw,ref word); } }
/// <summary> /// Splits the text into words and saves the result /// </summary> private void UpdateWords() { Words.Clear(); if (WhiteSpace == CssConstants.Nowrap) { CssBoxWord b = new CssBoxWord(this); b.Text = Text; Words.Add(b); } else { CssBoxWordSplitter splitter = new CssBoxWordSplitter(this, Text); splitter.SplitWords(); Words.AddRange(splitter.Words); } }
/// <summary> /// Recursively flows the content of the box using the inline model /// </summary> /// <param name="g">Device Info</param> /// <param name="blockbox">Blockbox that contains the text flow</param> /// <param name="box">Current box to flow its content</param> /// <param name="maxright">Maximum reached right</param> /// <param name="linespacing">Space to use between rows of text</param> /// <param name="startx">x starting coordinate for when breaking lines of text</param> /// <param name="line">Current linebox being used</param> /// <param name="curx">Current x coordinate that will be the left of the next word</param> /// <param name="cury">Current y coordinate that will be the top of the next word</param> /// <param name="maxbottom">Maximum bottom reached so far</param> private static void FlowBox(Graphics g, CssBox blockbox, CssBox box, float maxright, float linespacing, float startx,ref CssLineBox line, ref float curx, ref float cury, ref float maxbottom) { box.FirstHostingLineBox = line; foreach (CssBox b in box.Boxes) { float leftspacing = b.ActualMarginLeft + b.ActualBorderLeftWidth + b.ActualPaddingLeft; float rightspacing = b.ActualMarginRight + b.ActualBorderRightWidth + b.ActualPaddingRight; float topspacing = b.ActualBorderTopWidth + b.ActualPaddingTop; float bottomspacing = b.ActualBorderBottomWidth + b.ActualPaddingTop; b.RectanglesReset(); b.MeasureWordsSize(g); curx += leftspacing; if (b.Words.Count > 0) { #region Flow words foreach (CssBoxWord word in b.Words) { //curx += word.SpacesBeforeWidth; if ((b.WhiteSpace != CssConstants.Nowrap && curx + word.Width + rightspacing > maxright) || word.IsLineBreak) { #region Break line curx = startx; cury = maxbottom + linespacing; line = new CssLineBox(blockbox); if (word.IsImage || word.Equals(b.FirstWord)) { curx += leftspacing; } #endregion } line.ReportExistanceOf(word); word.Left = curx;// -word.LastMeasureOffset.X + 1; word.Top = cury;// - word.LastMeasureOffset.Y; curx = word.Right;// +word.SpacesAfterWidth; maxbottom = Math.Max(maxbottom, word.Bottom );//+ (word.IsImage ? topspacing + bottomspacing : 0)); _lastTreatedWord = word; } #endregion } else { FlowBox(g, blockbox, b, maxright, linespacing, startx,ref line, ref curx, ref cury, ref maxbottom); } curx += rightspacing; } box.LastHostingLineBox = line; }
/// <summary> /// Recursively flows the content of the box using the inline model /// </summary> /// <param name="g">Device Info</param> /// <param name="blockbox">Blockbox that contains the text flow</param> /// <param name="box">Current box to flow its content</param> /// <param name="maxright">Maximum reached right</param> /// <param name="linespacing">Space to use between rows of text</param> /// <param name="startx">x starting coordinate for when breaking lines of text</param> /// <param name="line">Current linebox being used</param> /// <param name="curx">Current x coordinate that will be the left of the next word</param> /// <param name="cury">Current y coordinate that will be the top of the next word</param> /// <param name="maxbottom">Maximum bottom reached so far</param> private static void FlowBox(Graphics g, CssBox blockbox, CssBox box, float maxright, float linespacing, float startx, ref CssLineBox line, ref float curx, ref float cury, ref float maxbottom) { box.FirstHostingLineBox = line; foreach (CssBox b in box.Boxes) { float leftspacing = b.ActualMarginLeft + b.ActualBorderLeftWidth + b.ActualPaddingLeft; float rightspacing = b.ActualMarginRight + b.ActualBorderRightWidth + b.ActualPaddingRight; float topspacing = b.ActualBorderTopWidth + b.ActualPaddingTop; float bottomspacing = b.ActualBorderBottomWidth + b.ActualPaddingTop; b.RectanglesReset(); b.MeasureWordsSize(g); curx += leftspacing; if (b.Words.Count > 0) { #region Flow words foreach (CssBoxWord word in b.Words) { //curx += word.SpacesBeforeWidth; if ((b.WhiteSpace != CssConstants.Nowrap && curx + word.Width + rightspacing > maxright) || word.IsLineBreak) { #region Break line curx = startx; cury = maxbottom + linespacing; line = new CssLineBox(blockbox); if (word.IsImage || word.Equals(b.FirstWord)) { curx += leftspacing; } #endregion } line.ReportExistanceOf(word); word.Left = curx; // -word.LastMeasureOffset.X + 1; word.Top = cury; // - word.LastMeasureOffset.Y; curx = word.Right; // +word.SpacesAfterWidth; maxbottom = Math.Max(maxbottom, word.Bottom); //+ (word.IsImage ? topspacing + bottomspacing : 0)); _lastTreatedWord = word; } #endregion } else { FlowBox(g, blockbox, b, maxright, linespacing, startx, ref line, ref curx, ref cury, ref maxbottom); } curx += rightspacing; } box.LastHostingLineBox = line; }
/// <summary> /// Splits the text on words using rules of the specified box /// </summary> /// <param name="text"></param> /// <returns></returns> public void SplitWords() { if (string.IsNullOrEmpty(Text)) return; _curword = new CssBoxWord(Box); bool onspace = IsSpace(Text[0]); for (int i = 0; i < Text.Length; i++) { if (IsSpace(Text[i])) { if (!onspace) CutWord(); if (IsLineBreak(Text[i])) { _curword.AppendChar('\n'); CutWord(); } else if (IsTab(Text[i])) { _curword.AppendChar('\t'); CutWord(); } else { _curword.AppendChar(' '); } onspace = true; } else { if (onspace) CutWord(); _curword.AppendChar(Text[i]); onspace = false; } } CutWord(); }
private CssBoxWordSplitter() { _words = new List<CssBoxWord>(); _curword = null; }
private void CutWord() { if(_curword.Text.Length > 0) Words.Add(_curword); _curword = new CssBoxWord(Box); }