1 | /* |
2 | * Copyright (C) 2011 Google Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions are |
6 | * met: |
7 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * |
11 | * 2. Redistributions in binary form must reproduce the above |
12 | * copyright notice, this list of conditions and the following disclaimer |
13 | * in the documentation and/or other materials provided with the |
14 | * distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS |
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. |
20 | * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | #include "XMLErrors.h" |
31 | |
32 | #include "Document.h" |
33 | #include "Frame.h" |
34 | #include "HTMLBodyElement.h" |
35 | #include "HTMLDivElement.h" |
36 | #include "HTMLHeadElement.h" |
37 | #include "HTMLHeadingElement.h" |
38 | #include "HTMLHtmlElement.h" |
39 | #include "HTMLNames.h" |
40 | #include "HTMLParagraphElement.h" |
41 | #include "HTMLStyleElement.h" |
42 | #include "SVGNames.h" |
43 | #include "Text.h" |
44 | |
45 | namespace WebCore { |
46 | |
47 | using namespace HTMLNames; |
48 | |
49 | const int maxErrors = 25; |
50 | |
51 | XMLErrors::XMLErrors(Document& document) |
52 | : m_document(document) |
53 | { |
54 | } |
55 | |
56 | void XMLErrors::handleError(ErrorType type, const char* message, int lineNumber, int columnNumber) |
57 | { |
58 | handleError(type, message, TextPosition(OrdinalNumber::fromOneBasedInt(lineNumber), OrdinalNumber::fromOneBasedInt(columnNumber))); |
59 | } |
60 | |
61 | void XMLErrors::handleError(ErrorType type, const char* message, TextPosition position) |
62 | { |
63 | if (type == fatal || (m_errorCount < maxErrors && (!m_lastErrorPosition || (m_lastErrorPosition->m_line != position.m_line && m_lastErrorPosition->m_column != position.m_column)))) { |
64 | switch (type) { |
65 | case warning: |
66 | appendErrorMessage("warning" , position, message); |
67 | break; |
68 | case fatal: |
69 | case nonFatal: |
70 | appendErrorMessage("error" , position, message); |
71 | } |
72 | |
73 | m_lastErrorPosition = position; |
74 | ++m_errorCount; |
75 | } |
76 | } |
77 | |
78 | void XMLErrors::appendErrorMessage(const String& typeString, TextPosition position, const char* message) |
79 | { |
80 | // <typeString> on line <lineNumber> at column <columnNumber>: <message> |
81 | m_errorMessages.append(typeString); |
82 | m_errorMessages.appendLiteral(" on line " ); |
83 | m_errorMessages.appendNumber(position.m_line.oneBasedInt()); |
84 | m_errorMessages.appendLiteral(" at column " ); |
85 | m_errorMessages.appendNumber(position.m_column.oneBasedInt()); |
86 | m_errorMessages.appendLiteral(": " ); |
87 | m_errorMessages.append(message); |
88 | } |
89 | |
90 | static inline Ref<Element> (Document& document, const String& errorMessages) |
91 | { |
92 | Ref<Element> reportElement = document.createElement(QualifiedName(nullAtom(), "parsererror" , xhtmlNamespaceURI), true); |
93 | |
94 | Vector<Attribute> reportAttributes; |
95 | reportAttributes.append(Attribute(styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black" )); |
96 | reportElement->parserSetAttributes(reportAttributes); |
97 | |
98 | auto h3 = HTMLHeadingElement::create(h3Tag, document); |
99 | reportElement->parserAppendChild(h3); |
100 | h3->parserAppendChild(Text::create(document, "This page contains the following errors:"_s )); |
101 | |
102 | auto fixed = HTMLDivElement::create(document); |
103 | Vector<Attribute> fixedAttributes; |
104 | fixedAttributes.append(Attribute(styleAttr, "font-family:monospace;font-size:12px" )); |
105 | fixed->parserSetAttributes(fixedAttributes); |
106 | reportElement->parserAppendChild(fixed); |
107 | |
108 | fixed->parserAppendChild(Text::create(document, errorMessages)); |
109 | |
110 | h3 = HTMLHeadingElement::create(h3Tag, document); |
111 | reportElement->parserAppendChild(h3); |
112 | h3->parserAppendChild(Text::create(document, "Below is a rendering of the page up to the first error."_s )); |
113 | |
114 | return reportElement; |
115 | } |
116 | |
117 | void XMLErrors::insertErrorMessageBlock() |
118 | { |
119 | // One or more errors occurred during parsing of the code. Display an error block to the user above |
120 | // the normal content (the DOM tree is created manually and includes line/col info regarding |
121 | // where the errors are located) |
122 | |
123 | // Create elements for display |
124 | RefPtr<Element> documentElement = m_document.documentElement(); |
125 | if (!documentElement) { |
126 | auto rootElement = HTMLHtmlElement::create(m_document); |
127 | auto body = HTMLBodyElement::create(m_document); |
128 | rootElement->parserAppendChild(body); |
129 | m_document.parserAppendChild(rootElement); |
130 | documentElement = WTFMove(body); |
131 | } else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) { |
132 | auto rootElement = HTMLHtmlElement::create(m_document); |
133 | auto head = HTMLHeadElement::create(m_document); |
134 | auto style = HTMLStyleElement::create(m_document); |
135 | head->parserAppendChild(style); |
136 | style->parserAppendChild(m_document.createTextNode("html, body { height: 100% } parsererror + svg { width: 100%; height: 100% }"_s )); |
137 | style->finishParsingChildren(); |
138 | rootElement->parserAppendChild(head); |
139 | auto body = HTMLBodyElement::create(m_document); |
140 | rootElement->parserAppendChild(body); |
141 | |
142 | m_document.parserRemoveChild(*documentElement); |
143 | if (!documentElement->parentNode()) |
144 | body->parserAppendChild(*documentElement); |
145 | |
146 | m_document.parserAppendChild(rootElement); |
147 | |
148 | documentElement = WTFMove(body); |
149 | } |
150 | |
151 | String errorMessages = m_errorMessages.toString(); |
152 | auto reportElement = createXHTMLParserErrorHeader(m_document, errorMessages); |
153 | |
154 | #if ENABLE(XSLT) |
155 | if (m_document.transformSourceDocument()) { |
156 | Vector<Attribute> attributes; |
157 | attributes.append(Attribute(styleAttr, "white-space: normal" )); |
158 | auto paragraph = HTMLParagraphElement::create(m_document); |
159 | paragraph->parserSetAttributes(attributes); |
160 | paragraph->parserAppendChild(m_document.createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."_s )); |
161 | reportElement->parserAppendChild(paragraph); |
162 | } |
163 | #endif |
164 | |
165 | Node* firstChild = documentElement->firstChild(); |
166 | if (firstChild) |
167 | documentElement->parserInsertBefore(reportElement, *firstChild); |
168 | else |
169 | documentElement->parserAppendChild(reportElement); |
170 | |
171 | m_document.updateStyleIfNeeded(); |
172 | } |
173 | |
174 | } // namespace WebCore |
175 | |