Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Merged branch https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ProcessingFeedback into Trunk. Changes on branch: ........ r615153 | jeremias | 2008-01-25 10:07:21 +0100 (Fr, 25 Jan 2008) | 1 line Created temporary branch for processing feedback. ........ r615155 | jeremias | 2008-01-25 10:11:59 +0100 (Fr, 25 Jan 2008) | 1 line Initial commit of what I've built already for those who prefer code to minimalistic design docs. ........ r615278 | jeremias | 2008-01-25 18:25:00 +0100 (Fr, 25 Jan 2008) | 1 line EventProducer interfaces now operational. ........ r615773 | jeremias | 2008-01-28 10:06:16 +0100 (Mo, 28 Jan 2008) | 1 line No casting in client code when creating EventProducer instances. ........ r616242 | vhennebert | 2008-01-29 11:34:45 +0100 (Di, 29 Jan 2008) | 3 lines Trick to avoid hard-coding the class name of EventProducer in the source file. Feel free to revert if it's not ok. ........ r616900 | jeremias | 2008-01-30 21:59:31 +0100 (Mi, 30 Jan 2008) | 1 line Generate event model XMLs in to the build directory: build/gensrc and build/test-gensrc (the latter is new and needs to be setup as source folder in your IDE!) ........ r616907 | jeremias | 2008-01-30 22:12:59 +0100 (Mi, 30 Jan 2008) | 1 line Added an XMLResourceBundle that uses an XML file instead of a properties file to load the translations. The XML format is the same as for Cocoon's XMLResourceBundle. ........ r617097 | vhennebert | 2008-01-31 11:53:21 +0100 (Do, 31 Jan 2008) | 2 lines Minor typo + slight improvement of Javadoc ........ r617176 | jeremias | 2008-01-31 19:14:19 +0100 (Do, 31 Jan 2008) | 5 lines Renamed FopEvent to Event as suggested by Simon. EventProducerCollectorTask.java now reads the EventSeverity from a doclet tag. Added generation of EventProducer translations (including simple merging, no validation, yet) EventFormatter introduced (only basic functionality, yet). Added a simple EventListener implementation that uses EventFormatter to convert the events to human-readable, localized messages that are sent to the log via Commons Logging. ........ r617362 | jeremias | 2008-02-01 08:18:07 +0100 (Fr, 01 Feb 2008) | 1 line Some remaining rename operations based on an earlier discussion. ........ r617413 | jeremias | 2008-02-01 10:46:26 +0100 (Fr, 01 Feb 2008) | 2 lines Extracted formatting functionality into utility class AdvancedMessageFormat.java. AdvancedMessageFormat.java now supports conditional sub-groups (delimited by []). ........ r618682 | jeremias | 2008-02-05 17:07:08 +0100 (Di, 05 Feb 2008) | 1 line Add support for special object formatters (where toString() isn't good enough). ATM, it's hard-coded but could later be hooked into dynamic discovery if we have multiple such formatters. The SAX Locator is the only example for now. ........ r618686 | jeremias | 2008-02-05 17:12:56 +0100 (Di, 05 Feb 2008) | 3 lines Hooked most of FONode into the new event mechanism. The FOUserAgent provides a DefaultEventBroadcaster instance. If a producer method declares throwing an exception, the event is automatically marked FATAL and the dynamic proxy throws an exception right after notifying the listeners. The exceptions are created through the EventExceptionManager. It currently contains only one exception factory for ValidationException. If we need more such factories it's better to register them dynamically. Right now, they're hard-coded. ........ r619313 | jeremias | 2008-02-07 10:14:15 +0100 (Do, 07 Feb 2008) | 1 line Make sure no events are now just silently swallowed because after upgrading a user doesn't know about the event system. ........ r619314 | jeremias | 2008-02-07 10:14:46 +0100 (Do, 07 Feb 2008) | 1 line Log what translation file is being written. ........ r619320 | jeremias | 2008-02-07 10:31:00 +0100 (Do, 07 Feb 2008) | 2 lines FObj hooked into the event system. Code reduction using a protected method on FONode to acquire a FOValidationEventProducer. ........ r619359 | jeremias | 2008-02-07 11:59:19 +0100 (Do, 07 Feb 2008) | 2 lines Fop's QName now extends XGCommons' QName to initiate a transition. Hooked PropertyList into the event mechanism. ........ r631252 | jeremias | 2008-02-26 16:24:33 +0100 (Di, 26 Feb 2008) | 1 line Removed superfluous warning. ........ r631268 | jeremias | 2008-02-26 17:08:11 +0100 (Di, 26 Feb 2008) | 1 line Deprecated two methods which are a problem for localization. Also helps finding additional spots to switch over to the event mechanism. ........ r633852 | jeremias | 2008-03-05 15:20:24 +0100 (Mi, 05 Mrz 2008) | 1 line Add severity to formatting parameters. ........ r633855 | jeremias | 2008-03-05 15:21:57 +0100 (Mi, 05 Mrz 2008) | 4 lines Added support for additional field styles: {<fieldname>,if,<true-text>,<false-text>} {<fieldname>,equals,<test-string>,<true-text>,<false-text>} ........ r633856 | jeremias | 2008-03-05 15:24:04 +0100 (Mi, 05 Mrz 2008) | 2 lines Javadocs and TODOs. EventListeners can change the event severity. ........ r633857 | jeremias | 2008-03-05 15:27:08 +0100 (Mi, 05 Mrz 2008) | 4 lines Javadocs. Moved out event listener registration into a CompositeEventListener. Event broadcaster uses the events effective severity, not the initial value (for the case where listeners override the initial value). Set up a special EventBroadCaster in the FOUserAgent that filters events through a class (FOValidationEventListenerProxy) that adjusts the event severity for relaxed validation. ........ r633858 | jeremias | 2008-03-05 15:32:07 +0100 (Mi, 05 Mrz 2008) | 2 lines Instead of always decentrally checking whether strict validation is enabled or not, this is now done in a special event listener. The event producer method caller simply indicates whether it can recover from the error condition and continue. Started switching to event production in table FOs. ........ r634027 | jeremias | 2008-03-05 21:58:35 +0100 (Mi, 05 Mrz 2008) | 7 lines Moved AdvancedMessageFormat into its own package. AdvancedMessageFormat got the following added functionality: - Alternative conditional regions [ bla {field}] -> [ bla {field1}| even more bla {field2}] - Functions: functions get access to the parameters and they can produce an object that is then formatted ({#gatherContextInfo}) - "if" and "equals" format moved to top-level classes and added by dynamic registration. EventFormatter now supports includes in the form {{includeName}} so you can include other entries from the resource bundle for better reuse. Some more events in table code. ........ r634031 | jeremias | 2008-03-05 22:05:22 +0100 (Mi, 05 Mrz 2008) | 1 line SVN Props ........ r634208 | jeremias | 2008-03-06 11:26:52 +0100 (Do, 06 Mrz 2008) | 2 lines Improved context gathering. Moved GatherContextInfoFunction to an inner class of FONode to reduce visibilities. ........ r634209 | jeremias | 2008-03-06 11:28:14 +0100 (Do, 06 Mrz 2008) | 1 line Made FOPException localizable. ........ r634280 | jeremias | 2008-03-06 15:38:30 +0100 (Do, 06 Mrz 2008) | 2 lines ExceptionFactory is now dynamically registered. More table warnings and errors switch to events. ........ r634326 | jeremias | 2008-03-06 17:08:16 +0100 (Do, 06 Mrz 2008) | 1 line Remaining table FOs switched to events. ........ r634328 | jeremias | 2008-03-06 17:09:21 +0100 (Do, 06 Mrz 2008) | 1 line Deprecated FOP's QName. Mixing with Commons' variant only produces problems. ........ r634381 | jeremias | 2008-03-06 20:12:57 +0100 (Do, 06 Mrz 2008) | 2 lines Made the "invalidChild" event fully localizable by adding a "lookup" field for the optional rule to be displayed. And a few switches to the event system. ........ r634692 | jeremias | 2008-03-07 15:31:43 +0100 (Fr, 07 Mrz 2008) | 1 line More FO tree stuff switched to events. ........ r634712 | jeremias | 2008-03-07 16:19:21 +0100 (Fr, 07 Mrz 2008) | 1 line Avoid an NPE that says nothing (ex. could happen if the message template is wrong). ........ r634738 | jeremias | 2008-03-07 17:38:21 +0100 (Fr, 07 Mrz 2008) | 2 lines Non-FO children were not properly run through validation by FOTreeBuilder. Unified the way that non-FO elements are validated. Some FOs were already fixed. I now fixed the rest, so foreign elements can occur everywhere. ........ r637833 | jeremias | 2008-03-17 12:01:41 +0100 (Mo, 17 Mrz 2008) | 1 line Exception while cloning for RetrieveMarker to be handled by user as suggested by Andreas. ........ r637835 | jeremias | 2008-03-17 12:03:31 +0100 (Mo, 17 Mrz 2008) | 1 line Throw a RuntimeException of no other Exception class is specified for an event as a fallback if someone just sets the event severity to FATAL. ........ r637838 | jeremias | 2008-03-17 12:06:10 +0100 (Mo, 17 Mrz 2008) | 1 line Throw a meaningful exception when the property name is wrong. Otherwise, there will be an ArrayIndexOutOfBoundsException. ........ r637859 | jeremias | 2008-03-17 13:35:26 +0100 (Mo, 17 Mrz 2008) | 1 line Throw a meaningful exception when the property name is wrong. Otherwise, there will be an ArrayIndexOutOfBoundsException. ........ r637938 | jeremias | 2008-03-17 16:19:51 +0100 (Mo, 17 Mrz 2008) | 1 line Switched pagination package to events. ........ r637947 | jeremias | 2008-03-17 16:45:16 +0100 (Mo, 17 Mrz 2008) | 1 line Removed unlocalizable validation helper methods. ........ r637952 | jeremias | 2008-03-17 16:59:02 +0100 (Mo, 17 Mrz 2008) | 1 line Events on FOTreeBuilder. ........ r638299 | jeremias | 2008-03-18 11:09:30 +0100 (Di, 18 Mrz 2008) | 2 lines Added support for java.util.text's ChoiceFormat to AdvancedMessageFormat. Reuse the regexes as constants. ........ r638302 | jeremias | 2008-03-18 11:17:06 +0100 (Di, 18 Mrz 2008) | 1 line Events for inline-level layout managers. ........ r638774 | jeremias | 2008-03-19 11:17:36 +0100 (Mi, 19 Mrz 2008) | 1 line Added DEBUG level. ........ r638777 | jeremias | 2008-03-19 11:23:40 +0100 (Mi, 19 Mrz 2008) | 3 lines Generalized FOValidationEventListenerProxy into FOPEventListenerProxy, the main proxy for FOP's own event manipulation proxy. Done because of support for overflow="hidden" vs. overflow="error-if-overflow". Switched block-level layout managers to events. Some cleanup along the way. ........ r639222 | jeremias | 2008-03-20 10:27:34 +0100 (Do, 20 Mrz 2008) | 2 lines Some initial work for event forwarding from Batik. Missing errors/exceptions converted to events in PageSequenceMaster. ........ r639270 | jeremias | 2008-03-20 13:50:35 +0100 (Do, 20 Mrz 2008) | 1 line Removed DEBUG event severity again. Promoted constrained geometry adjustment event to INFO level as per discussion. ........ r640395 | jeremias | 2008-03-24 13:39:13 +0100 (Mo, 24 Mrz 2008) | 3 lines Moved the creation of the fallback LoggingEventListener to FOUserAgent so event before the startDocument() SAX event arrive in the log. Dynamic discovery of event models. Renderers and extensions can register renderer-specific event models. Switched the most important parts of the renderers to events (maybe not everything is converted). ........ r640397 | jeremias | 2008-03-24 13:43:04 +0100 (Mo, 24 Mrz 2008) | 1 line Remaining fixcrlfs. Xalan likes to mix CRLF and LF on Windows. ........ r640398 | jeremias | 2008-03-24 13:43:54 +0100 (Mo, 24 Mrz 2008) | 1 line Ignore namespace declarations for property handling. ........ r640463 | jeremias | 2008-03-24 17:59:52 +0100 (Mo, 24 Mrz 2008) | 2 lines Event in area package. Exposed getUserAgent() in Renderer interface (was already public in AbstractRenderer). ........ r642972 | jeremias | 2008-03-31 14:18:39 +0200 (Mo, 31 Mrz 2008) | 1 line Code restructured a bit. ........ r642975 | jeremias | 2008-03-31 14:24:07 +0200 (Mo, 31 Mrz 2008) | 2 lines Plugged fonts package into the event subsystem. Note: I did not follow the same pattern as for the rest as the font package is to be considered FOP-external, so I just added a manual adapter for the FontEventListener. This demonstrates how an external library can be integrated with the event system. Missing warning for unknown formatting objects added. Warning is not issued by the ElementMappingRegistry anymore but by FOTreeBuilder which has access to more context information. ........ r642997 | jeremias | 2008-03-31 16:10:08 +0200 (Mo, 31 Mrz 2008) | 1 line Added an example to demonstrate how to write your own event listener and how to deal with the exceptions thrown in the process. ........ r642998 | jeremias | 2008-03-31 16:13:40 +0200 (Mo, 31 Mrz 2008) | 1 line Removed unused method. Event formatting should not be part of the Event class. Use EventFormatter.format(Event) instead. ........ r643066 | jeremias | 2008-03-31 19:18:54 +0200 (Mo, 31 Mrz 2008) | 1 line First part of the event subsystem documentation (DRAFT). ........ r643784 | jeremias | 2008-04-02 10:05:33 +0200 (Mi, 02 Apr 2008) | 1 line More documentation. ........ r643785 | jeremias | 2008-04-02 10:06:38 +0200 (Mi, 02 Apr 2008) | 1 line Some nits. ........ r643787 | jeremias | 2008-04-02 10:24:41 +0200 (Mi, 02 Apr 2008) | 1 line Completed javadocs ........ r643824 | jeremias | 2008-04-02 12:00:30 +0200 (Mi, 02 Apr 2008) | 1 line Javadocs. ........ r645847 | vhennebert | 2008-04-08 12:54:16 +0200 (Di, 08 Apr 2008) | 2 lines Minor typo fixes ........ r645848 | vhennebert | 2008-04-08 12:58:30 +0200 (Di, 08 Apr 2008) | 2 lines Another small typo fix ........ r647678 | jeremias | 2008-04-14 09:20:26 +0200 (Mo, 14 Apr 2008) | 1 line Renamed *EventProducer.Factory.create() to *EventProducer.Provider.get() to better reflect what the method does (instances may be cached and reused). ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@647742 13f79535-47bb-0310-9956-ffa450edef68
pirms 16 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  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.fo;
  19. import java.awt.Color;
  20. import java.nio.CharBuffer;
  21. import java.util.NoSuchElementException;
  22. import org.xml.sax.Locator;
  23. import org.apache.fop.accessibility.StructureTreeElement;
  24. import org.apache.fop.apps.FOPException;
  25. import org.apache.fop.datatypes.Length;
  26. import org.apache.fop.fo.flow.Block;
  27. import org.apache.fop.fo.properties.CommonFont;
  28. import org.apache.fop.fo.properties.CommonHyphenation;
  29. import org.apache.fop.fo.properties.CommonTextDecoration;
  30. import org.apache.fop.fo.properties.KeepProperty;
  31. import org.apache.fop.fo.properties.Property;
  32. import org.apache.fop.fo.properties.SpaceProperty;
  33. import org.apache.fop.util.CharUtilities;
  34. /**
  35. * A text node (PCDATA) in the formatting object tree.
  36. */
  37. public class FOText extends FONode implements CharSequence {
  38. /** the <code>CharBuffer</code> containing the text */
  39. private CharBuffer charBuffer;
  40. /** properties relevant for #PCDATA */
  41. private CommonFont commonFont;
  42. private CommonHyphenation commonHyphenation;
  43. private Color color;
  44. private KeepProperty keepTogether;
  45. private Property letterSpacing;
  46. private SpaceProperty lineHeight;
  47. private int whiteSpaceTreatment;
  48. private int whiteSpaceCollapse;
  49. private int textTransform;
  50. private Property wordSpacing;
  51. private int wrapOption;
  52. private Length baselineShift;
  53. /**
  54. * Points to the previous FOText object created within the current
  55. * block. If this is "null", this is the first such object.
  56. */
  57. private FOText prevFOTextThisBlock = null;
  58. /**
  59. * Points to the next FOText object created within the current
  60. * block. If this is "null", this is the last such object.
  61. */
  62. private FOText nextFOTextThisBlock = null;
  63. /**
  64. * Points to the ancestor Block object. This is used to keep track of
  65. * which FOText nodes are descendants of the same block.
  66. */
  67. private Block ancestorBlock = null;
  68. /** Holds the text decoration values. May be null */
  69. private CommonTextDecoration textDecoration;
  70. private StructureTreeElement structureTreeElement;
  71. private static final int IS_WORD_CHAR_FALSE = 0;
  72. private static final int IS_WORD_CHAR_TRUE = 1;
  73. private static final int IS_WORD_CHAR_MAYBE = 2;
  74. /**
  75. * Creates a new FO text node.
  76. *
  77. * @param parent FONode that is the parent of this object
  78. */
  79. public FOText(FONode parent) {
  80. super(parent);
  81. }
  82. /** {@inheritDoc} */
  83. protected void characters(char[] data, int start, int length,
  84. PropertyList list, Locator locator) throws FOPException {
  85. if (this.charBuffer == null) {
  86. // buffer not yet initialized, do so now
  87. this.charBuffer = CharBuffer.allocate(length);
  88. } else {
  89. // allocate a larger buffer, and transfer contents
  90. int newLength = this.charBuffer.limit() + length;
  91. CharBuffer newBuffer = CharBuffer.allocate(newLength);
  92. this.charBuffer.rewind();
  93. newBuffer.put(this.charBuffer);
  94. this.charBuffer = newBuffer;
  95. }
  96. // append characters
  97. this.charBuffer.put(data, start, length);
  98. }
  99. /**
  100. * Return the array of characters for this instance.
  101. *
  102. * @return a char sequence containing the text
  103. */
  104. public CharSequence getCharSequence() {
  105. if (this.charBuffer == null) {
  106. return null;
  107. }
  108. this.charBuffer.rewind();
  109. return this.charBuffer.asReadOnlyBuffer().subSequence(0, this.charBuffer.limit());
  110. }
  111. /** {@inheritDoc} */
  112. public FONode clone(FONode parent, boolean removeChildren)
  113. throws FOPException {
  114. FOText ft = (FOText) super.clone(parent, removeChildren);
  115. if (removeChildren) {
  116. // not really removing, just make sure the char buffer
  117. // pointed to is really a different one
  118. if (this.charBuffer != null) {
  119. ft.charBuffer = CharBuffer.allocate(this.charBuffer.limit());
  120. this.charBuffer.rewind();
  121. ft.charBuffer.put(this.charBuffer);
  122. ft.charBuffer.rewind();
  123. }
  124. }
  125. ft.prevFOTextThisBlock = null;
  126. ft.nextFOTextThisBlock = null;
  127. ft.ancestorBlock = null;
  128. return ft;
  129. }
  130. /** {@inheritDoc} */
  131. public void bind(PropertyList pList) throws FOPException {
  132. this.commonFont = pList.getFontProps();
  133. this.commonHyphenation = pList.getHyphenationProps();
  134. this.color = pList.get(Constants.PR_COLOR).getColor(getUserAgent());
  135. this.keepTogether = pList.get(Constants.PR_KEEP_TOGETHER).getKeep();
  136. this.lineHeight = pList.get(Constants.PR_LINE_HEIGHT).getSpace();
  137. this.letterSpacing = pList.get(Constants.PR_LETTER_SPACING);
  138. this.whiteSpaceCollapse = pList.get(Constants.PR_WHITE_SPACE_COLLAPSE).getEnum();
  139. this.whiteSpaceTreatment = pList.get(Constants.PR_WHITE_SPACE_TREATMENT).getEnum();
  140. this.textTransform = pList.get(Constants.PR_TEXT_TRANSFORM).getEnum();
  141. this.wordSpacing = pList.get(Constants.PR_WORD_SPACING);
  142. this.wrapOption = pList.get(Constants.PR_WRAP_OPTION).getEnum();
  143. this.textDecoration = pList.getTextDecorationProps();
  144. this.baselineShift = pList.get(Constants.PR_BASELINE_SHIFT).getLength();
  145. }
  146. /** {@inheritDoc} */
  147. protected void endOfNode() throws FOPException {
  148. super.endOfNode();
  149. getFOEventHandler().characters(this);
  150. }
  151. /** {@inheritDoc} */
  152. public void finalizeNode() {
  153. textTransform();
  154. }
  155. /**
  156. * Check if this text node will create an area.
  157. * This means either there is non-whitespace or it is
  158. * preserved whitespace.
  159. * Maybe this just needs to check length > 0, since char iterators
  160. * handle whitespace.
  161. *
  162. * @return true if this will create an area in the output
  163. */
  164. public boolean willCreateArea() {
  165. if (whiteSpaceCollapse == Constants.EN_FALSE
  166. && this.charBuffer.limit() > 0) {
  167. return true;
  168. }
  169. char ch;
  170. this.charBuffer.rewind();
  171. while (this.charBuffer.hasRemaining()) {
  172. ch = this.charBuffer.get();
  173. if (!((ch == CharUtilities.SPACE)
  174. || (ch == CharUtilities.LINEFEED_CHAR)
  175. || (ch == CharUtilities.CARRIAGE_RETURN)
  176. || (ch == CharUtilities.TAB))) {
  177. // not whitespace
  178. this.charBuffer.rewind();
  179. return true;
  180. }
  181. }
  182. return false;
  183. }
  184. /**
  185. * @return a new TextCharIterator
  186. */
  187. public CharIterator charIterator() {
  188. return new TextCharIterator();
  189. }
  190. /**
  191. * This method is run as part of the ancestor Block's flushText(), to
  192. * create xref pointers to the previous FOText objects within the same Block
  193. * @param ancestorBlock the ancestor fo:block
  194. */
  195. protected void createBlockPointers(Block ancestorBlock) {
  196. this.ancestorBlock = ancestorBlock;
  197. // if the last FOText is a sibling, point to it, and have it point here
  198. if (ancestorBlock.lastFOTextProcessed != null) {
  199. if (ancestorBlock.lastFOTextProcessed.ancestorBlock
  200. == this.ancestorBlock) {
  201. prevFOTextThisBlock = ancestorBlock.lastFOTextProcessed;
  202. prevFOTextThisBlock.nextFOTextThisBlock = this;
  203. } else {
  204. prevFOTextThisBlock = null;
  205. }
  206. }
  207. }
  208. /**
  209. * This method is run as part of endOfNode(), to handle the
  210. * text-transform property for accumulated FOText
  211. */
  212. private void textTransform() {
  213. if (getBuilderContext().inMarker()
  214. || textTransform == Constants.EN_NONE) {
  215. return;
  216. }
  217. this.charBuffer.rewind();
  218. CharBuffer tmp = this.charBuffer.slice();
  219. char c;
  220. int lim = this.charBuffer.limit();
  221. int pos = -1;
  222. while (++pos < lim) {
  223. c = this.charBuffer.get();
  224. switch (textTransform) {
  225. case Constants.EN_UPPERCASE:
  226. tmp.put(Character.toUpperCase(c));
  227. break;
  228. case Constants.EN_LOWERCASE:
  229. tmp.put(Character.toLowerCase(c));
  230. break;
  231. case Constants.EN_CAPITALIZE:
  232. if (isStartOfWord(pos)) {
  233. /*
  234. Use toTitleCase here. Apparently, some languages use
  235. a different character to represent a letter when using
  236. initial caps than when all of the letters in the word
  237. are capitalized. We will try to let Java handle this.
  238. */
  239. tmp.put(Character.toTitleCase(c));
  240. } else {
  241. tmp.put(c);
  242. }
  243. break;
  244. default:
  245. //should never happen as the property subsystem catches that case
  246. assert false;
  247. //nop
  248. }
  249. }
  250. }
  251. /**
  252. * Determines whether a particular location in an FOText object's text is
  253. * the start of a new "word". The use of "word" here is specifically for
  254. * the text-transform property, but may be useful for other things as
  255. * well, such as word-spacing. The definition of "word" is somewhat ambiguous
  256. * and appears to be definable by the user agent.
  257. *
  258. * @param i index into charBuffer
  259. *
  260. * @return True if the character at this location is the start of a new
  261. * word.
  262. */
  263. private boolean isStartOfWord(int i) {
  264. char prevChar = getRelativeCharInBlock(i, -1);
  265. /* All we are really concerned about here is of what type prevChar
  266. * is. If inputChar is not part of a word, then the Java
  267. * conversions will (we hope) simply return inputChar.
  268. */
  269. switch (isWordChar(prevChar)) {
  270. case IS_WORD_CHAR_TRUE:
  271. return false;
  272. case IS_WORD_CHAR_FALSE:
  273. return true;
  274. /* "MAYBE" implies that additional context is needed. An example is a
  275. * single-quote, either straight or closing, which might be interpreted
  276. * as a possessive or a contraction, or might be a closing quote.
  277. */
  278. case IS_WORD_CHAR_MAYBE:
  279. char prevPrevChar = getRelativeCharInBlock(i, -2);
  280. switch (isWordChar(prevPrevChar)) {
  281. case IS_WORD_CHAR_TRUE:
  282. return false;
  283. case IS_WORD_CHAR_FALSE:
  284. return true;
  285. case IS_WORD_CHAR_MAYBE:
  286. return true;
  287. default:
  288. return false;
  289. }
  290. default:
  291. return false;
  292. }
  293. }
  294. /**
  295. * Finds a character within the current Block that is relative in location
  296. * to a character in the current FOText. Treats all FOText objects within a
  297. * block as one unit, allowing text in adjoining FOText objects to be
  298. * returned if the parameters are outside of the current object.
  299. *
  300. * @param i index into the CharBuffer
  301. * @param offset signed integer with relative position within the
  302. * block of the character to return. To return the character immediately
  303. * preceding i, pass -1. To return the character immediately after i,
  304. * pass 1.
  305. * @return the character in the offset position within the block; \u0000 if
  306. * the offset points to an area outside of the block.
  307. */
  308. private char getRelativeCharInBlock(int i, int offset) {
  309. int charIndex = i + offset;
  310. // The easy case is where the desired character is in the same FOText
  311. if (charIndex >= 0 && charIndex < this.length()) {
  312. return this.charAt(i + offset);
  313. }
  314. // For now, we can't look at following FOText nodes
  315. if (offset > 0) {
  316. return CharUtilities.NULL_CHAR;
  317. }
  318. // Remaining case has the text in some previous FOText node
  319. boolean foundChar = false;
  320. char charToReturn = CharUtilities.NULL_CHAR;
  321. FOText nodeToTest = this;
  322. int remainingOffset = offset + i;
  323. while (!foundChar) {
  324. if (nodeToTest.prevFOTextThisBlock == null) {
  325. break;
  326. }
  327. nodeToTest = nodeToTest.prevFOTextThisBlock;
  328. int diff = nodeToTest.length() + remainingOffset - 1;
  329. if (diff >= 0) {
  330. charToReturn = nodeToTest.charAt(diff);
  331. foundChar = true;
  332. } else {
  333. remainingOffset += diff;
  334. }
  335. }
  336. return charToReturn;
  337. }
  338. /**
  339. * @return The previous FOText node in this Block; null, if this is the
  340. * first FOText in this Block.
  341. */
  342. public FOText getPrevFOTextThisBlock () {
  343. return prevFOTextThisBlock;
  344. }
  345. /**
  346. * @return The next FOText node in this Block; null if this is the last
  347. * FOText in this Block; null if subsequent FOText nodes have not yet been
  348. * processed.
  349. */
  350. public FOText getNextFOTextThisBlock () {
  351. return nextFOTextThisBlock;
  352. }
  353. /**
  354. * @return The nearest ancestor block object which contains this FOText.
  355. */
  356. public Block getAncestorBlock () {
  357. return ancestorBlock;
  358. }
  359. /**
  360. * Determines whether the input char should be considered part of a
  361. * "word". This is used primarily to determine whether the character
  362. * immediately following starts a new word, but may have other uses.
  363. * We have not found a definition of "word" in the standard (1.0), so the
  364. * logic used here is based on the programmer's best guess.
  365. *
  366. * @param inputChar the character to be tested.
  367. * @return int IS_WORD_CHAR_TRUE, IS_WORD_CHAR_FALSE, or IS_WORD_CHAR_MAYBE,
  368. * depending on whether the character should be considered part of a word
  369. * or not.
  370. */
  371. private static int isWordChar(char inputChar) {
  372. switch (Character.getType(inputChar)) {
  373. case Character.COMBINING_SPACING_MARK:
  374. return IS_WORD_CHAR_TRUE;
  375. case Character.CONNECTOR_PUNCTUATION:
  376. return IS_WORD_CHAR_TRUE;
  377. case Character.CONTROL:
  378. return IS_WORD_CHAR_FALSE;
  379. case Character.CURRENCY_SYMBOL:
  380. return IS_WORD_CHAR_TRUE;
  381. case Character.DASH_PUNCTUATION:
  382. if (inputChar == '-') {
  383. return IS_WORD_CHAR_TRUE; //hyphen
  384. }
  385. return IS_WORD_CHAR_FALSE;
  386. case Character.DECIMAL_DIGIT_NUMBER:
  387. return IS_WORD_CHAR_TRUE;
  388. case Character.ENCLOSING_MARK:
  389. return IS_WORD_CHAR_FALSE;
  390. case Character.END_PUNCTUATION:
  391. if (inputChar == '\u2019') {
  392. return IS_WORD_CHAR_MAYBE; //apostrophe, right single quote
  393. }
  394. return IS_WORD_CHAR_FALSE;
  395. case Character.FORMAT:
  396. return IS_WORD_CHAR_FALSE;
  397. case Character.LETTER_NUMBER:
  398. return IS_WORD_CHAR_TRUE;
  399. case Character.LINE_SEPARATOR:
  400. return IS_WORD_CHAR_FALSE;
  401. case Character.LOWERCASE_LETTER:
  402. return IS_WORD_CHAR_TRUE;
  403. case Character.MATH_SYMBOL:
  404. return IS_WORD_CHAR_FALSE;
  405. case Character.MODIFIER_LETTER:
  406. return IS_WORD_CHAR_TRUE;
  407. case Character.MODIFIER_SYMBOL:
  408. return IS_WORD_CHAR_TRUE;
  409. case Character.NON_SPACING_MARK:
  410. return IS_WORD_CHAR_TRUE;
  411. case Character.OTHER_LETTER:
  412. return IS_WORD_CHAR_TRUE;
  413. case Character.OTHER_NUMBER:
  414. return IS_WORD_CHAR_TRUE;
  415. case Character.OTHER_PUNCTUATION:
  416. if (inputChar == '\'') {
  417. return IS_WORD_CHAR_MAYBE; //ASCII apostrophe
  418. }
  419. return IS_WORD_CHAR_FALSE;
  420. case Character.OTHER_SYMBOL:
  421. return IS_WORD_CHAR_TRUE;
  422. case Character.PARAGRAPH_SEPARATOR:
  423. return IS_WORD_CHAR_FALSE;
  424. case Character.PRIVATE_USE:
  425. return IS_WORD_CHAR_FALSE;
  426. case Character.SPACE_SEPARATOR:
  427. return IS_WORD_CHAR_FALSE;
  428. case Character.START_PUNCTUATION:
  429. return IS_WORD_CHAR_FALSE;
  430. case Character.SURROGATE:
  431. return IS_WORD_CHAR_FALSE;
  432. case Character.TITLECASE_LETTER:
  433. return IS_WORD_CHAR_TRUE;
  434. case Character.UNASSIGNED:
  435. return IS_WORD_CHAR_FALSE;
  436. case Character.UPPERCASE_LETTER:
  437. return IS_WORD_CHAR_TRUE;
  438. default:
  439. return IS_WORD_CHAR_FALSE;
  440. }
  441. }
  442. private class TextCharIterator extends CharIterator {
  443. private int currentPosition = 0;
  444. private boolean canRemove = false;
  445. private boolean canReplace = false;
  446. /** {@inheritDoc} */
  447. public boolean hasNext() {
  448. return (this.currentPosition < charBuffer.limit());
  449. }
  450. /** {@inheritDoc} */
  451. public char nextChar() {
  452. if (this.currentPosition < charBuffer.limit()) {
  453. this.canRemove = true;
  454. this.canReplace = true;
  455. return charBuffer.get(currentPosition++);
  456. } else {
  457. throw new NoSuchElementException();
  458. }
  459. }
  460. /** {@inheritDoc} */
  461. public void remove() {
  462. if (this.canRemove) {
  463. charBuffer.position(currentPosition);
  464. // Slice the buffer at the current position
  465. CharBuffer tmp = charBuffer.slice();
  466. // Reset position to before current character
  467. charBuffer.position(--currentPosition);
  468. if (tmp.hasRemaining()) {
  469. // Transfer any remaining characters
  470. charBuffer.mark();
  471. charBuffer.put(tmp);
  472. charBuffer.reset();
  473. }
  474. // Decrease limit
  475. charBuffer.limit(charBuffer.limit() - 1);
  476. // Make sure following calls fail, unless nextChar() was called
  477. this.canRemove = false;
  478. } else {
  479. throw new IllegalStateException();
  480. }
  481. }
  482. /** {@inheritDoc} */
  483. public void replaceChar(char c) {
  484. if (this.canReplace) {
  485. charBuffer.put(currentPosition - 1, c);
  486. } else {
  487. throw new IllegalStateException();
  488. }
  489. }
  490. }
  491. /**
  492. * @return the Common Font Properties.
  493. */
  494. public CommonFont getCommonFont() {
  495. return commonFont;
  496. }
  497. /**
  498. * @return the Common Hyphenation Properties.
  499. */
  500. public CommonHyphenation getCommonHyphenation() {
  501. return commonHyphenation;
  502. }
  503. /**
  504. * @return the "color" property.
  505. */
  506. public Color getColor() {
  507. return color;
  508. }
  509. /**
  510. * @return the "keep-together" property.
  511. */
  512. public KeepProperty getKeepTogether() {
  513. return keepTogether;
  514. }
  515. /**
  516. * @return the "letter-spacing" property.
  517. */
  518. public Property getLetterSpacing() {
  519. return letterSpacing;
  520. }
  521. /**
  522. * @return the "line-height" property.
  523. */
  524. public SpaceProperty getLineHeight() {
  525. return lineHeight;
  526. }
  527. /**
  528. * @return the "white-space-treatment" property
  529. */
  530. public int getWhitespaceTreatment() {
  531. return whiteSpaceTreatment;
  532. }
  533. /**
  534. * @return the "word-spacing" property.
  535. */
  536. public Property getWordSpacing() {
  537. return wordSpacing;
  538. }
  539. /**
  540. * @return the "wrap-option" property.
  541. */
  542. public int getWrapOption() {
  543. return wrapOption;
  544. }
  545. /** @return the "text-decoration" property. */
  546. public CommonTextDecoration getTextDecoration() {
  547. return textDecoration;
  548. }
  549. /** @return the baseline-shift property */
  550. public Length getBaseLineShift() {
  551. return baselineShift;
  552. }
  553. /** {@inheritDoc} */
  554. public String toString() {
  555. return (this.charBuffer == null) ? "" : this.charBuffer.toString();
  556. }
  557. /** {@inheritDoc} */
  558. public String getLocalName() {
  559. return "#PCDATA";
  560. }
  561. /** {@inheritDoc} */
  562. public String getNormalNamespacePrefix() {
  563. return null;
  564. }
  565. /** {@inheritDoc} */
  566. protected String gatherContextInfo() {
  567. if (this.locator != null) {
  568. return super.gatherContextInfo();
  569. } else {
  570. return this.toString();
  571. }
  572. }
  573. /** {@inheritDoc} */
  574. public char charAt(int position) {
  575. return this.charBuffer.get(position);
  576. }
  577. /** {@inheritDoc} */
  578. public CharSequence subSequence(int start, int end) {
  579. return this.charBuffer.subSequence(start, end);
  580. }
  581. /** {@inheritDoc} */
  582. public int length() {
  583. return this.charBuffer.limit();
  584. }
  585. /**
  586. * Resets the backing <code>java.nio.CharBuffer</code>
  587. */
  588. public void resetBuffer() {
  589. if (this.charBuffer != null) {
  590. this.charBuffer.rewind();
  591. }
  592. }
  593. @Override
  594. public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
  595. this.structureTreeElement = structureTreeElement;
  596. }
  597. /** @return the structure tree element. */
  598. public StructureTreeElement getStructureTreeElement() {
  599. return structureTreeElement;
  600. }
  601. }