123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.svg;
-
- import java.awt.Color;
- import java.awt.Graphics2D;
- import java.awt.Paint;
- import java.awt.Shape;
- import java.awt.Stroke;
- import java.awt.geom.AffineTransform;
- import java.awt.geom.GeneralPath;
- import java.awt.geom.Point2D;
- import java.io.IOException;
-
- import org.apache.batik.gvt.text.TextPaintInfo;
-
- import org.apache.fop.fonts.Font;
- import org.apache.fop.fonts.FontInfo;
- import org.apache.fop.svg.font.FOPGVTFont;
- import org.apache.fop.svg.font.FOPGVTGlyphVector;
-
- /**
- * Renders the attributed character iterator of a {@link org.apache.batik.bridge.TextNode}.
- * This class draws the text directly into the PDFGraphics2D so that
- * the text is not drawn using shapes which makes the PDF files larger.
- * If the text is simple enough to draw then it sets the font and calls
- * drawString. If the text is complex or the cannot be translated
- * into a simple drawString the StrokingTextPainter is used instead.
- *
- * @version $Id$
- */
- class PDFTextPainter extends NativeTextPainter {
-
- private PDFGraphics2D pdf;
-
- private PDFTextUtil textUtil;
-
- private double prevVisibleGlyphWidth;
-
- private boolean repositionNextGlyph;
-
- /**
- * Create a new PDF text painter with the given font information.
- *
- * @param fi the font info
- */
- public PDFTextPainter(FontInfo fi) {
- super(fi);
- }
-
- /** {@inheritDoc} */
- @Override
- protected boolean isSupported(Graphics2D g2d) {
- return g2d instanceof PDFGraphics2D;
- }
-
- @Override
- protected void preparePainting(Graphics2D g2d) {
- pdf = (PDFGraphics2D) g2d;
- }
-
- @Override
- protected void saveGraphicsState() {
- pdf.saveGraphicsState();
- }
-
- @Override
- protected void restoreGraphicsState() {
- pdf.restoreGraphicsState();
- }
-
- @Override
- protected void setInitialTransform(AffineTransform transform) {
- createTextUtil();
- textUtil.concatMatrix(transform);
- }
-
- private void createTextUtil() {
- textUtil = new PDFTextUtil(pdf.fontInfo) {
- protected void write(String code) {
- pdf.currentStream.write(code);
- }
- protected void write(StringBuffer code) {
- pdf.currentStream.append(code);
- }
- };
- }
-
- @Override
- protected void clip(Shape clip) {
- pdf.writeClip(clip);
- }
-
- private static int[] paZero = new int[4];
-
- protected void writeGlyphs(FOPGVTGlyphVector gv, GeneralPath debugShapes) throws IOException {
- if (gv.getGlyphPositionAdjustments() == null) {
- super.writeGlyphs(gv, debugShapes);
- } else {
- FOPGVTFont gvtFont = (FOPGVTFont) gv.getFont();
- String fk = gvtFont.getFontKey();
- Font f = gvtFont.getFont();
- Point2D initialPos = gv.getGlyphPosition(0);
- if (f.isMultiByte()) {
- int fs = f.getFontSize();
- float fsPoints = fs / 1000f;
- double xc = 0f;
- double yc = 0f;
- double xoLast = 0f;
- double yoLast = 0f;
- textUtil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, initialPos.getX(), initialPos.getY()));
- textUtil.updateTf(fk, fsPoints, true, false);
- int[][] dp = gv.getGlyphPositionAdjustments();
- for (int i = 0, n = gv.getNumGlyphs(); i < n; i++) {
- int gc = gv.getGlyphCode(i);
- int[] pa = ((i > dp.length) || (dp[i] == null)) ? paZero : dp[i];
- double xo = xc + pa[0];
- double yo = yc + pa[1];
- double xa = f.getWidth(gc);
- double ya = 0;
- double xd = (xo - xoLast) / 1000f;
- double yd = (yo - yoLast) / 1000f;
- textUtil.writeTd(xd, yd);
- textUtil.writeTj((char) gc, true, false);
- xc += xa + pa[2];
- yc += ya + pa[3];
- xoLast = xo;
- yoLast = yo;
- }
- }
- }
- }
-
- @Override
- protected void beginTextObject() {
- applyColorAndPaint(tpi);
- textUtil.beginTextObject();
- boolean stroke = (tpi.strokePaint != null) && (tpi.strokeStroke != null);
- textUtil.setTextRenderingMode(tpi.fillPaint != null, stroke, false);
- }
-
- @Override
- protected void endTextObject() {
- textUtil.writeTJ();
- textUtil.endTextObject();
- }
-
- private void applyColorAndPaint(TextPaintInfo tpi) {
- Paint fillPaint = tpi.fillPaint;
- Paint strokePaint = tpi.strokePaint;
- Stroke stroke = tpi.strokeStroke;
- int fillAlpha = PDFGraphics2D.OPAQUE;
- if (fillPaint instanceof Color) {
- Color col = (Color) fillPaint;
- pdf.applyColor(col, true);
- fillAlpha = col.getAlpha();
- }
- if (strokePaint instanceof Color) {
- Color col = (Color) strokePaint;
- pdf.applyColor(col, false);
- }
- pdf.applyPaint(fillPaint, true);
- pdf.applyStroke(stroke);
- if (strokePaint != null) {
- pdf.applyPaint(strokePaint, false);
- }
- pdf.applyAlpha(fillAlpha, PDFGraphics2D.OPAQUE);
- }
-
- @Override
- protected void positionGlyph(Point2D prevPos, Point2D glyphPos, boolean reposition) {
- // TODO Glyph transforms could be refined so not every char has to be painted
- // with its own TJ command (stretch/squeeze case could be optimized)
- repositionNextGlyph = (prevPos == null
- || prevPos.getY() != glyphPos.getY()
- || reposition);
- if (!repositionNextGlyph) {
- double xdiff = glyphPos.getX() - prevPos.getX();
- //Width of previous character
- double cw = prevVisibleGlyphWidth;
- double effxdiff = (1000 * xdiff) - cw;
- if (effxdiff != 0) {
- double adjust = (-effxdiff / font.getFontSize());
- textUtil.adjustGlyphTJ(adjust * 1000);
- }
- }
- }
-
- @Override
- protected void writeGlyph(char glyph, AffineTransform transform) {
- prevVisibleGlyphWidth = font.getWidth(glyph);
- boolean encodingChanging = false; // used for single byte
- if (!textUtil.isMultiByteFont(font.getFontName())) {
- int encoding = glyph / 256;
- glyph = (char) (glyph % 256);
- if (textUtil.getCurrentEncoding() != encoding) {
- textUtil.setCurrentEncoding(encoding);
- encodingChanging = true;
- }
- }
- if (repositionNextGlyph || encodingChanging) {
- textUtil.writeTJ();
- if (font != textUtil.getCurrentFont() || encodingChanging) {
- textUtil.setCurrentFont(font);
- textUtil.writeTf(font);
- }
- textUtil.writeTextMatrix(transform);
- }
- textUtil.writeTJMappedChar(glyph);
- }
-
- }
|