| 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 | |