+++ /dev/null
-/*
- * Copyright (c) 2009, Takeyuki Nagao
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the
- * following conditions are met:
- *
- * * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the
- * following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-package jp.sourceforge.dvibrowser.dvicore.font;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import jp.sourceforge.dvibrowser.dvicore.DviException;
-import jp.sourceforge.dvibrowser.dvicore.DviPoint;
-import jp.sourceforge.dvibrowser.dvicore.DviRect;
-import jp.sourceforge.dvibrowser.dvicore.DviResolution;
-import jp.sourceforge.dvibrowser.dvicore.api.BinaryDevice;
-import jp.sourceforge.dvibrowser.dvicore.render.AbstractDevice;
-
-
-// mutable.
-
-public final class RunLengthEncodedGlyph
-{
- private static final int DEFAULT_ARRAY_SIZE = 256;
-
- private int width;
- private int height;
- private int xOffset;
- private int yOffset;
- private ArrayList<RunLengthEncodedLine> lines;
-
- public RunLengthEncodedGlyph()
- {
- this(0, 0, 0, 0);
- }
-
- private RunLengthEncodedGlyph(int width, int height, int xOffset, int yOffset)
- {
- this.width = width;
- this.height = height;
- this.xOffset = xOffset;
- this.yOffset = yOffset;
- this.lines = new ArrayList<RunLengthEncodedLine>(DEFAULT_ARRAY_SIZE);
- }
-
- public static RunLengthEncodedGlyph readByteBinary(
- byte [] buf, int width, int height,
- int xOffset, int yOffset)
- {
- RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset);
-
- RunLengthEncodedLine prev = null;
- int pitch = ((width + 7) >>> 3) << 3;
- int bitOffset = 0;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = new RunLengthEncodedLine();
- line.append(buf, bitOffset, width);
- if (line.equals(prev)) {
- rlg.lines.add(prev);
- } else {
- rlg.lines.add(line);
- prev = line;
- }
- bitOffset += pitch;
- }
-
- rlg.compact();
-
- return rlg;
- }
-
- public static RunLengthEncodedGlyph readRasterByBits(
- byte [] buf, int width, int height,
- int xOffset, int yOffset)
- {
- RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset);
-
- int bitOffset = 0;
- RunLengthEncodedLine prev = null;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = new RunLengthEncodedLine();
- line.append(buf, bitOffset, width);
- bitOffset += width;
- if (line.equals(prev)) {
- rlg.lines.add(prev);
- } else {
- rlg.lines.add(line);
- prev = line;
- }
- }
- rlg.compact();
-
- return rlg;
- }
-
- public static RunLengthEncodedGlyph readByteGray(
- byte [] buf, int width, int height,
- int xOffset, int yOffset)
- {
- RunLengthEncodedGlyph rlg = new RunLengthEncodedGlyph(width, height, xOffset, yOffset);
-
- int ptr = 0;
- RunLengthEncodedLine prev = null;
- for (int i=0; i<height; i++) {
- final RunLengthEncodedLine line = new RunLengthEncodedLine();
-
- int last = 314; // A MAGIC value to denote the begin of line.
- int count = 0;
- for (int j=0; j<width; j++) {
- final int c = buf[ptr++];
- if (c == last) {
- count++;
- } else {
- if (last != 314)
- line.append(count, (0 != last));
- count = 1;
- last = c;
- }
- }
- if (count > 0)
- line.append(count, (0 != last));
-
- if (line.equals(prev)) {
- rlg.lines.add(prev);
- } else {
- rlg.lines.add(line);
- prev = line;
- }
- }
- rlg.compact();
-
- return rlg;
- }
-
-
- public DviRect getBounds()
- {
- return new DviRect(-xOffset, -yOffset, width, height);
- }
- public int width() { return width; }
- public int height() { return height; }
- public int xOffset() { return xOffset; }
- public int yOffset() { return yOffset; }
-
- public boolean isEmpty()
- {
- return (width <= 0 || height <= 0 || lines.size() == 0);
- }
-
- public void rasterizeTo(BinaryDevice out)
- throws DviException
- {
- out.save();
- try {
- out.translate(-xOffset, -yOffset);
- if (out.beginRaster(width, height)) {
- // TODO: use repeat.
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- out.beginLine();
- line.rasterizeTo(out);
- out.endLine(0);
- }
- }
- out.endRaster();
- } finally {
- out.restore();
- }
- }
-
- public void compact()
- {
- int lskip = Integer.MAX_VALUE;
- int rskip = Integer.MAX_VALUE;
-
- RunLengthEncodedLine prev = null;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- if (prev == line) continue;
- if (lskip > 0) {
- if (line.headOn()) {
- lskip = 0;
- } else {
- lskip = Math.min(lskip, line.head());
- }
- }
- }
-
- prev = null;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- if (prev == line) continue;
- line.cropHead(lskip);
- prev = line;
- }
- width -= lskip;
- xOffset -= lskip;
-
- if (width <= 0) {
- width = height = 0;
- lines.clear();
- xOffset = yOffset = 0;
- return;
- }
-
- prev = null;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- if (prev == line) continue;
- if (rskip > 0) {
- if (line.tailOn()) {
- rskip = 0;
- } else {
- rskip = Math.min(rskip, line.tail());
- }
- }
- prev = line;
- }
-
- prev = null;
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- if (prev == line) continue;
- line.cropTail(rskip);
- prev = line;
- }
- width -= rskip;
-
- if (width <= 0) {
- width = height = 0;
- lines.clear();
- xOffset = yOffset = 0;
- return;
- }
-
- int tskip = 0;
- int bskip = 0;
-
- while (height > 0) {
- RunLengthEncodedLine line = lines.get(0);
- if (!line.allOff())
- break;
- lines.remove(0);
- height--;
- yOffset--;
- tskip++;
- }
-
- while (height > 0) {
- RunLengthEncodedLine line = lines.get(height-1);
- if (!line.allOff())
- break;
- lines.remove(height-1);
- height--;
- bskip++;
- }
-
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- if (line.isEmpty()) {
- throw new IllegalStateException
- ("width=" + width + " height=" + height);
- }
- }
- if (width <= 0 || height <= 0) {
- throw new IllegalStateException
- ("width=" + width + " height=" + height);
- }
- }
-
- public String dump()
- {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- for (int i=0; i<height; i++) {
- RunLengthEncodedLine line = lines.get(i);
- boolean duplicate = (
- (i > 0) && lines.get(i-1) == line
- );
- pw.println((duplicate ? "+ " : " " ) + line.dump());
- }
- return sw.toString();
- }
-
- public String toString()
- {
- return getClass().getName()
- + "[width=" + width
- + " height=" +height
- + "]";
- }
-
- public PkGlyph toPkGlyph()
- {
- if (isEmpty())
- return PkGlyph.EMPTY;
-
- ArrayList<Integer> counts = new ArrayList<Integer>(DEFAULT_ARRAY_SIZE);
-
- int count=0;
- int repeat=0;
- RunLengthEncodedLine line = lines.get(0);
- boolean turnOn = line.headOn();
- int i = 0;
- while (line != null) {
- ArrayList<Integer> data = line.getData();
- final int ds = data.size();
- for (int j=0; j<ds; j++) {
- int c = data.get(j);
- boolean needFlush = true;
- if (j == ds - 1) {
- // at the end of the line.
- int r = 0;
- RunLengthEncodedLine next = null;
- while (++i < height) {
- next = lines.get(i);
- if (next != line)
- break;
- r++;
- }
- needFlush = (
- next == null ||
- next.headOn() != line.tailOn()
- );
- line = next;
- if (count > 0) {
- count += data.get(j) + r * width;
- // repeat is unchanged.
- } else {
- count = data.get(j);
- repeat = r;
- }
- } else {
- count += c;
- }
- if (needFlush) {
- if (repeat > 0) {
- counts.add(-repeat);
- repeat = 0;
- }
- counts.add(count);
- count = 0;
- }
- }
- }
-
- PackedSequence ps = new SequencePacker(counts).pack();
-
- return new PkGlyph(
- width, height,
- ps.data(), ps.dynF(),
- turnOn,
- xOffset, yOffset
- );
- }
-
- public DviRect bounds()
- throws DviException
- {
- if (isEmpty())
- return DviRect.EMPTY;
- else
- return new DviRect(-xOffset, -yOffset, width, height);
- }
-
- public void unite(RunLengthEncodedGlyph rlg)
- {
- DviRect u = rlg.getBounds().union(getBounds());
-
- ArrayList<RunLengthEncodedLine> newLines
- = new ArrayList<RunLengthEncodedLine>(DEFAULT_ARRAY_SIZE);
- RunLengthEncodedLine last = null;
- int ey = u.bottom();
- for (int y = u.top(); y<=ey; y++) {
- RunLengthEncodedLine a = new RunLengthEncodedLine();
- RunLengthEncodedLine b = new RunLengthEncodedLine();
- int ia = y + yOffset;
- int ib = y + rlg.yOffset;
-
- if (0 <= ia && ia < height) {
- int w = u.width();
- int lpad = -xOffset-u.left();
- if (lpad > 0) {
- a.append(lpad, false);
- w -= lpad;
- }
- a.append(lines.get(ia));
- w -= width;
- a.append(w, false);
- } else {
- a.append(u.width(), false);
- }
-
- if (0 <= ib && ib < rlg.height) {
- int w = u.width();
- int lpad = -rlg.xOffset-u.left();
- if (lpad > 0) {
- b.append(lpad, false);
- w -= lpad;
- }
- b.append(rlg.lines.get(ib));
- w -= rlg.width;
- b.append(w, false);
- } else {
- b.append(u.width(), false);
- }
-
- a = RunLengthEncodedLine.union(a, b);
-
- if (a.equals(last)) {
- newLines.add(last);
- } else {
- newLines.add(a);
- last = a;
- }
- }
-
- this.width = u.width();
- this.height = u.height();
- this.xOffset = -u.x();
- this.yOffset = -u.y();
- this.lines = newLines;
- compact();
- }
-
-
- public BinaryDevice getBinaryDevice(DviResolution res)
- throws DviException
- {
- return new BinaryDeviceImpl(res);
- }
-
-// private static String dumpCounts(ArrayList<Integer> counts, boolean flag)
-// {
-// String str = "";
-//
-// for (int k=0; k<counts.size(); k++) {
-// int c = counts.get(k);
-//
-// if (c < 0) {
-// str += "[" + (-c) + "]";
-// } else if (flag) {
-// str += String.valueOf(c);
-// flag = !flag;
-// } else {
-// str += "(" + c + ")";
-// flag = !flag;
-// }
-// }
-//
-// return str;
-// }
-
- private class BinaryDeviceImpl
- extends AbstractDevice
- implements BinaryDevice
- {
- private BinaryDeviceImpl(DviResolution res)
- {
- super(res);
- }
-
- public void begin()
- throws DviException
- {
- }
-
- public void end()
- throws DviException
- {
- }
-
- private RunLengthEncodedGlyph rlg = null;
- public boolean beginRaster(int w, int h)
- throws DviException
- {
- rlg = new RunLengthEncodedGlyph();
- rlg.width = w;
- rlg.height = h;
- return true;
- }
-
- public void endRaster()
- throws DviException
- {
- DviPoint p = getReferencePoint();
- // The reference point of rlg is at the origin of this device.
- rlg.xOffset = -p.x;
- rlg.yOffset = -p.y;
- rlg.compact();
-
- unite(rlg);
- rlg = null;
- }
-
- private RunLengthEncodedLine line = null;
- public void beginLine()
- throws DviException
- {
- line = new RunLengthEncodedLine();
- }
-
- public void endLine(int repeat)
- throws DviException
- {
- for (int i=0; i<=repeat; i++) {
- rlg.lines.add(line);
- }
- line = null;
- }
-
- public void putBits(int count, boolean paintFlag)
- {
- line.append(count, paintFlag);
- }
- }
-}