/** * <summary>Shows the specified external object.</summary> * <param name="xObject">External object.</param> * <param name="size">Size of the external object.</param> * <param name="lineAlignment">Line alignment. It can be: * <list type="bullet"> * <item><see cref="LineAlignmentEnum"/></item> * <item><see cref="Length">: arbitrary super-/sub-script, depending on whether the value is * positive or not.</item> * </list> * </param> * <returns>Whether the external object was successfully shown.</returns> */ public bool ShowXObject( xObjects::XObject xObject, SizeF?size, object lineAlignment ) { if (xObject == null || !EnsureRow(true)) { return(false); } if (!size.HasValue) { size = xObject.Size; } lineAlignment = ResolveLineAlignment(lineAlignment); while (true) { if (OperationUtils.Compare(currentRow.Y + size.Value.Height, frame.Height) == 1) // Object's height exceeds block's remaining vertical space. { // Terminate current row and exit! EndRow(false); return(false); } else if (OperationUtils.Compare(currentRow.Width + size.Value.Width, frame.Width) < 1) // There's room for the object in the current row. { PointF location = new PointF( (float)currentRow.Width, (float)currentRow.Y ); RowObject obj; { obj = new RowObject( RowObject.TypeEnum.XObject, baseComposer.BeginLocalState(), // Opens the row object's local state. size.Value.Height, size.Value.Width, 0, lineAlignment, size.Value.Height, 0, 0 ); baseComposer.ShowXObject(xObject, location, size); baseComposer.End(); // Closes the row object's local state. } AddRowObject(obj, lineAlignment); return(true); } else // There's NOT enough room for the object in the current row. { // Go to next row! EndRow(false); BeginRow(); } } }
private object ResolveLineAlignment( object lineAlignment ) { if (!(lineAlignment is LineAlignmentEnum || lineAlignment is Length)) { throw new ArgumentException("MUST be either LineAlignmentEnum or Length.", "lineAlignment"); } if (lineAlignment.Equals(LineAlignmentEnum.Super)) { lineAlignment = new Length(0.33, Length.UnitModeEnum.Relative); } else if (lineAlignment.Equals(LineAlignmentEnum.Sub)) { lineAlignment = new Length(-0.33, Length.UnitModeEnum.Relative); } if (lineAlignment is Length) { if (lastFontSize == 0) { lastFontSize = baseComposer.State.FontSize; } lineAlignment = ((Length)lineAlignment).GetValue(lastFontSize); } return(lineAlignment); }
private void BuildTextBlockPage2( Document document ) { // 1. Add the page to the document! Page page = new Page(document); // Instantiates the page inside the document context. document.Pages.Add(page); // Puts the page in the pages collection. SizeF pageSize = page.Size; // 2. Create a content composer for the page! PrimitiveComposer composer = new PrimitiveComposer(page); // 3. Drawing the page contents... fonts::Font mainFont = new fonts::StandardType1Font(document, fonts::StandardType1Font.FamilyEnum.Courier, true, false); int stepCount = 5; int step = (int)(pageSize.Height) / (stepCount + 1); BlockComposer blockComposer = new BlockComposer(composer); { blockComposer.Begin( new RectangleF( 30, 0, pageSize.Width - 60, step * .8f ), XAlignmentEnum.Center, YAlignmentEnum.Middle ); composer.SetFont(mainFont, 32); blockComposer.ShowText("Block line alignment"); blockComposer.End(); } // Drawing the text block... { fonts::Font sampleFont = new fonts::StandardType1Font(document, fonts::StandardType1Font.FamilyEnum.Times, false, false); entities::Image sampleImage = entities::Image.Get(GetResourcePath("images" + System.IO.Path.DirectorySeparatorChar + "gnu.jpg")); xObjects::XObject sampleImageXObject = sampleImage.ToXObject(document); IList <LineAlignmentEnum> lineAlignments = new List <LineAlignmentEnum>((LineAlignmentEnum[])Enum.GetValues(typeof(LineAlignmentEnum))); float frameHeight = (pageSize.Height - 130 - 5 * lineAlignments.Count * 2) / (lineAlignments.Count * 2); float frameWidth = (pageSize.Width - 60 - 5 * lineAlignments.Count) / lineAlignments.Count; int imageSize = 7; for (int index = 0, length = lineAlignments.Count; index < length; index++) { LineAlignmentEnum lineAlignment = lineAlignments[index]; for (int imageIndex = 0, imageLength = lineAlignments.Count; imageIndex < imageLength; imageIndex++) { LineAlignmentEnum imageAlignment = lineAlignments[imageIndex]; for (int index2 = 0, length2 = 2; index2 < length2; index2++) { RectangleF frame = new RectangleF( 30 + (frameWidth + 5) * imageIndex, 100 + (frameHeight + 5) * (index * 2 + index2), frameWidth, frameHeight ); blockComposer.Begin(frame, XAlignmentEnum.Left, YAlignmentEnum.Top); { composer.SetFont(mainFont, 3); blockComposer.ShowText("Text: " + lineAlignment); blockComposer.ShowBreak(); blockComposer.ShowText("Image: " + imageAlignment); } blockComposer.End(); blockComposer.Begin(frame, XAlignmentEnum.Left, YAlignmentEnum.Middle); { composer.SetFont(sampleFont, 3); blockComposer.ShowText("Previous row boundary."); blockComposer.ShowBreak(); composer.SetFont(sampleFont, index2 == 0 ? 3 : 6); blockComposer.ShowText("Alignment:"); composer.SetFont(sampleFont, index2 == 0 ? 6 : 3); blockComposer.ShowText(" aligned to " + lineAlignment + " ", lineAlignment); blockComposer.ShowXObject(sampleImageXObject, new SizeF(imageSize, imageSize), imageAlignment); blockComposer.ShowBreak(); composer.SetFont(sampleFont, 3); blockComposer.ShowText("Next row boundary."); } blockComposer.End(); composer.BeginLocalState(); { composer.SetLineWidth(0.1f); composer.SetLineDash(new LineDash(new double[] { 1, 4 }, 4)); composer.DrawRectangle(blockComposer.Frame); composer.Stroke(); } composer.End(); composer.BeginLocalState(); { composer.SetLineWidth(0.1f); composer.SetLineDash(new LineDash(new double[] { 1, 1 }, 1)); composer.DrawRectangle(blockComposer.BoundBox); composer.Stroke(); } composer.End(); } } } } // 4. Flush the contents into the page! composer.Flush(); }
/** * <summary>Ends the content row.</summary> * <param name="broken">Indicates whether this is the end of a paragraph.</param> */ private void EndRow( bool broken ) { if (rowEnded) { return; } rowEnded = true; double[] objectXOffsets = new double[currentRow.Objects.Count]; // Horizontal object displacements. double wordSpace = 0; // Exceeding space among words. double rowXOffset = 0; // Horizontal row offset. List <RowObject> objects = currentRow.Objects; // Horizontal alignment. XAlignmentEnum xAlignment = this.xAlignment; switch (xAlignment) { case XAlignmentEnum.Left: break; case XAlignmentEnum.Right: rowXOffset = frame.Width - currentRow.Width; break; case XAlignmentEnum.Center: rowXOffset = (frame.Width - currentRow.Width) / 2; break; case XAlignmentEnum.Justify: // Are there NO spaces? if (currentRow.SpaceCount == 0 || broken) // NO spaces. { /* NOTE: This situation equals a simple left alignment. */ xAlignment = XAlignmentEnum.Left; } else // Spaces exist. { // Calculate the exceeding spacing among the words! wordSpace = (frame.Width - currentRow.Width) / currentRow.SpaceCount; // Define the horizontal offsets for justified alignment. for ( int index = 1, count = objects.Count; index < count; index++ ) { /* * NOTE: The offset represents the horizontal justification gap inserted * at the left side of each object. */ objectXOffsets[index] = objectXOffsets[index - 1] + objects[index - 1].SpaceCount * wordSpace; } } break; } SetWordSpace wordSpaceOperation = new SetWordSpace(wordSpace); // Vertical alignment and translation. for ( int index = objects.Count - 1; index >= 0; index-- ) { RowObject obj = objects[index]; // Vertical alignment. double objectYOffset = 0; { LineAlignmentEnum lineAlignment; double lineRise; { object objectLineAlignment = obj.LineAlignment; if (objectLineAlignment is Double) { lineAlignment = LineAlignmentEnum.BaseLine; lineRise = (double)objectLineAlignment; } else { lineAlignment = (LineAlignmentEnum)objectLineAlignment; lineRise = 0; } } switch (lineAlignment) { case LineAlignmentEnum.Top: /* NOOP */ break; case LineAlignmentEnum.Middle: objectYOffset = -(currentRow.Height - obj.Height) / 2; break; case LineAlignmentEnum.BaseLine: objectYOffset = -(currentRow.BaseLine - obj.BaseLine - lineRise); break; case LineAlignmentEnum.Bottom: objectYOffset = -(currentRow.Height - obj.Height); break; default: throw new NotImplementedException("Line alignment " + lineAlignment + " unknown."); } } IList <ContentObject> containedGraphics = obj.Container.Objects; // Word spacing. containedGraphics.Insert(0, wordSpaceOperation); // Translation. containedGraphics.Insert( 0, new ModifyCTM( 1, 0, 0, 1, objectXOffsets[index] + rowXOffset, // Horizontal alignment. objectYOffset // Vertical alignment. ) ); } // Update the actual block height! boundBox.Height = (float)(currentRow.Y + currentRow.Height); // Update the actual block vertical location! double yOffset; switch (yAlignment) { case YAlignmentEnum.Bottom: yOffset = frame.Height - boundBox.Height; break; case YAlignmentEnum.Middle: yOffset = (frame.Height - boundBox.Height) / 2; break; case YAlignmentEnum.Top: default: yOffset = 0; break; } boundBox.Y = (float)(frame.Y + yOffset); // Discard the current row! currentRow = null; }
/** * <summary>Shows text.</summary> * <param name="text">Text to show.</param> * <param name="lineAlignment">Line alignment. It can be: * <list type="bullet"> * <item><see cref="LineAlignmentEnum"/></item> * <item><see cref="Length">: arbitrary super-/sub-script, depending on whether the value is * positive or not.</item> * </list> * </param> * <returns>Last shown character index.</returns> */ public int ShowText( string text, object lineAlignment ) { if (currentRow == null || text == null) { return(0); } ContentScanner.GraphicsState state = baseComposer.State; fonts::Font font = state.Font; double fontSize = state.FontSize; double lineHeight = font.GetLineHeight(fontSize); double baseLine = font.GetAscent(fontSize); lineAlignment = ResolveLineAlignment(lineAlignment); TextFitter textFitter = new TextFitter( text, 0, font, fontSize, hyphenation, hyphenationCharacter ); int textLength = text.Length; int index = 0; while (true) { if (currentRow.Width == 0) // Current row has just begun. { // Removing leading space... while (true) { if (index == textLength) // Text end reached. { goto endTextShowing; } else if (text[index] != ' ') // No more leading spaces. { break; } index++; } } if (OperationUtils.Compare(currentRow.Y + lineHeight, frame.Height) == 1) // Text's height exceeds block's remaining vertical space. { // Terminate the current row and exit! EndRow(false); goto endTextShowing; } // Does the text fit? if (textFitter.Fit( index, frame.Width - currentRow.Width, // Remaining row width. currentRow.SpaceCount == 0 )) { // Get the fitting text! string textChunk = textFitter.FittedText; double textChunkWidth = textFitter.FittedWidth; PointF textChunkLocation = new PointF( (float)currentRow.Width, (float)currentRow.Y ); // Insert the fitting text! RowObject obj; { obj = new RowObject( RowObject.TypeEnum.Text, baseComposer.BeginLocalState(), // Opens the row object's local state. lineHeight, textChunkWidth, CountOccurrence(' ', textChunk), lineAlignment, baseLine ); baseComposer.ShowText(textChunk, textChunkLocation); baseComposer.End(); // Closes the row object's local state. } AddRowObject(obj, lineAlignment); index = textFitter.EndIndex; } // Evaluating trailing text... while (true) { if (index == textLength) // Text end reached. { goto endTextShowing; } switch (text[index]) { case '\r': break; case '\n': // New paragraph! index++; ShowBreak(); goto endTrailParsing; default: // New row (within the same paragraph)! EndRow(false); BeginRow(); goto endTrailParsing; } index++; } endTrailParsing :; } endTextShowing :; if (index >= 0 && lineAlignment.Equals(LineAlignmentEnum.BaseLine)) { lastFontSize = fontSize; } return(index); }
/** * <summary>Ends the content row.</summary> * <param name="broken">Indicates whether this is the end of a paragraph.</param> */ private void EndRow( bool broken ) { if (rowEnded) { return; } rowEnded = true; List <RowObject> objects = currentRow.Objects; double[] objectXOffsets = new double[objects.Count]; // Horizontal object displacements. double wordSpace = 0; // Exceeding space among words. double rowXOffset = 0; // Horizontal row offset. // Horizontal alignment. XAlignmentEnum xAlignment = this.xAlignment; switch (xAlignment) { case XAlignmentEnum.Left: break; case XAlignmentEnum.Right: rowXOffset = frame.Width - currentRow.Width; break; case XAlignmentEnum.Center: rowXOffset = (frame.Width - currentRow.Width) / 2; break; case XAlignmentEnum.Justify: if (currentRow.SpaceCount == 0 || broken) // NO spaces. { /* NOTE: This situation equals a simple left alignment. */ xAlignment = XAlignmentEnum.Left; } else // Spaces exist. { // Calculate the exceeding spacing among the words! wordSpace = (frame.Width - currentRow.Width) / currentRow.SpaceCount; // Define the horizontal offsets for justified alignment. for ( int index = 1, count = objects.Count; index < count; index++ ) { /* * NOTE: The offset represents the horizontal justification gap inserted at the left * side of each object. */ objectXOffsets[index] = objectXOffsets[index - 1] + objects[index - 1].SpaceCount * wordSpace; } } currentRow.WordSpaceAdjustment.Value = wordSpace; break; } // Vertical alignment and translation. for ( int index = objects.Count - 1; index >= 0; index-- ) { RowObject obj = objects[index]; // Vertical alignment. double objectYOffset = 0; { LineAlignmentEnum lineAlignment; double lineRise; { object objectLineAlignment = obj.LineAlignment; if (objectLineAlignment is Double) { lineAlignment = LineAlignmentEnum.BaseLine; lineRise = (double)objectLineAlignment; } else { lineAlignment = (LineAlignmentEnum)objectLineAlignment; lineRise = 0; } } switch (lineAlignment) { case LineAlignmentEnum.Top: /* NOOP */ break; case LineAlignmentEnum.Middle: objectYOffset = -(currentRow.Height - obj.Height) / 2; break; case LineAlignmentEnum.BaseLine: objectYOffset = -(currentRow.BaseLine - obj.BaseLine - lineRise); break; case LineAlignmentEnum.Bottom: objectYOffset = -(currentRow.Height - obj.Height); break; default: throw new NotImplementedException("Line alignment " + lineAlignment + " unknown."); } } IList <ContentObject> containedGraphics = obj.Container.Objects; // Translation. containedGraphics.Insert( 0, new ModifyCTM( 1, 0, 0, 1, objectXOffsets[index] + rowXOffset, // Horizontal alignment. objectYOffset // Vertical alignment. ) ); // Word spacing. if (obj.Type == RowObject.TypeEnum.Text) { /* * TODO: This temporary hack adjusts the word spacing in case of composite font. * When DocumentComposer replaces BlockComposer, all the graphical properties of contents * will be declared as styles and their composition will occur as a single pass without such * ugly tweakings. */ ShowText showTextOperation = (ShowText)((Text)((LocalGraphicsState)containedGraphics[1]).Objects[1]).Objects[1]; if (showTextOperation is ShowAdjustedText) { PdfInteger wordSpaceObject = PdfInteger.Get((int)Math.Round(-wordSpace * 1000 * obj.Scale / obj.FontSize)); PdfArray textParams = (PdfArray)showTextOperation.Operands[0]; for (int textParamIndex = 1, textParamsLength = textParams.Count; textParamIndex < textParamsLength; textParamIndex += 2) { textParams[textParamIndex] = wordSpaceObject; } } } } // Update the actual block height! boundBox.Height = (float)(currentRow.Y + currentRow.Height); // Update the actual block vertical location! double yOffset; switch (yAlignment) { case YAlignmentEnum.Bottom: yOffset = frame.Height - boundBox.Height; break; case YAlignmentEnum.Middle: yOffset = (frame.Height - boundBox.Height) / 2; break; case YAlignmentEnum.Top: default: yOffset = 0; break; } boundBox.Y = (float)(frame.Y + yOffset); // Discard the current row! currentRow = null; }
private object ResolveLineAlignment( object lineAlignment ) { if(!(lineAlignment is LineAlignmentEnum || lineAlignment is Length)) throw new ArgumentException("MUST be either LineAlignmentEnum or Length.", "lineAlignment"); if(lineAlignment.Equals(LineAlignmentEnum.Super)) {lineAlignment = new Length(0.33, Length.UnitModeEnum.Relative);} else if(lineAlignment.Equals(LineAlignmentEnum.Sub)) {lineAlignment = new Length(-0.33, Length.UnitModeEnum.Relative);} if(lineAlignment is Length) { if(lastFontSize == 0) {lastFontSize = baseComposer.State.FontSize;} lineAlignment = ((Length)lineAlignment).GetValue(lastFontSize); } return lineAlignment; }
/** <summary>Ends the content row.</summary> <param name="broken">Indicates whether this is the end of a paragraph.</param> */ private void EndRow( bool broken ) { if(rowEnded) return; rowEnded = true; double[] objectXOffsets = new double[currentRow.Objects.Count]; // Horizontal object displacements. double wordSpace = 0; // Exceeding space among words. double rowXOffset = 0; // Horizontal row offset. List<RowObject> objects = currentRow.Objects; // Horizontal alignment. XAlignmentEnum xAlignment = this.xAlignment; switch(xAlignment) { case XAlignmentEnum.Left: break; case XAlignmentEnum.Right: rowXOffset = frame.Width - currentRow.Width; break; case XAlignmentEnum.Center: rowXOffset = (frame.Width - currentRow.Width) / 2; break; case XAlignmentEnum.Justify: // Are there NO spaces? if(currentRow.SpaceCount == 0 || broken) // NO spaces. { /* NOTE: This situation equals a simple left alignment. */ xAlignment = XAlignmentEnum.Left; } else // Spaces exist. { // Calculate the exceeding spacing among the words! wordSpace = (frame.Width - currentRow.Width) / currentRow.SpaceCount; // Define the horizontal offsets for justified alignment. for( int index = 1, count = objects.Count; index < count; index++ ) { /* NOTE: The offset represents the horizontal justification gap inserted at the left side of each object. */ objectXOffsets[index] = objectXOffsets[index - 1] + objects[index - 1].SpaceCount * wordSpace; } } break; } SetWordSpace wordSpaceOperation = new SetWordSpace(wordSpace); // Vertical alignment and translation. for( int index = objects.Count - 1; index >= 0; index-- ) { RowObject obj = objects[index]; // Vertical alignment. double objectYOffset = 0; { LineAlignmentEnum lineAlignment; double lineRise; { object objectLineAlignment = obj.LineAlignment; if(objectLineAlignment is Double) { lineAlignment = LineAlignmentEnum.BaseLine; lineRise = (double)objectLineAlignment; } else { lineAlignment = (LineAlignmentEnum)objectLineAlignment; lineRise = 0; } } switch (lineAlignment) { case LineAlignmentEnum.Top: /* NOOP */ break; case LineAlignmentEnum.Middle: objectYOffset = -(currentRow.Height - obj.Height) / 2; break; case LineAlignmentEnum.BaseLine: objectYOffset = -(currentRow.BaseLine - obj.BaseLine - lineRise); break; case LineAlignmentEnum.Bottom: objectYOffset = -(currentRow.Height - obj.Height); break; default: throw new NotImplementedException("Line alignment " + lineAlignment + " unknown."); } } IList<ContentObject> containedGraphics = obj.Container.Objects; // Word spacing. containedGraphics.Insert(0,wordSpaceOperation); // Translation. containedGraphics.Insert( 0, new ModifyCTM( 1, 0, 0, 1, objectXOffsets[index] + rowXOffset, // Horizontal alignment. objectYOffset // Vertical alignment. ) ); } // Update the actual block height! boundBox.Height = (float)(currentRow.Y + currentRow.Height); // Update the actual block vertical location! double yOffset; switch(yAlignment) { case YAlignmentEnum.Bottom: yOffset = frame.Height - boundBox.Height; break; case YAlignmentEnum.Middle: yOffset = (frame.Height - boundBox.Height) / 2; break; case YAlignmentEnum.Top: default: yOffset = 0; break; } boundBox.Y = (float)(frame.Y + yOffset); // Discard the current row! currentRow = null; }
/** <summary>Shows the specified external object.</summary> <param name="xObject">External object.</param> <param name="size">Size of the external object.</param> <param name="lineAlignment">Line alignment. It can be: <list type="bullet"> <item><see cref="LineAlignmentEnum"/></item> <item><see cref="Length">: arbitrary super-/sub-script, depending on whether the value is positive or not.</item> </list> </param> <returns>Whether the external object was successfully shown.</returns> */ public bool ShowXObject( xObjects::XObject xObject, SizeF? size, object lineAlignment ) { if(currentRow == null || xObject == null) return false; if(!size.HasValue) {size = xObject.Size;} lineAlignment = ResolveLineAlignment(lineAlignment); while(true) { if(OperationUtils.Compare(currentRow.Y + size.Value.Height, frame.Height) == 1) // Object's height exceeds block's remaining vertical space. { // Terminate current row and exit! EndRow(false); return false; } else if(OperationUtils.Compare(currentRow.Width + size.Value.Width, frame.Width) < 1) // There's room for the object in the current row. { PointF location = new PointF( (float)currentRow.Width, (float)currentRow.Y ); RowObject obj; { obj = new RowObject( RowObject.TypeEnum.XObject, baseComposer.BeginLocalState(), // Opens the row object's local state. size.Value.Height, size.Value.Width, 0, lineAlignment, size.Value.Height ); baseComposer.ShowXObject(xObject, location, size); baseComposer.End(); // Closes the row object's local state. } AddRowObject(obj, lineAlignment); return true; } else // There's NOT enough room for the object in the current row. { // Go to next row! EndRow(false); BeginRow(); } } }
/** <summary>Shows text.</summary> <param name="text">Text to show.</param> <param name="lineAlignment">Line alignment. It can be: <list type="bullet"> <item><see cref="LineAlignmentEnum"/></item> <item><see cref="Length">: arbitrary super-/sub-script, depending on whether the value is positive or not.</item> </list> </param> <returns>Last shown character index.</returns> */ public int ShowText( string text, object lineAlignment ) { if(currentRow == null || text == null) return 0; ContentScanner.GraphicsState state = baseComposer.State; fonts::Font font = state.Font; double fontSize = state.FontSize; double lineHeight = font.GetLineHeight(fontSize); double baseLine = font.GetAscent(fontSize); lineAlignment = ResolveLineAlignment(lineAlignment); TextFitter textFitter = new TextFitter( text, 0, font, fontSize, hyphenation, hyphenationCharacter ); int textLength = text.Length; int index = 0; while(true) { if(currentRow.Width == 0) // Current row has just begun. { // Removing leading space... while(true) { if(index == textLength) // Text end reached. goto endTextShowing; else if(text[index] != ' ') // No more leading spaces. break; index++; } } if(OperationUtils.Compare(currentRow.Y + lineHeight, frame.Height) == 1) // Text's height exceeds block's remaining vertical space. { // Terminate the current row and exit! EndRow(false); goto endTextShowing; } // Does the text fit? if(textFitter.Fit( index, frame.Width - currentRow.Width, // Remaining row width. currentRow.SpaceCount == 0 )) { // Get the fitting text! string textChunk = textFitter.FittedText; double textChunkWidth = textFitter.FittedWidth; PointF textChunkLocation = new PointF( (float)currentRow.Width, (float)currentRow.Y ); // Insert the fitting text! RowObject obj; { obj = new RowObject( RowObject.TypeEnum.Text, baseComposer.BeginLocalState(), // Opens the row object's local state. lineHeight, textChunkWidth, CountOccurrence(' ',textChunk), lineAlignment, baseLine ); baseComposer.ShowText(textChunk, textChunkLocation); baseComposer.End(); // Closes the row object's local state. } AddRowObject(obj, lineAlignment); index = textFitter.EndIndex; } // Evaluating trailing text... while(true) { if(index == textLength) // Text end reached. goto endTextShowing; switch(text[index]) { case '\r': break; case '\n': // New paragraph! index++; ShowBreak(); goto endTrailParsing; default: // New row (within the same paragraph)! EndRow(false); BeginRow(); goto endTrailParsing; } index++; } endTrailParsing:; } endTextShowing:; if(index >= 0 && lineAlignment.Equals(LineAlignmentEnum.BaseLine)) {lastFontSize = fontSize;} return index; }