]> git.lyx.org Git - lyx.git/blob - src/xml.h
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / xml.h
1 // -*- C++ -*-
2 /**
3  * \file xml.h
4  * This file is part of LyX, the document processor.
5  * License details can be found in the file COPYING.
6  *
7  * \author José Matos
8  * \author John Levon
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #ifndef XML_H
14 #define XML_H
15
16 #include "support/docstring.h"
17
18 #include <deque>
19 #include <memory>
20
21 namespace lyx {
22
23 class Buffer;
24 class Paragraph;
25 class OutputParams;
26
27 // Inspiration for the *Tag structs and for XMLStream
28 // came from MathMLStream and its cousins.
29
30 namespace xml {
31 struct StartTag;
32 struct EndTag;
33 struct CompTag;
34 struct NullTag;
35 struct ParTag;
36 struct FontTag;
37 struct CR;
38 }
39
40 class XMLStream {
41 public:
42         ///
43         explicit XMLStream(odocstream & os): os_(os), escape_(ESCAPE_ALL), is_last_tag_cr_(true) {}
44         ///
45         odocstream & os() { return os_; }
46         ///
47         // int & tab() { return tab_; }
48         /// closes any font tags that are eligible to be closed,
49         /// i.e., last on the tag_stack_.
50         /// \return false if there are open font tags we could not close.
51         /// because they are "blocked" by open non-font tags on the stack.
52         bool closeFontTags();
53         /// sets a mark so we know what tags to close at the end.
54         /// normally called at the start of a paragraph.
55         void startDivision(bool keep_empty);
56         /// clears the mark set by previous method.
57         /// there should not be any other tags open before it on the stack,
58         /// but if there are, we will close them.
59         void endDivision();
60         ///
61         XMLStream & operator<<(docstring const &);
62         ///
63         XMLStream & operator<<(const char *);
64         ///
65         XMLStream & operator<<(char_type);
66         ///
67         XMLStream & operator<<(int);
68         ///
69         XMLStream & operator<<(char);
70         ///
71         XMLStream & operator<<(xml::NullTag const &);
72         ///
73         XMLStream & operator<<(xml::StartTag const &);
74         ///
75         XMLStream & operator<<(xml::EndTag const &);
76         ///
77         XMLStream & operator<<(xml::CompTag const &);
78         ///
79         XMLStream & operator<<(xml::ParTag const &);
80         ///
81         XMLStream & operator<<(xml::FontTag const &);
82         ///
83         XMLStream & operator<<(xml::CR const &);
84         ///
85         enum EscapeSettings {
86                 ESCAPE_NONE,
87                 ESCAPE_AND, // meaning &
88                 ESCAPE_ALL, // meaning <, >, &, at present, except things that are forbidden in comments
89                 ESCAPE_COMMENTS // Anything that is forbidden within comments
90         };
91         /// Sets what we are going to escape on the NEXT write.
92         /// Everything is reset for the next time.
93         XMLStream & operator<<(EscapeSettings);
94         /// This routine is for debugging the tag stack, etc. Code
95         /// for it is disabled by default, however, so you will need
96         /// to enable it if you want to use it.
97         void dumpTagStack(std::string const & msg);
98         ///
99         bool isTagOpen(xml::StartTag const &, int maxdepth = -1) const;
100         ///
101         bool isTagOpen(xml::EndTag const &, int maxdepth = -1) const;
102         ///
103         bool isTagPending(xml::StartTag const &, int maxdepth = -1) const;
104         /// Is the last tag that was added to the stream a new line (CR)? This is mostly to known
105         /// whether a new line must be added. Therefore, consider that an empty stream just had a CR,
106         /// that simplifies the logic using this code.
107         bool isLastTagCR() const { return is_last_tag_cr_; }
108         ///
109         void writeError(std::string const &);
110         ///
111         void writeError(docstring const &);
112         ///
113         typedef std::shared_ptr<xml::StartTag> TagPtr;
114         /// Returns the last element on the tag stack. XMLStream keeps ownership of the item.
115         TagPtr getLastStackTag();
116 private:
117         ///
118         void clearTagDeque();
119         ///
120         odocstream & os_;
121         ///
122         EscapeSettings escape_;
123         // What we would really like to do here is simply use a
124         // deque<StartTag>. But we want to store both StartTags and
125         // sub-classes thereof on this stack, which means we run into the
126         // so-called polymorphic class problem with the STL. We therefore have
127         // to use a deque<StartTag *>, which leads to the question who will
128         // own these pointers and how they will be deleted, so we use shared
129         // pointers.
130         ///
131         typedef std::deque<TagPtr> TagDeque;
132         ///
133         template <typename T>
134         TagPtr makeTagPtr(T const & tag) { return std::make_shared<T>(tag); }
135         ///
136         TagDeque pending_tags_;
137         ///
138         TagDeque tag_stack_;
139         ///
140         bool is_last_tag_cr_;
141 };
142
143 namespace xml {
144
145 /// Escape the given character, if necessary, to an entity.
146 docstring escapeChar(char_type c, XMLStream::EscapeSettings e);
147
148 /// Escape the given character, if necessary, to an entity.
149 /// \param c must be ASCII
150 docstring escapeChar(char c, XMLStream::EscapeSettings e);
151
152 /// Escape a word instead of a single character
153 docstring escapeString(docstring const & raw, XMLStream::EscapeSettings e=XMLStream::ESCAPE_ALL);
154
155 /// cleans \param str for use as an attribute by replacing all non-altnum by "_"
156 docstring cleanAttr(docstring const & str);
157
158 /// replaces illegal characters from ID attributes
159 docstring cleanID(docstring const &orig);
160
161 /// returns a unique numeric ID
162 docstring uniqueID(docstring const & label);
163
164 /// determines whether a string only contains space characters
165 bool isNotOnlySpace(docstring const & str);
166
167 /// trims the string to the left, i.e. remove any space-like character at the beginning of the string
168 docstring trimLeft(docstring const & str);
169
170 struct FontTag;
171 struct EndFontTag;
172
173 /// Attributes will be escaped automatically and so should NOT
174 /// be escaped before being passed to the constructor.
175 struct StartTag
176 {
177         ///
178         explicit StartTag(std::string const & tag) : tag_(from_ascii(tag)), keepempty_(false), tagtype_("none") {}
179         ///
180         explicit StartTag(docstring const & tag) : tag_(tag), keepempty_(false), tagtype_("none") {}
181         ///
182         explicit StartTag(docstring const & tag, docstring const & attr,
183                                           bool keepempty = false, std::string const & tagtype = "none")
184                         : tag_(tag), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
185         ///
186         explicit StartTag(std::string const & tag, std::string const & attr,
187                                           bool keepempty = false, std::string const & tagtype = "none")
188                         : tag_(from_ascii(tag)), attr_(from_utf8(attr)), keepempty_(keepempty), tagtype_(tagtype) {}
189         ///
190         explicit StartTag(std::string const & tag, docstring const & attr,
191                                           bool keepempty = false, std::string const & tagtype = "none")
192                         : tag_(from_ascii(tag)), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
193         ///
194         virtual ~StartTag() = default;
195         /// <tag_ attr_>
196         virtual docstring writeTag() const;
197         /// </tag_>
198         virtual docstring writeEndTag() const;
199         ///
200         virtual FontTag const * asFontTag() const { return nullptr; }
201         ///
202         docstring tag_;
203         ///
204         docstring attr_;
205         /// whether to keep things like "<tag></tag>" or discard them
206         /// you would want this for td, e.g, but maybe not for a div
207         bool keepempty_;
208         /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
209         std::string tagtype_;
210 };
211
212
213 ///
214 struct EndTag
215 {
216         ///
217         explicit EndTag(std::string const & tag, std::string const & tagtype = "none")
218                 : tag_(from_ascii(tag)), tagtype_(tagtype) {}
219         ///
220         explicit EndTag(docstring const & tag, std::string const & tagtype = "none")
221                 : tag_(tag), tagtype_(tagtype) {}
222         ///
223         virtual ~EndTag() = default;
224         /// </tag_>
225         virtual docstring writeEndTag() const;
226         ///
227         virtual EndFontTag const * asFontTag() const { return nullptr; }
228         ///
229         docstring tag_;
230         /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
231         /// The value should match that of the corresponding xml::StartTag.
232         std::string tagtype_;
233 };
234
235
236 /// Tags like <img />
237 /// Attributes will be escaped automatically and so should NOT
238 /// be escaped before being passed to the constructor.
239 struct CompTag
240 {
241         ///
242         explicit CompTag(std::string const & tag)
243                         : tag_(from_utf8(tag)), tagtype_("none") {}
244         ///
245         explicit CompTag(docstring const & tag)
246                         : tag_(tag), tagtype_("none") {}
247         ///
248         explicit CompTag(std::string const & tag, std::string const & attr, std::string const & tagtype = "none")
249                         : tag_(from_utf8(tag)), attr_(from_utf8(attr)), tagtype_(tagtype) {}
250         ///
251         explicit CompTag(std::string const & tag, docstring const & attr, std::string const & tagtype = "none")
252                         : tag_(from_utf8(tag)), attr_(attr), tagtype_(tagtype) {}
253         ///
254         explicit CompTag(docstring const & tag, std::string const & attr, std::string const & tagtype = "none")
255                         : tag_(tag), attr_(from_utf8(attr)), tagtype_(tagtype) {}
256         ///
257         explicit CompTag(docstring const & tag, docstring const & attr, std::string const & tagtype = "none")
258                         : tag_(tag), attr_(attr), tagtype_(tagtype) {}
259         /// <tag_ attr_ />
260         docstring writeTag() const;
261         ///
262         docstring tag_;
263         ///
264         docstring attr_;
265         /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
266         std::string tagtype_;
267 };
268
269
270 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
271 struct ParTag : public StartTag
272 {
273         ///
274         explicit ParTag(std::string const & tag, const std::string & attr): StartTag(tag, from_utf8(attr)) {}
275         ///
276         ~ParTag() override = default;
277 };
278
279
280 /// A special tag that doesn't produce any XML output, but makes the XMLStream behave as it it output some text.
281 struct NullTag : public StartTag
282 {
283         ///
284         NullTag(): StartTag("NULLTAG", from_utf8(""), true) {}
285         ///
286         ~NullTag() override = default;
287 };
288
289
290 ///
291 enum FontTypes {
292         // ranges
293         FT_EMPH,
294         FT_NOUN,
295         FT_UBAR,
296         FT_DBAR,
297         FT_WAVE,
298         FT_SOUT,
299         FT_XOUT,
300         // bold
301         FT_BOLD,
302         // shapes
303         FT_UPRIGHT,
304         FT_ITALIC,
305         FT_SLANTED,
306         FT_SMALLCAPS,
307         // families
308         FT_ROMAN,
309         FT_SANS,
310         FT_TYPE,
311         // sizes
312         FT_SIZE_TINY,
313         FT_SIZE_SCRIPT,
314         FT_SIZE_FOOTNOTE,
315         FT_SIZE_SMALL,
316         FT_SIZE_NORMAL,
317         FT_SIZE_LARGE,
318         FT_SIZE_LARGER,
319         FT_SIZE_LARGEST,
320         FT_SIZE_HUGE,
321         FT_SIZE_HUGER,
322         FT_SIZE_INCREASE,
323         FT_SIZE_DECREASE
324
325         // When updating this list, also update fontToTag in both output_docbook.cpp and output_xhtml.cpp,
326         // fontToRole in output_docbook.cpp, and fontToAttribute in output_xhtml.cpp.
327 };
328
329
330 ///
331 struct FontTag : public StartTag
332 {
333         ///
334         FontTag(docstring const & tag, FontTypes type): StartTag(tag), font_type_(type) {}
335         ///
336         FontTag(std::string const & tag, FontTypes type): StartTag(from_utf8(tag)), font_type_(type) {}
337         ///
338         FontTag(docstring const & tag, docstring const & attr, FontTypes type): StartTag(tag, attr), font_type_(type) {}
339         ///
340         FontTag(std::string const & tag, std::string const & attr, FontTypes type): StartTag(from_utf8(tag), from_utf8(attr)), font_type_(type) {}
341         ///
342         FontTag const * asFontTag() const override { return this; }
343         ///
344         FontTypes font_type_;
345 };
346
347
348 ///
349 struct EndFontTag : public EndTag
350 {
351         ///
352         EndFontTag(docstring const & tag, FontTypes type): EndTag(tag), font_type_(type) {}
353         ///
354         EndFontTag(std::string const & tag, FontTypes type): EndTag(from_utf8(tag)), font_type_(type) {}
355         ///
356         EndFontTag const * asFontTag() const override { return this; }
357         ///
358         FontTypes font_type_;
359 };
360
361
362 // trivial struct for output of newlines
363 struct CR{};
364
365 // an illegal tag for internal use
366 xml::StartTag const parsep_tag("&LyX_parsep_tag&");
367
368 /// Open tag
369 void openTag(odocstream & os, std::string const & name,
370              std::string const & attribute = std::string());
371
372 /// Open tag
373 void openTag(Buffer const & buf, odocstream & os,
374              OutputParams const & runparams, Paragraph const & par);
375
376 /// Close tag
377 void closeTag(odocstream & os, std::string const & name);
378
379 /// Close tag
380 void closeTag(odocstream & os, Paragraph const & par);
381
382 // Convenience functions to open and close tags. First, very low-level ones to ensure a consistent new-line behaviour.
383 // Block style:
384 //        Content before
385 //        <blocktag>
386 //          Contents of the block.
387 //        </blocktag>
388 //        Content after
389 // Paragraph style:
390 //        Content before
391 //          <paratag>Contents of the paragraph.</paratag>
392 //        Content after
393 // Inline style:
394 //    Content before<inlinetag>Contents of the paragraph.</inlinetag>Content after
395
396 ///
397 void openTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
398 ///
399 void openTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
400 ///
401 void openTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
402 ///
403 void openTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
404 ///
405 void closeTag(XMLStream & xs, const docstring & tag, const std::string & tagtype);
406 ///
407 void closeTag(XMLStream & xs, const std::string & tag, const std::string & tagtype);
408 ///
409 void compTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
410 ///
411 void compTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
412 ///
413 void compTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
414 ///
415 void compTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
416
417 } // namespace xml
418
419
420 /// Comparison operators for tags. They are defined as free functions, otherwise comparison of casts does not work.
421 /// For font tags, do not only compare the XML tag, but also the font type: several fonts can be using the same tag.
422 /// In XHTML, <span>; in DocBook, <emphasis>.
423 bool operator==(xml::StartTag const & lhs, xml::StartTag const & rhs);
424 bool operator==(xml::EndTag const & lhs, xml::StartTag const & rhs);
425 bool operator!=(xml::EndTag const & lhs, xml::StartTag const & rhs);
426 bool operator!=(xml::StartTag const & lhs, xml::StartTag const & rhs);
427
428 } // namespace lyx
429
430 #endif // XML_H