/**
* Writes a text line to the document. It takes care of all the attributes.
* <P>
* Before entering the line position must have been established and the
* <CODE>text</CODE> argument must be in text object scope (<CODE>beginText()</CODE>).
* @param line the line to be written
* @param text the <CODE>PdfContentByte</CODE> where the text will be written to
* @param graphics the <CODE>PdfContentByte</CODE> where the graphics will be written to
* @param currentValues the current font and extra spacing values
* @param ratio
* @throws DocumentException on error
*/
internal void WriteLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphics, Object[] currentValues, float ratio)
{
PdfFont currentFont = (PdfFont)(currentValues[0]);
float lastBaseFactor = (float)currentValues[1];
//PdfChunk chunkz;
int numberOfSpaces;
int lineLen;
bool isJustified;
float hangingCorrection = 0;
float hScale = 1;
float lastHScale = float.NaN;
float baseWordSpacing = 0;
float baseCharacterSpacing = 0;
numberOfSpaces = line.NumberOfSpaces;
lineLen = line.ToString().Length;
// does the line need to be justified?
isJustified = line.HasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1);
if (isJustified) {
if (line.NewlineSplit && line.WidthLeft >= (lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1))) {
if (line.RTL) {
text.MoveText(line.WidthLeft - lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1), 0);
}
baseWordSpacing = ratio * lastBaseFactor;
baseCharacterSpacing = lastBaseFactor;
}
else {
float width = line.WidthLeft;
PdfChunk last = line.GetChunk(line.Size - 1);
if (last != null) {
String s = last.ToString();
char c;
if (s.Length > 0 && hangingPunctuation.IndexOf((c = s[s.Length - 1])) >= 0) {
float oldWidth = width;
width += last.Font.Width(c) * 0.4f;
hangingCorrection = width - oldWidth;
}
}
float baseFactor = width / (ratio * numberOfSpaces + lineLen - 1);
baseWordSpacing = ratio * baseFactor;
baseCharacterSpacing = baseFactor;
lastBaseFactor = baseFactor;
}
}
int lastChunkStroke = line.LastStrokeChunk;
int chunkStrokeIdx = 0;
float xMarker = text.XTLM;
float baseXMarker = xMarker;
float yMarker = text.YTLM;
bool adjustMatrix = false;
// looping over all the chunks in 1 line
foreach (PdfChunk chunk in line) {
Color color = chunk.Color;
hScale = 1;
if (chunkStrokeIdx <= lastChunkStroke) {
float width;
if (isJustified) {
width = chunk.GetWidthCorrected(baseCharacterSpacing, baseWordSpacing);
}
else
width = chunk.Width;
if (chunk.IsStroked()) {
PdfChunk nextChunk = line.GetChunk(chunkStrokeIdx + 1);
if (chunk.IsAttribute(Chunk.BACKGROUND)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.BACKGROUND))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
float fontSize = chunk.Font.Size;
float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize);
float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize);
Object[] bgr = (Object[])chunk.GetAttribute(Chunk.BACKGROUND);
graphics.SetColorFill((Color)bgr[0]);
float[] extra = (float[])bgr[1];
graphics.Rectangle(xMarker - extra[0],
yMarker + descender - extra[1] + chunk.TextRise,
width - subtract + extra[0] + extra[2],
ascender - descender + extra[1] + extra[3]);
graphics.Fill();
graphics.SetGrayFill(0);
}
if (chunk.IsAttribute(Chunk.UNDERLINE)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.UNDERLINE))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
Object[][] unders = (Object[][])chunk.GetAttribute(Chunk.UNDERLINE);
Color scolor = null;
for (int k = 0; k < unders.Length; ++k) {
Object[] obj = unders[k];
scolor = (Color)obj[0];
float[] ps = (float[])obj[1];
if (scolor == null)
scolor = color;
if (scolor != null)
graphics.SetColorStroke(scolor);
float fsize = chunk.Font.Size;
graphics.SetLineWidth(ps[0] + fsize * ps[1]);
float shift = ps[2] + fsize * ps[3];
int cap2 = (int)ps[4];
if (cap2 != 0)
graphics.SetLineCap(cap2);
graphics.MoveTo(xMarker, yMarker + shift);
graphics.LineTo(xMarker + width - subtract, yMarker + shift);
graphics.Stroke();
if (scolor != null)
graphics.ResetGrayStroke();
if (cap2 != 0)
graphics.SetLineCap(0);
}
graphics.SetLineWidth(1);
}
if (chunk.IsAttribute(Chunk.ACTION)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.ACTION))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
text.AddAnnotation(new PdfAnnotation(writer, xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size, (PdfAction)chunk.GetAttribute(Chunk.ACTION)));
}
if (chunk.IsAttribute(Chunk.REMOTEGOTO)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.REMOTEGOTO))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
Object[] obj = (Object[])chunk.GetAttribute(Chunk.REMOTEGOTO);
String filename = (String)obj[0];
if (obj[1] is String)
RemoteGoto(filename, (String)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size);
else
RemoteGoto(filename, (int)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size);
}
if (chunk.IsAttribute(Chunk.LOCALGOTO)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALGOTO))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
LocalGoto((String)chunk.GetAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size);
}
if (chunk.IsAttribute(Chunk.LOCALDESTINATION)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALDESTINATION))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
LocalDestination((String)chunk.GetAttribute(Chunk.LOCALDESTINATION), new PdfDestination(PdfDestination.XYZ, xMarker, yMarker + chunk.Font.Size, 0));
}
if (chunk.IsAttribute(Chunk.GENERICTAG)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.GENERICTAG))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
Rectangle rect = new Rectangle(xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size);
IPdfPageEvent pev = writer.PageEvent;
if (pev != null)
pev.OnGenericTag(writer, this, rect, (String)chunk.GetAttribute(Chunk.GENERICTAG));
}
if (chunk.IsAttribute(Chunk.PDFANNOTATION)) {
float subtract = lastBaseFactor;
if (nextChunk != null && nextChunk.IsAttribute(Chunk.PDFANNOTATION))
subtract = 0;
if (nextChunk == null)
subtract += hangingCorrection;
float fontSize = chunk.Font.Size;
float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize);
float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize);
PdfAnnotation annot = PdfFormField.ShallowDuplicate((PdfAnnotation)chunk.GetAttribute(Chunk.PDFANNOTATION));
annot.Put(PdfName.RECT, new PdfRectangle(xMarker, yMarker + descender, xMarker + width - subtract, yMarker + ascender));
text.AddAnnotation(annot);
}
float[] paramsx = (float[])chunk.GetAttribute(Chunk.SKEW);
object hs = chunk.GetAttribute(Chunk.HSCALE);
if (paramsx != null || hs != null) {
float b = 0, c = 0;
if (paramsx != null) {
b = paramsx[0];
c = paramsx[1];
}
if (hs != null)
hScale = (float)hs;
text.SetTextMatrix(hScale, b, c, 1, xMarker, yMarker);
}
if (chunk.IsImage()) {
Image image = chunk.Image;
float[] matrix = image.Matrix;
matrix[Image.CX] = xMarker + chunk.ImageOffsetX - matrix[Image.CX];
matrix[Image.CY] = yMarker + chunk.ImageOffsetY - matrix[Image.CY];
graphics.AddImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
text.MoveText(xMarker + lastBaseFactor + image.ScaledWidth - text.XTLM, 0);
}
}
xMarker += width;
++chunkStrokeIdx;
}
if (chunk.Font.CompareTo(currentFont) != 0) {
currentFont = chunk.Font;
text.SetFontAndSize(currentFont.Font, currentFont.Size);
}
float rise = 0;
Object[] textRender = (Object[])chunk.GetAttribute(Chunk.TEXTRENDERMODE);
int tr = 0;
float strokeWidth = 1;
Color strokeColor = null;
object fr = chunk.GetAttribute(Chunk.SUBSUPSCRIPT);
if (textRender != null) {
tr = (int)textRender[0] & 3;
if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
text.SetTextRenderingMode(tr);
if (tr == PdfContentByte.TEXT_RENDER_MODE_STROKE || tr == PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE) {
strokeWidth = (float)textRender[1];
if (strokeWidth != 1)
text.SetLineWidth(strokeWidth);
strokeColor = (Color)textRender[2];
if (strokeColor == null)
strokeColor = color;
if (strokeColor != null)
text.SetColorStroke(strokeColor);
}
}
if (fr != null)
rise = (float)fr;
if (color != null)
text.SetColorFill(color);
if (rise != 0)
text.SetTextRise(rise);
if (chunk.IsImage()) {
adjustMatrix = true;
}
// If it is a CJK chunk or Unicode TTF we will have to simulate the
// space adjustment.
else if (isJustified && numberOfSpaces > 0 && chunk.IsSpecialEncoding()) {
if (hScale != lastHScale) {
lastHScale = hScale;
text.SetWordSpacing(baseWordSpacing / hScale);
text.SetCharacterSpacing(baseCharacterSpacing / hScale);
}
String s = chunk.ToString();
int idx = s.IndexOf(' ');
if (idx < 0)
text.ShowText(chunk.ToString());
else {
float spaceCorrection = - baseWordSpacing * 1000f / chunk.Font.Size / hScale;
PdfTextArray textArray = new PdfTextArray(s.Substring(0, idx));
int lastIdx = idx;
while ((idx = s.IndexOf(' ', lastIdx + 1)) >= 0) {
textArray.Add(spaceCorrection);
textArray.Add(s.Substring(lastIdx, idx - lastIdx));
lastIdx = idx;
}
textArray.Add(spaceCorrection);
textArray.Add(s.Substring(lastIdx));
text.ShowText(textArray);
}
}
else {
if (isJustified && hScale != lastHScale) {
lastHScale = hScale;
text.SetWordSpacing(baseWordSpacing / hScale);
text.SetCharacterSpacing(baseCharacterSpacing / hScale);
}
text.ShowText(chunk.ToString());
}
if (rise != 0)
text.SetTextRise(0);
if (color != null)
text.ResetRGBColorFill();
if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
text.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
if (strokeColor != null)
text.ResetRGBColorStroke();
if (strokeWidth != 1)
text.SetLineWidth(1);
if (chunk.IsAttribute(Chunk.SKEW) || chunk.IsAttribute(Chunk.HSCALE)) {
adjustMatrix = true;
text.SetTextMatrix(xMarker, yMarker);
}
}
if (isJustified) {
text.SetWordSpacing(0);
text.SetCharacterSpacing(0);
if (line.NewlineSplit)
lastBaseFactor = 0;
}
if (adjustMatrix)
text.MoveText(baseXMarker - text.XTLM, 0);
currentValues[0] = currentFont;
currentValues[1] = lastBaseFactor;
}