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.

LeaderLayoutManager.java 14KB

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