123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*
- * 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.Iterator;
- 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.SpaceArea;
- import org.apache.fop.area.inline.TextArea;
- import org.apache.fop.area.inline.UnresolvedPageNumber;
-
- // CSOFF: LineLengthCheck
-
- /**
- * <p>The <code>UnflattenProcessor</code> class is used to reconstruct (by unflattening) a line
- * area's internal area hierarachy after leaf inline area reordering is completed.</p>
- *
- * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
- */
- class UnflattenProcessor {
- private List<InlineArea> il; // list of flattened inline areas being unflattened
- private List<InlineArea> 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<InlineParent> icOrig; // stack of original inline parent containers
- private Stack<InlineParent> icNew; // stack of new inline parent containers being constructed
- UnflattenProcessor(List<InlineArea> inlines) {
- this.il = inlines;
- this.ilNew = new ArrayList<InlineArea>();
- this.iaLevelLast = -1;
- this.icOrig = new Stack<InlineParent>();
- this.icNew = new Stack<InlineParent>();
- }
- List unflatten() {
- if (il != null) {
- for (Iterator<InlineArea> it = il.iterator(); it.hasNext(); ) {
- process(it.next());
- }
- }
- finishAll();
- return ilNew;
- }
- private void process(InlineArea ia) {
- process(findInlineContainers(ia), findTextContainer(ia), ia);
- }
- private void process(List<InlineParent> 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<InlineParent> 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<InlineParent> ich, TextArea tc, InlineArea ia) {
- if ((ich != null) && !ich.isEmpty()) { // finish non-matching inner inline container(s)
- for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) {
- InlineParent ic = it.next();
- 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<InlineParent> ich, TextArea tc, InlineArea ia) {
- if (shouldFinishInlineContainer(ich, tc, ia)) {
- finishInlineContainer(ich, tc, ia);
- }
- }
- private void finishAll() {
- finishTextContainer();
- finishInlineContainer();
- }
- private void update(List<InlineParent> 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 (Iterator<InlineArea> it = ilNew.iterator(); it.hasNext(); ) {
- if (ia.isAncestorOrSelf(it.next())) {
- return true;
- }
- }
- return false;
- }
- private void pushInlineContainers(List<InlineParent> ich) {
- LinkedList<InlineParent> icl = new LinkedList<InlineParent>();
- for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) {
- InlineParent ic = it.next();
- if (icOrig.search(ic) >= 0) {
- break;
- } else {
- icl.addFirst(ic);
- }
- }
- for (Iterator<InlineParent> it = icl.iterator(); it.hasNext(); ) {
- InlineParent ic = it.next();
- icOrig.push(ic);
- icNew.push(generateInlineContainer(ic));
- }
- }
- private void pushTextContainer(TextArea tc, InlineArea ia) {
- 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 (Iterator it = tc.getChildAreas().iterator(); it.hasNext(); ) {
- InlineArea ia = (InlineArea) it.next();
- 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<InlineParent> findInlineContainers(InlineArea ia) {
- assert ia != null;
- List<InlineParent> ich = new ArrayList<InlineParent>();
- 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;
- }
- }
|