1 /*
2  * Copyright 2004 Paulo Soares
3  *
4  * The contents of this file are subject to the Mozilla Public License Version 1.1
5  * (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the License.
11  *
12  * The Original Code is 'iText, a free JAVA-PDF library'.
13  *
14  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
15  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
16  * All Rights Reserved.
17  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
18  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
19  *
20  * Contributor(s): all the names of the contributors are added in the source code
21  * where applicable.
22  *
23  * Alternatively, the contents of this file may be used under the terms of the
24  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
25  * provisions of LGPL are applicable instead of those above.  If you wish to
26  * allow use of your version of this file only under the terms of the LGPL
27  * License and not to allow others to use your version of this file under
28  * the MPL, indicate your decision by deleting the provisions above and
29  * replace them with the notice and other provisions required by the LGPL.
30  * If you do not delete the provisions above, a recipient may use your version
31  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
32  *
33  * This library is free software; you can redistribute it and/or modify it
34  * under the terms of the MPL as stated above or under the terms of the GNU
35  * Library General Public License as published by the Free Software Foundation;
36  * either version 2 of the License, or any later version.
37  *
38  * This library is distributed in the hope that it will be useful, but WITHOUT
39  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
41  * details.
42  *
43  * Contributions by:
44  * Lubos Strapko
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */
50 
51 package com.lowagie.text.html.simpleparser;
52 
53 import java.io.File;
54 import java.io.IOException;
55 import java.io.Reader;
56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.Stack;
59 import java.util.StringTokenizer;
60 
61 import com.lowagie.text.html.HtmlTags;
62 import com.lowagie.text.html.Markup;
63 import com.lowagie.text.Chunk;
64 import com.lowagie.text.DocListener;
65 import com.lowagie.text.DocumentException;
66 import com.lowagie.text.Element;
67 import com.lowagie.text.ElementTags;
68 import com.lowagie.text.ExceptionConverter;
69 import com.lowagie.text.HeaderFooter;
70 import com.lowagie.text.Image;
71 import com.lowagie.text.ListItem;
72 import com.lowagie.text.Paragraph;
73 import com.lowagie.text.Phrase;
74 import com.lowagie.text.Rectangle;
75 import com.lowagie.text.TextElementArray;
76 import com.lowagie.text.pdf.PdfPTable;
77 import com.lowagie.text.pdf.draw.LineSeparator;
78 import com.lowagie.text.FontProvider;
79 import com.lowagie.text.xml.simpleparser.SimpleXMLDocHandler;
80 import com.lowagie.text.xml.simpleparser.SimpleXMLParser;
81 
82 public class HTMLWorker implements SimpleXMLDocHandler, DocListener {
83 
84 	protected ArrayList objectList;
85 
86 	protected DocListener document;
87 
88 	private Paragraph currentParagraph;
89 
90 	private ChainedProperties cprops = new ChainedProperties();
91 
92 	private Stack stack = new Stack();
93 
94 	private boolean pendingTR = false;
95 
96 	private boolean pendingTD = false;
97 
98 	private boolean pendingLI = false;
99 
100 	private StyleSheet style = new StyleSheet();
101 
102 	private boolean isPRE = false;
103 
104 	private Stack tableState = new Stack();
105 
106 	private boolean skipText = false;
107 
108 	private HashMap interfaceProps;
109 
110 	private FactoryProperties factoryProperties = new FactoryProperties();
111 
112 	/** Creates a new instance of HTMLWorker
113 	 * @param document A class that implements <CODE>DocListener</CODE>
114 	 * */
HTMLWorker(DocListener document)115 	public HTMLWorker(DocListener document) {
116 		this.document = document;
117 	}
118 
setStyleSheet(StyleSheet style)119 	public void setStyleSheet(StyleSheet style) {
120 		this.style = style;
121 	}
122 
getStyleSheet()123 	public StyleSheet getStyleSheet() {
124 		return style;
125 	}
126 
setInterfaceProps(HashMap interfaceProps)127 	public void setInterfaceProps(HashMap interfaceProps) {
128 		this.interfaceProps = interfaceProps;
129 		FontProvider ff = null;
130 		if (interfaceProps != null)
131 			ff = (FontProvider) interfaceProps.get("font_factory");
132 		if (ff != null)
133 			factoryProperties.setFontImp(ff);
134 	}
135 
getInterfaceProps()136 	public HashMap getInterfaceProps() {
137 		return interfaceProps;
138 	}
139 
parse(Reader reader)140 	public void parse(Reader reader) throws IOException {
141 		SimpleXMLParser.parse(this, null, reader, true);
142 	}
143 
parseToList(Reader reader, StyleSheet style)144 	public static ArrayList parseToList(Reader reader, StyleSheet style)
145 			throws IOException {
146 		return parseToList(reader, style, null);
147 	}
148 
parseToList(Reader reader, StyleSheet style, HashMap interfaceProps)149 	public static ArrayList parseToList(Reader reader, StyleSheet style,
150 			HashMap interfaceProps) throws IOException {
151 		HTMLWorker worker = new HTMLWorker(null);
152 		if (style != null)
153 			worker.style = style;
154 		worker.document = worker;
155 		worker.setInterfaceProps(interfaceProps);
156 		worker.objectList = new ArrayList();
157 		worker.parse(reader);
158 		return worker.objectList;
159 	}
160 
endDocument()161 	public void endDocument() {
162 		try {
163 			for (int k = 0; k < stack.size(); ++k)
164 				document.add((Element) stack.elementAt(k));
165 			if (currentParagraph != null)
166 				document.add(currentParagraph);
167 			currentParagraph = null;
168 		} catch (Exception e) {
169 			throw new ExceptionConverter(e);
170 		}
171 	}
172 
startDocument()173 	public void startDocument() {
174 		HashMap h = new HashMap();
175 		style.applyStyle("body", h);
176 		cprops.addToChain("body", h);
177 	}
178 
startElement(String tag, HashMap h)179 	public void startElement(String tag, HashMap h) {
180 		if (!tagsSupported.containsKey(tag))
181 			return;
182 		try {
183 			style.applyStyle(tag, h);
184 			String follow = (String) FactoryProperties.followTags.get(tag);
185 			if (follow != null) {
186 				HashMap prop = new HashMap();
187 				prop.put(follow, null);
188 				cprops.addToChain(follow, prop);
189 				return;
190 			}
191 			FactoryProperties.insertStyle(h, cprops);
192 			if (tag.equals(HtmlTags.ANCHOR)) {
193 				cprops.addToChain(tag, h);
194 				if (currentParagraph == null) {
195 					currentParagraph = new Paragraph();
196 				}
197 				stack.push(currentParagraph);
198 				currentParagraph = new Paragraph();
199 				return;
200 			}
201 			if (tag.equals(HtmlTags.NEWLINE)) {
202 				if (currentParagraph == null) {
203 					currentParagraph = new Paragraph();
204 				}
205 				currentParagraph.add(factoryProperties
206 						.createChunk("\n", cprops));
207 				return;
208 			}
209 			if (tag.equals(HtmlTags.HORIZONTALRULE)) {
210 				// Attempting to duplicate the behavior seen on Firefox with
211 				// http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_hr_test
212 				// where an initial break is only inserted when the preceding element doesn't
213 				// end with a break, but a trailing break is always inserted.
214 				boolean addLeadingBreak = true;
215 				if (currentParagraph == null) {
216 					currentParagraph = new Paragraph();
217 					addLeadingBreak = false;
218 				}
219 				if (addLeadingBreak) { // Not a new paragraph
220 					int numChunks = currentParagraph.getChunks().size();
221 					if (numChunks == 0 ||
222 							((Chunk)(currentParagraph.getChunks().get(numChunks - 1))).getContent().endsWith("\n"))
223 						addLeadingBreak = false;
224 				}
225 				String align = (String) h.get("align");
226 				int hrAlign = Element.ALIGN_CENTER;
227 				if (align != null) {
228 					if (align.equalsIgnoreCase("left"))
229 						hrAlign = Element.ALIGN_LEFT;
230 					if (align.equalsIgnoreCase("right"))
231 						hrAlign = Element.ALIGN_RIGHT;
232 				}
233 				String width = (String) h.get("width");
234 				float hrWidth = 1;
235 				if (width != null) {
236 					float tmpWidth = Markup.parseLength(width, Markup.DEFAULT_FONT_SIZE);
237 					if (tmpWidth > 0) hrWidth = tmpWidth;
238 					if (!width.endsWith("%"))
239 						hrWidth = 100; // Treat a pixel width as 100% for now.
240 				}
241 				String size = (String) h.get("size");
242 				float hrSize = 1;
243 				if (size != null) {
244 					float tmpSize = Markup.parseLength(size, Markup.DEFAULT_FONT_SIZE);
245 					if (tmpSize > 0)
246 						hrSize = tmpSize;
247 				}
248 				if (addLeadingBreak)
249 					currentParagraph.add(Chunk.NEWLINE);
250 				currentParagraph.add(new LineSeparator(hrSize, hrWidth, null, hrAlign, currentParagraph.getLeading()/2));
251 				currentParagraph.add(Chunk.NEWLINE);
252 				return;
253 			}
254 			if (tag.equals(HtmlTags.CHUNK) || tag.equals(HtmlTags.SPAN)) {
255 				cprops.addToChain(tag, h);
256 				return;
257 			}
258 			if (tag.equals(HtmlTags.IMAGE)) {
259 				String src = (String) h.get(ElementTags.SRC);
260 				if (src == null)
261 					return;
262 				cprops.addToChain(tag, h);
263 				Image img = null;
264 				if (interfaceProps != null) {
265 					ImageProvider ip = (ImageProvider) interfaceProps
266 							.get("img_provider");
267 					if (ip != null)
268 						img = ip.getImage(src, h, cprops, document);
269 					if (img == null) {
270 						HashMap images = (HashMap) interfaceProps
271 								.get("img_static");
272 						if (images != null) {
273 							Image tim = (Image) images.get(src);
274 							if (tim != null)
275 								img = Image.getInstance(tim);
276 						} else {
277 							if (!src.startsWith("http")) { // relative src references only
278 								String baseurl = (String) interfaceProps
279 										.get("img_baseurl");
280 								if (baseurl != null) {
281 									src = baseurl + src;
282 									img = Image.getInstance(src);
283 								}
284 							}
285 						}
286 					}
287 				}
288 				if (img == null) {
289 					if (!src.startsWith("http")) {
290 						String path = cprops.getProperty("image_path");
291 						if (path == null)
292 							path = "";
293 						src = new File(path, src).getPath();
294 					}
295 					img = Image.getInstance(src);
296 				}
297 				String align = (String) h.get("align");
298 				String width = (String) h.get("width");
299 				String height = (String) h.get("height");
300 				String before = cprops.getProperty("before");
301 				String after = cprops.getProperty("after");
302 				if (before != null)
303 					img.setSpacingBefore(Float.parseFloat(before));
304 				if (after != null)
305 					img.setSpacingAfter(Float.parseFloat(after));
306 				float actualFontSize = Markup.parseLength(cprops
307 						.getProperty(ElementTags.SIZE),
308 						Markup.DEFAULT_FONT_SIZE);
309 				if (actualFontSize <= 0f)
310 					actualFontSize = Markup.DEFAULT_FONT_SIZE;
311 				float widthInPoints = Markup.parseLength(width, actualFontSize);
312 				float heightInPoints = Markup.parseLength(height,
313 						actualFontSize);
314 				if (widthInPoints > 0 && heightInPoints > 0) {
315 					img.scaleAbsolute(widthInPoints, heightInPoints);
316 				} else if (widthInPoints > 0) {
317 					heightInPoints = img.getHeight() * widthInPoints
318 							/ img.getWidth();
319 					img.scaleAbsolute(widthInPoints, heightInPoints);
320 				} else if (heightInPoints > 0) {
321 					widthInPoints = img.getWidth() * heightInPoints
322 							/ img.getHeight();
323 					img.scaleAbsolute(widthInPoints, heightInPoints);
324 				}
325 				img.setWidthPercentage(0);
326 				if (align != null) {
327 					endElement("p");
328 					int ralign = Image.MIDDLE;
329 					if (align.equalsIgnoreCase("left"))
330 						ralign = Image.LEFT;
331 					else if (align.equalsIgnoreCase("right"))
332 						ralign = Image.RIGHT;
333 					img.setAlignment(ralign);
334 					Img i = null;
335 					boolean skip = false;
336 					if (interfaceProps != null) {
337 						i = (Img) interfaceProps.get("img_interface");
338 						if (i != null)
339 							skip = i.process(img, h, cprops, document);
340 					}
341 					if (!skip)
342 						document.add(img);
343 					cprops.removeChain(tag);
344 				} else {
345 					cprops.removeChain(tag);
346 					if (currentParagraph == null) {
347 						currentParagraph = FactoryProperties
348 								.createParagraph(cprops);
349 					}
350 					currentParagraph.add(new Chunk(img, 0, 0));
351 				}
352 				return;
353 			}
354 			endElement("p");
355 			if (tag.equals("h1") || tag.equals("h2") || tag.equals("h3")
356 					|| tag.equals("h4") || tag.equals("h5") || tag.equals("h6")) {
357 				if (!h.containsKey(ElementTags.SIZE)) {
358 					int v = 7 - Integer.parseInt(tag.substring(1));
359 					h.put(ElementTags.SIZE, Integer.toString(v));
360 				}
361 				cprops.addToChain(tag, h);
362 				return;
363 			}
364 			if (tag.equals(HtmlTags.UNORDEREDLIST)) {
365 				if (pendingLI)
366 					endElement(HtmlTags.LISTITEM);
367 				skipText = true;
368 				cprops.addToChain(tag, h);
369 				com.lowagie.text.List list = new com.lowagie.text.List(false);
370 				try{
371 					list.setIndentationLeft(new Float(cprops.getProperty("indent")).floatValue());
372 				}catch (Exception e) {
373 					list.setAutoindent(true);
374 				}
375 				list.setListSymbol("\u2022");
376 				stack.push(list);
377 				return;
378 			}
379 			if (tag.equals(HtmlTags.ORDEREDLIST)) {
380 				if (pendingLI)
381 					endElement(HtmlTags.LISTITEM);
382 				skipText = true;
383 				cprops.addToChain(tag, h);
384 				com.lowagie.text.List list = new com.lowagie.text.List(true);
385 				try{
386 					list.setIndentationLeft(new Float(cprops.getProperty("indent")).floatValue());
387 				}catch (Exception e) {
388 					list.setAutoindent(true);
389 				}
390 				stack.push(list);
391 				return;
392 			}
393 			if (tag.equals(HtmlTags.LISTITEM)) {
394 				if (pendingLI)
395 					endElement(HtmlTags.LISTITEM);
396 				skipText = false;
397 				pendingLI = true;
398 				cprops.addToChain(tag, h);
399 				ListItem item = FactoryProperties.createListItem(cprops);
400 				stack.push(item);
401 				return;
402 			}
403 			if (tag.equals(HtmlTags.DIV) || tag.equals(HtmlTags.BODY) || tag.equals("p")) {
404 				cprops.addToChain(tag, h);
405 				return;
406 			}
407 			if (tag.equals(HtmlTags.PRE)) {
408 				if (!h.containsKey(ElementTags.FACE)) {
409 					h.put(ElementTags.FACE, "Courier");
410 				}
411 				cprops.addToChain(tag, h);
412 				isPRE = true;
413 				return;
414 			}
415 			if (tag.equals("tr")) {
416 				if (pendingTR)
417 					endElement("tr");
418 				skipText = true;
419 				pendingTR = true;
420 				cprops.addToChain("tr", h);
421 				return;
422 			}
423 			if (tag.equals("td") || tag.equals("th")) {
424 				if (pendingTD)
425 					endElement(tag);
426 				skipText = false;
427 				pendingTD = true;
428 				cprops.addToChain("td", h);
429 				stack.push(new IncCell(tag, cprops));
430 				return;
431 			}
432 			if (tag.equals("table")) {
433 				cprops.addToChain("table", h);
434 				IncTable table = new IncTable(h);
435 				stack.push(table);
436 				tableState.push(new boolean[] { pendingTR, pendingTD });
437 				pendingTR = pendingTD = false;
438 				skipText = true;
439 				return;
440 			}
441 		} catch (Exception e) {
442 			throw new ExceptionConverter(e);
443 		}
444 	}
445 
endElement(String tag)446 	public void endElement(String tag) {
447 		if (!tagsSupported.containsKey(tag))
448 			return;
449 		try {
450 			String follow = (String) FactoryProperties.followTags.get(tag);
451 			if (follow != null) {
452 				cprops.removeChain(follow);
453 				return;
454 			}
455 			if (tag.equals("font") || tag.equals("span")) {
456 				cprops.removeChain(tag);
457 				return;
458 			}
459 			if (tag.equals("a")) {
460 				if (currentParagraph == null) {
461 					currentParagraph = new Paragraph();
462 				}
463 				boolean skip = false;
464 				if (interfaceProps != null) {
465 					ALink i = (ALink) interfaceProps.get("alink_interface");
466 					if (i != null)
467 						skip = i.process(currentParagraph, cprops);
468 				}
469 				if (!skip) {
470 					String href = cprops.getProperty("href");
471 					if (href != null) {
472 						ArrayList chunks = currentParagraph.getChunks();
473 						int size = chunks.size();
474 						for (int k = 0; k < size; ++k) {
475 							Chunk ck = (Chunk) chunks.get(k);
476 							ck.setAnchor(href);
477 						}
478 					}
479 				}
480 				Paragraph tmp = (Paragraph) stack.pop();
481 				Phrase tmp2 = new Phrase();
482 				tmp2.add(currentParagraph);
483 				tmp.add(tmp2);
484 				currentParagraph = tmp;
485 				cprops.removeChain("a");
486 				return;
487 			}
488 			if (tag.equals("br")) {
489 				return;
490 			}
491 			if (currentParagraph != null) {
492 				if (stack.empty())
493 					document.add(currentParagraph);
494 				else {
495 					Object obj = stack.pop();
496 					if (obj instanceof TextElementArray) {
497 						TextElementArray current = (TextElementArray) obj;
498 						current.add(currentParagraph);
499 					}
500 					stack.push(obj);
501 				}
502 			}
503 			currentParagraph = null;
504 			if (tag.equals(HtmlTags.UNORDEREDLIST)
505 					|| tag.equals(HtmlTags.ORDEREDLIST)) {
506 				if (pendingLI)
507 					endElement(HtmlTags.LISTITEM);
508 				skipText = false;
509 				cprops.removeChain(tag);
510 				if (stack.empty())
511 					return;
512 				Object obj = stack.pop();
513 				if (!(obj instanceof com.lowagie.text.List)) {
514 					stack.push(obj);
515 					return;
516 				}
517 				if (stack.empty())
518 					document.add((Element) obj);
519 				else
520 					((TextElementArray) stack.peek()).add(obj);
521 				return;
522 			}
523 			if (tag.equals(HtmlTags.LISTITEM)) {
524 				pendingLI = false;
525 				skipText = true;
526 				cprops.removeChain(tag);
527 				if (stack.empty())
528 					return;
529 				Object obj = stack.pop();
530 				if (!(obj instanceof ListItem)) {
531 					stack.push(obj);
532 					return;
533 				}
534 				if (stack.empty()) {
535 					document.add((Element) obj);
536 					return;
537 				}
538 				Object list = stack.pop();
539 				if (!(list instanceof com.lowagie.text.List)) {
540 					stack.push(list);
541 					return;
542 				}
543 				ListItem item = (ListItem) obj;
544 				((com.lowagie.text.List) list).add(item);
545 				ArrayList cks = item.getChunks();
546 				if (!cks.isEmpty())
547 					item.getListSymbol()
548 							.setFont(((Chunk) cks.get(0)).getFont());
549 				stack.push(list);
550 				return;
551 			}
552 			if (tag.equals("div") || tag.equals("body")) {
553 				cprops.removeChain(tag);
554 				return;
555 			}
556 			if (tag.equals(HtmlTags.PRE)) {
557 				cprops.removeChain(tag);
558 				isPRE = false;
559 				return;
560 			}
561 			if (tag.equals("p")) {
562 				cprops.removeChain(tag);
563 				return;
564 			}
565 			if (tag.equals("h1") || tag.equals("h2") || tag.equals("h3")
566 					|| tag.equals("h4") || tag.equals("h5") || tag.equals("h6")) {
567 				cprops.removeChain(tag);
568 				return;
569 			}
570 			if (tag.equals("table")) {
571 				if (pendingTR)
572 					endElement("tr");
573 				cprops.removeChain("table");
574 				IncTable table = (IncTable) stack.pop();
575 				PdfPTable tb = table.buildTable();
576 				tb.setSplitRows(true);
577 				if (stack.empty())
578 					document.add(tb);
579 				else
580 					((TextElementArray) stack.peek()).add(tb);
581 				boolean state[] = (boolean[]) tableState.pop();
582 				pendingTR = state[0];
583 				pendingTD = state[1];
584 				skipText = false;
585 				return;
586 			}
587 			if (tag.equals("tr")) {
588 				if (pendingTD)
589 					endElement("td");
590 				pendingTR = false;
591 				cprops.removeChain("tr");
592 				ArrayList cells = new ArrayList();
593 				IncTable table = null;
594 				while (true) {
595 					Object obj = stack.pop();
596 					if (obj instanceof IncCell) {
597 						cells.add(((IncCell) obj).getCell());
598 					}
599 					if (obj instanceof IncTable) {
600 						table = (IncTable) obj;
601 						break;
602 					}
603 				}
604 				table.addCols(cells);
605 				table.endRow();
606 				stack.push(table);
607 				skipText = true;
608 				return;
609 			}
610 			if (tag.equals("td") || tag.equals("th")) {
611 				pendingTD = false;
612 				cprops.removeChain("td");
613 				skipText = true;
614 				return;
615 			}
616 		} catch (Exception e) {
617 			throw new ExceptionConverter(e);
618 		}
619 	}
620 
text(String str)621 	public void text(String str) {
622 		if (skipText)
623 			return;
624 		String content = str;
625 		if (isPRE) {
626 			if (currentParagraph == null) {
627 				currentParagraph = FactoryProperties.createParagraph(cprops);
628 			}
629 			Chunk chunk = factoryProperties.createChunk(content, cprops);
630 			currentParagraph.add(chunk);
631 			return;
632 		}
633 		if (content.trim().length() == 0 && content.indexOf(' ') < 0) {
634 			return;
635 		}
636 
637 		StringBuffer buf = new StringBuffer();
638 		int len = content.length();
639 		char character;
640 		boolean newline = false;
641 		for (int i = 0; i < len; i++) {
642 			switch (character = content.charAt(i)) {
643 			case ' ':
644 				if (!newline) {
645 					buf.append(character);
646 				}
647 				break;
648 			case '\n':
649 				if (i > 0) {
650 					newline = true;
651 					buf.append(' ');
652 				}
653 				break;
654 			case '\r':
655 				break;
656 			case '\t':
657 				break;
658 			default:
659 				newline = false;
660 				buf.append(character);
661 			}
662 		}
663 		if (currentParagraph == null) {
664 			currentParagraph = FactoryProperties.createParagraph(cprops);
665 		}
666 		Chunk chunk = factoryProperties.createChunk(buf.toString(), cprops);
667 		currentParagraph.add(chunk);
668 	}
669 
add(Element element)670 	public boolean add(Element element) throws DocumentException {
671 		objectList.add(element);
672 		return true;
673 	}
674 
clearTextWrap()675 	public void clearTextWrap() throws DocumentException {
676 	}
677 
close()678 	public void close() {
679 	}
680 
newPage()681 	public boolean newPage() {
682 		return true;
683 	}
684 
open()685 	public void open() {
686 	}
687 
resetFooter()688 	public void resetFooter() {
689 	}
690 
resetHeader()691 	public void resetHeader() {
692 	}
693 
resetPageCount()694 	public void resetPageCount() {
695 	}
696 
setFooter(HeaderFooter footer)697 	public void setFooter(HeaderFooter footer) {
698 	}
699 
setHeader(HeaderFooter header)700 	public void setHeader(HeaderFooter header) {
701 	}
702 
setMarginMirroring(boolean marginMirroring)703 	public boolean setMarginMirroring(boolean marginMirroring) {
704 		return false;
705 	}
706 
707 	/**
708      * @see com.lowagie.text.DocListener#setMarginMirroring(boolean)
709 	 * @since	2.1.6
710 	 */
setMarginMirroringTopBottom(boolean marginMirroring)711 	public boolean setMarginMirroringTopBottom(boolean marginMirroring) {
712 		return false;
713 	}
714 
setMargins(float marginLeft, float marginRight, float marginTop, float marginBottom)715 	public boolean setMargins(float marginLeft, float marginRight,
716 			float marginTop, float marginBottom) {
717 		return true;
718 	}
719 
setPageCount(int pageN)720 	public void setPageCount(int pageN) {
721 	}
722 
setPageSize(Rectangle pageSize)723 	public boolean setPageSize(Rectangle pageSize) {
724 		return true;
725 	}
726 
727 	public static final String tagsSupportedString = "ol ul li a pre font span br p div body table td th tr i b u sub sup em strong s strike"
728 			+ " h1 h2 h3 h4 h5 h6 img hr";
729 
730 	public static final HashMap tagsSupported = new HashMap();
731 
732 	static {
733 		StringTokenizer tok = new StringTokenizer(tagsSupportedString);
734 		while (tok.hasMoreTokens())
tok.nextToken()735 			tagsSupported.put(tok.nextToken(), null);
736 	}
737 
738 }
739