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.

LineArea.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*-- $Id$ --
  2. ============================================================================
  3. The Apache Software License, Version 1.1
  4. ============================================================================
  5. Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without modifica-
  7. tion, are permitted provided that the following conditions are met:
  8. 1. Redistributions of source code must retain the above copyright notice,
  9. this list of conditions and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. 3. The end-user documentation included with the redistribution, if any, must
  14. include the following acknowledgment: "This product includes software
  15. developed by the Apache Software Foundation (http://www.apache.org/)."
  16. Alternately, this acknowledgment may appear in the software itself, if
  17. and wherever such third-party acknowledgments normally appear.
  18. 4. The names "Fop" and "Apache Software Foundation" must not be used to
  19. endorse or promote products derived from this software without prior
  20. written permission. For written permission, please contact
  21. apache@apache.org.
  22. 5. Products derived from this software may not be called "Apache", nor may
  23. "Apache" appear in their name, without prior written permission of the
  24. Apache Software Foundation.
  25. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  26. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  27. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28. APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  29. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  30. DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  31. OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  32. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  33. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  34. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35. This software consists of voluntary contributions made by many individuals
  36. on behalf of the Apache Software Foundation and was originally created by
  37. James Tauber <jtauber@jtauber.com>. For more information on the Apache
  38. Software Foundation, please see <http://www.apache.org/>.
  39. */
  40. package org.apache.xml.fop.layout;
  41. import org.apache.xml.fop.render.Renderer;
  42. import java.util.Vector;
  43. import java.util.Enumeration;
  44. import org.apache.xml.fop.fo.properties.WrapOption; // for enumerated
  45. // values
  46. import org.apache.xml.fop.fo.properties.WhiteSpaceTreatment; // for
  47. // enumerated values
  48. import org.apache.xml.fop.fo.properties.TextAlign; // for enumerated
  49. // values
  50. import org.apache.xml.fop.fo.properties.TextAlignLast; // for enumerated
  51. // values
  52. public class LineArea extends Area {
  53. protected int lineHeight;
  54. protected int halfLeading;
  55. protected int nominalFontSize;
  56. protected int nominalGlyphHeight;
  57. protected int allocationHeight;
  58. protected int startIndent;
  59. protected int endIndent;
  60. private int placementOffset;
  61. private FontState currentFontState; // not the nominal, which is
  62. // in this.fontState
  63. private float red, green, blue;
  64. private int wrapOption;
  65. private int whiteSpaceTreatment;
  66. /* the width of text that has definitely made it into the line
  67. area */
  68. protected int finalWidth = 0;
  69. /* the width of the current word so far */
  70. protected int wordWidth = 0;
  71. /* values that prev (below) may take */
  72. protected static final int NOTHING = 0;
  73. protected static final int WHITESPACE = 1;
  74. protected static final int TEXT = 2;
  75. /* the character type of the previous character */
  76. protected int prev = NOTHING;
  77. /* the position in data[] of the start of the current word */
  78. protected int wordStart;
  79. /* the length (in characters) of the current word */
  80. protected int wordLength = 0;
  81. /* width of spaces before current word */
  82. protected int spaceWidth = 0;
  83. /* the inline areas that have not yet been added to the line
  84. because subsequent characters to come (in a different addText)
  85. may be part of the same word */
  86. protected Vector pendingAreas = new Vector();
  87. /* the width of the pendingAreas */
  88. protected int pendingWidth = 0;
  89. public LineArea(FontState fontState, int lineHeight, int
  90. halfLeading, int allocationWidth, int startIndent,
  91. int endIndent) {
  92. super(fontState);
  93. this.currentFontState = fontState;
  94. this.lineHeight = lineHeight;
  95. this.nominalFontSize = fontState.getFontSize();
  96. this.nominalGlyphHeight = fontState.getAscender() -
  97. fontState.getDescender();
  98. this.placementOffset = fontState.getAscender();
  99. this.contentRectangleWidth = allocationWidth - startIndent -
  100. endIndent;
  101. this.fontState = fontState;
  102. this.allocationHeight = this.nominalGlyphHeight;
  103. this.halfLeading = this.lineHeight - this.allocationHeight;
  104. this.startIndent = startIndent;
  105. this.endIndent = endIndent;
  106. }
  107. public void render(Renderer renderer) {
  108. renderer.renderLineArea(this);
  109. }
  110. public int addText(char data[], int start, int end) {
  111. boolean overrun = false;
  112. wordStart = start;
  113. wordLength = 0;
  114. wordWidth = 0;
  115. /* iterate over each character */
  116. for (int i = start; i < end; i++) {
  117. int charWidth;
  118. /* get the character */
  119. char c = data[i];
  120. if (c > 127) {
  121. /* this class shouldn't be hard coded */
  122. char d =
  123. org.apache.xml.fop.render.pdf.CodePointMapping.map[c];
  124. if (d != 0) {
  125. c = data[i] = d;
  126. } else {
  127. System.err.print("ch"
  128. + (int)c + "?");
  129. c = data[i] = '#';
  130. }
  131. }
  132. charWidth = currentFontState.width(c);
  133. if ((c == ' ') ||
  134. (c == '\n') ||
  135. (c == '\r') ||
  136. (c == '\t')) { // whitespace
  137. if (prev == WHITESPACE) {
  138. // if current & previous are WHITESPACE
  139. if (this.whiteSpaceTreatment ==
  140. WhiteSpaceTreatment.PRESERVE) {
  141. if (c == ' ') {
  142. spaceWidth += currentFontState.width(32);
  143. } else if (c == '\n') {
  144. // force line break
  145. return i;
  146. } else if (c == '\t') {
  147. spaceWidth += 8 * currentFontState.width(32);
  148. }
  149. } // else ignore it
  150. } else if (prev == TEXT) {
  151. // if current is WHITESPACE and previous TEXT
  152. // the current word made it, so
  153. // add the space before the current word (if there
  154. // was some)
  155. if (spaceWidth > 0) {
  156. addChild(new InlineSpace(spaceWidth));
  157. finalWidth += spaceWidth;
  158. spaceWidth = 0;
  159. }
  160. // add any pending areas
  161. Enumeration e = pendingAreas.elements();
  162. while (e.hasMoreElements()) {
  163. InlineArea inlineArea = (InlineArea) e.nextElement();
  164. addChild(inlineArea);
  165. }
  166. finalWidth += pendingWidth;
  167. // reset pending areas array
  168. pendingWidth = 0;
  169. pendingAreas = new Vector();
  170. // add the current word
  171. if (wordLength > 0) {
  172. addChild(new InlineArea(currentFontState,
  173. this.red, this.green,
  174. this.blue, new
  175. String(data, wordStart,
  176. wordLength),
  177. wordWidth));
  178. finalWidth += wordWidth;
  179. // reset word width
  180. wordWidth = 0;
  181. }
  182. // deal with this new whitespace following the
  183. // word we just added
  184. prev = WHITESPACE;
  185. if (this.whiteSpaceTreatment ==
  186. WhiteSpaceTreatment.IGNORE) {
  187. // do nothing
  188. } else {
  189. spaceWidth = currentFontState.width(32);
  190. }
  191. if (this.whiteSpaceTreatment ==
  192. WhiteSpaceTreatment.PRESERVE) {
  193. if (c == '\n') {
  194. // force a line break
  195. return i;
  196. } else if (c == '\t') {
  197. spaceWidth = currentFontState.width(32);
  198. }
  199. }
  200. } else {
  201. // if current is WHITESPACE and no previous
  202. if (this.whiteSpaceTreatment ==
  203. WhiteSpaceTreatment.PRESERVE) {
  204. prev = WHITESPACE;
  205. spaceWidth = currentFontState.width(32);
  206. } else {
  207. // skip over it
  208. start++;
  209. }
  210. }
  211. } else { // current is TEXT
  212. if (prev == WHITESPACE) {
  213. // if current is TEXT and previous WHITESPACE
  214. wordWidth = charWidth;
  215. if ((finalWidth + spaceWidth + wordWidth) >
  216. this.contentRectangleWidth) {
  217. if (overrun)
  218. System.err.print(">");
  219. if (this.wrapOption == WrapOption.WRAP)
  220. return i;
  221. }
  222. prev = TEXT;
  223. wordStart = i;
  224. wordLength = 1;
  225. } else if (prev == TEXT) {
  226. wordLength++;
  227. wordWidth += charWidth;
  228. } else { // nothing previous
  229. prev = TEXT;
  230. wordStart = i;
  231. wordLength = 1;
  232. wordWidth = charWidth;
  233. }
  234. if ((finalWidth + spaceWidth + pendingWidth + wordWidth) >
  235. this.contentRectangleWidth) {
  236. // BREAK MID WORD
  237. if (wordStart == start) { // if couldn't even fit
  238. // first word
  239. overrun = true;
  240. // if not at start of line, return word start
  241. // to try again on a new line
  242. if (finalWidth > 0) {
  243. return wordStart;
  244. }
  245. } else if (this.wrapOption == WrapOption.WRAP) {
  246. return wordStart;
  247. }
  248. }
  249. }
  250. } // end of iteration over text
  251. if (prev == TEXT) {
  252. pendingAreas.addElement(new InlineArea(currentFontState, this.red,
  253. this.green, this.blue, new
  254. String(data, wordStart,
  255. wordLength), wordWidth));
  256. pendingWidth += wordWidth;
  257. wordWidth = 0;
  258. }
  259. if (overrun)
  260. System.err.print(">");
  261. return -1;
  262. }
  263. public void addPending() {
  264. if (spaceWidth > 0) {
  265. addChild(new InlineSpace(spaceWidth));
  266. finalWidth += spaceWidth;
  267. spaceWidth = 0;
  268. }
  269. Enumeration e = pendingAreas.elements();
  270. while (e.hasMoreElements()) {
  271. InlineArea inlineArea = (InlineArea) e.nextElement();
  272. addChild(inlineArea);
  273. }
  274. finalWidth += pendingWidth;
  275. // reset pending areas array
  276. pendingWidth = 0;
  277. pendingAreas = new Vector();
  278. }
  279. public void align(int type) {
  280. int padding;
  281. switch (type) {
  282. case TextAlign.START: // left
  283. padding = this.contentRectangleWidth - finalWidth;
  284. endIndent += padding;
  285. break;
  286. case TextAlign.END: // right
  287. padding = this.contentRectangleWidth - finalWidth;
  288. startIndent += padding;
  289. break;
  290. case TextAlign.CENTERED: // center
  291. padding = (this.contentRectangleWidth - finalWidth)/2;
  292. startIndent += padding;
  293. endIndent += padding;
  294. break;
  295. case TextAlign.JUSTIFIED: // justify
  296. Vector spaceList = new Vector();
  297. int spaceCount = 0;
  298. Enumeration e = children.elements();
  299. while (e.hasMoreElements()) {
  300. Box b = (Box)e.nextElement();
  301. if (b instanceof InlineSpace) {
  302. InlineSpace space = (InlineSpace)b;
  303. spaceList.addElement(space);
  304. spaceCount++;
  305. }
  306. }
  307. if (spaceCount > 0) {
  308. padding = (this.contentRectangleWidth - finalWidth) /
  309. spaceCount;
  310. } else { // no spaces
  311. padding = 0;
  312. }
  313. Enumeration f = spaceList.elements();
  314. while (f.hasMoreElements()) {
  315. InlineSpace space2 = (InlineSpace)f.nextElement();
  316. int i = space2.getSize();
  317. space2.setSize(i + padding);
  318. }
  319. }
  320. }
  321. public void changeColor(float red, float green, float blue) {
  322. this.red = red;
  323. this.green = green;
  324. this.blue = blue;
  325. }
  326. public void changeFont(FontState fontState) {
  327. this.currentFontState = fontState;
  328. }
  329. public void changeWhiteSpaceTreatment(int whiteSpaceTreatment) {
  330. this.whiteSpaceTreatment = whiteSpaceTreatment;
  331. }
  332. public void changeWrapOption(int wrapOption) {
  333. this.wrapOption = wrapOption;
  334. }
  335. public int getEndIndent() {
  336. return endIndent;
  337. }
  338. public int getHeight() {
  339. return this.allocationHeight;
  340. }
  341. public int getPlacementOffset() {
  342. return this.placementOffset;
  343. }
  344. public int getStartIndent() {
  345. return startIndent;
  346. }
  347. public boolean isEmpty() {
  348. return (prev==0);
  349. }
  350. public Vector getPendingAreas() {
  351. return pendingAreas;
  352. }
  353. public int getPendingWidth() {
  354. return pendingWidth;
  355. }
  356. public void setPendingAreas(Vector areas) {
  357. pendingAreas = areas;
  358. }
  359. public void setPendingWidth(int width) {
  360. pendingWidth = width;
  361. }
  362. }