1 // -*- C++ -*-
2 /**
3  * \file output_xhtml.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Richard Heck
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11 
12 #ifndef OUTPUT_XHTML_H
13 #define OUTPUT_XHTML_H
14 
15 #include "LayoutEnums.h"
16 
17 #include "support/docstream.h"
18 #include "support/strfwd.h"
19 
20 #include <deque>
21 #include <memory>
22 
23 
24 namespace lyx {
25 
26 class Buffer;
27 class OutputParams;
28 class Text;
29 
30 // Inspiration for the *Tag structs and for XHTMLStream
31 // came from MathStream and its cousins.
32 
33 namespace html {
34 
35 struct FontTag;
36 struct EndFontTag;
37 
38 /// Attributes will be escaped automatically and so should NOT
39 /// be escaped before being passed to the constructor.
40 struct StartTag
41 {
42 	///
StartTagStartTag43 	explicit StartTag(std::string const & tag) : tag_(tag), keepempty_(false) {}
44 	///
45 	explicit StartTag(std::string const & tag, std::string const & attr,
46 		bool keepempty = false)
tag_StartTag47 		: tag_(tag), attr_(attr), keepempty_(keepempty) {}
48 	///
~StartTagStartTag49 	virtual ~StartTag() {}
50 	/// <tag_ attr_>
51 	virtual docstring writeTag() const;
52 	/// </tag_>
53 	virtual docstring writeEndTag() const;
54 	///
asFontTagStartTag55 	virtual FontTag const * asFontTag() const { return 0; }
56 	///
57 	virtual bool operator==(StartTag const & rhs) const
58 		{ return tag_ == rhs.tag_; }
59 	///
60 	virtual bool operator!=(StartTag const & rhs) const
61 		{ return !(*this == rhs); }
62 	///
63 	virtual bool operator==(FontTag const & rhs) const;
64 	///
65 	std::string tag_;
66 	///
67 	std::string attr_;
68 	/// whether to keep things like "<tag></tag>" or discard them
69 	/// you would want this for td, e.g, but maybe not for a div
70 	bool keepempty_;
71 };
72 
73 
74 ///
75 struct EndTag
76 {
77 	///
EndTagEndTag78 	explicit EndTag(std::string tag) : tag_(tag) {}
79 	///
~EndTagEndTag80 	virtual ~EndTag() {}
81 	/// </tag_>
82 	virtual docstring writeEndTag() const;
83 	///
84 	bool operator==(StartTag const & rhs) const
85 		{ return tag_ == rhs.tag_; }
86 	///
87 	bool operator!=(StartTag const & rhs) const
88 		{ return !(*this == rhs); }
89 	///
asFontTagEndTag90 	virtual EndFontTag const * asFontTag() const { return 0; }
91 	///
92 	std::string tag_;
93 };
94 
95 
96 /// Tags like <img />
97 /// Attributes will be escaped automatically and so should NOT
98 /// be escaped before being passed to the constructor.
99 struct CompTag
100 {
101 	///
CompTagCompTag102 	explicit CompTag(std::string const & tag)
103 		: tag_(tag) {}
104 	///
CompTagCompTag105 	explicit CompTag(std::string const & tag, std::string const & attr)
106 		: tag_(tag), attr_(attr) {}
107 	/// <tag_ attr_ />
108 	docstring writeTag() const;
109 	///
110 	std::string tag_;
111 	///
112 	std::string attr_;
113 };
114 
115 
116 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
117 struct ParTag : public StartTag
118 {
119 	///
120 	explicit ParTag(std::string const & tag, std::string attr,
121 	       std::string const & parid);
122 	///
~ParTagParTag123 	~ParTag() {}
124 };
125 
126 
127 ///
128 enum FontTypes {
129 	// ranges
130 	FT_EMPH,
131 	FT_NOUN,
132 	FT_UBAR,
133 	FT_DBAR,
134 	FT_WAVE,
135 	FT_SOUT,
136 	FT_XOUT,
137 	// bold
138 	FT_BOLD,
139 	// shapes
140 	FT_UPRIGHT,
141 	FT_ITALIC,
142 	FT_SLANTED,
143 	FT_SMALLCAPS,
144 	// families
145 	FT_ROMAN,
146 	FT_SANS,
147 	FT_TYPE,
148 	// sizes
149 	FT_SIZE_TINY,
150 	FT_SIZE_SCRIPT,
151 	FT_SIZE_FOOTNOTE,
152 	FT_SIZE_SMALL,
153 	FT_SIZE_NORMAL,
154 	FT_SIZE_LARGE,
155 	FT_SIZE_LARGER,
156 	FT_SIZE_LARGEST,
157 	FT_SIZE_HUGE,
158 	FT_SIZE_HUGER,
159 	FT_SIZE_INCREASE,
160 	FT_SIZE_DECREASE
161 };
162 
163 
164 ///
165 struct FontTag : public StartTag
166 {
167 	///
168 	explicit FontTag(FontTypes type);
169 	///
asFontTagFontTag170 	FontTag const * asFontTag() const { return this; }
171 	///
172 	bool operator==(StartTag const &) const;
173 	///
174 	FontTypes font_type_;
175 };
176 
177 
178 ///
179 struct EndFontTag : public EndTag
180 {
181 	///
182 	explicit EndFontTag(FontTypes type);
183 	///
asFontTagEndFontTag184 	EndFontTag const * asFontTag() const { return this; }
185 	///
186 	FontTypes font_type_;
187 };
188 
189 
190 // trivial struct for output of newlines
191 struct CR{};
192 
193 } // namespace html
194 
195 class XHTMLStream {
196 public:
197 	///
198 	explicit XHTMLStream(odocstream & os);
199 	///
os()200 	odocstream & os() { return os_; }
201 	///
202 	// int & tab() { return tab_; }
203 	/// closes any font tags that are eligible to be closed,
204 	/// i.e., last on the tag_stack_.
205 	/// \return false if there are open font tags we could not close.
206 	/// because they are "blocked" by open non-font tags on the stack.
207 	bool closeFontTags();
208 	/// sets a mark so we know what tags to close at the end.
209 	/// normally called at the start of a paragraph.
210 	void startDivision(bool keep_empty);
211 	/// clears the mark set by previous method.
212 	/// there should not be any other tags open before it on the stack,
213 	/// but if there are, we will close them.
214 	void endDivision();
215 	///
216 	XHTMLStream & operator<<(docstring const &);
217 	///
218 	XHTMLStream & operator<<(const char *);
219 	///
220 	XHTMLStream & operator<<(char_type);
221 	///
222 	XHTMLStream & operator<<(int);
223 	///
224 	XHTMLStream & operator<<(char);
225 	///
226 	XHTMLStream & operator<<(html::StartTag const &);
227 	///
228 	XHTMLStream & operator<<(html::EndTag const &);
229 	///
230 	XHTMLStream & operator<<(html::CompTag const &);
231 	///
232 	XHTMLStream & operator<<(html::ParTag const &);
233 	///
234 	XHTMLStream & operator<<(html::FontTag const &);
235 	///
236 	XHTMLStream & operator<<(html::CR const &);
237 	///
238 	enum EscapeSettings {
239 		ESCAPE_NONE,
240 		ESCAPE_AND, // meaning &
241 		ESCAPE_ALL  // meaning <, >, &, at present
242 	};
243 	/// Sets what we are going to escape on the NEXT write.
244 	/// Everything is reset for the next time.
245 	XHTMLStream & operator<<(EscapeSettings);
246 	/// This routine is for debugging the tag stack, etc. Code
247 	/// for it is disabled by default, however, so you will need
248 	/// to enable it if you want to use it.
249 	void dumpTagStack(std::string const & msg);
250 private:
251 	///
252 	void clearTagDeque();
253 	///
254 	bool isTagOpen(html::StartTag const &) const;
255 	///
256 	bool isTagOpen(html::EndTag const &) const;
257 	///
258 	bool isTagPending(html::StartTag const &) const;
259 	///
260 	void writeError(std::string const &) const;
261 	///
262 	odocstream & os_;
263 	///
264 	EscapeSettings escape_;
265 	// What we would really like to do here is simply use a
266 	// deque<StartTag>. But we want to store both StartTags and
267 	// sub-classes thereof on this stack, which means we run into the
268 	// so-called polymorphic class problem with the STL. We therefore have
269 	// to use a deque<StartTag *>, which leads to the question who will
270 	// own these pointers and how they will be deleted, so we use shared
271 	// pointers.
272 	///
273 	typedef std::shared_ptr<html::StartTag> TagPtr;
274 	typedef std::deque<TagPtr> TagDeque;
275 	///
276 	template <typename T>
makeTagPtr(T const & tag)277 	TagPtr makeTagPtr(T const & tag) { return std::make_shared<T>(tag); }
278 	///
279 	TagDeque pending_tags_;
280 	///
281 	TagDeque tag_stack_;
282 };
283 
284 ///
285 void xhtmlParagraphs(Text const & text,
286 		       Buffer const & buf,
287 		       XHTMLStream & xs,
288 		       OutputParams const & runparams);
289 
290 /// \return a string appropriate for setting alignment in CSS
291 /// Does NOT return "justify" for "block"
292 std::string alignmentToCSS(LyXAlignment align);
293 
294 namespace html {
295 ///
296 docstring escapeChar(char_type c, XHTMLStream::EscapeSettings e);
297 /// converts a string to a form safe for links, etc
298 docstring htmlize(docstring const & str, XHTMLStream::EscapeSettings e);
299 /// cleans \param str for use as an atttribute by replacing
300 /// all non-alnum by "_"
301 docstring cleanAttr(docstring const & str);
302 /// \p c must be ASCII
303 docstring escapeChar(char c, XHTMLStream::EscapeSettings e);
304 
305 } // namespace html
306 } // namespace lyx
307 
308 #endif
309