1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17/**
18 * @author Ilya S. Okomin
19 * @version $Revision$
20 */
21package org.apache.harmony.awt.gl.render;
22
23import java.awt.*;
24import java.awt.image.*;
25
26
27import java.awt.font.GlyphMetrics;
28import java.awt.font.GlyphVector;
29import java.awt.geom.AffineTransform;
30import java.awt.geom.Point2D;
31
32import org.apache.harmony.awt.gl.TextRenderer;
33import org.apache.harmony.awt.gl.font.CommonGlyphVector;
34import org.apache.harmony.awt.gl.font.FontPeerImpl;
35import org.apache.harmony.awt.gl.font.Glyph;
36import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
37
38public class JavaTextRenderer extends TextRenderer {
39
40    public static final JavaTextRenderer inst = new JavaTextRenderer();
41
42    @Override
43    public void drawGlyphVector(Graphics2D g, GlyphVector glyphVector,
44            float x, float y) {
45
46        AffineTransform at = g.getTransform();
47        Rectangle c = g.getClipBounds();
48        if (at != null){
49            int atType = at.getType();
50            if (atType == AffineTransform.TYPE_TRANSLATION) {
51                c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
52            }
53        }
54
55        WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
56        ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
57
58        Rectangle rBounds = wr.getBounds();
59
60        Object color = cm.getDataElements(g.getColor().getRGB(), null);
61
62        drawClipGlyphVector(wr, color, glyphVector, (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
63        Math.max(c.x,rBounds.x),
64        Math.max(c.y,rBounds.y),
65        Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
66        Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
67
68    }
69
70    @SuppressWarnings("deprecation")
71    @Override
72    public void drawString(Graphics2D g, String str, float x, float y) {
73        AffineTransform at = g.getTransform();
74        Rectangle c = g.getClipBounds();
75        if (at != null){
76            int atType = at.getType();
77            if (atType == AffineTransform.TYPE_TRANSLATION) {
78                c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
79            }
80        }
81        WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
82        ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
83        Rectangle rBounds = wr.getBounds();
84
85        Object color = cm.getDataElements(g.getColor().getRGB(), null);
86
87        drawClipString(wr, color, str, (FontPeerImpl) (g.getFont().getPeer()),
88                (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
89                Math.max(c.x,rBounds.x),
90                Math.max(c.y,rBounds.y),
91                Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
92                Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
93
94    }
95
96    /**
97     *
98     * Draws string on specified raster at desired position.
99     *
100     * @param raster specified WritableRaster to draw at
101     * @param color color of the text
102     * @param glyphVector GlyphVector object to draw
103     * @param x start X position to draw
104     * @param y start Y position to draw
105     * @param cMinX minimum x of the raster area to draw
106     * @param cMinY minimum y of the raster area to draw
107     * @param cMaxX maximum x of the raster area to draw
108     * @param cMaxY maximum y of the raster area to draw
109     */
110    public void drawClipGlyphVector(WritableRaster raster, Object color,
111            GlyphVector glyphVector, int x, int y,
112            int cMinX, int cMinY, int cMaxX, int cMaxY) {
113        // TODO: implement complex clipping
114
115        int xSrcSurf, ySrcSurf; // Start point in String rectangle
116        int xDstSurf, yDstSurf; // Start point in Surface rectangle
117        int clWidth, clHeight;
118
119        for (int i = 0; i < glyphVector.getNumGlyphs(); i++) {
120            Glyph gl = ((CommonGlyphVector) glyphVector).vector[i];
121
122            if (gl.getPointWidth() == 0) {
123                continue;
124            }
125
126            byte[] data = gl.getBitmap();
127            if (data != null) {
128                Point2D pos = glyphVector.getGlyphPosition(i);
129
130                xSrcSurf = 0;//gl.bmp_left;
131                ySrcSurf = 0;//gl.bmp_rows - gl.bmp_top;
132
133                xDstSurf = x + (int)pos.getX() + (int) gl.getGlyphPointMetrics().getLSB();// + gl.bmp_left;
134                yDstSurf = y - gl.bmp_top/*getPointHeight()*/  + (int) pos.getY();// - (gl.bmp_rows-gl.bmp_top);
135
136                int textWidth = gl.bmp_width;
137                int textHeight = gl.getPointHeight();
138
139                // if Regions don't intersect
140                if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
141                        || (yDstSurf + textHeight < cMinY)) {
142                    // Nothing to do
143                } else {
144                    if (xDstSurf >= cMinX) {
145                        clWidth = Math.min(textWidth, cMaxX - xDstSurf);
146                    } else {
147                        xSrcSurf += cMinX - xDstSurf;
148                        clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
149                        xDstSurf = cMinX;
150                    }
151                    if (yDstSurf >= cMinY) {
152                        clHeight = Math.min(textHeight, cMaxY - yDstSurf);
153                    } else {
154                        ySrcSurf += cMinY - yDstSurf;
155                        clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
156                        yDstSurf = cMinY;
157                    }
158                    //     Drawing on the Raster
159                    for (int h=0; h<clHeight; h++){
160                        for (int w=0; w < clWidth ; w++) {
161                            byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
162                            boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
163                            if (emptyByte) {
164                                raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
165                            } else {
166                                // Nothing to do
167                            }
168                        }
169                    }
170                }
171            }
172        }
173    }
174
175    /**
176     * Draws string on specified raster at desired position.
177     *
178     * @param raster specified WritableRaster to draw at
179     * @param color color of the text
180     * @param str text to draw
181     * @param font font peer to use for drawing text
182     * @param x start X position to draw
183     * @param y start Y position to draw
184     * @param cMinX minimum x of the raster area to draw
185     * @param cMinY minimum y of the raster area to draw
186     * @param cMaxX maximum x of the raster area to draw
187     * @param cMaxY maximum y of the raster area to draw
188     */
189    public void drawClipString(WritableRaster raster, Object color, String str,
190            FontPeerImpl font, int x, int y, int cMinX, int cMinY, int cMaxX,
191            int cMaxY) {
192        // TODO: implement complex clipping
193
194        int xSrcSurf, ySrcSurf; // Start point in String rectangle
195        int xDstSurf, yDstSurf; // Start point in Surface rectangle
196        int clWidth, clHeight;
197
198        char[] chars = str.toCharArray();
199
200        int xBaseLine = x;
201        int yBaseLine = y;
202
203        for (char element : chars) {
204            Glyph gl = font.getGlyph(element);
205            GlyphMetrics pointMetrics = gl.getGlyphPointMetrics();
206            if (gl.getWidth() == 0) {
207                xBaseLine += pointMetrics.getAdvanceX();
208                continue;
209            }
210
211            byte[] data = gl.getBitmap();
212            if (data == null) {
213                xBaseLine += pointMetrics.getAdvanceX();
214            } else {
215
216                xSrcSurf = 0;
217                ySrcSurf = 0;
218
219                xDstSurf = Math.round(xBaseLine + gl.getGlyphPointMetrics().getLSB());
220                yDstSurf = yBaseLine - gl.bmp_top;
221
222                int textWidth = gl.bmp_width;
223                int textHeight = gl.getPointHeight();
224
225                // if Regions don't intersect
226                if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
227                        || (yDstSurf + textHeight < cMinY)) {
228                    // Nothing to do
229                } else {
230                    if (xDstSurf >= cMinX) {
231                        clWidth = Math.min(textWidth, cMaxX - xDstSurf);
232                    } else {
233                        xSrcSurf += cMinX - xDstSurf;
234                        clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
235                        xDstSurf = cMinX;
236                    }
237                    if (yDstSurf >= cMinY) {
238                        clHeight = Math.min(textHeight, cMaxY - yDstSurf);
239                    } else {
240                        ySrcSurf += cMinY - yDstSurf;
241                        clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
242                        yDstSurf = cMinY;
243                    }
244
245                    // Drawing on the Raster
246                    for (int h=0; h<clHeight; h++){
247                        for (int w=0; w < clWidth ; w++) {
248                            byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
249                            boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
250                            if (emptyByte) {
251                                raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
252                            } else {
253                                // Nothing to do
254                            }
255                        }
256                    }
257                }
258                xBaseLine += pointMetrics.getAdvanceX();
259            }
260        }
261    }
262
263}