// constructors /** * Constructs a <CODE>PdfChunk</CODE>-object. * * @param string the content of the <CODE>PdfChunk</CODE>-object * @param font the <CODE>PdfFont</CODE> * @param attributes the metrics attributes * @param noStroke the non metric attributes */ internal PdfChunk(string str, PdfChunk other) { thisChunk[0] = this; value = str; this.font = other.font; this.attributes = other.attributes; this.noStroke = other.noStroke; this.baseFont = other.baseFont; Object[] obj = (Object[])attributes[Chunk.IMAGE]; if (obj == null) { image = null; } else { image = (Image)obj[0]; offsetX = (float)obj[1]; offsetY = (float)obj[2]; changeLeading = (bool)obj[3]; } encoding = font.Font.Encoding; splitCharacter = (ISplitCharacter)noStroke[Chunk.SPLITCHARACTER]; if (splitCharacter == null) { splitCharacter = DefaultSplitCharacter.DEFAULT; } }
/** * Creates a line from the chunk array. * @param width the width of the line * @return the line or null if no more chunks */ protected PdfLine CreateLine(float width) { if (chunks.Count == 0) { return(null); } splittedChunkText = null; currentStandbyChunk = null; PdfLine line = new PdfLine(0, width, alignment, 0); string total; for (currentChunkMarker = 0; currentChunkMarker < chunks.Count; ++currentChunkMarker) { PdfChunk original = (PdfChunk)(chunks[currentChunkMarker]); total = original.ToString(); currentStandbyChunk = line.Add(original); if (currentStandbyChunk != null) { splittedChunkText = original.ToString(); original.Value = total; return(line); } } return(line); }
public float GetWidthCorrected(float charSpacing, float wordSpacing) { float total = 0; for (int k = 0; k < line.Count; ++k) { PdfChunk ck = (PdfChunk)line[k]; total += ck.GetWidthCorrected(charSpacing, wordSpacing); } return(total); }
private void AddToLine(PdfChunk chunk) { if (chunk.ChangeLeading && chunk.IsImage()) { float f = chunk.Image.ScaledHeight + chunk.ImageOffsetY + chunk.Image.BorderWidthTop; if (f > height) { height = f; } } line.Add(chunk); }
/** * Normalizes the list of chunks when the line is accepted. */ protected void ShortenChunkArray() { if (currentChunkMarker < 0) { return; } if (currentChunkMarker >= chunks.Count) { chunks.Clear(); return; } PdfChunk split = (PdfChunk)(chunks[currentChunkMarker]); split.Value = splittedChunkText; chunks[currentChunkMarker] = currentStandbyChunk; for (int j = currentChunkMarker - 1; j >= 0; --j) { chunks.RemoveAt(j); } }
private void AddList(List list, float left, float right, int alignment) { PdfChunk chunk; PdfChunk overflow; ArrayList allActions = new ArrayList(); ProcessActions(list, null, allActions); int aCounter = 0; foreach (IElement ele in list.Items) { switch (ele.Type) { case Element.LISTITEM: ListItem item = (ListItem)ele; line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); line.ListItem = item; foreach (Chunk c in item.Chunks) { chunk = new PdfChunk(c, (PdfAction)(allActions[aCounter++])); while ((overflow = line.Add(chunk)) != null) { AddLine(line); line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); chunk = overflow; } line.ResetAlignment(); AddLine(line); line = new PdfLine(left + item.IndentationLeft, right, alignment, leading); } break; case Element.LIST: List sublist = (List)ele; AddList(sublist, left + sublist.IndentationLeft, right, alignment); break; } } }
// methods /** * Adds a <CODE>PdfChunk</CODE> to the <CODE>PdfLine</CODE>. * * @param chunk the <CODE>PdfChunk</CODE> to add * @return <CODE>null</CODE> if the chunk could be added completely; if not * a <CODE>PdfChunk</CODE> containing the part of the chunk that could * not be added is returned */ internal PdfChunk Add(PdfChunk chunk) { // nothing happens if the chunk is null. if (chunk == null || chunk.ToString().Equals("")) { return(null); } // we split the chunk to be added PdfChunk overflow = chunk.Split(width); newlineSplit = (chunk.IsNewlineSplit() || overflow == null); // if (chunk.IsNewlineSplit() && alignment == Element.ALIGN_JUSTIFIED) // alignment = Element.ALIGN_LEFT; if (chunk.IsTab()) { Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); float tabPosition = (float)tab[1]; bool newline = (bool)tab[2]; if (newline && tabPosition < originalWidth - width) { return(chunk); } width = originalWidth - tabPosition; chunk.AdjustLeft(left); AddToLine(chunk); } // if the length of the chunk > 0 we add it to the line else if (chunk.Length > 0 || chunk.IsImage()) { if (overflow != null) { chunk.TrimLastSpace(); } width -= chunk.Width; AddToLine(chunk); } // if the length == 0 and there were no other chunks added to the line yet, // we risk to end up in an endless loop trying endlessly to add the same chunk else if (line.Count < 1) { chunk = overflow; overflow = chunk.Truncate(width); width -= chunk.Width; if (chunk.Length > 0) { AddToLine(chunk); return(overflow); } // if the chunck couldn't even be truncated, we add everything, so be it else { if (overflow != null) { AddToLine(chunk); } return(null); } } else { width += ((PdfChunk)(line[line.Count - 1])).TrimLastSpace(); } return(overflow); }
/** * Truncates this <CODE>PdfChunk</CODE> if it's too long for the given width. * <P> * Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated. * * @param width a given width * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width. */ internal PdfChunk Truncate(float width) { if (image != null) { if (image.ScaledWidth > width) { PdfChunk pc = new PdfChunk("", this); value = ""; attributes.Remove(Chunk.IMAGE); image = null; font = PdfFont.DefaultFont; return(pc); } else { return(null); } } int currentPosition = 0; float currentWidth = 0; // it's no use trying to split if there isn't even enough place for a space if (width < font.Width()) { string returnValue = value.Substring(1); value = value.Substring(0, 1); PdfChunk pc = new PdfChunk(returnValue, this); return(pc); } // loop over all the characters of a string // or until the totalWidth is reached int length = value.Length; bool surrogate = false; while (currentPosition < length) { // the width of every character is added to the currentWidth surrogate = Utilities.IsSurrogatePair(value, currentPosition); if (surrogate) { currentWidth += font.Width(Utilities.ConvertToUtf32(value, currentPosition)); } else { currentWidth += font.Width(value[currentPosition]); } if (currentWidth > width) { break; } if (surrogate) { currentPosition++; } currentPosition++; } // if all the characters fit in the total width, null is returned (there is no overflow) if (currentPosition == length) { return(null); } // otherwise, the string has to be truncated //currentPosition -= 2; // we have to chop off minimum 1 character from the chunk if (currentPosition == 0) { currentPosition = 1; if (surrogate) { ++currentPosition; } } string retVal = value.Substring(currentPosition); value = value.Substring(0, currentPosition); PdfChunk tmp = new PdfChunk(retVal, this); return(tmp); }
/** * Splits this <CODE>PdfChunk</CODE> if it's too long for the given width. * <P> * Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated. * * @param width a given width * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width. */ internal PdfChunk Split(float width) { newlineSplit = false; if (image != null) { if (image.ScaledWidth > width) { PdfChunk pc = new PdfChunk(Chunk.OBJECT_REPLACEMENT_CHARACTER, this); value = ""; attributes = new Hashtable(); image = null; font = PdfFont.DefaultFont; return(pc); } else { return(null); } } IHyphenationEvent hyphenationEvent = (IHyphenationEvent)noStroke[Chunk.HYPHENATION]; int currentPosition = 0; int splitPosition = -1; float currentWidth = 0; // loop over all the characters of a string // or until the totalWidth is reached int lastSpace = -1; float lastSpaceWidth = 0; int length = value.Length; char[] valueArray = value.ToCharArray(); char character = (char)0; BaseFont ft = font.Font; bool surrogate = false; if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { while (currentPosition < length) { // the width of every character is added to the currentWidth char cidChar = valueArray[currentPosition]; character = (char)ft.GetUnicodeEquivalent(cidChar); // if a newLine or carriageReturn is encountered if (character == '\n') { newlineSplit = true; string returnValue = value.Substring(currentPosition + 1); value = value.Substring(0, currentPosition); if (value.Length < 1) { value = "\u0001"; } PdfChunk pc = new PdfChunk(returnValue, this); return(pc); } currentWidth += font.Width(cidChar); if (character == ' ') { lastSpace = currentPosition + 1; lastSpaceWidth = currentWidth; } if (currentWidth > width) { break; } // if a split-character is encountered, the splitPosition is altered if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, thisChunk)) { splitPosition = currentPosition + 1; } currentPosition++; } } else { while (currentPosition < length) { // the width of every character is added to the currentWidth character = valueArray[currentPosition]; // if a newLine or carriageReturn is encountered if (character == '\r' || character == '\n') { newlineSplit = true; int inc = 1; if (character == '\r' && currentPosition + 1 < length && valueArray[currentPosition + 1] == '\n') { inc = 2; } string returnValue = value.Substring(currentPosition + inc); value = value.Substring(0, currentPosition); if (value.Length < 1) { value = " "; } PdfChunk pc = new PdfChunk(returnValue, this); return(pc); } surrogate = Utilities.IsSurrogatePair(valueArray, currentPosition); if (surrogate) { currentWidth += font.Width(Utilities.ConvertToUtf32(valueArray[currentPosition], valueArray[currentPosition + 1])); } else { currentWidth += font.Width(character); } if (character == ' ') { lastSpace = currentPosition + 1; lastSpaceWidth = currentWidth; } if (surrogate) { currentPosition++; } if (currentWidth > width) { break; } // if a split-character is encountered, the splitPosition is altered if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, null)) { splitPosition = currentPosition + 1; } currentPosition++; } } // if all the characters fit in the total width, null is returned (there is no overflow) if (currentPosition == length) { return(null); } // otherwise, the string has to be truncated if (splitPosition < 0) { string returnValue = value; value = ""; PdfChunk pc = new PdfChunk(returnValue, this); return(pc); } if (lastSpace > splitPosition && splitCharacter.IsSplitCharacter(0, 0, 1, singleSpace, null)) { splitPosition = lastSpace; } if (hyphenationEvent != null && lastSpace >= 0 && lastSpace < currentPosition) { int wordIdx = GetWord(value, lastSpace); if (wordIdx > lastSpace) { string pre = hyphenationEvent.GetHyphenatedWordPre(value.Substring(lastSpace, wordIdx - lastSpace), font.Font, font.Size, width - lastSpaceWidth); string post = hyphenationEvent.HyphenatedWordPost; if (pre.Length > 0) { string returnValue = post + value.Substring(wordIdx); value = Trim(value.Substring(0, lastSpace) + pre); PdfChunk pc = new PdfChunk(returnValue, this); return(pc); } } } string retVal = value.Substring(splitPosition); value = Trim(value.Substring(0, splitPosition)); PdfChunk tmp = new PdfChunk(retVal, this); return(tmp); }
// constructors /** * Constructs a <CODE>PdfCell</CODE>-object. * * @param cell the original <CODE>Cell</CODE> * @param rownumber the number of the <CODE>Row</CODE> the <CODE>Cell</CODE> was in. * @param left the left border of the <CODE>PdfCell</CODE> * @param right the right border of the <CODE>PdfCell</CODE> * @param top the top border of the <CODE>PdfCell</CODE> * @param cellspacing the cellspacing of the <CODE>Table</CODE> * @param cellpadding the cellpadding of the <CODE>Table</CODE> */ public PdfCell(Cell cell, int rownumber, float left, float right, float top, float cellspacing, float cellpadding) : base(left, top, right, top) { // copying the other Rectangle attributes from class Cell CloneNonPositionParameters(cell); this.cellpadding = cellpadding; this.cellspacing = cellspacing; this.verticalAlignment = cell.VerticalAlignment; this.useAscender = cell.UseAscender; this.useDescender = cell.UseDescender; this.useBorderPadding = cell.UseBorderPadding; // initialisation of some parameters PdfChunk chunk; PdfChunk overflow; lines = new ArrayList(); images = new ArrayList(); leading = cell.Leading; int alignment = cell.HorizontalAlignment; left += cellspacing + cellpadding; right -= cellspacing + cellpadding; left += GetBorderWidthInside(LEFT_BORDER); right -= GetBorderWidthInside(RIGHT_BORDER); contentHeight = 0; rowspan = cell.Rowspan; ArrayList allActions; int aCounter; // we loop over all the elements of the cell foreach (IElement ele in cell.Elements) { switch (ele.Type) { case Element.JPEG: case Element.JPEG2000: case Element.JBIG2: case Element.IMGRAW: case Element.IMGTEMPLATE: AddImage((Image)ele, left, right, 0.4f * leading, alignment); break; // if the element is a list case Element.LIST: if (line != null && line.Size > 0) { line.ResetAlignment(); AddLine(line); } // we loop over all the listitems AddList((List)ele, left, right, alignment); line = new PdfLine(left, right, alignment, leading); break; // if the element is something else default: allActions = new ArrayList(); ProcessActions(ele, null, allActions); aCounter = 0; float currentLineLeading = leading; float currentLeft = left; float currentRight = right; if (ele is Phrase) { currentLineLeading = ((Phrase)ele).Leading; } if (ele is Paragraph) { Paragraph p = (Paragraph)ele; currentLeft += p.IndentationLeft; currentRight -= p.IndentationRight; } if (line == null) { line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); } // we loop over the chunks ArrayList chunks = ele.Chunks; if (chunks.Count == 0) { AddLine(line); // add empty line - all cells need some lines even if they are empty line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); } else { foreach (Chunk c in chunks) { chunk = new PdfChunk(c, (PdfAction)allActions[aCounter++]); while ((overflow = line.Add(chunk)) != null) { AddLine(line); line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); chunk = overflow; } } } // if the element is a paragraph, section or chapter, we reset the alignment and add the line switch (ele.Type) { case Element.PARAGRAPH: case Element.SECTION: case Element.CHAPTER: line.ResetAlignment(); FlushCurrentLine(); break; } break; } } FlushCurrentLine(); if (lines.Count > cell.MaxLines) { while (lines.Count > cell.MaxLines) { RemoveLine(lines.Count - 1); } if (cell.MaxLines > 0) { String more = cell.ShowTruncation; if (more != null && more.Length > 0) { // Denote that the content has been truncated lastLine = (PdfLine)lines[lines.Count - 1]; if (lastLine.Size >= 0) { PdfChunk lastChunk = lastLine.GetChunk(lastLine.Size - 1); float moreWidth = new PdfChunk(more, lastChunk).Width; while (lastChunk.ToString().Length > 0 && lastChunk.Width + moreWidth > right - left) { // Remove characters to leave room for the 'more' indicator lastChunk.Value = lastChunk.ToString().Substring(0, lastChunk.Length - 1); } lastChunk.Value = lastChunk.ToString() + more; } else { lastLine.Add(new PdfChunk(new Chunk(more), null)); } } } } // we set some additional parameters if (useDescender && lastLine != null) { contentHeight -= lastLine.Descender; } // adjust first line height so that it touches the top if (lines.Count > 0) { firstLine = (PdfLine)lines[0]; float firstLineRealHeight = FirstLineRealHeight; contentHeight -= firstLine.Height; firstLine.height = firstLineRealHeight; contentHeight += firstLineRealHeight; } float newBottom = top - contentHeight - (2f * Cellpadding) - (2f * Cellspacing); newBottom -= GetBorderWidthInside(TOP_BORDER) + GetBorderWidthInside(BOTTOM_BORDER); Bottom = newBottom; this.rownumber = rownumber; }