2009-01-17 Felix Zielcke <fzielcke@z-51.de>

* Makefile.in: Change font compilation to use new grub-mkfont instead
	of java version.

	* util/fonttool/src/org/gnu/grub/fonttool/BDFLoader.java: Remove.
	* util/fonttool/src/org/gnu/grub/fonttool/CharDefs.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/CharacterRange.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/CharacterRange.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/Converter.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/Font.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/Glyph.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/PFF2Sections.java: Likewise.
	* util/fonttool/src/org/gnu/grub/fonttool/PFF2Writer.java: Likewise.
This commit is contained in:
fzielcke 2009-01-17 09:38:38 +00:00
parent 7086085ba3
commit 4fa809981f
11 changed files with 23 additions and 1155 deletions

View File

@ -1,3 +1,18 @@
2009-01-17 Felix Zielcke <fzielcke@z-51.de>
* Makefile.in: Change font compilation to use new grub-mkfont instead
of java version.
* util/fonttool/src/org/gnu/grub/fonttool/BDFLoader.java: Remove.
* util/fonttool/src/org/gnu/grub/fonttool/CharDefs.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/CharacterRange.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/CharacterRange.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/Converter.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/Font.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/Glyph.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/PFF2Sections.java: Likewise.
* util/fonttool/src/org/gnu/grub/fonttool/PFF2Writer.java: Likewise.
2009-01-16 Christian Franke <franke@computer.org>
* disk/ata.c (enum grub_ata_commands): Remove EXEC_DEV_DIAGNOSTICS.

View File

@ -153,24 +153,21 @@ partmap.lst: $(PARTMAPFILES)
ifeq (, $(UNIFONT_BDF))
else
ifeq ($(enable_grub_mkfont),yes)
pkgdata_DATA += unicode.pf2 ascii.pf2
# Arrows and lines are needed to draw the menu, so we always include them
UNICODE_ARROWS=0x2190-0x2193
UNICODE_LINES=0x2501-0x251B
# Note: fonttool should be replaced with C only implementation
unicode.pf2: $(UNIFONT_BDF) grub-mkfont
$(builddir)/grub-mkfont -o $@ $(UNIFONT_BDF)
$(builddir)/fonttool/fonttool.jar:
mkdir -p "$(builddir)/fonttool/src"
javac -source 1.5 -target 1.5 -g -deprecation -encoding UTF-8 -d "$(builddir)/fonttool/src" `find "$(srcdir)/util/fonttool/src/" -name '*.java'`
jar cf $(builddir)/fonttool/fonttool.jar -C $(builddir)/fonttool/src .
unicode.pf2: $(UNIFONT_BDF) $(builddir)/fonttool/fonttool.jar
java -cp $(builddir)/fonttool/fonttool.jar org.gnu.grub.fonttool.Converter --in=$(UNIFONT_BDF) --out=$@
ascii.pf2: $(UNIFONT_BDF) $(builddir)/fonttool/fonttool.jar
java -cp $(builddir)/fonttool/fonttool.jar org.gnu.grub.fonttool.Converter --in=$(UNIFONT_BDF) --out=$@ 0x0-0x7f $(UNICODE_ARROWS) $(UNICODE_LINES)
ascii.pf2: $(UNIFONT_BDF) grub-mkfont
$(builddir)/grub-mkfont -o $@ $(UNIFONT_BDF) -r 0x0-0x7f,$(UNICODE_ARROWS),$(UNICODE_LINES)
endif
endif
# Used for building modules externally

View File

@ -1,271 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
import java.io.*;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BDFLoader {
private final BufferedReader in;
private final Font font;
private int maxCharWidth;
private int maxCharHeight;
BDFLoader(BufferedReader in) {
this.in = in;
this.font = new Font();
this.maxCharWidth = 0;
this.maxCharHeight = 0;
}
public static boolean isBDFFile(String filename) {
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(filename));
final String signature = "STARTFONT ";
byte[] b = new byte[signature.length()];
in.readFully(b);
in.close();
String s = new String(b, "US-ASCII");
return signature.equals(s);
} catch (IOException e) {
if (in != null) {
try {
in.close();
} catch (IOException e1) {
// Ignore.
}
}
return false;
}
}
public static Font loadFontResource(String resourceName) throws IOException {
InputStream in = BDFLoader.class.getClassLoader().getResourceAsStream(resourceName);
if (in == null)
throw new FileNotFoundException("Font resource " + resourceName + " not found");
return loadFontFromStream(in);
}
public static Font loadFontFile(String filename) throws IOException {
InputStream in = new FileInputStream(filename);
return loadFontFromStream(in);
}
private static Font loadFontFromStream(InputStream inStream) throws IOException {
BufferedReader in;
try {
in = new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Encoding not supported: " + e.getMessage(), e);
}
return new BDFLoader(in).loadFont();
}
private Font loadFont() throws IOException {
loadFontInfo();
while (loadChar()) {
/* Loop. */
}
font.setMaxCharWidth(maxCharWidth);
font.setMaxCharHeight(maxCharHeight);
return font;
}
private void loadFontInfo() throws IOException {
final Pattern stringSettingPattern = Pattern.compile("^(\\w+)\\s+\"([^\"]+)\"$");
String line;
// Load the global font information that appears before CHARS.
final int UNSET = Integer.MIN_VALUE;
font.setAscent(UNSET);
font.setDescent(UNSET);
font.setFamily("Unknown");
font.setBold(false);
font.setItalic(false);
font.setPointSize(Font.UNKNOWN_POINT_SIZE);
do {
line = in.readLine();
if (line == null)
throw new IOException("BDF format error: end of file while " +
"reading global font information");
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
String name = st.nextToken();
if (name.equals("FONT_ASCENT")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: " +
"no tokens after " + name);
font.setAscent(Integer.parseInt(st.nextToken()));
} else if (name.equals("FONT_DESCENT")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: " +
"no tokens after " + name);
font.setDescent(Integer.parseInt(st.nextToken()));
} else if (name.equals("POINT_SIZE")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: " +
"no tokens after " + name);
// Divide by 10, since it is stored X10.
font.setPointSize(Integer.parseInt(st.nextToken()) / 10);
} else if (name.equals("FAMILY_NAME")) {
Matcher matcher = stringSettingPattern.matcher(line);
if (!matcher.matches())
throw new IOException("BDF format error: " +
"line doesn't match string " +
"setting pattern: " + line);
font.setFamily(matcher.group(2));
} else if (name.equals("WEIGHT_NAME")) {
Matcher matcher = stringSettingPattern.matcher(line);
if (!matcher.matches())
throw new IOException("BDF format error: " +
"line doesn't match string " +
"setting pattern: " + line);
String weightName = matcher.group(2);
font.setBold("bold".equalsIgnoreCase(weightName));
} else if (name.equals("SLANT")) {
Matcher matcher = stringSettingPattern.matcher(line);
if (!matcher.matches())
throw new IOException("BDF format error: " +
"line doesn't match string " +
"setting pattern: " + line);
String slantType = matcher.group(2);
font.setItalic(!"R".equalsIgnoreCase(slantType));
} else if (name.equals("CHARS")) {
// This is the end of the global font information and
// the beginning of the character definitions.
break;
} else {
// Skip other fields.
}
}
} while (true);
if (font.getAscent() == UNSET)
throw new IOException("BDF format error: no FONT_ASCENT property");
if (font.getDescent() == UNSET)
throw new IOException("BDF format error: no FONT_DESCENT property");
}
private boolean loadChar() throws IOException {
String line;
// Find start of character
do {
line = in.readLine();
if (line == null)
return false;
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens() && st.nextToken().equals("STARTCHAR")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: no character name after STARTCHAR");
break;
}
} while (true);
// Find properties
final int UNSET = Integer.MIN_VALUE;
int codePoint = UNSET;
int bbx = UNSET;
int bby = UNSET;
int bbox = UNSET;
int bboy = UNSET;
int dwidth = UNSET;
do {
line = in.readLine();
if (line == null)
return false;
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
String field = st.nextToken();
if (field.equals("ENCODING")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: no encoding # after ENCODING");
String codePointStr = st.nextToken();
codePoint = Integer.parseInt(codePointStr);
} else if (field.equals("BBX")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: no tokens after BBX");
bbx = Integer.parseInt(st.nextToken());
bby = Integer.parseInt(st.nextToken());
bbox = Integer.parseInt(st.nextToken());
bboy = Integer.parseInt(st.nextToken());
} else if (field.equals("DWIDTH")) {
if (!st.hasMoreTokens())
throw new IOException("BDF format error: no tokens after DWIDTH");
dwidth = Integer.parseInt(st.nextToken());
int dwidthY = Integer.parseInt(st.nextToken());
// The DWIDTH Y value should be zero for any normal font.
if (dwidthY != 0) {
throw new IOException("BDF format error: dwidth Y value" +
"is nonzero (" + dwidthY + ") " +
"for char " + codePoint + ".");
}
} else if (field.equals("BITMAP")) {
break; // now read the bitmap
}
}
} while (true);
if (codePoint == UNSET)
throw new IOException("BDF format error: " +
"no code point set");
if (bbx == UNSET || bby == UNSET)
throw new IOException("BDF format error: " +
"bbx/bby missing: " + bbx + ", " + bby +
" for char " + codePoint);
if (bbox == UNSET || bboy == UNSET)
throw new IOException("BDF format error: " +
"bbox/bboy missing: " + bbox + ", " + bboy +
" for char " + codePoint);
if (dwidth == UNSET)
throw new IOException("BDF format error: " +
"dwidth missing for char " + codePoint);
final int glyphWidth = bbx;
final int glyphHeight = bby;
if (glyphWidth > maxCharWidth)
maxCharWidth = glyphWidth;
if (glyphHeight > maxCharHeight)
maxCharHeight = glyphHeight;
// Read the bitmap
Glyph glyph = new Glyph(codePoint, glyphWidth, glyphHeight, bbox, bboy, dwidth);
for (int y = 0; y < glyphHeight; y++) {
line = in.readLine();
if (line == null)
return false;
for (int b = 0; b < line.length(); b++) {
int v = Integer.parseInt(Character.toString(line.charAt(b)), 16);
for (int x = b * 4, i = 0; i < 4 && x < glyphWidth; x++, i++) {
boolean set = (v & 0x8) != 0;
v <<= 1;
glyph.setPixel(x, y, set);
}
}
}
font.putGlyph(codePoint, glyph);
return true;
}
}

View File

@ -1,181 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
class CharDefs {
private boolean debug = "1".equals(System.getProperty("fonttool.debug"));
private TreeMap<Integer, Glyph> glyphs;
private ByteArrayOutputStream charDefsData;
private int maxCharWidth;
private int maxCharHeight;
private HashMap<Integer, CharStorageInfo> charIndex;
public CharDefs(Font font) {
this.glyphs = font.getGlyphs();
this.charIndex = null;
this.charDefsData = null;
calculateMaxSizes();
}
private void calculateMaxSizes() {
maxCharWidth = 0;
maxCharHeight = 0;
for (Glyph glyph : glyphs.values()) {
final int w = glyph.getWidth();
final int h = glyph.getHeight();
if (w > maxCharWidth)
maxCharWidth = w;
if (h > maxCharHeight)
maxCharHeight = h;
}
}
void buildDefinitions(List<CharacterRange> rangeList) {
charIndex = new HashMap<Integer, CharStorageInfo>();
HashMap<CharDef, Long> charDefIndex = new HashMap<CharDef, Long>();
charDefsData = new ByteArrayOutputStream();
DataOutputStream charDefs = new DataOutputStream(charDefsData);
try {
// Loop through all the glyphs, writing the glyph data to the
// in-memory byte stream, collapsing duplicate glyphs, and
// constructing index information.
for (Glyph glyph : glyphs.values()) {
// Determine if glyph should be included in written file
if (rangeList.size() > 0) {
boolean skip = true;
for (Iterator<CharacterRange> iter = rangeList.iterator(); iter
.hasNext();) {
CharacterRange item = iter.next();
if (item.isWithinRange(glyph.getCodePoint())) {
skip = false;
break;
}
}
if (skip) {
continue;
}
}
CharDef charDef = new CharDef(glyph.getWidth(),
glyph.getHeight(),
glyph.getBitmap());
if (charDefIndex.containsKey(charDef)) {
// Use already-written glyph.
if (debug)
System.out.printf("Duplicate glyph for character U+%04X%n",
glyph.getCodePoint());
final int charOffset = charDefIndex.get(charDef).intValue();
final CharStorageInfo info =
new CharStorageInfo(glyph.getCodePoint(), charOffset);
charIndex.put(glyph.getCodePoint(), info);
} else {
// Write glyph data.
final int charOffset = charDefs.size();
final CharStorageInfo info =
new CharStorageInfo(glyph.getCodePoint(), charOffset);
charIndex.put(glyph.getCodePoint(), info);
charDefIndex.put(charDef, (long) charOffset);
charDefs.writeShort(glyph.getWidth());
charDefs.writeShort(glyph.getHeight());
charDefs.writeShort(glyph.getBbox());
charDefs.writeShort(glyph.getBboy());
charDefs.writeShort(glyph.getDeviceWidth());
charDefs.write(glyph.getBitmap());
}
}
} catch (IOException e) {
throw new RuntimeException("Error writing to in-memory byte stream", e);
}
}
public int getMaxCharWidth() {
return maxCharWidth;
}
public int getMaxCharHeight() {
return maxCharHeight;
}
public HashMap<Integer, CharStorageInfo> getCharIndex() {
if (charIndex == null) throw new IllegalStateException();
return charIndex;
}
public byte[] getDefinitionData() {
if (charDefsData == null) throw new IllegalStateException();
return charDefsData.toByteArray();
}
private static class CharDef {
private final int width;
private final int height;
private final byte[] data;
public CharDef(int width, int height, byte[] data) {
this.width = width;
this.height = height;
this.data = data;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CharDef charDef = (CharDef) o;
if (height != charDef.height) return false;
if (width != charDef.width) return false;
if (!Arrays.equals(data, charDef.data)) return false;
return true;
}
public int hashCode() {
int result;
result = width;
result = 31 * result + height;
result = 31 * result + Arrays.hashCode(data);
return result;
}
}
public int getIndexSize() {
if (charIndex == null)
return 0;
return charIndex.size();
}
}

View File

@ -1,36 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
class CharStorageInfo {
private final int codePoint;
private final int fileOffset;
public CharStorageInfo(int codePoint, int fileOffset) {
this.codePoint = codePoint;
this.fileOffset = fileOffset;
}
public int getCodePoint() {
return codePoint;
}
public int getFileOffset() {
return fileOffset;
}
}

View File

@ -1,75 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
/**
* @author chaac
*
*/
public class CharacterRange {
private int start;
private int end;
public CharacterRange(int start, int end) {
this.start = start;
this.end = end;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
protected boolean isCombinable(CharacterRange range) {
if (getStart() <= range.getStart() && range.getStart() <= getEnd())
return true;
if (range.getStart() <= getStart() && getStart() <= range.getEnd())
return true;
return false;
}
public boolean isWithinRange(int value) {
if (value >= start && value <= end)
return true;
return false;
}
public boolean combine(CharacterRange range) {
int start;
int end;
if (! isCombinable(range))
return false;
start = getStart();
if (range.getStart() < start)
start = range.getStart();
end = getEnd();
if (range.getEnd() > end)
end = range.getEnd();
return true;
}
}

View File

@ -1,168 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Program to convert BDF fonts into PFF2 fonts for use with GRUB.
*/
public class Converter {
public static void main(String[] args) {
if (args.length < 1) {
printUsageAndExit();
}
String in = null;
String out = null;
List <CharacterRange> rangeList = new ArrayList<CharacterRange>();
try {
for (String arg : args) {
if (arg.startsWith("--")) {
String option;
String value;
int equalsPos = arg.indexOf('=');
if (equalsPos < 0) {
option = arg.substring(2);
value = null;
} else {
option = arg.substring(2, equalsPos);
value = arg.substring(equalsPos + 1);
}
if ("in".equals(option)) {
if (value == null)
throw new CommandLineException(option
+ " option requires a value.");
in = value;
} else if ("out".equals(option)) {
if (value == null)
throw new CommandLineException(option
+ " option requires a value.");
out = value;
}
} else if (arg.startsWith("0x")) {
// Range specifier
String strRange[] = arg.split("-");
if (strRange.length > 0) {
boolean validRange = true;
int start;
int end;
if (strRange.length > 2) {
validRange = false;
} else if (strRange.length == 2
&& !strRange[1].startsWith("0x")) {
validRange = false;
} else
{
try {
start = Integer.parseInt(strRange[0]
.substring(2), 16);
end = start;
if (strRange.length == 2) {
end = Integer.parseInt(strRange[1]
.substring(2), 16);
}
CharacterRange range = new CharacterRange(
start, end);
boolean add = true;
// First, try to combine range to existing ranges
for (Iterator<CharacterRange> iter = rangeList.iterator(); iter.hasNext(); )
{
CharacterRange item = iter.next();
if (range.equals(item))
{
add = false;
continue;
}
if (item.combine(range))
{
// Start from beginning of list using combined range
range = item;
iter = rangeList.iterator();
add = false;
}
}
// If range could not be combined or no matching range, add it to the list
if (add)
{
rangeList.add(range);
}
} catch (NumberFormatException e) {
validRange = false;
}
}
if (!validRange) {
throw new CommandLineException("Invalid range `"
+ arg + "'.");
}
}
} else {
throw new CommandLineException("Non-option argument `" + arg + "'.");
}
}
if (in == null || out == null) {
throw new CommandLineException("Both --in=X and --out=Y must be specified.");
}
} catch (CommandLineException e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
try {
// Read BDF.
Font font = BDFLoader.loadFontFile(in);
// Write PFF2.
new PFF2Writer(out).writeFont(font, rangeList);
} catch (IOException e) {
System.err.println("I/O error converting font: " + e);
e.printStackTrace();
System.exit(1);
}
}
private static class CommandLineException extends Exception {
public CommandLineException(String message) {
super(message);
}
}
private static void printUsageAndExit() {
System.err.println("GNU GRUB Font Conversion Tool");
System.err.println();
System.err.println("Usage: Converter --in=IN.bdf --out=OUT.pf2");
System.err.println();
System.exit(1);
}
}

View File

@ -1,123 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
import java.util.TreeMap;
public class Font {
public static final int UNKNOWN_POINT_SIZE = -1;
private TreeMap<Integer, Glyph> glyphs;
private String family;
private boolean bold;
private boolean italic;
private int pointSize;
private int maxCharWidth;
private int maxCharHeight;
private int ascent;
private int descent;
public Font() {
glyphs = new TreeMap<Integer, Glyph>();
}
public String getFamily() {
return family;
}
public void setFamily(String family) {
this.family = family;
}
public boolean isBold() {
return bold;
}
public void setBold(boolean bold) {
this.bold = bold;
}
public boolean isItalic() {
return italic;
}
public void setItalic(boolean italic) {
this.italic = italic;
}
public int getPointSize() {
return pointSize;
}
public void setPointSize(int pointSize) {
this.pointSize = pointSize;
}
public int getMaxCharWidth() {
return maxCharWidth;
}
public void setMaxCharWidth(int maxCharWidth) {
this.maxCharWidth = maxCharWidth;
}
public int getMaxCharHeight() {
return maxCharHeight;
}
public void setMaxCharHeight(int maxCharHeight) {
this.maxCharHeight = maxCharHeight;
}
public int getAscent() {
return ascent;
}
public void setAscent(int ascent) {
this.ascent = ascent;
}
public int getDescent() {
return descent;
}
public void setDescent(int descent) {
this.descent = descent;
}
public void putGlyph(int codePoint, Glyph glyph) {
glyphs.put(codePoint, glyph);
}
public TreeMap<Integer, Glyph> getGlyphs() {
return glyphs;
}
public Glyph getGlyph(int codePoint) {
return glyphs.get(codePoint);
}
public String getStandardName() {
StringBuilder name = new StringBuilder(getFamily());
if (isBold()) name.append(" Bold");
if (isItalic()) name.append(" Italic");
name.append(' ');
name.append(getPointSize());
return name.toString();
}
}

View File

@ -1,100 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
public class Glyph {
private final int codePoint;
private final int width;
private final int height;
// These define the amounts to shift the character bitmap by
// before drawing it. See
// http://www.adobe.com/devnet/font/pdfs/5005.BDF_Spec.pdf
// and
// http://www.linuxbabble.com/documentation/x/bdf/
// for explanatory figures.
private final int bbox;
private final int bboy;
// Number of pixels to advance horizontally from this character's origin
// to the origin of the next character.
private final int deviceWidth;
// Row-major order, no padding. Rows can break within a byte.
// MSb is first (leftmost/uppermost) pixel.
private final byte[] bitmap;
public Glyph(int codePoint, int width, int height, int bbox, int bboy, int deviceWidth) {
this(codePoint, width, height, bbox, bboy, deviceWidth,
new byte[(width * height + 7) / 8]);
}
public Glyph(int codePoint, int width, int height,
int bbox, int bboy, int deviceWidth,
byte[] bitmap) {
this.codePoint = codePoint;
this.width = width;
this.height = height;
this.bboy = bboy;
this.bbox = bbox;
this.deviceWidth = deviceWidth;
this.bitmap = bitmap;
}
public void setPixel(int x, int y, boolean value) {
if (x < 0 || y < 0 || x >= width || y >= height)
throw new IllegalArgumentException(
"Invalid pixel location (" + x + ", " + y + ") for "
+ width + "x" + height + " glyph");
int bitIndex = y * width + x;
int byteIndex = bitIndex / 8;
int bitPos = bitIndex % 8;
int v = value ? 0x80 >>> bitPos : 0;
int mask = ~(0x80 >>> bitPos);
bitmap[byteIndex] = (byte) ((bitmap[byteIndex] & mask) | v);
}
public int getCodePoint() {
return codePoint;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getBbox() {
return bbox;
}
public int getBboy() {
return bboy;
}
public int getDeviceWidth() {
return deviceWidth;
}
public byte[] getBitmap() {
return bitmap;
}
}

View File

@ -1,36 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
/**
* Section name constants for the PFF2 file format.
*/
public class PFF2Sections {
static final String FILE = "FILE";
static final String FONT_NAME = "NAME";
static final String FONT_FAMILY = "FAMI";
static final String FONT_WEIGHT = "WEIG";
static final String FONT_SLANT = "SLAN";
static final String FONT_POINT_SIZE = "PTSZ";
static final String MAX_CHAR_WIDTH = "MAXW";
static final String MAX_CHAR_HEIGHT = "MAXH";
static final String FONT_ASCENT = "ASCE";
static final String FONT_DESCENT = "DESC";
static final String CHAR_INDEX = "CHIX";
static final String REMAINDER_IS_DATA = "DATA";
}

View File

@ -1,154 +0,0 @@
/**
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gnu.grub.fonttool;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;
// TODO Add DEFLATE compressed blocks of characters.
public class PFF2Writer {
private RandomAccessFile f;
private String currentSection;
private long currentSectionStart;
public PFF2Writer(String filename) throws FileNotFoundException {
this.f = new RandomAccessFile(filename, "rw");
this.currentSection = null;
this.currentSectionStart = -1;
}
public void writeFont(Font font, List<CharacterRange> rangeList) throws IOException {
// Clear existing file.
f.setLength(0);
// Write file type ID header.
writeSection(PFF2Sections.FILE, "PFF2");
writeSection(PFF2Sections.FONT_NAME, font.getStandardName());
writeSection(PFF2Sections.FONT_FAMILY, font.getFamily());
writeSection(PFF2Sections.FONT_WEIGHT, font.isBold() ? "bold" : "normal");
writeSection(PFF2Sections.FONT_SLANT, font.isItalic() ? "italic" : "normal");
if (font.getPointSize() != Font.UNKNOWN_POINT_SIZE)
writeShortSection(PFF2Sections.FONT_POINT_SIZE, font.getPointSize());
// Construct character definitions.
CharDefs charDefs = new CharDefs(font);
charDefs.buildDefinitions(rangeList);
// Write max character width and height metrics.
writeShortSection(PFF2Sections.MAX_CHAR_WIDTH, charDefs.getMaxCharWidth());
writeShortSection(PFF2Sections.MAX_CHAR_HEIGHT, charDefs.getMaxCharHeight());
writeShortSection(PFF2Sections.FONT_ASCENT, font.getAscent());
writeShortSection(PFF2Sections.FONT_DESCENT, font.getDescent());
// Write character index with pointers to the character definitions.
beginSection(PFF2Sections.CHAR_INDEX);
// Determine the size of the index, so we can properly refer to the
// character definition offset in the index. The actual number of
// bytes written is compared to the calculated value to ensure we
// are correct.
final int indexStart = (int) f.getFilePointer();
final int calculatedIndexLength =
charDefs.getIndexSize() * (4 + 1 + 4);
final int charDefStart = indexStart + calculatedIndexLength + 8;
for (CharStorageInfo storageInfo : charDefs.getCharIndex().values()) {
f.writeInt(storageInfo.getCodePoint());
f.writeByte(0); // Storage flags: bits 1..0 = 00b : uncompressed.
f.writeInt(charDefStart + storageInfo.getFileOffset());
}
final int indexEnd = (int) f.getFilePointer();
if (indexEnd - indexStart != calculatedIndexLength) {
throw new RuntimeException("Incorrect index length calculated, calc="
+ calculatedIndexLength
+ " actual=" + (indexEnd - indexStart));
}
endSection(PFF2Sections.CHAR_INDEX);
f.writeBytes(PFF2Sections.REMAINDER_IS_DATA);
f.writeInt(-1); // Data takes up the rest of the file.
f.write(charDefs.getDefinitionData());
f.close();
}
private void beginSection(String sectionName) throws IOException {
verifyOkToBeginSection(sectionName);
f.writeBytes(sectionName);
f.writeInt(-1); // Placeholder for the section length.
currentSection = sectionName;
currentSectionStart = f.getFilePointer();
}
private void endSection(String sectionName) throws IOException {
verifyOkToEndSection(sectionName);
long sectionEnd = f.getFilePointer();
long sectionLength = sectionEnd - currentSectionStart;
f.seek(currentSectionStart - 4);
f.writeInt((int) sectionLength);
f.seek(sectionEnd);
currentSection = null;
currentSectionStart = -1;
}
private void verifyOkToBeginSection(String sectionName) {
if (sectionName.length() != 4)
throw new IllegalArgumentException(
"Section names must be 4 characters: `" + sectionName + "'.");
if (currentSection != null)
throw new IllegalStateException(
"Attempt to start `" + sectionName
+ "' section before ending the previous section `"
+ currentSection + "'.");
}
private void verifyOkToEndSection(String sectionName) {
if (sectionName.length() != 4)
throw new IllegalStateException("Invalid section name '" + sectionName
+ "'; must be 4 characters.");
if (currentSection == null)
throw new IllegalStateException(
"Attempt to end section `" + sectionName
+ "' when no section active.");
if (!sectionName.equals(currentSection))
throw new IllegalStateException(
"Attempt to end `" + sectionName
+ "' section during active section `"
+ currentSection + "'.");
}
private void writeSection(String sectionName, String contents) throws IOException {
verifyOkToBeginSection(sectionName);
f.writeBytes(sectionName);
f.writeInt(contents.length());
f.writeBytes(contents);
}
private void writeShortSection(String sectionName, int value) throws IOException {
verifyOkToBeginSection(sectionName);
f.writeBytes(sectionName);
f.writeInt(2);
f.writeShort(value);
}
}