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 8.8KB

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