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