Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * nsIContentSerializer implementation that can be used with an
9 : * nsIDocumentEncoder to convert an XML DOM to an XML string that
10 : * could be parsed into more or less the original DOM.
11 : */
12 :
13 : #ifndef nsXMLContentSerializer_h__
14 : #define nsXMLContentSerializer_h__
15 :
16 : #include "mozilla/Attributes.h"
17 : #include "nsIContentSerializer.h"
18 : #include "nsISupportsUtils.h"
19 : #include "nsCOMPtr.h"
20 : #include "nsTArray.h"
21 : #include "nsString.h"
22 :
23 : #define kIndentStr NS_LITERAL_STRING(" ")
24 : #define kEndTag NS_LITERAL_STRING("</")
25 :
26 : class nsIAtom;
27 : class nsINode;
28 :
29 : namespace mozilla {
30 : class Encoding;
31 : }
32 :
33 : class nsXMLContentSerializer : public nsIContentSerializer {
34 : public:
35 : nsXMLContentSerializer();
36 :
37 : NS_DECL_ISUPPORTS
38 :
39 : NS_IMETHOD Init(uint32_t flags,
40 : uint32_t aWrapColumn,
41 : const mozilla::Encoding* aEncoding,
42 : bool aIsCopying,
43 : bool aRewriteEncodingDeclaration,
44 : bool* aNeedsPreformatScanning) override;
45 :
46 : NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
47 : int32_t aEndOffset, nsAString& aStr) override;
48 :
49 : NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
50 : int32_t aStartOffset, int32_t aEndOffset,
51 : nsAString& aStr) override;
52 :
53 : NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
54 : int32_t aStartOffset,
55 : int32_t aEndOffset,
56 : nsAString& aStr) override;
57 :
58 : NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset,
59 : int32_t aEndOffset, nsAString& aStr) override;
60 :
61 : NS_IMETHOD AppendDoctype(nsIContent *aDoctype,
62 : nsAString& aStr) override;
63 :
64 : NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
65 : mozilla::dom::Element* aOriginalElement,
66 : nsAString& aStr) override;
67 :
68 : NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
69 : nsAString& aStr) override;
70 :
71 0 : NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; }
72 :
73 : NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
74 : nsAString& aStr) override;
75 :
76 0 : NS_IMETHOD ScanElementForPreformat(mozilla::dom::Element* aElement) override
77 : {
78 0 : return NS_OK;
79 : }
80 0 : NS_IMETHOD ForgetElementForPreformat(mozilla::dom::Element* aElement) override
81 : {
82 0 : return NS_OK;
83 : }
84 :
85 : protected:
86 : virtual ~nsXMLContentSerializer();
87 :
88 : /**
89 : * Appends a char16_t character and increments the column position
90 : */
91 : MOZ_MUST_USE
92 : bool AppendToString(const char16_t aChar,
93 : nsAString& aOutputStr);
94 :
95 : /**
96 : * Appends a nsAString string and increments the column position
97 : */
98 : MOZ_MUST_USE
99 : bool AppendToString(const nsAString& aStr,
100 : nsAString& aOutputStr);
101 :
102 : /**
103 : * Appends a string by replacing all line-endings
104 : * by mLineBreak, except in the case of raw output.
105 : * It increments the column position.
106 : */
107 : MOZ_MUST_USE
108 : bool AppendToStringConvertLF(const nsAString& aStr,
109 : nsAString& aOutputStr);
110 :
111 : /**
112 : * Appends a string by wrapping it when necessary.
113 : * It updates the column position.
114 : */
115 : MOZ_MUST_USE
116 : bool AppendToStringWrapped(const nsAString& aStr,
117 : nsAString& aOutputStr);
118 :
119 : /**
120 : * Appends a string by formating and wrapping it when necessary
121 : * It updates the column position.
122 : */
123 : MOZ_MUST_USE
124 : bool AppendToStringFormatedWrapped(const nsAString& aStr,
125 : nsAString& aOutputStr);
126 :
127 : // used by AppendToStringWrapped
128 : MOZ_MUST_USE
129 : bool AppendWrapped_WhitespaceSequence(
130 : nsAString::const_char_iterator &aPos,
131 : const nsAString::const_char_iterator aEnd,
132 : const nsAString::const_char_iterator aSequenceStart,
133 : nsAString &aOutputStr);
134 :
135 : // used by AppendToStringFormatedWrapped
136 : MOZ_MUST_USE
137 : bool AppendFormatedWrapped_WhitespaceSequence(
138 : nsAString::const_char_iterator &aPos,
139 : const nsAString::const_char_iterator aEnd,
140 : const nsAString::const_char_iterator aSequenceStart,
141 : bool &aMayIgnoreStartOfLineWhitespaceSequence,
142 : nsAString &aOutputStr);
143 :
144 : // used by AppendToStringWrapped and AppendToStringFormatedWrapped
145 : MOZ_MUST_USE
146 : bool AppendWrapped_NonWhitespaceSequence(
147 : nsAString::const_char_iterator &aPos,
148 : const nsAString::const_char_iterator aEnd,
149 : const nsAString::const_char_iterator aSequenceStart,
150 : bool &aMayIgnoreStartOfLineWhitespaceSequence,
151 : bool &aSequenceStartAfterAWhiteSpace,
152 : nsAString &aOutputStr);
153 :
154 : /**
155 : * add mLineBreak to the string
156 : * It updates the column position and other flags.
157 : */
158 : MOZ_MUST_USE
159 : bool AppendNewLineToString(nsAString& aOutputStr);
160 :
161 :
162 : /**
163 : * Appends a string by translating entities
164 : * It doesn't increment the column position
165 : */
166 : MOZ_MUST_USE
167 : virtual bool AppendAndTranslateEntities(const nsAString& aStr,
168 : nsAString& aOutputStr);
169 :
170 : /**
171 : * retrieve the text content of the node and append it to the given string
172 : * It doesn't increment the column position
173 : */
174 : nsresult AppendTextData(nsIContent* aNode,
175 : int32_t aStartOffset,
176 : int32_t aEndOffset,
177 : nsAString& aStr,
178 : bool aTranslateEntities);
179 :
180 : virtual nsresult PushNameSpaceDecl(const nsAString& aPrefix,
181 : const nsAString& aURI,
182 : nsIContent* aOwner);
183 : void PopNameSpaceDeclsFor(nsIContent* aOwner);
184 :
185 : /**
186 : * The problem that ConfirmPrefix fixes is that anyone can insert nodes
187 : * through the DOM that have a namespace URI and a random or empty or
188 : * previously existing prefix that's totally unrelated to the prefixes
189 : * declared at that point through xmlns attributes. So what ConfirmPrefix
190 : * does is ensure that we can map aPrefix to the namespace URI aURI (for
191 : * example, that the prefix is not already mapped to some other namespace).
192 : * aPrefix will be adjusted, if necessary, so the value of the prefix
193 : * _after_ this call is what should be serialized.
194 : * @param aPrefix the prefix that may need adjusting
195 : * @param aURI the namespace URI we want aPrefix to point to
196 : * @param aElement the element we're working with (needed for proper default
197 : * namespace handling)
198 : * @param aIsAttribute true if we're confirming a prefix for an attribute.
199 : * @return true if we need to push the (prefix, uri) pair on the namespace
200 : * stack (note that this can happen even if the prefix is
201 : * empty).
202 : */
203 : bool ConfirmPrefix(nsAString& aPrefix,
204 : const nsAString& aURI,
205 : nsIContent* aElement,
206 : bool aIsAttribute);
207 : /**
208 : * GenerateNewPrefix generates a new prefix and writes it to aPrefix
209 : */
210 : void GenerateNewPrefix(nsAString& aPrefix);
211 :
212 : uint32_t ScanNamespaceDeclarations(nsIContent* aContent,
213 : nsIContent *aOriginalElement,
214 : const nsAString& aTagNamespaceURI);
215 :
216 : MOZ_MUST_USE
217 : virtual bool SerializeAttributes(nsIContent* aContent,
218 : nsIContent *aOriginalElement,
219 : nsAString& aTagPrefix,
220 : const nsAString& aTagNamespaceURI,
221 : nsIAtom* aTagName,
222 : nsAString& aStr,
223 : uint32_t aSkipAttr,
224 : bool aAddNSAttr);
225 :
226 : MOZ_MUST_USE
227 : bool SerializeAttr(const nsAString& aPrefix,
228 : const nsAString& aName,
229 : const nsAString& aValue,
230 : nsAString& aStr,
231 : bool aDoEscapeEntities);
232 :
233 : bool IsJavaScript(nsIContent * aContent,
234 : nsIAtom* aAttrNameAtom,
235 : int32_t aAttrNamespaceID,
236 : const nsAString& aValueString);
237 :
238 : /**
239 : * This method can be redefined to check if the element can be serialized.
240 : * It is called when the serialization of the start tag is asked
241 : * (AppendElementStart)
242 : * In this method you can also force the formating
243 : * by setting aForceFormat to true.
244 : * @return boolean true if the element can be output
245 : */
246 : virtual bool CheckElementStart(nsIContent * aContent,
247 : bool & aForceFormat,
248 : nsAString& aStr,
249 : nsresult& aResult);
250 :
251 : /**
252 : * This method is responsible for appending the '>' at the end of the start
253 : * tag, possibly preceded by '/' and maybe a ' ' before that too.
254 : *
255 : * aElement and aOriginalElement are the same as the corresponding arguments
256 : * to AppendElementStart.
257 : */
258 : MOZ_MUST_USE
259 : bool AppendEndOfElementStart(mozilla::dom::Element* aEleemnt,
260 : mozilla::dom::Element* aOriginalElement,
261 : nsAString& aStr);
262 :
263 : /**
264 : * This method can be redefine to serialize additional things just after
265 : * after the serialization ot the start tag.
266 : * (called at the end of AppendElementStart)
267 : */
268 : MOZ_MUST_USE
269 0 : virtual bool AfterElementStart(nsIContent* aContent,
270 : nsIContent* aOriginalElement,
271 0 : nsAString& aStr) { return true; };
272 :
273 : /**
274 : * This method can be redefined to check if the element can be serialized.
275 : * It is called when the serialization of the end tag is asked
276 : * (AppendElementEnd)
277 : * In this method you can also force the formating
278 : * by setting aForceFormat to true.
279 : * @return boolean true if the element can be output
280 : */
281 : virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
282 : bool& aForceFormat,
283 : nsAString& aStr);
284 :
285 : /**
286 : * This method can be redefine to serialize additional things just after
287 : * after the serialization ot the end tag.
288 : * (called at the end of AppendElementStart)
289 : */
290 0 : virtual void AfterElementEnd(nsIContent * aContent,
291 0 : nsAString& aStr) { };
292 :
293 : /**
294 : * Returns true if a line break should be inserted before an element open tag
295 : */
296 : virtual bool LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName);
297 :
298 : /**
299 : * Returns true if a line break should be inserted after an element open tag
300 : */
301 : virtual bool LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName);
302 :
303 : /**
304 : * Returns true if a line break should be inserted after an element close tag
305 : */
306 : virtual bool LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName);
307 :
308 : /**
309 : * Returns true if a line break should be inserted after an element close tag
310 : */
311 : virtual bool LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName);
312 :
313 : /**
314 : * add intendation. Call only in the case of formating and if the current
315 : * position is at 0. It updates the column position.
316 : */
317 : MOZ_MUST_USE
318 : bool AppendIndentation(nsAString& aStr);
319 :
320 : MOZ_MUST_USE
321 : bool IncrIndentation(nsIAtom* aName);
322 : void DecrIndentation(nsIAtom* aName);
323 :
324 : // Functions to check for newlines that needs to be added between nodes in
325 : // the root of a document. See mAddNewlineForRootNode
326 : MOZ_MUST_USE
327 : bool MaybeAddNewlineForRootNode(nsAString& aStr);
328 : void MaybeFlagNewlineForRootNode(nsINode* aNode);
329 :
330 : // Functions to check if we enter in or leave from a preformated content
331 : virtual void MaybeEnterInPreContent(nsIContent* aNode);
332 : virtual void MaybeLeaveFromPreContent(nsIContent* aNode);
333 :
334 : bool ShouldMaintainPreLevel() const;
335 : int32_t PreLevel() const {
336 : MOZ_ASSERT(ShouldMaintainPreLevel());
337 : return mPreLevel;
338 : }
339 0 : int32_t& PreLevel() {
340 0 : MOZ_ASSERT(ShouldMaintainPreLevel());
341 0 : return mPreLevel;
342 : }
343 :
344 : int32_t mPrefixIndex;
345 :
346 0 : struct NameSpaceDecl {
347 : nsString mPrefix;
348 : nsString mURI;
349 : nsIContent* mOwner;
350 : };
351 :
352 : nsTArray<NameSpaceDecl> mNameSpaceStack;
353 :
354 : // nsIDocumentEncoder flags
355 : MOZ_INIT_OUTSIDE_CTOR uint32_t mFlags;
356 :
357 : // characters to use for line break
358 : nsString mLineBreak;
359 :
360 : // The charset that was passed to Init()
361 : nsCString mCharset;
362 :
363 : // current column position on the current line
364 : uint32_t mColPos;
365 :
366 : // true = pretty formating should be done (OutputFormated flag)
367 : MOZ_INIT_OUTSIDE_CTOR bool mDoFormat;
368 :
369 : // true = no formatting,(OutputRaw flag)
370 : // no newline convertion and no rewrap long lines even if OutputWrap is set.
371 : MOZ_INIT_OUTSIDE_CTOR bool mDoRaw;
372 :
373 : // true = wrapping should be done (OutputWrap flag)
374 : MOZ_INIT_OUTSIDE_CTOR bool mDoWrap;
375 :
376 : // true = we can break lines (OutputDisallowLineBreaking flag)
377 : MOZ_INIT_OUTSIDE_CTOR bool mAllowLineBreaking;
378 :
379 : // number of maximum column in a line, in the wrap mode
380 : MOZ_INIT_OUTSIDE_CTOR uint32_t mMaxColumn;
381 :
382 : // current indent value
383 : nsString mIndent;
384 :
385 : // this is the indentation level after the indentation reached
386 : // the maximum length of indentation
387 : int32_t mIndentOverflow;
388 :
389 : // says if the indentation has been already added on the current line
390 : bool mIsIndentationAddedOnCurrentLine;
391 :
392 : // the string which is currently added is in an attribute
393 : bool mInAttribute;
394 :
395 : // true = a newline character should be added. It's only
396 : // useful when serializing root nodes. see MaybeAddNewlineForRootNode and
397 : // MaybeFlagNewlineForRootNode
398 : bool mAddNewlineForRootNode;
399 :
400 : // Indicates that a space will be added if and only if content is
401 : // continued on the same line while serializing source. Otherwise,
402 : // the newline character acts as the whitespace and no space is needed.
403 : // used when mDoFormat = true
404 : bool mAddSpace;
405 :
406 : // says that if the next string to add contains a newline character at the
407 : // begining, then this newline character should be ignored, because a
408 : // such character has already been added into the output string
409 : bool mMayIgnoreLineBreakSequence;
410 :
411 : bool mBodyOnly;
412 : int32_t mInBody;
413 :
414 : private:
415 : // number of nested elements which have preformated content
416 : MOZ_INIT_OUTSIDE_CTOR int32_t mPreLevel;
417 : };
418 :
419 : nsresult
420 : NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);
421 :
422 : #endif
|