/*
* $Id$
*
* JNode.org
* Copyright (C) 2003-2006 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.awt.font.bdf;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import org.jnode.awt.font.TextRenderer;
import org.jnode.driver.video.Surface;
import org.jnode.font.bdf.BDFFontContainer;
import org.jnode.font.bdf.BDFGlyph;
import org.jnode.font.bdf.BDFParser;
/**
* @author Stephane Meslin-Weber
* @author Fabien DUMINY (fduminy@jnode.org)
* @author Levente S\u00e1ntha
*/
public class BDFTextRenderer implements TextRenderer {
private BDFFontContainer bdfFont;
/**
* Create a new instance
*
* @param bdfFont the font used for rendering
*/
public BDFTextRenderer(BDFFontContainer bdfFont) {
this.bdfFont = bdfFont;
}
/**
* Strings are drawn using .pjaf font files read in <code>PJAFontData</code>
* objects by <code>PJAGraphicsManager</code>.
* <p/>
* NOTE: This method derived from PJA rendering code.
*
* @param surface the rendering surface
* @param clip clipping shape
* @param tx transformation
* @param str the string to render
* @param x location x
* @param y location y
* @param color string color
* @see java.awt.Graphics
*/
public final void render(Surface surface, Shape clip, AffineTransform tx, CharSequence str,
final int x, final int y, Color color) {
if (str == null || str.length() == 0)
return;
int charsCount = str.length();
if ((bdfFont != null) && (charsCount > 0)) {
int offset = 0;
final int bdfFontDepth = bdfFont.getDepth();
float f_max = (1 << bdfFontDepth) - 1;
if (f_max == 0) f_max = 1;
BDFParser.Rectangle glyph_box = new BDFParser.Rectangle();
final Point2D src = new Point2D.Double();
final Point2D dst = new Point2D.Double();
int x_min = Integer.MAX_VALUE;
int y_min = Integer.MAX_VALUE;
int x_max = Integer.MIN_VALUE;
int y_max = Integer.MIN_VALUE;
for (int i = 0; i < charsCount; i++) {
BDFGlyph glyph = bdfFont.getGlyph(str.charAt(i));
if (glyph == null) {
continue;
}
glyph_box = glyph.getBbx(glyph_box);
final int fHeight = glyph_box.height;
final int[] fData = glyph.getData();
final int scan = fData.length / fHeight;
int fg_r = color.getRed();
int fg_g = color.getGreen();
int fg_b = color.getBlue();
//box location
final int bx = x + offset + glyph_box.x;
final int by = y - fHeight - glyph_box.y;
for (int k = 0; k < fHeight; k++) {
final int offsetLine = k * scan;
for (int j = 0; j < scan; j++) {
int fPixel = fData[offsetLine + j];
if (fPixel != 0) {
//pixel location
int px = bx + j;
int py = by + k;
if (tx != null) {
src.setLocation(px, py);
tx.transform(src, dst);
px = (int) dst.getX();
py = (int) dst.getY();
}
//clip
if (clip == null || clip.contains(px, py)) {
//compute color
int bg_color = surface.getRGBPixel(px, py);
int bg_r = (bg_color & 0x00FF0000) >> 16;
int bg_g = (bg_color & 0x0000FF00) >> 8;
int bg_b = (bg_color & 0x000000FF);
//todo improve this pixel composition
float alpha = fPixel / f_max;
int r = bg_r + ((int) ((fg_r - bg_r) * alpha)) & 0xFF;
int g = bg_g + ((int) ((fg_g - bg_g) * alpha)) & 0xFF;
int b = bg_b + ((int) ((fg_b - bg_b) * alpha)) & 0xFF;
fPixel = (((r << 16) + (g << 8) + b) | 0xFF000000);
surface.setRGBPixel(px, py, fPixel);
if (x_min > px) x_min = px;
if (y_min > py) y_min = py;
if (x_max < px) x_max = px;
if (y_max < py) y_max = py;
}
}
}
}
offset += glyph.getDWidth().width;
}
if (x_min < Integer.MAX_VALUE && y_min < Integer.MAX_VALUE &&
x_max > Integer.MIN_VALUE && y_max > Integer.MIN_VALUE)
surface.update(x_min, y_min, x_max - x_min + 1, y_max - y_min + 1);
}
}
}