blob: 687fea75f255a8628a5f8f827f0aa72946a548ab [file] [log] [blame]
/*
* 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.
*/
/* $Id$ */
package org.apache.fop.afp.modca;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.afp.Factory;
import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.modca.triplets.AbstractTriplet;
import org.apache.fop.afp.modca.triplets.EncodingTriplet;
import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet;
import org.apache.fop.afp.util.BinaryUtils;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fonts.FontType;
import org.apache.fop.render.afp.AFPFontConfig;
/**
* An Active Environment Group (AEG) is associated with each page,
* and is contained in the page's begin-end envelope in the data stream.
* The active environment group contains layout and formatting information
* that defines the measurement units and size of the page, and may contain
* resource information.
*
* Any objects that are required for page presentation and that are to be
* treated as resource objects must be mapped with a map structured field
* in the AEG. The scope of an active environment group is the scope of its
* containing page or overlay.
*
*/
public final class ActiveEnvironmentGroup extends AbstractEnvironmentGroup {
/** The collection of MapCodedFont objects */
private final List<AbstractStructuredObject> mapCodedFonts
= new java.util.ArrayList<AbstractStructuredObject>();
/** the collection of MapPageSegments objects */
private List mapPageSegments;
/** the Object Area Descriptor for the active environment group */
private ObjectAreaDescriptor objectAreaDescriptor;
/** the Object Area Position for the active environment group */
private ObjectAreaPosition objectAreaPosition;
/** the PresentationTextDescriptor for the active environment group */
private PresentationTextDescriptor presentationTextDataDescriptor;
/** the PageDescriptor for the active environment group */
private PageDescriptor pageDescriptor;
/** the resource manager */
private final Factory factory;
private MapDataResource mdr;
private MapCodedFont mapCodedFont;
/**
* Constructor for the ActiveEnvironmentGroup, this takes a
* name parameter which must be 8 characters long.
*
* @param factory the object factory
* @param name the active environment group name
* @param width the page width
* @param height the page height
* @param widthRes the page width resolution
* @param heightRes the page height resolution
*/
public ActiveEnvironmentGroup(Factory factory,
String name, int width, int height, int widthRes, int heightRes) {
super(name);
this.factory = factory;
// Create PageDescriptor
this.pageDescriptor
= factory.createPageDescriptor(width, height, widthRes, heightRes);
// Create ObjectAreaDescriptor
this.objectAreaDescriptor
= factory.createObjectAreaDescriptor(width, height, widthRes, heightRes);
// Create PresentationTextDataDescriptor
this.presentationTextDataDescriptor
= factory.createPresentationTextDataDescriptor(width, height,
widthRes, heightRes);
}
/**
* Set the position of the object area
*
* @param x the x offset
* @param y the y offset
* @param rotation the rotation
*/
public void setObjectAreaPosition(int x, int y, int rotation) {
this.objectAreaPosition = factory.createObjectAreaPosition(x, y, rotation);
}
/**
* Accessor method to obtain the PageDescriptor object of the
* active environment group.
*
* @return the page descriptor object
*/
public PageDescriptor getPageDescriptor() {
return pageDescriptor;
}
/**
* Accessor method to obtain the PresentationTextDataDescriptor object of
* the active environment group.
*
* @return the presentation text descriptor
*/
public PresentationTextDescriptor getPresentationTextDataDescriptor() {
return presentationTextDataDescriptor;
}
/** {@inheritDoc} */
public void writeContent(OutputStream os) throws IOException {
super.writeTriplets(os);
writeObjects(mapCodedFonts, os);
writeObjects(mapDataResources, os);
writeObjects(mapPageOverlays, os);
writeObjects(mapPageSegments, os);
if (pageDescriptor != null) {
pageDescriptor.writeToStream(os);
}
if (objectAreaDescriptor != null && objectAreaPosition != null) {
objectAreaDescriptor.writeToStream(os);
objectAreaPosition.writeToStream(os);
}
if (presentationTextDataDescriptor != null) {
presentationTextDataDescriptor.writeToStream(os);
}
}
/** {@inheritDoc} */
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.ACTIVE_ENVIRONMENT_GROUP);
os.write(data);
}
/** {@inheritDoc} */
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.ACTIVE_ENVIRONMENT_GROUP);
os.write(data);
}
/**
* Method to create a map coded font object
*
* @param fontRef the font number used as the resource identifier
* @param font the font
* @param size the point size of the font
* @param orientation the orientation of the font (e.g. 0, 90, 180, 270)
*/
public void createFont(int fontRef, AFPFont font, int size, int orientation) {
if (font.getFontType() == FontType.TRUETYPE) {
if (mdr == null) {
mdr = factory.createMapDataResource();
mapCodedFonts.add(mdr);
}
mdr.addTriplet(new EncodingTriplet(1200));
String name = font.getFontName();
if (((AFPFontConfig.AFPTrueTypeFont)font).getTTC() != null) {
name = ((AFPFontConfig.AFPTrueTypeFont)font).getTTC();
}
mdr.setFullyQualifiedName(FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_EXTERNAL_RESOURCE_REF,
FullyQualifiedNameTriplet.FORMAT_CHARSTR, name, true);
mdr.addTriplet(new FontFullyQualifiedNameTriplet((byte) fontRef));
setupTruetypeMDR(mdr, false);
mdr.addTriplet(new DataObjectFontTriplet(size / 1000));
mdr.finishElement();
} else {
if (mapCodedFont == null) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(0, mapCodedFont);
}
try {
mapCodedFont.addFont(fontRef, font, size, orientation);
} catch (MaximumSizeExceededException msee) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(0, mapCodedFont);
try {
mapCodedFont.addFont(fontRef, font, size, orientation);
} catch (MaximumSizeExceededException ex) {
// Should never happen (but log just in case)
LOG.error("createFont():: resulted in a MaximumSizeExceededException");
}
}
}
}
public static void setupTruetypeMDR(AbstractTripletStructuredObject mdr, boolean res) {
AFPDataObjectInfo dataInfo = new AFPDataObjectInfo();
dataInfo.setMimeType(MimeConstants.MIME_AFP_TRUETYPE);
mdr.setObjectClassification(ObjectClassificationTriplet.CLASS_DATA_OBJECT_FONT,
dataInfo.getObjectType(), res, false, res);
}
public static class FontFullyQualifiedNameTriplet extends AbstractTriplet {
private byte fqName;
public FontFullyQualifiedNameTriplet(byte fqName) {
super(FULLY_QUALIFIED_NAME);
this.fqName = fqName;
}
public int getDataLength() {
return 5;
}
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_INTERNAL_RESOURCE_REF;
data[3] = FullyQualifiedNameTriplet.FORMAT_CHARSTR;
data[4] = fqName;
os.write(data);
}
}
static class DataObjectFontTriplet extends AbstractTriplet {
private int pointSize;
public DataObjectFontTriplet(int size) {
super(DATA_OBJECT_FONT_DESCRIPTOR);
pointSize = size;
}
public int getDataLength() {
return 16;
}
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[3] = 0x20;
byte[] pointSizeBytes = BinaryUtils.convert(pointSize * 20, 2);
data[4] = pointSizeBytes[0]; //vfs
data[5] = pointSizeBytes[1];
// data[6] = pointSizeBytes[0]; //hsf
// data[7] = pointSizeBytes[1];
//charrot
data[11] = 0x03; //encenv
data[13] = 0x01; //encid
os.write(data);
}
}
/**
* Getter method for the most recent MapCodedFont added to the
* Active Environment Group (returns null if no MapCodedFonts exist)
*
* @return the most recent Map Coded Font.
*/
private MapCodedFont getCurrentMapCodedFont() {
int size = mapCodedFonts.size();
if (size > 0) {
AbstractStructuredObject font = mapCodedFonts.get(size - 1);
if (font instanceof MapCodedFont) {
return (MapCodedFont) font;
}
}
return null;
}
/**
* Add map page segment.
* @param name of segment to add
*/
public void addMapPageSegment(String name) {
try {
needMapPageSegment().addPageSegment(name);
} catch (MaximumSizeExceededException e) {
//Should not happen, handled internally
throw new IllegalStateException("Internal error: " + e.getMessage());
}
}
private MapPageSegment getCurrentMapPageSegment() {
return (MapPageSegment)getLastElement(this.mapPageSegments);
}
private MapPageSegment needMapPageSegment() {
if (this.mapPageSegments == null) {
this.mapPageSegments = new java.util.ArrayList();
}
MapPageSegment seg = getCurrentMapPageSegment();
if (seg == null || seg.isFull()) {
seg = new MapPageSegment();
this.mapPageSegments.add(seg);
}
return seg;
}
}