/** * 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; float glueWidth = 0; numberOfSpaces = line.NumberOfSpaces; lineLen = line.GetLineLengthUtf32(); // does the line need to be justified? isJustified = line.HasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1); int separatorCount = line.GetSeparatorCount(); if (separatorCount > 0) { glueWidth = line.WidthLeft / separatorCount; } else 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; float tabPosition = 0; // 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.IsSeparator()) { width = glueWidth; Object[] sep = (Object[])chunk.GetAttribute(Chunk.SEPARATOR); IDrawInterface di = (IDrawInterface)sep[0]; bool vertical = (bool)sep[1]; float fontSize = chunk.Font.Size; float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); if (vertical) { di.Draw(graphics, baseXMarker, yMarker + descender, baseXMarker + line.OriginalWidth, ascender - descender, yMarker); } else { di.Draw(graphics, xMarker, yMarker + descender, xMarker + width, ascender - descender, yMarker); } } if (chunk.IsTab()) { Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); IDrawInterface di = (IDrawInterface)tab[0]; tabPosition = (float)tab[1] + (float)tab[3]; float fontSize = chunk.Font.Size; float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); if (tabPosition > xMarker) { di.Draw(graphics, xMarker, yMarker + descender, tabPosition, ascender - descender, yMarker); } float tmp = xMarker; xMarker = tabPosition; tabPosition = tmp; } 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; } else if (chunk.IsHorizontalSeparator()) { PdfTextArray array = new PdfTextArray(); array.Add(-glueWidth * 1000f / chunk.Font.Size / hScale); text.ShowText(array); } else if (chunk.IsTab()) { PdfTextArray array = new PdfTextArray(); array.Add((tabPosition - xMarker) * 1000f / chunk.Font.Size / hScale); text.ShowText(array); } // 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(s); 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; }