/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.fontbox.cff; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * This class represents a renderer for a charstring. * @author Villu Ruusmann * @version $Revision: 1.0 $ */ public class CharStringRenderer extends CharStringHandler { // TODO CharStringRenderer as abstract Class with two inherited classes according to the Charsstring type.... private boolean isCharstringType1 = true; private boolean isFirstCommand = true; private GeneralPath path = null; private Point2D sidebearingPoint = null; private Point2D referencePoint = null; private int width = 0; public CharStringRenderer() { isCharstringType1 = true; } public CharStringRenderer(boolean isType1) { isCharstringType1 = isType1; } /** * Renders the given sequence and returns the result as a GeneralPath. * @param sequence the given charstring sequence * @return the rendered GeneralPath */ public GeneralPath render(List<Object> sequence) throws IOException { path = new GeneralPath(); sidebearingPoint = new Point2D.Float(0, 0); referencePoint = null; setWidth(0); handleSequence(sequence); return path; } /** * {@inheritDoc} */ public List<Integer> handleCommand(List<Integer> numbers, CharStringCommand command) { if (isCharstringType1) { handleCommandType1(numbers, command); } else { handleCommandType2(numbers, command); } return null; } /** * * @param numbers * @param command */ private void handleCommandType2(List<Integer> numbers, CharStringCommand command) { String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey()); if ("vmoveto".equals(name)) // { if (isFirstCommand && numbers.size() == 2) { setWidth(numbers.get(0)); rmoveTo(Integer.valueOf(0), numbers.get(1)); } else { rmoveTo(Integer.valueOf(0), numbers.get(0)); } } else if ("rlineto".equals(name)) // { if (isFirstCommand && numbers.size() == 3) { setWidth(numbers.get(0)); rlineTo(numbers.get(1), numbers.get(2)); } else { rlineTo(numbers.get(0), numbers.get(1)); } } else if ("hlineto".equals(name))// { if (isFirstCommand && numbers.size() == 2) { setWidth(numbers.get(0)); rlineTo(numbers.get(1), Integer.valueOf(0)); } else { rlineTo(numbers.get(0), Integer.valueOf(0)); } } else if ("vlineto".equals(name))// { if (isFirstCommand && numbers.size() == 2) { setWidth(numbers.get(0)); rlineTo(Integer.valueOf(0), numbers.get(1)); } else { rlineTo(Integer.valueOf(0), numbers.get(0)); } } else if ("rrcurveto".equals(name))// { if (isFirstCommand && numbers.size() == 7) { setWidth(numbers.get(0)); rrcurveTo(numbers.get(1), numbers.get(2), numbers.get(3), numbers .get(4), numbers.get(5), numbers.get(6)); } else { rrcurveTo(numbers.get(0), numbers.get(1), numbers.get(2), numbers .get(3), numbers.get(4), numbers.get(5)); } } else if ("closepath".equals(name)) { closePath(); } else if ("rmoveto".equals(name))// { if (isFirstCommand && numbers.size() == 3) { setWidth(numbers.get(0)); rmoveTo(numbers.get(1), numbers.get(2)); } else { rmoveTo(numbers.get(0), numbers.get(1)); } } else if ("hmoveto".equals(name)) // { if (isFirstCommand && numbers.size() == 2) { setWidth(numbers.get(0)); rmoveTo(numbers.get(1), Integer.valueOf(0)); } else { rmoveTo(numbers.get(0), Integer.valueOf(0)); } } else if ("vhcurveto".equals(name)) { if (isFirstCommand && numbers.size() == 5) { setWidth(numbers.get(0)); rrcurveTo(Integer.valueOf(0), numbers.get(1), numbers.get(2), numbers.get(3), numbers.get(4), Integer.valueOf(0)); } else { rrcurveTo(Integer.valueOf(0), numbers.get(0), numbers.get(1), numbers.get(2), numbers.get(3), Integer.valueOf(0)); } } else if ("hvcurveto".equals(name)) { if (isFirstCommand && numbers.size() == 5) { setWidth(numbers.get(0)); rrcurveTo(numbers.get(1), Integer.valueOf(0), numbers.get(2), numbers.get(3), Integer.valueOf(0), numbers.get(4)); } else { rrcurveTo(numbers.get(0), Integer.valueOf(0), numbers.get(1), numbers.get(2), Integer.valueOf(0), numbers.get(3)); } } else if ("hstem".equals(name)) { if (numbers.size() % 2 == 1 ) { setWidth(numbers.get(0)); } } else if ("vstem".equals(name)) { if (numbers.size() % 2 == 1 ) { setWidth(numbers.get(0)); } } else if ("hstemhm".equals(name)) { if (numbers.size() % 2 == 1 ) { setWidth(numbers.get(0)); } } else if ("hstemhm".equals(name)) { if (numbers.size() % 2 == 1) { setWidth(numbers.get(0)); } } else if ("cntrmask".equals(name)) { if (numbers.size() == 1 ) { setWidth(numbers.get(0)); } } else if ("hintmask".equals(name)) { if (numbers.size() == 1 ) { setWidth(numbers.get(0)); } }else if ("endchar".equals(name)) { if (numbers.size() == 1 ) { setWidth(numbers.get(0)); } } if (isFirstCommand) { isFirstCommand = false; } } /** * * @param numbers * @param command */ private void handleCommandType1(List<Integer> numbers, CharStringCommand command) { String name = CharStringCommand.TYPE1_VOCABULARY.get(command.getKey()); if ("vmoveto".equals(name)) { rmoveTo(Integer.valueOf(0), numbers.get(0)); } else if ("rlineto".equals(name)) { rlineTo(numbers.get(0), numbers.get(1)); } else if ("hlineto".equals(name)) { rlineTo(numbers.get(0), Integer.valueOf(0)); } else if ("vlineto".equals(name)) { rlineTo(Integer.valueOf(0), numbers.get(0)); } else if ("rrcurveto".equals(name)) { rrcurveTo(numbers.get(0), numbers.get(1), numbers.get(2), numbers .get(3), numbers.get(4), numbers.get(5)); } else if ("closepath".equals(name)) { closePath(); } else if ("sbw".equals(name)) { pointSb(numbers.get(0), numbers.get(1)); setWidth(numbers.get(2).intValue()); } else if ("hsbw".equals(name)) { pointSb(numbers.get(0), Integer.valueOf(0)); setWidth(numbers.get(1).intValue()); } else if ("rmoveto".equals(name)) { rmoveTo(numbers.get(0), numbers.get(1)); } else if ("hmoveto".equals(name)) { rmoveTo(numbers.get(0), Integer.valueOf(0)); } else if ("vhcurveto".equals(name)) { rrcurveTo(Integer.valueOf(0), numbers.get(0), numbers.get(1), numbers.get(2), numbers.get(3), Integer.valueOf(0)); } else if ("hvcurveto".equals(name)) { rrcurveTo(numbers.get(0), Integer.valueOf(0), numbers.get(1), numbers.get(2), Integer.valueOf(0), numbers.get(3)); } } private void rmoveTo(Number dx, Number dy) { Point2D point = referencePoint; if (point == null) { point = sidebearingPoint; } referencePoint = null; path.moveTo((float)(point.getX() + dx.doubleValue()), (float)(point.getY() + dy.doubleValue())); } private void rlineTo(Number dx, Number dy) { Point2D point = path.getCurrentPoint(); path.lineTo((float)(point.getX() + dx.doubleValue()), (float)(point.getY() + dy.doubleValue())); } private void rrcurveTo(Number dx1, Number dy1, Number dx2, Number dy2, Number dx3, Number dy3) { Point2D point = path.getCurrentPoint(); float x1 = (float) point.getX() + dx1.floatValue(); float y1 = (float) point.getY() + dy1.floatValue(); float x2 = x1 + dx2.floatValue(); float y2 = y1 + dy2.floatValue(); float x3 = x2 + dx3.floatValue(); float y3 = y2 + dy3.floatValue(); path.curveTo(x1, y1, x2, y2, x3, y3); } private void closePath() { referencePoint = path.getCurrentPoint(); path.closePath(); } private void pointSb(Number x, Number y) { sidebearingPoint = new Point2D.Float(x.floatValue(), y.floatValue()); } /** * Returns the bounds of the renderer path. * @return the bounds as Rectangle2D */ public Rectangle2D getBounds() { return path.getBounds2D(); } /** * Returns the width of the current command. * @return the width */ public int getWidth() { return width; } private void setWidth(int width) { this.width = width; } }