org.apache.fop.complexscripts.bidi.UnflattenProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The newest version!
/*
* 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.complexscripts.bidi;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import org.apache.fop.area.Area;
import org.apache.fop.area.LinkResolver;
import org.apache.fop.area.inline.BasicLinkArea;
import org.apache.fop.area.inline.FilledArea;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.ResolvedPageNumber;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.UnresolvedPageNumber;
// CSOFF: LineLengthCheck
/**
* The UnflattenProcessor
class is used to reconstruct (by unflattening) a line
* area's internal area hierarachy after leaf inline area reordering is completed.
*
* This work was originally authored by Glenn Adams ([email protected]).
*/
class UnflattenProcessor {
private List il; // list of flattened inline areas being unflattened
private List ilNew; // list of unflattened inline areas being constructed
private int iaLevelLast; // last (previous) level of current inline area (if applicable) or -1
private TextArea tcOrig; // original text area container
private TextArea tcNew; // new text area container being constructed
private Stack icOrig; // stack of original inline parent containers
private Stack icNew; // stack of new inline parent containers being constructed
UnflattenProcessor(List inlines) {
this.il = inlines;
this.ilNew = new ArrayList();
this.iaLevelLast = -1;
this.icOrig = new Stack();
this.icNew = new Stack();
}
List unflatten() {
if (il != null) {
for (InlineArea anIl : il) {
process(anIl);
}
}
finishAll();
return ilNew;
}
private void process(InlineArea ia) {
process(findInlineContainers(ia), findTextContainer(ia), ia);
}
private void process(List ich, TextArea tc, InlineArea ia) {
if ((tcNew == null) || (tc != tcNew)) {
maybeFinishTextContainer(tc, ia);
maybeFinishInlineContainers(ich, tc, ia);
update(ich, tc, ia);
} else {
// skip inline area whose text container is the current new text container,
// which occurs in the context of the inline runs produced by a filled area
}
}
private boolean shouldFinishTextContainer(TextArea tc, InlineArea ia) {
if ((tcOrig != null) && (tc != tcOrig)) {
return true;
} else {
return (iaLevelLast != -1) && (ia.getBidiLevel() != iaLevelLast);
}
}
private void finishTextContainer() {
finishTextContainer(null, null);
}
private void finishTextContainer(TextArea tc, InlineArea ia) {
if (tcNew != null) {
updateIPD(tcNew);
if (!icNew.empty()) {
icNew.peek().addChildArea(tcNew);
} else {
ilNew.add(tcNew);
}
}
tcNew = null;
}
private void maybeFinishTextContainer(TextArea tc, InlineArea ia) {
if (shouldFinishTextContainer(tc, ia)) {
finishTextContainer(tc, ia);
}
}
private boolean shouldFinishInlineContainer(List ich, TextArea tc, InlineArea ia) {
if ((ich == null) || ich.isEmpty()) {
return !icOrig.empty();
} else {
if (!icOrig.empty()) {
InlineParent ic = ich.get(0);
InlineParent ic0 = icOrig.peek();
return (ic != ic0) && !isInlineParentOf(ic, ic0);
} else {
return false;
}
}
}
private void finishInlineContainer() {
finishInlineContainer(null, null, null);
}
private void finishInlineContainer(List ich, TextArea tc, InlineArea ia) {
if ((ich != null) && !ich.isEmpty()) { // finish non-matching inner inline container(s)
for (InlineParent ic : ich) {
InlineParent ic0 = icOrig.empty() ? null : icOrig.peek();
if (ic0 == null) {
assert icNew.empty();
} else if (ic != ic0) {
assert !icNew.empty();
InlineParent icO0 = icOrig.pop();
InlineParent icN0 = icNew.pop();
assert icO0 != null;
assert icN0 != null;
if (icNew.empty()) {
ilNew.add(icN0);
} else {
icNew.peek().addChildArea(icN0);
}
if (!icOrig.empty() && (icOrig.peek() == ic)) {
break;
}
} else {
break;
}
}
} else { // finish all inline containers
while (!icNew.empty()) {
InlineParent icO0 = icOrig.pop();
InlineParent icN0 = icNew.pop();
assert icO0 != null;
assert icN0 != null;
if (icNew.empty()) {
ilNew.add(icN0);
} else {
icNew.peek().addChildArea(icN0);
}
}
}
}
private void maybeFinishInlineContainers(List ich, TextArea tc, InlineArea ia) {
if (shouldFinishInlineContainer(ich, tc, ia)) {
finishInlineContainer(ich, tc, ia);
}
}
private void finishAll() {
finishTextContainer();
finishInlineContainer();
}
private void update(List ich, TextArea tc, InlineArea ia) {
if (!alreadyUnflattened(ia)) {
if ((ich != null) && !ich.isEmpty()) {
pushInlineContainers(ich);
}
if (tc != null) {
pushTextContainer(tc, ia);
} else {
pushNonTextInline(ia);
}
iaLevelLast = ia.getBidiLevel();
tcOrig = tc;
} else if (tcNew != null) {
finishTextContainer();
tcOrig = null;
} else {
tcOrig = null;
}
}
private boolean alreadyUnflattened(InlineArea ia) {
for (InlineArea anIlNew : ilNew) {
if (ia.isAncestorOrSelf(anIlNew)) {
return true;
}
}
return false;
}
private void pushInlineContainers(List ich) {
LinkedList icl = new LinkedList();
for (InlineParent ic : ich) {
if (icOrig.search(ic) >= 0) {
break;
} else {
icl.addFirst(ic);
}
}
for (InlineParent ic : icl) {
icOrig.push(ic);
icNew.push(generateInlineContainer(ic));
}
}
private void pushTextContainer(TextArea tc, InlineArea ia) {
if (tc instanceof ResolvedPageNumber) {
tcNew = tc;
} else if (tc instanceof UnresolvedPageNumber) {
tcNew = tc;
} else {
if (tcNew == null) {
tcNew = generateTextContainer(tc);
}
tcNew.addChildArea(ia);
}
}
private void pushNonTextInline(InlineArea ia) {
if (icNew.empty()) {
ilNew.add(ia);
} else {
icNew.peek().addChildArea(ia);
}
}
private InlineParent generateInlineContainer(InlineParent i) {
if (i instanceof BasicLinkArea) {
return generateBasicLinkArea((BasicLinkArea) i);
} else if (i instanceof FilledArea) {
return generateFilledArea((FilledArea) i);
} else {
return generateInlineContainer0(i);
}
}
private InlineParent generateBasicLinkArea(BasicLinkArea l) {
BasicLinkArea lc = new BasicLinkArea();
if (l != null) {
initializeInlineContainer(lc, l);
initializeLinkArea(lc, l);
}
return lc;
}
private void initializeLinkArea(BasicLinkArea lc, BasicLinkArea l) {
assert lc != null;
assert l != null;
LinkResolver r = l.getResolver();
if (r != null) {
String[] idrefs = r.getIDRefs();
if (idrefs.length > 0) {
String idref = idrefs[0];
LinkResolver lr = new LinkResolver(idref, lc);
lc.setResolver(lr);
r.addDependent(lr);
}
}
}
private InlineParent generateFilledArea(FilledArea f) {
FilledArea fc = new FilledArea();
if (f != null) {
initializeInlineContainer(fc, f);
initializeFilledArea(fc, f);
}
return fc;
}
private void initializeFilledArea(FilledArea fc, FilledArea f) {
assert fc != null;
assert f != null;
fc.setIPD(f.getIPD());
fc.setUnitWidth(f.getUnitWidth());
fc.setAdjustingInfo(f.getAdjustingInfo());
}
private InlineParent generateInlineContainer0(InlineParent i) {
InlineParent ic = new InlineParent();
if (i != null) {
initializeInlineContainer(ic, i);
}
return ic;
}
private void initializeInlineContainer(InlineParent ic, InlineParent i) {
assert ic != null;
assert i != null;
ic.setTraits(i.getTraits());
ic.setBPD(i.getBPD());
ic.setBlockProgressionOffset(i.getBlockProgressionOffset());
}
private TextArea generateTextContainer(TextArea t) {
TextArea tc = new TextArea();
if (t != null) {
tc.setTraits(t.getTraits());
tc.setBPD(t.getBPD());
tc.setBlockProgressionOffset(t.getBlockProgressionOffset());
tc.setBaselineOffset(t.getBaselineOffset());
tc.setTextWordSpaceAdjust(t.getTextWordSpaceAdjust());
tc.setTextLetterSpaceAdjust(t.getTextLetterSpaceAdjust());
}
return tc;
}
private void updateIPD(TextArea tc) {
int numAdjustable = 0;
for (InlineArea ia : tc.getChildAreas()) {
if (ia instanceof SpaceArea) {
SpaceArea sa = (SpaceArea) ia;
if (sa.isAdjustable()) {
numAdjustable++;
}
}
}
if (numAdjustable > 0) {
tc.setIPD(tc.getIPD() + (numAdjustable * tc.getTextWordSpaceAdjust()));
}
}
private TextArea findTextContainer(InlineArea ia) {
assert ia != null;
TextArea t = null;
while (t == null) {
if (ia instanceof TextArea) {
t = (TextArea) ia;
} else {
Area p = ia.getParentArea();
if (p instanceof InlineArea) {
ia = (InlineArea) p;
} else {
break;
}
}
}
return t;
}
private List findInlineContainers(InlineArea ia) {
assert ia != null;
List ich = new ArrayList();
Area a = ia.getParentArea();
while (a != null) {
if (a instanceof InlineArea) {
if ((a instanceof InlineParent) && !(a instanceof TextArea)) {
ich.add((InlineParent) a);
}
a = ((InlineArea) a) .getParentArea();
} else {
a = null;
}
}
return ich;
}
private boolean isInlineParentOf(InlineParent ic0, InlineParent ic1) {
assert ic0 != null;
return ic0.getParentArea() == ic1;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy