blob: 56452f12b27fec15173dbabf98842f3bd4de6796 [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
* OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/xml/parser/xml_errors.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/core/xml/document_xslt.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
const int kMaxErrors = 25;
XMLErrors::XMLErrors(Document* document)
: document_(document),
error_count_(0),
last_error_position_(TextPosition::BelowRangePosition()) {}
void XMLErrors::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
void XMLErrors::HandleError(ErrorType type,
const char* message,
int line_number,
int column_number) {
HandleError(type, message,
TextPosition(OrdinalNumber::FromOneBasedInt(line_number),
OrdinalNumber::FromOneBasedInt(column_number)));
}
void XMLErrors::HandleError(ErrorType type,
const char* message,
TextPosition position) {
if (type == kErrorTypeFatal ||
(error_count_ < kMaxErrors &&
last_error_position_.line_ != position.line_ &&
last_error_position_.column_ != position.column_)) {
switch (type) {
case kErrorTypeWarning:
AppendErrorMessage("warning", position, message);
break;
case kErrorTypeFatal:
case kErrorTypeNonFatal:
AppendErrorMessage("error", position, message);
}
last_error_position_ = position;
++error_count_;
}
}
void XMLErrors::AppendErrorMessage(const String& type_string,
TextPosition position,
const char* message) {
// <typeString> on line <lineNumber> at column <columnNumber>: <message>
error_messages_.Append(type_string);
error_messages_.Append(" on line ");
error_messages_.AppendNumber(position.line_.OneBasedInt());
error_messages_.Append(" at column ");
error_messages_.AppendNumber(position.column_.OneBasedInt());
error_messages_.Append(": ");
error_messages_.Append(message);
}
static inline Element* CreateXHTMLParserErrorHeader(
Document* doc,
const String& error_messages) {
const CreateElementFlags flags = CreateElementFlags::ByParser();
Element* report_element = doc->CreateRawElement(
QualifiedName(g_null_atom, "parsererror", html_names::xhtmlNamespaceURI),
flags);
Vector<Attribute> report_attributes;
report_attributes.push_back(Attribute(
html_names::kStyleAttr,
"display: block; white-space: pre; border: 2px solid #c77; padding: 0 "
"1em 0 1em; margin: 1em; background-color: #fdd; color: black"));
report_element->ParserSetAttributes(report_attributes);
Element* h3 = doc->CreateRawElement(html_names::kH3Tag, flags);
report_element->ParserAppendChild(h3);
h3->ParserAppendChild(
doc->createTextNode("This page contains the following errors:"));
Element* fixed = doc->CreateRawElement(html_names::kDivTag, flags);
Vector<Attribute> fixed_attributes;
fixed_attributes.push_back(Attribute(html_names::kStyleAttr,
"font-family:monospace;font-size:12px"));
fixed->ParserSetAttributes(fixed_attributes);
report_element->ParserAppendChild(fixed);
fixed->ParserAppendChild(doc->createTextNode(error_messages));
h3 = doc->CreateRawElement(html_names::kH3Tag, flags);
report_element->ParserAppendChild(h3);
h3->ParserAppendChild(doc->createTextNode(
"Below is a rendering of the page up to the first error."));
return report_element;
}
void XMLErrors::InsertErrorMessageBlock() {
// One or more errors occurred during parsing of the code. Display an error
// block to the user above the normal content (the DOM tree is created
// manually and includes line/col info regarding where the errors are located)
// Create elements for display
const CreateElementFlags flags = CreateElementFlags::ByParser();
Element* document_element = document_->documentElement();
if (!document_element) {
Element* root_element =
document_->CreateRawElement(html_names::kHTMLTag, flags);
Element* body = document_->CreateRawElement(html_names::kBodyTag, flags);
root_element->ParserAppendChild(body);
document_->ParserAppendChild(root_element);
document_element = body;
} else if (document_element->namespaceURI() == svg_names::kNamespaceURI) {
Element* root_element =
document_->CreateRawElement(html_names::kHTMLTag, flags);
Element* head = document_->CreateRawElement(html_names::kHeadTag, flags);
Element* style = document_->CreateRawElement(html_names::kStyleTag, flags);
head->ParserAppendChild(style);
style->ParserAppendChild(
document_->createTextNode("html, body { height: 100% } parsererror + "
"svg { width: 100%; height: 100% }"));
style->FinishParsingChildren();
root_element->ParserAppendChild(head);
Element* body = document_->CreateRawElement(html_names::kBodyTag, flags);
root_element->ParserAppendChild(body);
document_->ParserRemoveChild(*document_element);
body->ParserAppendChild(document_element);
document_->ParserAppendChild(root_element);
document_element = body;
}
String error_messages = error_messages_.ToString();
Element* report_element =
CreateXHTMLParserErrorHeader(document_, error_messages);
if (DocumentXSLT::HasTransformSourceDocument(*document_)) {
Vector<Attribute> attributes;
attributes.push_back(
Attribute(html_names::kStyleAttr, "white-space: normal"));
Element* paragraph = document_->CreateRawElement(html_names::kPTag, flags);
paragraph->ParserSetAttributes(attributes);
paragraph->ParserAppendChild(document_->createTextNode(
"This document was created as the result of an XSL transformation. The "
"line and column numbers given are from the transformed result."));
report_element->ParserAppendChild(paragraph);
}
Node* first_child = document_element->firstChild();
if (first_child)
document_element->ParserInsertBefore(report_element, *first_child);
else
document_element->ParserAppendChild(report_element);
// FIXME: Why do we need to call this manually?
document_->UpdateStyleAndLayoutTree();
}
} // namespace blink