aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/apache/fop/svg/PDFTextPainter.java
blob: ae5512e34d7ad5ff70da3042ddac6e5bf328a0cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
 * $Id$
 * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
 * For details on use and redistribution please refer to the
 * LICENSE file included with these sources.
 */

package org.apache.fop.svg;

import java.awt.Graphics2D;
import java.awt.*;
import java.text.AttributedCharacterIterator;
import java.awt.font.FontRenderContext;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.Font;

import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.CharacterIterator;
import java.awt.font.TextLayout;
import java.awt.font.TextAttribute;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.*;
import java.util.Set;

import org.apache.batik.gvt.text.Mark;
import org.apache.batik.gvt.*;
import org.apache.batik.gvt.text.*;
import org.apache.batik.gvt.renderer.*;
import org.apache.batik.gvt.font.*;

import org.apache.fop.layout.*;

/**
 * Renders the attributed character iterator of a <tt>TextNode</tt>.
 *
 * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
 * @version $Id$
 */
public class PDFTextPainter implements TextPainter {
    FontState fontState;

    public PDFTextPainter(FontState fs) {
        fontState = fs;
    }

    /**
     * Paints the specified attributed character iterator using the
     * specified Graphics2D and context and font context.
     * @param node the TextNode to paint
     * @param g2d the Graphics2D to use
     * @param context the rendering context.
     */
    public void paint(TextNode node, Graphics2D g2d,
                      GraphicsNodeRenderContext context) {
        // System.out.println("PDFText paint");
        String txt = node.getText();
        Point2D loc = node.getLocation();

        AttributedCharacterIterator aci =
            node.getAttributedCharacterIterator();
        // reset position to start of char iterator
        if (aci.getBeginIndex() == aci.getEndIndex()) {
            return;
        }
        char ch = aci.first();
        if (ch == AttributedCharacterIterator.DONE) {
            return;
        }
        TextNode.Anchor anchor =
            (TextNode.Anchor)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);

        Vector gvtFonts =
            (Vector)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
        Paint forg = (Paint)aci.getAttribute(TextAttribute.FOREGROUND);
        Float size = (Float)aci.getAttribute(TextAttribute.SIZE);
        Stroke stroke =
            (Stroke)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.STROKE);
        Float xpos =
            (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.X);
        Float ypos =
            (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.Y);

        Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
        Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT);

        if (forg instanceof Color) {
            g2d.setColor((Color)forg);
        }
        g2d.setPaint(forg);
        g2d.setStroke(stroke);

        String style = ((posture != null) && (posture.floatValue() > 0.0))
                       ? "italic" : "normal";
        String weight = ((taWeight != null) && (taWeight.floatValue() > 1.0))
                        ? "bold" : "normal";

        FontInfo fi = fontState.getFontInfo();
        boolean found = false;
        if (gvtFonts != null) {
            for (Enumeration e = gvtFonts.elements(); e.hasMoreElements(); ) {
                GVTFontFamily fam = (GVTFontFamily)e.nextElement();
                String name = fam.getFamilyName();
                if (fi.hasFont(name, weight, style)) {
                    try {
                        int fsize = (int)size.floatValue();
                        fontState = new FontState(fontState.getFontInfo(),
                                                  name, style, weight,
                                                  fsize * 1000, 0);
                    } catch (org.apache.fop.apps.FOPException fope) {
                        fope.printStackTrace();
                    }
                    found = true;
                    break;
                }
            }
        }
        if (!found) {
            try {
                int fsize = (int)size.floatValue();
                fontState = new FontState(fontState.getFontInfo(), "any",
                                          style, weight, fsize * 1000, 0);
            } catch (org.apache.fop.apps.FOPException fope) {
                fope.printStackTrace();
            }
        } else {
            if(g2d instanceof PDFGraphics2D) {
                ((PDFGraphics2D)g2d).setOverrideFontState(fontState);
            }
        }
        int fStyle = Font.PLAIN;
        if (fontState.getFontWeight().equals("bold")) {
            if (fontState.getFontStyle().equals("italic")) {
                fStyle = Font.BOLD | Font.ITALIC;
            } else {
                fStyle = Font.BOLD;
            }
        } else {
            if (fontState.getFontStyle().equals("italic")) {
                fStyle = Font.ITALIC;
            } else {
                fStyle = Font.PLAIN;
            }
        }
        Font font = new Font(fontState.getFontFamily(), fStyle,
                             (int)(fontState.getFontSize() / 1000));

        g2d.setFont(font);


        float advance = getStringWidth(txt);
        float tx = 0;
        if (anchor != null) {
            switch (anchor.getType()) {
            case TextNode.Anchor.ANCHOR_MIDDLE:
                tx = -advance / 2;
                break;
            case TextNode.Anchor.ANCHOR_END:
                tx = -advance;
            }
        }
        g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
    }

    public float getStringWidth(String str) {
        float wordWidth = 0;
        float whitespaceWidth = fontState.width(fontState.mapChar(' '));

        for (int i = 0; i < str.length(); i++) {
            float charWidth;
            char c = str.charAt(i);
            if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
                charWidth = fontState.width(fontState.mapChar(c));
                if (charWidth <= 0)
                    charWidth = whitespaceWidth;
            } else {
                charWidth = whitespaceWidth;
            }
            wordWidth += charWidth;
        }
        return wordWidth / 1000f;
    }

    /**
     * Initiates a text selection on a particular AttributedCharacterIterator,
     * using the text/font metrics employed by this TextPainter instance.
     * @param x the x coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param y the y coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param aci the AttributedCharacterIterator describing the text
     * @param context the GraphicsNodeRenderContext to use when doing text layout.
     * @return an instance of Mark which encapsulates the state necessary to
     * implement hit testing and text selection.
     */
    public Mark selectAt(double x, double y, AttributedCharacterIterator aci,
                         TextNode node, GraphicsNodeRenderContext context) {
        System.out.println("PDFText selectAt");
        return null;
    }

    /**
     * Continues a text selection on a particular AttributedCharacterIterator,
     * using the text/font metrics employed by this TextPainter instance.
     * @param x the x coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param y the y coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param aci the AttributedCharacterIterator describing the text
     * @param context the GraphicsNodeRenderContext to use when doing text layout.
     * @return an instance of Mark which encapsulates the state necessary to
     * implement hit testing and text selection.
     */
    public Mark selectTo(double x, double y, Mark beginMark,
                         AttributedCharacterIterator aci, TextNode node,
                         GraphicsNodeRenderContext context) {
        System.out.println("PDFText selectTo");
        return null;
    }

    /**
     * Select all of the text represented by an AttributedCharacterIterator,
     * using the text/font metrics employed by this TextPainter instance.
     * @param x the x coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param y the y coordinate, in the text layout's coordinate system,
     * of the selection event.
     * @param aci the AttributedCharacterIterator describing the text
     * @param context the GraphicsNodeRenderContext to use when doing text layout.
     * @return an instance of Mark which encapsulates the state necessary to
     * implement hit testing and text selection.
     */
    public Mark selectAll(double x, double y,
                          AttributedCharacterIterator aci, TextNode node,
                          GraphicsNodeRenderContext context) {
        System.out.println("PDFText selectAll");
        return null;
    }


    /**
     * Selects the first glyph in the text node.
     */
    public Mark selectFirst(double x, double y,
                            AttributedCharacterIterator aci, TextNode node,
                            GraphicsNodeRenderContext context) {
        System.out.println("PDFText selectFirst");
        return null;
    }


    /**
     * Selects the last glyph in the text node.
     */
    public Mark selectLast(double x, double y,
                           AttributedCharacterIterator aci, TextNode node,
                           GraphicsNodeRenderContext context) {
        System.out.println("PDFText selectLast");
        return null;
    }

    /*
     * Get an array of index pairs corresponding to the indices within an
     * AttributedCharacterIterator regions bounded by two Marks.
     * Note that the instances of Mark passed to this function
     * <em>must come</em>
     * from the same TextPainter that generated them via selectAt() and
     * selectTo(), since the TextPainter implementation may rely on hidden
     * implementation details of its own Mark implementation.
     */
    public int[] getSelected(AttributedCharacterIterator aci, Mark start,
                             Mark finish) {
        System.out.println("PDFText getSelected");
        return null;
    }


    /*
     * Get a Shape in userspace coords which encloses the textnode
     * glyphs bounded by two Marks.
     * Note that the instances of Mark passed to this function
     * <em>must come</em>
     * from the same TextPainter that generated them via selectAt() and
     * selectTo(), since the TextPainter implementation may rely on hidden
     * implementation details of its own Mark implementation.
     */
    public Shape getHighlightShape(Mark beginMark, Mark endMark) {
        System.out.println("PDFText getHighlightShape");
        return null;
    }

    /*
     * Get a Shape in userspace coords which defines the textnode glyph outlines.
     * @param node the TextNode to measure
     * @param frc the font rendering context.
     * @param includeDecoration whether to include text decoration
     * outlines.
     * @param includeStroke whether to create the "stroke shape outlines"
     * instead of glyph outlines.
     */
    public Shape getShape(TextNode node, FontRenderContext frc) {
        System.out.println("PDFText getShape");
        return null;
    }

    /*
     * Get a Shape in userspace coords which defines the textnode glyph outlines.
     * @param node the TextNode to measure
     * @param frc the font rendering context.
     * @param includeDecoration whether to include text decoration
     * outlines.
     * @param includeStroke whether to create the "stroke shape outlines"
     * instead of glyph outlines.
     */
    public Shape getDecoratedShape(TextNode node, FontRenderContext frc) {
        System.out.println("PDFText getDecoratedShape");
        return new Rectangle(1, 1);
    }

    /*
     * Get a Rectangle2D in userspace coords which encloses the textnode
     * glyphs composed from an AttributedCharacterIterator.
     * @param node the TextNode to measure
     * @param g2d the Graphics2D to use
     * @param context rendering context.
     */
    public Rectangle2D getBounds(TextNode node, FontRenderContext frc) {
        System.out.println("PDFText getBounds");
        return null;
    }

    /*
     * Get a Rectangle2D in userspace coords which encloses the textnode
     * glyphs composed from an AttributedCharacterIterator, inclusive of
     * glyph decoration (underline, overline, strikethrough).
     * @param node the TextNode to measure
     * @param g2d the Graphics2D to use
     * @param context rendering context.
     */
    public Rectangle2D getDecoratedBounds(TextNode node,
                                          FontRenderContext frc) {
        System.out.println("PDFText getDecoratedBounds");
        return null;
    }

    /*
     * Get a Rectangle2D in userspace coords which encloses the
     * textnode glyphs (as-painted, inclusive of decoration and stroke, but
     * exclusive of filters, etc.) composed from an AttributedCharacterIterator.
     * @param node the TextNode to measure
     * @param g2d the Graphics2D to use
     * @param context rendering context.
     */
    public Rectangle2D getPaintedBounds(TextNode node,
                                        FontRenderContext frc) {
        // System.out.println("PDFText getPaintedBounds");
        return null;
    }

}