You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ElementListUtils.java 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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.layoutmgr;
  19. import java.util.List;
  20. import java.util.ListIterator;
  21. import org.apache.fop.traits.MinOptMax;
  22. import org.apache.fop.util.ListUtil;
  23. /**
  24. * Utilities for Knuth element lists.
  25. */
  26. public final class ElementListUtils {
  27. private ElementListUtils() {
  28. // Utility class.
  29. }
  30. /**
  31. * Removes legal breaks in an element list. A constraint can be specified to limit the
  32. * range in which the breaks are removed. Legal breaks occuring before at least
  33. * constraint.opt space is filled will be removed.
  34. * @param elements the element list
  35. * @param constraint min/opt/max value to restrict the range in which the breaks are removed.
  36. * @return true if the opt constraint is bigger than the list contents
  37. */
  38. public static boolean removeLegalBreaks(List elements, MinOptMax constraint) {
  39. return removeLegalBreaks(elements, constraint.opt);
  40. }
  41. /**
  42. * Removes legal breaks in an element list. A constraint can be specified to limit the
  43. * range in which the breaks are removed. Legal breaks occuring before at least
  44. * constraint space is filled will be removed.
  45. * @param elements the element list
  46. * @param constraint value to restrict the range in which the breaks are removed.
  47. * @return true if the constraint is bigger than the list contents
  48. */
  49. public static boolean removeLegalBreaks(List elements, int constraint) {
  50. int len = 0;
  51. ListIterator iter = elements.listIterator();
  52. while (iter.hasNext()) {
  53. ListElement el = (ListElement)iter.next();
  54. if (el.isPenalty()) {
  55. KnuthPenalty penalty = (KnuthPenalty)el;
  56. //Convert all penalties to break inhibitors
  57. if (penalty.getPenalty() < KnuthPenalty.INFINITE) {
  58. iter.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE,
  59. penalty.isPenaltyFlagged(), penalty.getPosition(),
  60. penalty.isAuxiliary()));
  61. }
  62. } else if (el.isGlue()) {
  63. KnuthGlue glue = (KnuthGlue)el;
  64. len += glue.getWidth();
  65. iter.previous();
  66. el = (ListElement)iter.previous();
  67. iter.next();
  68. if (el.isBox()) {
  69. iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false,
  70. null, false));
  71. }
  72. iter.next();
  73. } else if (el instanceof BreakElement) {
  74. BreakElement breakEl = (BreakElement)el;
  75. if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
  76. breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
  77. }
  78. } else {
  79. KnuthElement kel = (KnuthElement)el;
  80. len += kel.getWidth();
  81. }
  82. if (len >= constraint) {
  83. return false;
  84. }
  85. }
  86. return true;
  87. }
  88. /**
  89. * Removes legal breaks in an element list. A constraint can be specified to limit the
  90. * range in which the breaks are removed. Legal breaks within the space specified through the
  91. * constraint (starting from the end of the element list) will be removed.
  92. * @param elements the element list
  93. * @param constraint value to restrict the range in which the breaks are removed.
  94. * @return true if the constraint is bigger than the list contents
  95. */
  96. public static boolean removeLegalBreaksFromEnd(List elements, int constraint) {
  97. int len = 0;
  98. ListIterator i = elements.listIterator(elements.size());
  99. while (i.hasPrevious()) {
  100. ListElement el = (ListElement)i.previous();
  101. if (el.isPenalty()) {
  102. KnuthPenalty penalty = (KnuthPenalty)el;
  103. //Convert all penalties to break inhibitors
  104. if (penalty.getPenalty() < KnuthPenalty.INFINITE) {
  105. i.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE,
  106. penalty.isPenaltyFlagged(), penalty.getPosition(),
  107. penalty.isAuxiliary()));
  108. }
  109. } else if (el.isGlue()) {
  110. KnuthGlue glue = (KnuthGlue)el;
  111. len += glue.getWidth();
  112. el = (ListElement)i.previous();
  113. i.next();
  114. if (el.isBox()) {
  115. i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false,
  116. null, false));
  117. }
  118. } else if (el.isUnresolvedElement()) {
  119. if (el instanceof BreakElement) {
  120. BreakElement breakEl = (BreakElement)el;
  121. if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
  122. breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
  123. }
  124. } else if (el instanceof UnresolvedListElementWithLength) {
  125. UnresolvedListElementWithLength uel = (UnresolvedListElementWithLength)el;
  126. len += uel.getLength().opt;
  127. }
  128. } else {
  129. KnuthElement kel = (KnuthElement)el;
  130. len += kel.getWidth();
  131. }
  132. if (len >= constraint) {
  133. return false;
  134. }
  135. }
  136. return true;
  137. }
  138. /**
  139. * Calculates the content length of the given element list. Warning: It doesn't take any
  140. * stretch and shrink possibilities into account.
  141. * @param elems the element list
  142. * @param start element at which to start
  143. * @param end element at which to stop
  144. * @return the content length
  145. */
  146. public static int calcContentLength(List elems, int start, int end) {
  147. ListIterator iter = elems.listIterator(start);
  148. int count = end - start + 1;
  149. int len = 0;
  150. while (iter.hasNext()) {
  151. ListElement el = (ListElement)iter.next();
  152. if (el.isBox()) {
  153. len += ((KnuthElement)el).getWidth();
  154. } else if (el.isGlue()) {
  155. len += ((KnuthElement)el).getWidth();
  156. } else {
  157. //log.debug("Ignoring penalty: " + el);
  158. //ignore penalties
  159. }
  160. count--;
  161. if (count == 0) {
  162. break;
  163. }
  164. }
  165. return len;
  166. }
  167. /**
  168. * Calculates the content length of the given element list. Warning: It doesn't take any
  169. * stretch and shrink possibilities into account.
  170. * @param elems the element list
  171. * @return the content length
  172. */
  173. public static int calcContentLength(List elems) {
  174. return calcContentLength(elems, 0, elems.size() - 1);
  175. }
  176. /**
  177. * Indicates whether the given element list ends with a forced break.
  178. * @param elems the element list
  179. * @return true if the list ends with a forced break
  180. */
  181. public static boolean endsWithForcedBreak(List elems) {
  182. ListElement last = (ListElement) ListUtil.getLast(elems);
  183. return last.isForcedBreak();
  184. }
  185. /**
  186. * Indicates whether the given element list starts with a forced break.
  187. * @param elems the element list
  188. * @return true if the list starts with a forced break
  189. */
  190. public static boolean startsWithForcedBreak(List elems) {
  191. return !elems.isEmpty() && ((ListElement) elems.get(0)).isForcedBreak();
  192. }
  193. /**
  194. * Indicates whether the given element list ends with a penalty with a non-infinite penalty
  195. * value.
  196. * @param elems the element list
  197. * @return true if the list ends with a non-infinite penalty
  198. */
  199. public static boolean endsWithNonInfinitePenalty(List elems) {
  200. ListElement last = (ListElement) ListUtil.getLast(elems);
  201. if (last.isPenalty() && ((KnuthPenalty)last).getPenalty() < KnuthElement.INFINITE) {
  202. return true;
  203. } else if (last instanceof BreakElement
  204. && ((BreakElement)last).getPenaltyValue() < KnuthElement.INFINITE) {
  205. return true;
  206. }
  207. return false;
  208. }
  209. /**
  210. * Determines the position of the previous break before the start index on an
  211. * element list.
  212. * @param elems the element list
  213. * @param startIndex the start index
  214. * @return the position of the previous break, or -1 if there was no previous break
  215. */
  216. public static int determinePreviousBreak(List elems, int startIndex) {
  217. int prevBreak = startIndex - 1;
  218. while (prevBreak >= 0) {
  219. KnuthElement el = (KnuthElement)elems.get(prevBreak);
  220. if (el.isPenalty() && el.getPenalty() < KnuthElement.INFINITE) {
  221. break;
  222. }
  223. prevBreak--;
  224. }
  225. return prevBreak;
  226. }
  227. }