2 * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "HTMLViewSourceDocument.h"
28 #include "Attribute.h"
29 #include "DOMImplementation.h"
30 #include "HTMLAnchorElement.h"
31 #include "HTMLBRElement.h"
32 #include "HTMLBaseElement.h"
33 #include "HTMLBodyElement.h"
34 #include "HTMLDivElement.h"
35 #include "HTMLHtmlElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLTableCellElement.h"
38 #include "HTMLTableElement.h"
39 #include "HTMLTableRowElement.h"
40 #include "HTMLTableSectionElement.h"
41 #include "HTMLToken.h"
42 #include "HTMLViewSourceParser.h"
43 #include "SegmentedString.h"
45 #include "TextViewSourceParser.h"
49 using namespace HTMLNames;
51 HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, const String& mimeType)
52 : HTMLDocument(frame, url)
55 setUsesBeforeAfterRules(true);
56 setIsViewSource(true);
58 setCompatibilityMode(QuirksMode);
59 lockCompatibilityMode();
62 PassRefPtr<DocumentParser> HTMLViewSourceDocument::createParser()
64 if (m_type == "text/html" || m_type == "application/xhtml+xml" || m_type == "image/svg+xml" || DOMImplementation::isXMLMIMEType(m_type)
66 || m_type == "application/vnd.wap.xhtml+xml"
69 return HTMLViewSourceParser::create(this);
71 return TextViewSourceParser::create(this);
74 void HTMLViewSourceDocument::createContainingTable()
76 RefPtr<HTMLHtmlElement> html = HTMLHtmlElement::create(this);
79 RefPtr<HTMLBodyElement> body = HTMLBodyElement::create(this);
80 html->parserAddChild(body);
83 // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole
85 RefPtr<HTMLDivElement> div = HTMLDivElement::create(this);
86 RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
87 attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-gutter-backdrop"));
88 div->setAttributeMap(attrs.release());
89 body->parserAddChild(div);
92 RefPtr<HTMLTableElement> table = HTMLTableElement::create(this);
93 body->parserAddChild(table);
95 m_tbody = HTMLTableSectionElement::create(tbodyTag, this);
96 table->parserAddChild(m_tbody);
101 void HTMLViewSourceDocument::addSource(const String& source, HTMLToken& token)
104 createContainingTable();
106 switch (token.type()) {
107 case HTMLTokenTypes::Uninitialized:
108 ASSERT_NOT_REACHED();
110 case HTMLTokenTypes::DOCTYPE:
111 processDoctypeToken(source, token);
113 case HTMLTokenTypes::EndOfFile:
114 if (!m_tbody->hasChildNodes())
117 case HTMLTokenTypes::StartTag:
118 case HTMLTokenTypes::EndTag:
119 processTagToken(source, token);
121 case HTMLTokenTypes::Comment:
122 processCommentToken(source, token);
124 case HTMLTokenTypes::Character:
125 processCharacterToken(source, token);
130 void HTMLViewSourceDocument::processDoctypeToken(const String& source, HTMLToken&)
133 createContainingTable();
134 m_current = addSpanWithClassName("webkit-html-doctype");
135 addText(source, "webkit-html-doctype");
139 void HTMLViewSourceDocument::processTagToken(const String& source, HTMLToken& token)
141 m_current = addSpanWithClassName("webkit-html-tag");
143 AtomicString tagName(token.name().data(), token.name().size());
146 HTMLToken::AttributeList::const_iterator iter = token.attributes().begin();
147 while (index < source.length()) {
148 if (iter == token.attributes().end()) {
149 // We want to show the remaining characters in the token.
150 index = addRange(source, index, source.length(), "");
151 ASSERT(index == source.length());
155 AtomicString name(iter->m_name.data(), iter->m_name.size());
156 String value(iter->m_value.data(), iter->m_value.size());
158 index = addRange(source, index, iter->m_nameRange.m_start - token.startIndex(), "");
159 index = addRange(source, index, iter->m_nameRange.m_end - token.startIndex(), "webkit-html-attribute-name");
161 if (tagName == baseTag && name == hrefAttr)
162 m_current = addBase(value);
164 index = addRange(source, index, iter->m_valueRange.m_start - token.startIndex(), "");
166 bool isLink = name == srcAttr || name == hrefAttr;
167 index = addRange(source, index, iter->m_valueRange.m_end - token.startIndex(), "webkit-html-attribute-value", isLink, tagName == aTag);
174 void HTMLViewSourceDocument::processCommentToken(const String& source, HTMLToken&)
176 m_current = addSpanWithClassName("webkit-html-comment");
177 addText(source, "webkit-html-comment");
181 void HTMLViewSourceDocument::processCharacterToken(const String& source, HTMLToken&)
186 PassRefPtr<Element> HTMLViewSourceDocument::addSpanWithClassName(const AtomicString& className)
188 if (m_current == m_tbody) {
193 RefPtr<HTMLElement> span = HTMLElement::create(spanTag, this);
194 RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
195 attrs->addAttribute(Attribute::createMapped(classAttr, className));
196 span->setAttributeMap(attrs.release());
197 m_current->parserAddChild(span);
199 return span.release();
202 void HTMLViewSourceDocument::addLine(const AtomicString& className)
204 // Create a table row.
205 RefPtr<HTMLTableRowElement> trow = HTMLTableRowElement::create(this);
206 m_tbody->parserAddChild(trow);
209 // Create a cell that will hold the line number (it is generated in the stylesheet using counters).
210 RefPtr<HTMLTableCellElement> td = HTMLTableCellElement::create(tdTag, this);
211 RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
212 attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-number"));
213 td->setAttributeMap(attrs.release());
214 trow->parserAddChild(td);
217 // Create a second cell for the line contents
218 td = HTMLTableCellElement::create(tdTag, this);
219 attrs = NamedNodeMap::create();
220 attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-content"));
221 td->setAttributeMap(attrs.release());
222 trow->parserAddChild(td);
224 m_current = m_td = td;
226 #ifdef DEBUG_LINE_NUMBERS
227 RefPtr<Text> lineNumberText = Text::create(this, String::number(parser()->lineNumber() + 1) + " ");
228 td->addChild(lineNumberText);
229 lineNumberText->attach();
232 // Open up the needed spans.
233 if (!className.isEmpty()) {
234 if (className == "webkit-html-attribute-name" || className == "webkit-html-attribute-value")
235 m_current = addSpanWithClassName("webkit-html-tag");
236 m_current = addSpanWithClassName(className);
240 void HTMLViewSourceDocument::finishLine()
242 if (!m_current->hasChildNodes()) {
243 RefPtr<HTMLBRElement> br = HTMLBRElement::create(this);
244 m_current->parserAddChild(br);
250 void HTMLViewSourceDocument::addText(const String& text, const AtomicString& className)
255 // Add in the content, splitting on newlines.
256 Vector<String> lines;
257 text.split('\n', true, lines);
258 unsigned size = lines.size();
259 for (unsigned i = 0; i < size; i++) {
260 String substring = lines[i];
261 if (m_current == m_tbody)
263 if (substring.isEmpty()) {
269 RefPtr<Text> t = Text::create(this, substring);
270 m_current->parserAddChild(t);
277 int HTMLViewSourceDocument::addRange(const String& source, int start, int end, const String& className, bool isLink, bool isAnchor)
279 ASSERT(start <= end);
283 String text = source.substring(start, end - start);
284 if (!className.isEmpty()) {
286 m_current = addLink(text, isAnchor);
288 m_current = addSpanWithClassName(className);
290 addText(text, className);
291 if (!className.isEmpty() && m_current != m_tbody)
292 m_current = static_cast<Element*>(m_current->parentNode());
296 PassRefPtr<Element> HTMLViewSourceDocument::addBase(const AtomicString& href)
298 RefPtr<HTMLBaseElement> base = HTMLBaseElement::create(baseTag, this);
299 RefPtr<NamedNodeMap> attributeMap = NamedNodeMap::create();
300 attributeMap->addAttribute(Attribute::createMapped(hrefAttr, href));
301 base->setAttributeMap(attributeMap.release());
302 m_current->parserAddChild(base);
304 return base.release();
307 PassRefPtr<Element> HTMLViewSourceDocument::addLink(const AtomicString& url, bool isAnchor)
309 if (m_current == m_tbody)
310 addLine("webkit-html-tag");
312 // Now create a link for the attribute value instead of a span.
313 RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(this);
314 RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
315 const char* classValue;
317 classValue = "webkit-html-attribute-value webkit-html-external-link";
319 classValue = "webkit-html-attribute-value webkit-html-resource-link";
320 attrs->addAttribute(Attribute::createMapped(classAttr, classValue));
321 attrs->addAttribute(Attribute::createMapped(targetAttr, "_blank"));
322 attrs->addAttribute(Attribute::createMapped(hrefAttr, url));
323 anchor->setAttributeMap(attrs.release());
324 m_current->parserAddChild(anchor);
326 return anchor.release();