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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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 List 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.Provider.get(
  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. if (width != 0) {
  166. Space spacer = null;
  167. if (fobj.getLeaderPatternWidth().getValue(this) > width) {
  168. spacer = new Space();
  169. spacer.setIPD(fobj.getLeaderPatternWidth().getValue(this) - width);
  170. width = fobj.getLeaderPatternWidth().getValue(this);
  171. }
  172. fa.setUnitWidth(width);
  173. if (spacer != null) {
  174. fa.addChildArea(spacer);
  175. }
  176. leaderArea = fa;
  177. } else {
  178. //Content collapsed to nothing, so use a space
  179. leaderArea = new Space();
  180. leaderArea.setBPD(1);
  181. }
  182. }
  183. TraitSetter.setProducerID(leaderArea, fobj.getId());
  184. return leaderArea;
  185. }
  186. /** {@inheritDoc} */
  187. public void addAreas(PositionIterator posIter, LayoutContext context) {
  188. if (fobj.getLeaderPattern() != EN_USECONTENT) {
  189. // use LeafNodeLayoutManager.addAreas()
  190. super.addAreas(posIter, context);
  191. } else {
  192. addId();
  193. widthAdjustArea(curArea, context);
  194. if (commonBorderPaddingBackground != null) {
  195. // Add border and padding to area
  196. TraitSetter.setBorderPaddingTraits(curArea,
  197. commonBorderPaddingBackground,
  198. false, false, this);
  199. TraitSetter.addBackground(curArea, commonBorderPaddingBackground, this);
  200. }
  201. // add content areas
  202. KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size());
  203. clm.addAreas(contentIter, context);
  204. parentLM.addChildArea(curArea);
  205. while (posIter.hasNext()) {
  206. posIter.next();
  207. }
  208. }
  209. }
  210. /** {@inheritDoc} */
  211. public List getNextKnuthElements(LayoutContext context,
  212. int alignment) {
  213. MinOptMax ipd;
  214. curArea = get(context);
  215. KnuthSequence seq = new InlineKnuthSequence();
  216. if (curArea == null) {
  217. setFinished(true);
  218. return null;
  219. }
  220. alignmentContext = new AlignmentContext(curArea.getBPD()
  221. , fobj.getAlignmentAdjust()
  222. , fobj.getAlignmentBaseline()
  223. , fobj.getBaselineShift()
  224. , fobj.getDominantBaseline()
  225. , context.getAlignmentContext());
  226. ipd = getAllocationIPD(context.getRefIPD());
  227. if (fobj.getLeaderPattern() == EN_USECONTENT && curArea instanceof FilledArea) {
  228. // If we have user supplied content make it fit if we can
  229. int unitWidth = ((FilledArea)curArea).getUnitWidth();
  230. if (ipd.opt < unitWidth && ipd.max >= unitWidth) {
  231. ipd.opt = unitWidth;
  232. }
  233. }
  234. // create the AreaInfo object to store the computed values
  235. areaInfo = new AreaInfo((short) 0, ipd, false, context.getAlignmentContext());
  236. curArea.setAdjustingInfo(ipd.max - ipd.opt, ipd.opt - ipd.min, 0);
  237. addKnuthElementsForBorderPaddingStart(seq);
  238. // node is a fo:Leader
  239. seq.add(new KnuthInlineBox(0, alignmentContext,
  240. new LeafPosition(this, -1), true));
  241. seq.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  242. new LeafPosition(this, -1), true));
  243. if (alignment == EN_JUSTIFY || alignment == 0) {
  244. seq.add
  245. (new KnuthGlue(areaInfo.ipdArea.opt,
  246. areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
  247. areaInfo.ipdArea.opt - areaInfo.ipdArea.min,
  248. new LeafPosition(this, 0), false));
  249. } else {
  250. seq.add
  251. (new KnuthGlue(areaInfo.ipdArea.opt,
  252. 0,
  253. 0,
  254. new LeafPosition(this, 0), false));
  255. }
  256. seq.add(new KnuthInlineBox(0, alignmentContext,
  257. new LeafPosition(this, -1), true));
  258. addKnuthElementsForBorderPaddingEnd(seq);
  259. LinkedList returnList = new LinkedList();
  260. returnList.add(seq);
  261. setFinished(true);
  262. return returnList;
  263. }
  264. /** {@inheritDoc} */
  265. public void hyphenate(Position pos, HyphContext hc) {
  266. // use the AbstractLayoutManager.hyphenate() null implementation
  267. super.hyphenate(pos, hc);
  268. }
  269. /** {@inheritDoc} */
  270. public boolean applyChanges(List oldList) {
  271. setFinished(false);
  272. return false;
  273. }
  274. /** {@inheritDoc} */
  275. public List getChangedKnuthElements(List oldList,
  276. int alignment) {
  277. if (isFinished()) {
  278. return null;
  279. }
  280. List returnList = new LinkedList();
  281. addKnuthElementsForBorderPaddingStart(returnList);
  282. returnList.add(new KnuthInlineBox(0, areaInfo.alignmentContext,
  283. new LeafPosition(this, -1), true));
  284. returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  285. new LeafPosition(this, -1), true));
  286. if (alignment == EN_JUSTIFY || alignment == 0) {
  287. returnList.add
  288. (new KnuthGlue(areaInfo.ipdArea.opt,
  289. areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
  290. areaInfo.ipdArea.opt - areaInfo.ipdArea.min,
  291. new LeafPosition(this, 0), false));
  292. } else {
  293. returnList.add
  294. (new KnuthGlue(areaInfo.ipdArea.opt,
  295. 0,
  296. 0,
  297. new LeafPosition(this, 0), false));
  298. }
  299. returnList.add(new KnuthInlineBox(0, areaInfo.alignmentContext,
  300. new LeafPosition(this, -1), true));
  301. addKnuthElementsForBorderPaddingEnd(returnList);
  302. setFinished(true);
  303. return returnList;
  304. }
  305. /** {@inheritDoc} */
  306. public int getBaseLength(int lengthBase, FObj fobj) {
  307. return getParent().getBaseLength(lengthBase, getParent().getFObj());
  308. }
  309. /**
  310. * Returns the IPD of the content area
  311. * @return the IPD of the content area
  312. */
  313. public int getContentAreaIPD() {
  314. return contentAreaIPD;
  315. }
  316. private void setContentAreaIPD(int contentAreaIPD) {
  317. this.contentAreaIPD = contentAreaIPD;
  318. }
  319. }