Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

LeaderLayoutManager.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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.inline;
  19. import java.util.Collections;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import org.apache.fop.area.Trait;
  23. import org.apache.fop.area.inline.FilledArea;
  24. import org.apache.fop.area.inline.InlineArea;
  25. import org.apache.fop.area.inline.Space;
  26. import org.apache.fop.area.inline.TextArea;
  27. import org.apache.fop.fo.FObj;
  28. import org.apache.fop.fo.flow.Leader;
  29. import org.apache.fop.fonts.Font;
  30. import org.apache.fop.fonts.FontInfo;
  31. import org.apache.fop.fonts.FontTriplet;
  32. import org.apache.fop.layoutmgr.InlineKnuthSequence;
  33. import org.apache.fop.layoutmgr.KnuthElement;
  34. import org.apache.fop.layoutmgr.KnuthGlue;
  35. import org.apache.fop.layoutmgr.KnuthPenalty;
  36. import org.apache.fop.layoutmgr.KnuthPossPosIter;
  37. import org.apache.fop.layoutmgr.KnuthSequence;
  38. import org.apache.fop.layoutmgr.LayoutContext;
  39. import org.apache.fop.layoutmgr.LeafPosition;
  40. import org.apache.fop.layoutmgr.Position;
  41. import org.apache.fop.layoutmgr.PositionIterator;
  42. import org.apache.fop.layoutmgr.TraitSetter;
  43. import org.apache.fop.traits.MinOptMax;
  44. /**
  45. * LayoutManager for the fo:leader formatting object
  46. */
  47. public class LeaderLayoutManager extends LeafNodeLayoutManager {
  48. private Leader fobj;
  49. private Font font;
  50. private List contentList;
  51. private ContentLayoutManager clm;
  52. private int contentAreaIPD;
  53. /**
  54. * Constructor
  55. *
  56. * @param node the formatting object that creates this area
  57. */
  58. public LeaderLayoutManager(Leader node) {
  59. super(node);
  60. fobj = node;
  61. }
  62. /** {@inheritDoc} */
  63. public void initialize() {
  64. FontInfo fi = fobj.getFOEventHandler().getFontInfo();
  65. FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi);
  66. font = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this));
  67. // the property leader-alignment does not affect vertical positioning
  68. // (see section 7.21.1 in the XSL Recommendation)
  69. // setAlignment(node.getLeaderAlignment());
  70. setCommonBorderPaddingBackground(fobj.getCommonBorderPaddingBackground());
  71. }
  72. /**
  73. * Return the inline area for this leader.
  74. * @param context the layout context
  75. * @return the inline area
  76. */
  77. public InlineArea get(LayoutContext context) {
  78. return getLeaderInlineArea(context);
  79. }
  80. /**
  81. * Return the allocated IPD for this area.
  82. * @param refIPD the IPD of the reference area
  83. * @return the allocated IPD
  84. */
  85. protected MinOptMax getAllocationIPD(int refIPD) {
  86. return getLeaderAllocIPD(refIPD);
  87. }
  88. private MinOptMax getLeaderAllocIPD(int ipd) {
  89. // length of the leader
  90. int borderPaddingWidth = 0;
  91. if (commonBorderPaddingBackground != null) {
  92. borderPaddingWidth = commonBorderPaddingBackground.getIPPaddingAndBorder(false, this);
  93. }
  94. setContentAreaIPD(ipd - borderPaddingWidth);
  95. int opt = fobj.getLeaderLength().getOptimum(this).getLength().getValue(this)
  96. - borderPaddingWidth;
  97. int min = fobj.getLeaderLength().getMinimum(this).getLength().getValue(this)
  98. - borderPaddingWidth;
  99. int max = fobj.getLeaderLength().getMaximum(this).getLength().getValue(this)
  100. - borderPaddingWidth;
  101. return MinOptMax.getInstance(min, opt, max);
  102. }
  103. private InlineArea getLeaderInlineArea(LayoutContext context) {
  104. InlineArea leaderArea = null;
  105. int level = fobj.getBidiLevel();
  106. if (fobj.getLeaderPattern() == EN_RULE) {
  107. if (fobj.getRuleStyle() != EN_NONE) {
  108. org.apache.fop.area.inline.Leader leader
  109. = new org.apache.fop.area.inline.Leader();
  110. leader.setRuleStyle(fobj.getRuleStyle());
  111. leader.setRuleThickness(fobj.getRuleThickness().getValue(this));
  112. leaderArea = leader;
  113. } else {
  114. leaderArea = new Space();
  115. if (level >= 0) {
  116. leaderArea.setBidiLevel(level);
  117. }
  118. }
  119. leaderArea.setBPD(fobj.getRuleThickness().getValue(this));
  120. leaderArea.addTrait(Trait.COLOR, fobj.getColor());
  121. if (level >= 0) {
  122. leaderArea.setBidiLevel(level);
  123. }
  124. } else if (fobj.getLeaderPattern() == EN_SPACE) {
  125. leaderArea = new Space();
  126. leaderArea.setBPD(fobj.getRuleThickness().getValue(this));
  127. if (level >= 0) {
  128. leaderArea.setBidiLevel(level);
  129. }
  130. } else if (fobj.getLeaderPattern() == EN_DOTS) {
  131. TextArea t = new TextArea();
  132. char dot = '.'; // userAgent.getLeaderDotCharacter();
  133. int width = font.getCharWidth(dot);
  134. int[] levels = (level < 0) ? null : new int[] {level};
  135. t.addWord("" + dot, width, null, levels, null, 0);
  136. t.setIPD(width);
  137. t.setBPD(width);
  138. t.setBaselineOffset(width);
  139. TraitSetter.addFontTraits(t, font);
  140. t.addTrait(Trait.COLOR, fobj.getColor());
  141. Space spacer = null;
  142. int widthLeaderPattern = fobj.getLeaderPatternWidth().getValue(this);
  143. if (widthLeaderPattern > width) {
  144. spacer = new Space();
  145. spacer.setIPD(widthLeaderPattern - width);
  146. if (level >= 0) {
  147. spacer.setBidiLevel(level);
  148. }
  149. width = widthLeaderPattern;
  150. }
  151. FilledArea fa = new FilledArea();
  152. fa.setUnitWidth(width);
  153. fa.addChildArea(t);
  154. if (spacer != null) {
  155. fa.addChildArea(spacer);
  156. }
  157. fa.setBPD(t.getBPD());
  158. leaderArea = fa;
  159. } else if (fobj.getLeaderPattern() == EN_USECONTENT) {
  160. if (fobj.getChildNodes() == null) {
  161. InlineLevelEventProducer eventProducer = InlineLevelEventProducer.Provider.get(
  162. getFObj().getUserAgent().getEventBroadcaster());
  163. eventProducer.leaderWithoutContent(this, getFObj().getLocator());
  164. return null;
  165. }
  166. // child FOs are assigned to the InlineStackingLM
  167. fobjIter = null;
  168. // get breaks then add areas to FilledArea
  169. FilledArea fa = new FilledArea();
  170. clm = new ContentLayoutManager(fa, this);
  171. addChildLM(clm);
  172. InlineLayoutManager lm;
  173. lm = new InlineLayoutManager(fobj);
  174. clm.addChildLM(lm);
  175. lm.initialize();
  176. LayoutContext childContext = LayoutContext.newInstance();
  177. childContext.setAlignmentContext(context.getAlignmentContext());
  178. contentList = clm.getNextKnuthElements(childContext, 0);
  179. int width = clm.getStackingSize();
  180. if (width != 0) {
  181. Space spacer = null;
  182. if (fobj.getLeaderPatternWidth().getValue(this) > width) {
  183. spacer = new Space();
  184. spacer.setIPD(fobj.getLeaderPatternWidth().getValue(this) - width);
  185. if (level >= 0) {
  186. spacer.setBidiLevel(level);
  187. }
  188. width = fobj.getLeaderPatternWidth().getValue(this);
  189. }
  190. fa.setUnitWidth(width);
  191. if (spacer != null) {
  192. fa.addChildArea(spacer);
  193. }
  194. leaderArea = fa;
  195. } else {
  196. //Content collapsed to nothing, so use a space
  197. leaderArea = new Space();
  198. leaderArea.setBPD(fobj.getRuleThickness().getValue(this));
  199. leaderArea.setBidiLevel(fobj.getBidiLevelRecursive());
  200. }
  201. }
  202. assert leaderArea != null;
  203. leaderArea.setChangeBarList(getChangeBarList());
  204. TraitSetter.setProducerID(leaderArea, fobj.getId());
  205. return leaderArea;
  206. }
  207. /** {@inheritDoc} */
  208. public void addAreas(PositionIterator posIter, LayoutContext context) {
  209. if (fobj.getLeaderPattern() != EN_USECONTENT) {
  210. // use LeafNodeLayoutManager.addAreas()
  211. super.addAreas(posIter, context);
  212. } else {
  213. addId();
  214. widthAdjustArea(curArea, context);
  215. if (commonBorderPaddingBackground != null) {
  216. // Add border and padding to area
  217. TraitSetter.setBorderPaddingTraits(curArea,
  218. commonBorderPaddingBackground,
  219. false, false, this);
  220. TraitSetter.addBackground(curArea, commonBorderPaddingBackground, this);
  221. }
  222. // add content areas
  223. KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size());
  224. clm.addAreas(contentIter, context);
  225. parentLayoutManager.addChildArea(curArea);
  226. while (posIter.hasNext()) {
  227. posIter.next();
  228. }
  229. }
  230. }
  231. /** {@inheritDoc} */
  232. public List getNextKnuthElements(LayoutContext context, int alignment) {
  233. MinOptMax ipd;
  234. curArea = get(context);
  235. KnuthSequence seq = new InlineKnuthSequence();
  236. if (curArea == null) {
  237. setFinished(true);
  238. return null;
  239. }
  240. alignmentContext = new AlignmentContext(curArea.getBPD()
  241. , fobj.getAlignmentAdjust()
  242. , fobj.getAlignmentBaseline()
  243. , fobj.getBaselineShift()
  244. , fobj.getDominantBaseline()
  245. , context.getAlignmentContext());
  246. ipd = getAllocationIPD(context.getRefIPD());
  247. if (fobj.getLeaderPattern() == EN_USECONTENT && curArea instanceof FilledArea) {
  248. // If we have user supplied content make it fit if we can
  249. int unitWidth = ((FilledArea) curArea).getUnitWidth();
  250. if (ipd.getOpt() < unitWidth && unitWidth <= ipd.getMax()) {
  251. ipd = MinOptMax.getInstance(ipd.getMin(), unitWidth, ipd.getMax());
  252. }
  253. }
  254. // create the AreaInfo object to store the computed values
  255. areaInfo = new AreaInfo((short) 0, ipd, false, context.getAlignmentContext());
  256. curArea.setAdjustingInfo(ipd.getStretch(), ipd.getShrink(), 0);
  257. addKnuthElementsForBorderPaddingStart(seq);
  258. // node is a fo:Leader
  259. seq.add(new KnuthInlineBox(0, alignmentContext, new LeafPosition(this, -1), true));
  260. seq.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  261. new LeafPosition(this, -1), true));
  262. if (alignment == EN_JUSTIFY || alignment == 0) {
  263. seq.add(new KnuthGlue(areaInfo.ipdArea, new LeafPosition(this, 0), false));
  264. } else {
  265. seq.add(new KnuthGlue(areaInfo.ipdArea.getOpt(), 0, 0,
  266. new LeafPosition(this, 0), false));
  267. }
  268. seq.add(new KnuthInlineBox(0, alignmentContext, new LeafPosition(this, -1), true));
  269. addKnuthElementsForBorderPaddingEnd(seq);
  270. setFinished(true);
  271. return Collections.singletonList(seq);
  272. }
  273. /** {@inheritDoc} */
  274. public void hyphenate(Position pos, HyphContext hc) {
  275. // use the AbstractLayoutManager.hyphenate() null implementation
  276. super.hyphenate(pos, hc);
  277. }
  278. /** {@inheritDoc} */
  279. public boolean applyChanges(List oldList) {
  280. setFinished(false);
  281. return false;
  282. }
  283. /** {@inheritDoc} */
  284. public List getChangedKnuthElements(List oldList, int alignment) {
  285. if (isFinished()) {
  286. return null;
  287. }
  288. List returnList = new LinkedList();
  289. addKnuthElementsForBorderPaddingStart(returnList);
  290. returnList.add(new KnuthInlineBox(0, areaInfo.alignmentContext,
  291. new LeafPosition(this, -1), true));
  292. returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  293. new LeafPosition(this, -1), true));
  294. if (alignment == EN_JUSTIFY || alignment == 0) {
  295. returnList.add(new KnuthGlue(areaInfo.ipdArea, new LeafPosition(this, 0), false));
  296. } else {
  297. returnList.add(new KnuthGlue(areaInfo.ipdArea.getOpt(), 0, 0,
  298. new LeafPosition(this, 0), false));
  299. }
  300. returnList.add(new KnuthInlineBox(0, areaInfo.alignmentContext,
  301. new LeafPosition(this, -1), true));
  302. addKnuthElementsForBorderPaddingEnd(returnList);
  303. setFinished(true);
  304. return returnList;
  305. }
  306. /** {@inheritDoc} */
  307. public int getBaseLength(int lengthBase, FObj fobj) {
  308. return getParent().getBaseLength(lengthBase, getParent().getFObj());
  309. }
  310. /**
  311. * Returns the IPD of the content area
  312. * @return the IPD of the content area
  313. */
  314. public int getContentAreaIPD() {
  315. return contentAreaIPD;
  316. }
  317. private void setContentAreaIPD(int contentAreaIPD) {
  318. this.contentAreaIPD = contentAreaIPD;
  319. }
  320. /** {@inheritDoc} */
  321. public void reset() {
  322. childLMs.clear();
  323. super.reset();
  324. }
  325. }