/// <summary>Gets a text line for the specified width.</summary> /// <param name="sText">Text</param> /// <param name="rWidthMax">Width</param> /// <param name="iStart">Start position in sText</param> /// <param name="textSplitMode">Text split mode</param> /// <returns>Line of text</returns> internal String sGetTextLine(String sText, Double rWidthMax, ref Int32 iStart, TextSplitMode textSplitMode) { if (iStart > sText.Length) { throw new ReportException("start position out of range"); } if (iStart == sText.Length) { iStart++; return(""); } Int32 iStartCopy = iStart; StringBuilder sb = new StringBuilder(120); Double rWidth = 0; Int32 iPos = iStart; Int32 iResultLength = 0; LastChar lastChar = LastChar.Space; while (true) { Char c = sText[iPos]; iPos++; Double rWidthChar = rGetRawWidth(c); UnicodeCategory unicodeCategory = Char.GetUnicodeCategory(c); switch (unicodeCategory) { case UnicodeCategory.Control: { // control character if (c == '\n') { goto case UnicodeCategory.LineSeparator; } if (lastChar != LastChar.Space) { iResultLength = sb.Length; lastChar = LastChar.Space; } iStart = iPos; break; } case UnicodeCategory.LineSeparator: case UnicodeCategory.ParagraphSeparator: { iResultLength = sb.Length; iStart = iPos; goto EndLoop; } case UnicodeCategory.ConnectorPunctuation: // connects two characters case UnicodeCategory.EnclosingMark: // nonspacing combining character that surrounds all previous characters up to and including a base character case UnicodeCategory.Format: // not normally rendered but affects the layout of text or the operation of text processes case UnicodeCategory.ModifierLetter: // free-standing spacing character that indicates modifications of a preceding letter case UnicodeCategory.ModifierSymbol: // indicates modifications of surrounding characters case UnicodeCategory.NonSpacingMark: // indicates modifications of a base character case UnicodeCategory.PrivateUse: // private-use character with unicode value in the range U+E000 through U+F8FF case UnicodeCategory.SpacingCombiningMark: // indicates modifications of a base character and affects the width of the glyph for that base character case UnicodeCategory.Surrogate: { // high-surrogate or a low-surrogate with code values in the range U+D800 through U+DFFF break; } case UnicodeCategory.SpaceSeparator: { // space if (lastChar != LastChar.Space) { iResultLength = sb.Length; lastChar = LastChar.Space; } rWidth += rWidthChar; sb.Append(c); iStart = iPos; break; } case UnicodeCategory.ClosePunctuation: // separator on this line: )]} case UnicodeCategory.DashPunctuation: // - case UnicodeCategory.FinalQuotePunctuation: { rWidth += rWidthChar; if (rWidth > rWidthMax) { iPos--; goto EndLoop; } sb.Append(c); lastChar = LastChar.SeparatorAtEndOfLine; break; } case UnicodeCategory.CurrencySymbol: // separator for next line: € case UnicodeCategory.InitialQuotePunctuation: // opening or initial quotation mark case UnicodeCategory.OpenPunctuation: { // ([{ if (lastChar == LastChar.SeparatorAtEndOfLine || lastChar == LastChar.Word) { iResultLength = sb.Length; iStart = iPos - 1; } rWidth += rWidthChar; if (rWidth > rWidthMax) { iPos--; goto EndLoop; } sb.Append(c); lastChar = LastChar.SeparatorAtStartOfLine; break; } case UnicodeCategory.OtherPunctuation: { // ., rWidth += rWidthChar; if (rWidth > rWidthMax) { iPos--; goto EndLoop; } sb.Append(c); lastChar = LastChar.Word; break; } case UnicodeCategory.DecimalDigitNumber: // character case UnicodeCategory.LetterNumber: case UnicodeCategory.LowercaseLetter: case UnicodeCategory.MathSymbol: // + = case UnicodeCategory.OtherLetter: case UnicodeCategory.OtherNotAssigned: case UnicodeCategory.UppercaseLetter: case UnicodeCategory.TitlecaseLetter: { if (lastChar == LastChar.SeparatorAtEndOfLine) { iResultLength = sb.Length; iStart = iPos; } rWidth += rWidthChar; if (rWidth > rWidthMax) { iPos--; goto EndLoop; } sb.Append(c); lastChar = LastChar.Word; break; } default: { Debug.Fail("unknown unicode category"); break; } } if (iPos >= sText.Length) { iResultLength = sb.Length; iStart = iPos + 1; goto EndLoop; } } EndLoop: if (textSplitMode == TextSplitMode.Truncate) { iStart = sb.Length; return(sb.ToString()); } if (iStart == iStartCopy) { if (sb.Length > 0) { iStart = iPos; return(sb.ToString()); } iStart++; return(sText[iStart - 1].ToString()); } return(sb.ToString(0, iResultLength)); }
//////////////////////////////////////////////////////////////////// // Write object to PDF file //////////////////////////////////////////////////////////////////// internal override void WriteObjectToPdfFile ( BinaryWriter PdfFile ) { // look for first and last character Int32 FirstChar; Int32 LastChar; for (FirstChar = 0; FirstChar < 256 && !ActiveChar[FirstChar]; FirstChar++) { ; } if (FirstChar == 256) { return; } for (LastChar = 255; !ActiveChar[LastChar]; LastChar--) { ; } // pdf font name StringBuilder PdfFontName = new StringBuilder("/"); // for embedded font add 6 alpha characters prefix if (EmbeddedFont) { PdfFontName.Append("PFWAAA+"); Int32 Ptr1 = 6; for (Int32 Ptr2 = ResourceCode.Length - 1; Ptr2 >= 0 && Char.IsDigit(ResourceCode[Ptr2]); Ptr2--) { PdfFontName[Ptr1--] = (Char)((Int32)ResourceCode[Ptr2] + ('A' - '0')); } } // PDF readers are not happy with space in font name PdfFontName.Append(FontFamily.Name.Replace(" ", "#20")); // font name if ((DesignFont.Style & FontStyle.Bold) != 0) { if ((DesignFont.Style & FontStyle.Italic) != 0) { PdfFontName.Append(",BoldItalic"); } else { PdfFontName.Append(",Bold"); } } else if ((DesignFont.Style & FontStyle.Italic) != 0) { PdfFontName.Append(",Italic"); } // add items to dictionary AddToDictionary("/Subtype", "/TrueType"); AddToDictionary("/BaseFont", PdfFontName.ToString()); // add first and last characters AddToDictionary("/FirstChar", FirstChar.ToString()); AddToDictionary("/LastChar", LastChar.ToString()); // create font descriptor FontDescriptor = new PdfObject(Document, false, "/FontDescriptor"); // add link to font object AddToDictionary("/FontDescriptor", FontDescriptor); // font descriptor dictionary FontDescriptor.AddToDictionary("/FontName", PdfFontName.ToString()); // must be the same as BaseFont above FontDescriptor.AddToDictionary("/Flags", ((Int32)FontFlags).ToString()); FontDescriptor.AddToDictionary("/ItalicAngle", String.Format(NFI.DecSep, "{0}", (Single)PdfItalicAngle)); FontDescriptor.AddToDictionary("/FontWeight", PdfFontWeight.ToString()); FontDescriptor.AddToDictionary("/Leading", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(PdfLeading))); FontDescriptor.AddToDictionary("/Ascent", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(PdfAscent))); FontDescriptor.AddToDictionary("/Descent", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(-PdfDescent))); // alphabetic (non symbolic) fonts if ((FontFlags & PdfFontFlags.Symbolic) == 0) { AddToDictionary("/Encoding", "/WinAnsiEncoding"); BoundingBox Box = FontInfo.GetGlyphMetricsApi('x'); FontDescriptor.AddToDictionary("/XHeight", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(Box.Rect.Top))); FontDescriptor.AddToDictionary("/AvgWidth", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(Box.Width))); Box = FontInfo.GetGlyphMetricsApi('M'); PdfCapHeight = Box.Rect.Top; FontDescriptor.AddToDictionary("/CapHeight", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(Box.Rect.Top))); FontDescriptor.AddToDictionary("/StemV", String.Format(NFI.DecSep, "{0}", (Single)StemV())); } // create width object array FontWidthArray = new PdfObject(Document, false); // add link to font object AddToDictionary("/Widths", FontWidthArray); // build bounding box and width array Double Left = Double.MaxValue; Double Bottom = Double.MaxValue; Double Right = Double.MinValue; Double Top = Double.MinValue; Double MaxWidth = Double.MinValue; FontWidthArray.ContentsString = new StringBuilder("["); Int32 EolLength = 100; for (Int32 Index = FirstChar; Index <= LastChar; Index++) { Double CharWidth; // not used if (!ActiveChar[Index]) { CharWidth = 0; } // used else { // bounding box BoundingBox GM = GlyphArray[Index]; if (GM.Rect.Left < Left) { Left = GM.Rect.Left; } if (GM.Rect.Bottom < Bottom) { Bottom = GM.Rect.Bottom; } if (GM.Rect.Right > Right) { Right = GM.Rect.Right; } if (GM.Rect.Top > Top) { Top = GM.Rect.Top; } // character advance width CharWidth = GM.Width; // max width if (CharWidth > MaxWidth) { MaxWidth = CharWidth; } } // add width to width array if (FontWidthArray.ContentsString.Length > EolLength) { FontWidthArray.ContentsString.Append('\n'); EolLength = FontWidthArray.ContentsString.Length + 100; } // add width to width array FontWidthArray.ContentsString.AppendFormat(NFI.DecSep, "{0} ", FontUnitsToPdfDic(CharWidth)); } // add to font descriptor array FontDescriptor.AddToDictionary("/MaxWidth", String.Format(NFI.DecSep, "{0}", (Single)FontUnitsToPdfDic(MaxWidth))); FontDescriptor.AddToDictionary("/FontBBox", String.Format(NFI.DecSep, "[{0} {1} {2} {3}]", FontUnitsToPdfDic(Left), FontUnitsToPdfDic(Bottom), FontUnitsToPdfDic(Right), FontUnitsToPdfDic(Top))); // terminate width array FontWidthArray.ContentsString.Length--; FontWidthArray.ContentsString.Append("]"); // create font file if (EmbeddedFont) { // create font file stream PdfFontFile EmbeddedFontObj = new PdfFontFile(this); // add link to font object FontDescriptor.AddToDictionary("/FontFile2", EmbeddedFontObj); } // call base write PdfObject to file method base.WriteObjectToPdfFile(PdfFile); // exit return; }