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.

PDFPaintingState.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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.pdf;
  19. import java.awt.Color;
  20. import java.awt.Paint;
  21. import java.awt.Shape;
  22. import java.awt.geom.Area;
  23. import java.awt.geom.GeneralPath;
  24. import org.apache.xmlgraphics.java2d.color.ColorUtil;
  25. import org.apache.fop.util.AbstractPaintingState;
  26. /**
  27. * This keeps information about the current painting state when writing to pdf.
  28. * It allows for creating new graphics states with the q operator.
  29. * This class is only used to store the information about the state
  30. * the caller needs to handle the actual pdf operators.
  31. *
  32. * When setting the state for pdf there are three possible ways of
  33. * handling the situation.
  34. * The values can be set to override previous or default values.
  35. * A new state can be added and then the values set.
  36. * The current state can be popped and values will return to a
  37. * previous state then the necessary values can be overridden.
  38. * The current transform behaves differently to other values as the
  39. * matrix is combined with the current resolved value.
  40. */
  41. public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState {
  42. private static final long serialVersionUID = 5384726143906371279L;
  43. /**
  44. * PDF State for storing graphics state.
  45. */
  46. public PDFPaintingState() {
  47. }
  48. /**
  49. * Set the current paint.
  50. * This checks if the paint will change and then sets the current paint.
  51. *
  52. * @param p the new paint
  53. * @return true if the new paint changes the current paint
  54. */
  55. public boolean setPaint(Paint p) {
  56. PDFData data = getPDFData();
  57. Paint currentPaint = data.paint;
  58. if (currentPaint == null) {
  59. if (p != null) {
  60. data.paint = p;
  61. return true;
  62. }
  63. } else if (p instanceof Color && currentPaint instanceof Color) {
  64. if (!ColorUtil.isSameColor((Color)p, (Color)currentPaint)) {
  65. data.paint = p;
  66. return true;
  67. }
  68. } else if (!currentPaint.equals(p)) {
  69. data.paint = p;
  70. return true;
  71. }
  72. return false;
  73. }
  74. /**
  75. * Check if the clip will change the current state.
  76. * A clip is assumed to be used in a situation where it will add
  77. * to any clip in the current or parent states.
  78. * A clip cannot be cleared, this can only be achieved by going to
  79. * a parent level with the correct clip.
  80. * If the clip is different then it may start a new state so that
  81. * it can return to the previous clip.
  82. *
  83. * @param cl the clip shape to check
  84. * @return true if the clip will change the current clip.
  85. */
  86. public boolean checkClip(Shape cl) {
  87. Shape clip = getPDFData().clip;
  88. if (clip == null) {
  89. if (cl != null) {
  90. return true;
  91. }
  92. } else if (!new Area(clip).equals(new Area(cl))) {
  93. return true;
  94. }
  95. //TODO check for clips that are larger than the current
  96. return false;
  97. }
  98. /**
  99. * Set the current clip.
  100. * This either sets a new clip or sets the clip to the intersect of
  101. * the old clip and the new clip.
  102. *
  103. * @param cl the new clip in the current state
  104. */
  105. public void setClip(Shape cl) {
  106. PDFData data = getPDFData();
  107. Shape clip = data.clip;
  108. if (clip != null) {
  109. Area newClip = new Area(clip);
  110. newClip.intersect(new Area(cl));
  111. data.clip = new GeneralPath(newClip);
  112. } else {
  113. data.clip = cl;
  114. }
  115. }
  116. /**
  117. * Sets the character spacing (Tc).
  118. * @param value the new value
  119. * @return true if the value was changed with respect to the previous value
  120. */
  121. public boolean setCharacterSpacing(float value) {
  122. PDFData data = getPDFData();
  123. if (value != data.characterSpacing) {
  124. data.characterSpacing = value;
  125. return true;
  126. }
  127. return false;
  128. }
  129. /**
  130. * Returns the current character spacing (Tc) value.
  131. * @return the Tc value
  132. */
  133. public float getCharacterSpacing() {
  134. return getPDFData().characterSpacing;
  135. }
  136. /**
  137. * Get the current stack level.
  138. *
  139. * @return the current stack level
  140. */
  141. public int getStackLevel() {
  142. return getStateStack().size();
  143. }
  144. /**
  145. * Get the graphics state.
  146. * This gets the combination of all graphic states for
  147. * the current context.
  148. * This is the graphic state set with the gs operator not
  149. * the other graphic state changes.
  150. *
  151. * @return the calculated ExtGState in the current context
  152. */
  153. public PDFGState getGState() {
  154. PDFGState defaultState = PDFGState.DEFAULT;
  155. PDFGState state;
  156. PDFGState newState = new PDFGState();
  157. newState.addValues(defaultState);
  158. for (AbstractData abstractData : getStateStack()) {
  159. PDFData data = (PDFData) abstractData;
  160. state = data.gstate;
  161. if (state != null) {
  162. newState.addValues(state);
  163. }
  164. }
  165. if (getPDFData().gstate != null) {
  166. newState.addValues(getPDFData().gstate);
  167. }
  168. return newState;
  169. }
  170. public void setLayer(String layer) {
  171. getPDFData().setLayer(layer);
  172. }
  173. public String getLayer() {
  174. return getPDFData().getLayer();
  175. }
  176. public boolean getLayerChanged() {
  177. String layerCurrent = getLayer();
  178. if (layerCurrent == null) {
  179. return false;
  180. } else if (getStateStack().isEmpty()) {
  181. return true;
  182. } else {
  183. for (int i = getStackLevel(); i > 0; --i) {
  184. String layerPrev = ((PDFData) getStateStack().get(i - 1)).getLayer();
  185. if (layerPrev == null) {
  186. continue;
  187. } else {
  188. // Both current and prior are set, so, if same, then we know layer
  189. // didn't change (and can stop search), otherwise it did change.
  190. return !layerCurrent.equals(layerPrev);
  191. }
  192. }
  193. // Current layer set, but no prior saved layer set, so must have changed.
  194. return true;
  195. }
  196. }
  197. /** {@inheritDoc} */
  198. @Override
  199. protected AbstractData instantiateData() {
  200. return new PDFData();
  201. }
  202. /** {@inheritDoc} */
  203. @Override
  204. protected AbstractPaintingState instantiate() {
  205. return new PDFPaintingState();
  206. }
  207. /**
  208. * Push the current state onto the stack.
  209. * This call should be used when the q operator is used
  210. * so that the state is known when popped.
  211. */
  212. @Override
  213. public void save() {
  214. AbstractData data = getData();
  215. AbstractData copy = (AbstractData)data.clone();
  216. data.clearTransform();
  217. getStateStack().push(copy);
  218. }
  219. private PDFData getPDFData() {
  220. return (PDFData)getData();
  221. }
  222. // @SuppressFBWarnings("SE_INNER_CLASS")
  223. private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData {
  224. private static final long serialVersionUID = 3527950647293177764L;
  225. private Paint paint;
  226. private Paint backPaint;
  227. //private int lineCap = 0; //Disabled the ones that are not used, yet
  228. //private int lineJoin = 0;
  229. //private float miterLimit = 0;
  230. //private int dashOffset = 0;
  231. private Shape clip;
  232. private PDFGState gstate;
  233. //text state
  234. private float characterSpacing;
  235. /** {@inheritDoc} */
  236. @Override
  237. public Object clone() {
  238. PDFData obj = (PDFData)super.clone();
  239. obj.paint = this.paint;
  240. obj.backPaint = this.paint;
  241. //obj.lineCap = this.lineCap;
  242. //obj.lineJoin = this.lineJoin;
  243. //obj.miterLimit = this.miterLimit;
  244. //obj.dashOffset = this.dashOffset;
  245. obj.clip = this.clip;
  246. obj.gstate = this.gstate;
  247. obj.characterSpacing = this.characterSpacing;
  248. return obj;
  249. }
  250. /** {@inheritDoc} */
  251. @Override
  252. public String toString() {
  253. return super.toString()
  254. + ", paint=" + paint
  255. + ", backPaint=" + backPaint
  256. //+ ", lineCap=" + lineCap
  257. //+ ", miterLimit=" + miterLimit
  258. //+ ", dashOffset=" + dashOffset
  259. + ", clip=" + clip
  260. + ", gstate=" + gstate;
  261. }
  262. /** {@inheritDoc} */
  263. @Override
  264. protected AbstractData instantiate() {
  265. return new PDFData();
  266. }
  267. }
  268. }