public PdfLine ProcessLine(float leftX, float width, int alignment, int runDirection, int arabicOptions, float minY, float yLine, float descender)
{
this.arabicOptions = arabicOptions;
Save();
bool isRTL = (runDirection == PdfWriter.RUN_DIRECTION_RTL);
if (currentChar >= totalTextLength) {
bool hasText = GetParagraph(runDirection);
if (!hasText)
return null;
if (totalTextLength == 0) {
List<PdfChunk> ar = new List<PdfChunk>();
PdfChunk ckx = new PdfChunk("", detailChunks[0]);
ar.Add(ckx);
return new PdfLine(0, 0, 0, alignment, true, ar, isRTL);
}
}
float originalWidth = width;
int lastSplit = -1;
if (currentChar != 0)
currentChar = TrimLeftEx(currentChar, totalTextLength - 1);
int oldCurrentChar = currentChar;
int uniC = 0;
PdfChunk ck = null;
float charWidth = 0;
PdfChunk lastValidChunk = null;
bool splitChar = false;
bool surrogate = false;
for (; currentChar < totalTextLength; ++currentChar) {
ck = detailChunks[currentChar];
if (ck.IsImage() && minY < yLine) {
Image img = ck.Image;
if (img.ScaleToFitLineWhenOverflow && yLine + 2 * descender - img.ScaledHeight - ck.ImageOffsetY - img.SpacingBefore < minY) {
float scalePercent = (yLine + 2 * descender - ck.ImageOffsetY - img.SpacingBefore - minY) / img.Height * 100;
img.ScalePercent(scalePercent);
}
}
surrogate = Utilities.IsSurrogatePair(text, currentChar);
if (surrogate)
uniC = ck.GetUnicodeEquivalent(Utilities.ConvertToUtf32(text, currentChar));
else
uniC = ck.GetUnicodeEquivalent(text[currentChar]);
if (PdfChunk.NoPrint(uniC))
continue;
if (surrogate)
charWidth = ck.GetCharWidth(uniC);
else
charWidth = ck.GetCharWidth(text[currentChar]);
splitChar = ck.IsExtSplitCharacter(oldCurrentChar, currentChar, totalTextLength, text, detailChunks);
if (splitChar && Char.IsWhiteSpace((char)uniC))
lastSplit = currentChar;
if (width - charWidth < 0) {
// If the chunk is an image and it is the first one in line, check if resize requested
// If so, resize to fit the current line width
if (lastValidChunk == null && ck.IsImage()) {
Image img = ck.Image;
if (img.ScaleToFitLineWhenOverflow) {
float scalePercent = width / img.Width * 100;
img.ScalePercent(scalePercent);
charWidth = width;
}
}
}
if (width - charWidth < 0)
break;
if (splitChar)
lastSplit = currentChar;
if (!ck.IsTabSpace())
width -= charWidth;
lastValidChunk = ck;
if (ck.IsTab()) {
Object[] tab = (Object[])ck.GetAttribute(Chunk.TAB);
float tabPosition = (float)tab[1];
bool newLine = (bool)tab[2];
if (newLine && tabPosition < originalWidth - width) {
return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL);
}
detailChunks[currentChar].AdjustLeft(leftX);
width = originalWidth - tabPosition;
}
else if (ck.IsTabSpace())
{
float module = (float)ck.GetAttribute(Chunk.TABSPACE);
float decrement = module - ((originalWidth - width) % module);
if (width < decrement)
return new PdfLine(0, originalWidth, width, alignment, true,
CreateArrayOfPdfChunks(oldCurrentChar, currentChar-1), isRTL);
width -= decrement;
}
else if (ck.IsSeparator()) {
Object[] sep = (Object[])ck.GetAttribute(Chunk.SEPARATOR);
IDrawInterface di = (IDrawInterface)sep[0];
bool vertical = (bool)sep[1];
if (vertical && di is LineSeparator) {
float separatorWidth = originalWidth * ((LineSeparator) di).Percentage / 100f;
width -= separatorWidth;
if (width < 0) {
width = 0;
}
}
}
if (surrogate)
++currentChar;
}
if (lastValidChunk == null) {
// not even a single char fit; must output the first char
++currentChar;
if (surrogate)
++currentChar;
return new PdfLine(0, originalWidth, 0, alignment, false, CreateArrayOfPdfChunks(currentChar - 1, currentChar - 1), isRTL);
}
if (currentChar >= totalTextLength) {
// there was more line than text
return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, totalTextLength - 1), isRTL);
}
int newCurrentChar = TrimRightEx(oldCurrentChar, currentChar - 1);
if (newCurrentChar < oldCurrentChar) {
// only WS
return new PdfLine(0, originalWidth, width, alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL);
}
if (newCurrentChar == currentChar - 1) { // middle of word
IHyphenationEvent he = (IHyphenationEvent)lastValidChunk.GetAttribute(Chunk.HYPHENATION);
if (he != null) {
int[] word = GetWord(oldCurrentChar, newCurrentChar);
if (word != null) {
float testWidth = width + GetWidth(word[0], currentChar - 1);
String pre = he.GetHyphenatedWordPre(new String(text, word[0], word[1] - word[0]), lastValidChunk.Font.Font, lastValidChunk.Font.Size, testWidth);
String post = he.HyphenatedWordPost;
if (pre.Length > 0) {
PdfChunk extra = new PdfChunk(pre, lastValidChunk);
currentChar = word[1] - post.Length;
return new PdfLine(0, originalWidth, testWidth - lastValidChunk.Font.Width(pre), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, word[0] - 1, extra), isRTL);
}
}
}
}
if (lastSplit == -1 || lastSplit >= newCurrentChar) {
// no split point or split point ahead of end
return new PdfLine(0, originalWidth, width + GetWidth(newCurrentChar + 1, currentChar - 1), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL);
}
// standard split
currentChar = lastSplit + 1;
newCurrentChar = TrimRightEx(oldCurrentChar, lastSplit);
if (newCurrentChar < oldCurrentChar) {
// only WS again
newCurrentChar = currentChar - 1;
}
return new PdfLine(0, originalWidth, originalWidth - GetWidth(oldCurrentChar, newCurrentChar), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL);
}