Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

UnflattenProcessor.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.complexscripts.bidi;
  19. import java.util.ArrayList;
  20. import java.util.Iterator;
  21. import java.util.LinkedList;
  22. import java.util.List;
  23. import java.util.Stack;
  24. import org.apache.fop.area.Area;
  25. import org.apache.fop.area.LinkResolver;
  26. import org.apache.fop.area.inline.BasicLinkArea;
  27. import org.apache.fop.area.inline.FilledArea;
  28. import org.apache.fop.area.inline.InlineArea;
  29. import org.apache.fop.area.inline.InlineParent;
  30. import org.apache.fop.area.inline.SpaceArea;
  31. import org.apache.fop.area.inline.TextArea;
  32. import org.apache.fop.area.inline.UnresolvedPageNumber;
  33. // CSOFF: LineLengthCheck
  34. /**
  35. * <p>The <code>UnflattenProcessor</code> class is used to reconstruct (by unflattening) a line
  36. * area's internal area hierarachy after leaf inline area reordering is completed.</p>
  37. *
  38. * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
  39. */
  40. class UnflattenProcessor {
  41. private List<InlineArea> il; // list of flattened inline areas being unflattened
  42. private List<InlineArea> ilNew; // list of unflattened inline areas being constructed
  43. private int iaLevelLast; // last (previous) level of current inline area (if applicable) or -1
  44. private TextArea tcOrig; // original text area container
  45. private TextArea tcNew; // new text area container being constructed
  46. private Stack<InlineParent> icOrig; // stack of original inline parent containers
  47. private Stack<InlineParent> icNew; // stack of new inline parent containers being constructed
  48. UnflattenProcessor(List<InlineArea> inlines) {
  49. this.il = inlines;
  50. this.ilNew = new ArrayList<InlineArea>();
  51. this.iaLevelLast = -1;
  52. this.icOrig = new Stack<InlineParent>();
  53. this.icNew = new Stack<InlineParent>();
  54. }
  55. List unflatten() {
  56. if (il != null) {
  57. for (Iterator<InlineArea> it = il.iterator(); it.hasNext(); ) {
  58. process(it.next());
  59. }
  60. }
  61. finishAll();
  62. return ilNew;
  63. }
  64. private void process(InlineArea ia) {
  65. process(findInlineContainers(ia), findTextContainer(ia), ia);
  66. }
  67. private void process(List<InlineParent> ich, TextArea tc, InlineArea ia) {
  68. if ((tcNew == null) || (tc != tcNew)) {
  69. maybeFinishTextContainer(tc, ia);
  70. maybeFinishInlineContainers(ich, tc, ia);
  71. update(ich, tc, ia);
  72. } else {
  73. // skip inline area whose text container is the current new text container,
  74. // which occurs in the context of the inline runs produced by a filled area
  75. }
  76. }
  77. private boolean shouldFinishTextContainer(TextArea tc, InlineArea ia) {
  78. if ((tcOrig != null) && (tc != tcOrig)) {
  79. return true;
  80. } else {
  81. return (iaLevelLast != -1) && (ia.getBidiLevel() != iaLevelLast);
  82. }
  83. }
  84. private void finishTextContainer() {
  85. finishTextContainer(null, null);
  86. }
  87. private void finishTextContainer(TextArea tc, InlineArea ia) {
  88. if (tcNew != null) {
  89. updateIPD(tcNew);
  90. if (!icNew.empty()) {
  91. icNew.peek().addChildArea(tcNew);
  92. } else {
  93. ilNew.add(tcNew);
  94. }
  95. }
  96. tcNew = null;
  97. }
  98. private void maybeFinishTextContainer(TextArea tc, InlineArea ia) {
  99. if (shouldFinishTextContainer(tc, ia)) {
  100. finishTextContainer(tc, ia);
  101. }
  102. }
  103. private boolean shouldFinishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) {
  104. if ((ich == null) || ich.isEmpty()) {
  105. return !icOrig.empty();
  106. } else {
  107. if (!icOrig.empty()) {
  108. InlineParent ic = ich.get(0);
  109. InlineParent ic0 = icOrig.peek();
  110. return (ic != ic0) && !isInlineParentOf(ic, ic0);
  111. } else {
  112. return false;
  113. }
  114. }
  115. }
  116. private void finishInlineContainer() {
  117. finishInlineContainer(null, null, null);
  118. }
  119. private void finishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) {
  120. if ((ich != null) && !ich.isEmpty()) { // finish non-matching inner inline container(s)
  121. for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) {
  122. InlineParent ic = it.next();
  123. InlineParent ic0 = icOrig.empty() ? null : icOrig.peek();
  124. if (ic0 == null) {
  125. assert icNew.empty();
  126. } else if (ic != ic0) {
  127. assert !icNew.empty();
  128. InlineParent icO0 = icOrig.pop();
  129. InlineParent icN0 = icNew.pop();
  130. assert icO0 != null;
  131. assert icN0 != null;
  132. if (icNew.empty()) {
  133. ilNew.add(icN0);
  134. } else {
  135. icNew.peek().addChildArea(icN0);
  136. }
  137. if (!icOrig.empty() && (icOrig.peek() == ic)) {
  138. break;
  139. }
  140. } else {
  141. break;
  142. }
  143. }
  144. } else { // finish all inline containers
  145. while (!icNew.empty()) {
  146. InlineParent icO0 = icOrig.pop();
  147. InlineParent icN0 = icNew.pop();
  148. assert icO0 != null;
  149. assert icN0 != null;
  150. if (icNew.empty()) {
  151. ilNew.add(icN0);
  152. } else {
  153. icNew.peek().addChildArea(icN0);
  154. }
  155. }
  156. }
  157. }
  158. private void maybeFinishInlineContainers(List<InlineParent> ich, TextArea tc, InlineArea ia) {
  159. if (shouldFinishInlineContainer(ich, tc, ia)) {
  160. finishInlineContainer(ich, tc, ia);
  161. }
  162. }
  163. private void finishAll() {
  164. finishTextContainer();
  165. finishInlineContainer();
  166. }
  167. private void update(List<InlineParent> ich, TextArea tc, InlineArea ia) {
  168. if (!alreadyUnflattened(ia)) {
  169. if ((ich != null) && !ich.isEmpty()) {
  170. pushInlineContainers(ich);
  171. }
  172. if (tc != null) {
  173. pushTextContainer(tc, ia);
  174. } else {
  175. pushNonTextInline(ia);
  176. }
  177. iaLevelLast = ia.getBidiLevel();
  178. tcOrig = tc;
  179. } else if (tcNew != null) {
  180. finishTextContainer();
  181. tcOrig = null;
  182. } else {
  183. tcOrig = null;
  184. }
  185. }
  186. private boolean alreadyUnflattened(InlineArea ia) {
  187. for (Iterator<InlineArea> it = ilNew.iterator(); it.hasNext(); ) {
  188. if (ia.isAncestorOrSelf(it.next())) {
  189. return true;
  190. }
  191. }
  192. return false;
  193. }
  194. private void pushInlineContainers(List<InlineParent> ich) {
  195. LinkedList<InlineParent> icl = new LinkedList<InlineParent>();
  196. for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) {
  197. InlineParent ic = it.next();
  198. if (icOrig.search(ic) >= 0) {
  199. break;
  200. } else {
  201. icl.addFirst(ic);
  202. }
  203. }
  204. for (Iterator<InlineParent> it = icl.iterator(); it.hasNext(); ) {
  205. InlineParent ic = it.next();
  206. icOrig.push(ic);
  207. icNew.push(generateInlineContainer(ic));
  208. }
  209. }
  210. private void pushTextContainer(TextArea tc, InlineArea ia) {
  211. if (tc instanceof UnresolvedPageNumber) {
  212. tcNew = tc;
  213. } else {
  214. if (tcNew == null) {
  215. tcNew = generateTextContainer(tc);
  216. }
  217. tcNew.addChildArea(ia);
  218. }
  219. }
  220. private void pushNonTextInline(InlineArea ia) {
  221. if (icNew.empty()) {
  222. ilNew.add(ia);
  223. } else {
  224. icNew.peek().addChildArea(ia);
  225. }
  226. }
  227. private InlineParent generateInlineContainer(InlineParent i) {
  228. if (i instanceof BasicLinkArea) {
  229. return generateBasicLinkArea((BasicLinkArea) i);
  230. } else if (i instanceof FilledArea) {
  231. return generateFilledArea((FilledArea) i);
  232. } else {
  233. return generateInlineContainer0(i);
  234. }
  235. }
  236. private InlineParent generateBasicLinkArea(BasicLinkArea l) {
  237. BasicLinkArea lc = new BasicLinkArea();
  238. if (l != null) {
  239. initializeInlineContainer(lc, l);
  240. initializeLinkArea(lc, l);
  241. }
  242. return lc;
  243. }
  244. private void initializeLinkArea(BasicLinkArea lc, BasicLinkArea l) {
  245. assert lc != null;
  246. assert l != null;
  247. LinkResolver r = l.getResolver();
  248. if (r != null) {
  249. String[] idrefs = r.getIDRefs();
  250. if (idrefs.length > 0) {
  251. String idref = idrefs[0];
  252. LinkResolver lr = new LinkResolver(idref, lc);
  253. lc.setResolver(lr);
  254. r.addDependent(lr);
  255. }
  256. }
  257. }
  258. private InlineParent generateFilledArea(FilledArea f) {
  259. FilledArea fc = new FilledArea();
  260. if (f != null) {
  261. initializeInlineContainer(fc, f);
  262. initializeFilledArea(fc, f);
  263. }
  264. return fc;
  265. }
  266. private void initializeFilledArea(FilledArea fc, FilledArea f) {
  267. assert fc != null;
  268. assert f != null;
  269. fc.setIPD(f.getIPD());
  270. fc.setUnitWidth(f.getUnitWidth());
  271. fc.setAdjustingInfo(f.getAdjustingInfo());
  272. }
  273. private InlineParent generateInlineContainer0(InlineParent i) {
  274. InlineParent ic = new InlineParent();
  275. if (i != null) {
  276. initializeInlineContainer(ic, i);
  277. }
  278. return ic;
  279. }
  280. private void initializeInlineContainer(InlineParent ic, InlineParent i) {
  281. assert ic != null;
  282. assert i != null;
  283. ic.setTraits(i.getTraits());
  284. ic.setBPD(i.getBPD());
  285. ic.setBlockProgressionOffset(i.getBlockProgressionOffset());
  286. }
  287. private TextArea generateTextContainer(TextArea t) {
  288. TextArea tc = new TextArea();
  289. if (t != null) {
  290. tc.setTraits(t.getTraits());
  291. tc.setBPD(t.getBPD());
  292. tc.setBlockProgressionOffset(t.getBlockProgressionOffset());
  293. tc.setBaselineOffset(t.getBaselineOffset());
  294. tc.setTextWordSpaceAdjust(t.getTextWordSpaceAdjust());
  295. tc.setTextLetterSpaceAdjust(t.getTextLetterSpaceAdjust());
  296. }
  297. return tc;
  298. }
  299. private void updateIPD(TextArea tc) {
  300. int numAdjustable = 0;
  301. for (Iterator it = tc.getChildAreas().iterator(); it.hasNext(); ) {
  302. InlineArea ia = (InlineArea) it.next();
  303. if (ia instanceof SpaceArea) {
  304. SpaceArea sa = (SpaceArea) ia;
  305. if (sa.isAdjustable()) {
  306. numAdjustable++;
  307. }
  308. }
  309. }
  310. if (numAdjustable > 0) {
  311. tc.setIPD(tc.getIPD() + (numAdjustable * tc.getTextWordSpaceAdjust()));
  312. }
  313. }
  314. private TextArea findTextContainer(InlineArea ia) {
  315. assert ia != null;
  316. TextArea t = null;
  317. while (t == null) {
  318. if (ia instanceof TextArea) {
  319. t = (TextArea) ia;
  320. } else {
  321. Area p = ia.getParentArea();
  322. if (p instanceof InlineArea) {
  323. ia = (InlineArea) p;
  324. } else {
  325. break;
  326. }
  327. }
  328. }
  329. return t;
  330. }
  331. private List<InlineParent> findInlineContainers(InlineArea ia) {
  332. assert ia != null;
  333. List<InlineParent> ich = new ArrayList<InlineParent>();
  334. Area a = ia.getParentArea();
  335. while (a != null) {
  336. if (a instanceof InlineArea) {
  337. if ((a instanceof InlineParent) && !(a instanceof TextArea)) {
  338. ich.add((InlineParent) a);
  339. }
  340. a = ((InlineArea) a) .getParentArea();
  341. } else {
  342. a = null;
  343. }
  344. }
  345. return ich;
  346. }
  347. private boolean isInlineParentOf(InlineParent ic0, InlineParent ic1) {
  348. assert ic0 != null;
  349. return ic0.getParentArea() == ic1;
  350. }
  351. }