/*
 * 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: CharacterLayoutManager.java 1610839 2014-07-15 20:25:58Z vhennebert $ */

package org.apache.fop.layoutmgr.inline;

import java.util.LinkedList;
import java.util.List;

import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
import org.apache.fop.util.CharUtilities;

LayoutManager for the fo:character formatting object
/** * LayoutManager for the fo:character formatting object */
public class CharacterLayoutManager extends LeafNodeLayoutManager { private MinOptMax letterSpaceIPD; private int hyphIPD; private Font font; private CommonBorderPaddingBackground borderProps;
Constructor
Params:
  • node – the fo:character formatting object
/** * Constructor * * @param node the fo:character formatting object */
public CharacterLayoutManager(Character node) { super(node); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void initialize() { Character fobj = (Character)this.fobj; font = FontSelector.selectFontForCharacter(fobj, this); SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing()); letterSpaceIPD = ls.getSpace(); hyphIPD = fobj.getCommonHyphenation().getHyphIPD(font); borderProps = fobj.getCommonBorderPaddingBackground(); setCommonBorderPaddingBackground(borderProps); } private TextArea createCharacterArea() { Character fobj = (Character) this.fobj; TextArea text = new TextArea(); char ch = fobj.getCharacter(); int ipd = font.getCharWidth(ch); int blockProgressionOffset = 0; int level = fobj.getBidiLevel(); if (CharUtilities.isAnySpace(ch)) { // add space unless it's zero-width: if (!CharUtilities.isZeroWidthSpace(ch)) { text.addSpace(ch, ipd, CharUtilities.isAdjustableSpace(ch), blockProgressionOffset, level); } } else { int[] levels = (level >= 0) ? new int[] {level} : null; text.addWord(String.valueOf(ch), ipd, null, levels, null, blockProgressionOffset); } TraitSetter.setProducerID(text, fobj.getId()); TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); text.setIPD(font.getCharWidth(fobj.getCharacter())); text.setBPD(font.getAscender() - font.getDescender()); text.setBaselineOffset(font.getAscender()); TraitSetter.addFontTraits(text, font); text.addTrait(Trait.COLOR, fobj.getColor()); return text; } @Override protected InlineArea getEffectiveArea(LayoutContext layoutContext) { InlineArea area = createCharacterArea(); if (!layoutContext.treatAsArtifact()) { TraitSetter.addStructureTreeElement(area, ((Character) fobj).getStructureTreeElement()); } return area; }
{@inheritDoc}
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) { Character fobj = (Character) this.fobj; // TODO: may need some special handling for fo:character alignmentContext = new AlignmentContext(font , font.getFontSize() , fobj.getAlignmentAdjust() , fobj.getAlignmentBaseline() , fobj.getBaselineShift() , fobj.getDominantBaseline() , context.getAlignmentContext()); KnuthSequence seq = new InlineKnuthSequence(); addKnuthElementsForBorderPaddingStart(seq); // create the AreaInfo object to store the computed values MinOptMax ipd = MinOptMax.getInstance(font.getCharWidth(fobj.getCharacter())); areaInfo = new AreaInfo((short) 0, ipd, false, alignmentContext); // node is a fo:Character if (letterSpaceIPD.isStiff()) { // constant letter space, only return a box seq.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext, notifyPos(new LeafPosition(this, 0)), false)); } else { // adjustable letter space, return a sequence of elements; // at the moment the character is supposed to have no letter spaces, // but returning this sequence allows us to change only one element // if addALetterSpaceTo() is called seq.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext, notifyPos(new LeafPosition(this, 0)), false)); seq.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, new LeafPosition(this, -1), true)); seq.add(new KnuthGlue(0, 0, 0, new LeafPosition(this, -1), true)); seq.add(new KnuthInlineBox(0, null, notifyPos(new LeafPosition(this, -1)), true)); } addKnuthElementsForBorderPaddingEnd(seq); LinkedList<KnuthSequence> returnList = new LinkedList<KnuthSequence>(); returnList.add(seq); setFinished(true); return returnList; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public String getWordChars(Position pos) { return String.valueOf(((Character) fobj).getCharacter()); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void hyphenate(Position pos, HyphContext hc) { if (hc.getNextHyphPoint() == 1) { // the character ends a syllable areaInfo.isHyphenated = true; somethingChanged = true; } else { // hc.getNextHyphPoint() returned -1 (no more hyphenation points) // or a number > 1; // the character does not end a syllable } hc.updateOffset(1); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public boolean applyChanges(List oldList) { setFinished(false); return somethingChanged; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public List getChangedKnuthElements(List oldList, int alignment) { if (isFinished()) { return null; } LinkedList<KnuthElement> returnList = new LinkedList<KnuthElement>(); addKnuthElementsForBorderPaddingStart(returnList); if (letterSpaceIPD.isStiff() || areaInfo.letterSpaces == 0) { // constant letter space, or no letter space returnList.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext, notifyPos(new LeafPosition(this, 0)), false)); if (areaInfo.isHyphenated) { returnList.add(new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true, new LeafPosition(this, -1), false)); } } else { // adjustable letter space returnList.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt() - areaInfo.letterSpaces * letterSpaceIPD.getOpt(), areaInfo.alignmentContext, notifyPos(new LeafPosition(this, 0)), false)); returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, new LeafPosition(this, -1), true)); returnList.add(new KnuthGlue(letterSpaceIPD.mult(areaInfo.letterSpaces), new LeafPosition(this, -1), true)); returnList.add( new KnuthInlineBox(0, null, notifyPos(new LeafPosition(this, -1)), true)); if (areaInfo.isHyphenated) { returnList.add(new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true, new LeafPosition(this, -1), false)); } } addKnuthElementsForBorderPaddingEnd(returnList); setFinished(true); return returnList; } }