WebCore/html/HTMLViewSourceDocument.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006, 2008, 2009, 2010 Apple 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
       
     6  * are met:
       
     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.
       
    12  *
       
    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. 
       
    23  */
       
    24 
       
    25 #include "config.h"
       
    26 #include "HTMLViewSourceDocument.h"
       
    27 
       
    28 #include "Attribute.h"
       
    29 #include "DOMImplementation.h"
       
    30 #include "HTMLAnchorElement.h"
       
    31 #include "HTMLBodyElement.h"
       
    32 #include "HTMLDivElement.h"
       
    33 #include "HTMLHtmlElement.h"
       
    34 #include "HTMLNames.h"
       
    35 #include "HTMLTableCellElement.h"
       
    36 #include "HTMLTableElement.h"
       
    37 #include "HTMLTableRowElement.h"
       
    38 #include "HTMLTableSectionElement.h"
       
    39 #include "LegacyHTMLDocumentParser.h"
       
    40 #include "Text.h"
       
    41 #include "TextDocument.h"
       
    42 
       
    43 namespace WebCore {
       
    44 
       
    45 using namespace HTMLNames;
       
    46 
       
    47 HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, const String& mimeType)
       
    48     : HTMLDocument(frame, url)
       
    49     , m_type(mimeType)
       
    50 {
       
    51     setUsesBeforeAfterRules(true);
       
    52 }
       
    53 
       
    54 DocumentParser* HTMLViewSourceDocument::createParser()
       
    55 {
       
    56     // Use LegacyHTMLDocumentParser if applicable, otherwise use TextDocumentParser.
       
    57     if (m_type == "text/html" || m_type == "application/xhtml+xml" || m_type == "image/svg+xml" || DOMImplementation::isXMLMIMEType(m_type)
       
    58 #if ENABLE(XHTMLMP)
       
    59         || m_type == "application/vnd.wap.xhtml+xml"
       
    60 #endif
       
    61         ) {
       
    62         // FIXME: Should respect Settings::html5ParserEnabled()
       
    63         return new LegacyHTMLDocumentParser(this);
       
    64     }
       
    65 
       
    66     return createTextDocumentParser(this);
       
    67 }
       
    68 
       
    69 void HTMLViewSourceDocument::createContainingTable()
       
    70 {
       
    71     RefPtr<HTMLHtmlElement> html = HTMLHtmlElement::create(this);
       
    72     legacyParserAddChild(html);
       
    73     html->attach();
       
    74     RefPtr<HTMLBodyElement> body = HTMLBodyElement::create(this);
       
    75     html->legacyParserAddChild(body);
       
    76     body->attach();
       
    77     
       
    78     // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole
       
    79     // document.
       
    80     RefPtr<HTMLDivElement> div = HTMLDivElement::create(this);
       
    81     RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
       
    82     attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-gutter-backdrop"));
       
    83     div->setAttributeMap(attrs.release());
       
    84     body->legacyParserAddChild(div);
       
    85     div->attach();
       
    86 
       
    87     RefPtr<HTMLTableElement> table = HTMLTableElement::create(this);
       
    88     body->legacyParserAddChild(table);
       
    89     table->attach();
       
    90     m_tbody = HTMLTableSectionElement::create(tbodyTag, this);
       
    91     table->legacyParserAddChild(m_tbody);
       
    92     m_tbody->attach();
       
    93     m_current = m_tbody;
       
    94 }
       
    95 
       
    96 void HTMLViewSourceDocument::addViewSourceText(const String& text)
       
    97 {
       
    98     if (!m_current)
       
    99         createContainingTable();
       
   100     addText(text, "");
       
   101 }
       
   102 
       
   103 void HTMLViewSourceDocument::addViewSourceToken(Token* token)
       
   104 {
       
   105     if (!m_current)
       
   106         createContainingTable();
       
   107 
       
   108     if (token->tagName == textAtom)
       
   109         addText(token->text.get(), "");
       
   110     else if (token->tagName == commentAtom) {
       
   111         if (token->beginTag) {
       
   112             m_current = addSpanWithClassName("webkit-html-comment");
       
   113             addText(String("<!--") + token->text.get() + "-->", "webkit-html-comment");
       
   114         }
       
   115     } else {
       
   116         // Handle the tag.
       
   117         String classNameStr = "webkit-html-tag";
       
   118         m_current = addSpanWithClassName(classNameStr);
       
   119 
       
   120         String text = "<";
       
   121         if (!token->beginTag)
       
   122             text += "/";
       
   123         text += token->tagName;
       
   124         Vector<UChar>* guide = token->m_sourceInfo.get();
       
   125         if (!guide || !guide->size())
       
   126             text += ">";
       
   127 
       
   128         addText(text, classNameStr);
       
   129 
       
   130         // Walk our guide string that tells us where attribute names/values should go.
       
   131         if (guide && guide->size()) {
       
   132             unsigned size = guide->size();
       
   133             unsigned begin = 0;
       
   134             unsigned currAttr = 0;
       
   135             RefPtr<Attribute> attr = 0;
       
   136             for (unsigned i = 0; i < size; i++) {
       
   137                 if (guide->at(i) == 'a' || guide->at(i) == 'x' || guide->at(i) == 'v') {
       
   138                     // Add in the string.
       
   139                     addText(String(static_cast<UChar*>(guide->data()) + begin, i - begin), classNameStr);
       
   140                      
       
   141                     begin = i + 1;
       
   142 
       
   143                     if (guide->at(i) == 'a') {
       
   144                         if (token->attrs && currAttr < token->attrs->length())
       
   145                             attr = token->attrs->attributeItem(currAttr++);
       
   146                         else
       
   147                             attr = 0;
       
   148                     }
       
   149                     if (attr) {
       
   150                         if (guide->at(i) == 'a') {
       
   151                             String name = attr->name().toString();
       
   152                             
       
   153                             m_current = addSpanWithClassName("webkit-html-attribute-name");
       
   154                             addText(name, "webkit-html-attribute-name");
       
   155                             if (m_current != m_tbody)
       
   156                                 m_current = static_cast<Element*>(m_current->parent());
       
   157                         } else {
       
   158                             const String& value = attr->value().string();
       
   159 
       
   160                             // Compare ignoring case since LegacyHTMLDocumentParser doesn't
       
   161                             // lower names when passing in tokens to
       
   162                             // HTMLViewSourceDocument.
       
   163                             if (equalIgnoringCase(token->tagName, "base") && equalIgnoringCase(attr->name().localName(), "href")) {
       
   164                                 // Catch the href attribute in the base element.
       
   165                                 // It will be used for rendering anchors created
       
   166                                 // by addLink() below.
       
   167                                 setBaseElementURL(KURL(url(), value));
       
   168                             }
       
   169 
       
   170                             // FIXME: XML could use namespace prefixes and confuse us.
       
   171                             if (equalIgnoringCase(attr->name().localName(), "src") || equalIgnoringCase(attr->name().localName(), "href"))
       
   172                                 m_current = addLink(value, equalIgnoringCase(token->tagName, "a"));
       
   173                             else
       
   174                                 m_current = addSpanWithClassName("webkit-html-attribute-value");
       
   175                             addText(value, "webkit-html-attribute-value");
       
   176                             if (m_current != m_tbody)
       
   177                                 m_current = static_cast<Element*>(m_current->parent());
       
   178                         }
       
   179                     }
       
   180                 }
       
   181             }
       
   182             
       
   183             // Add in any string that might be left.
       
   184             if (begin < size)
       
   185                 addText(String(static_cast<UChar*>(guide->data()) + begin, size - begin), classNameStr);
       
   186 
       
   187             // Add in the end tag.
       
   188             addText(">", classNameStr);
       
   189         }
       
   190         
       
   191         m_current = m_td;
       
   192     }
       
   193 }
       
   194 
       
   195 void HTMLViewSourceDocument::addViewSourceDoctypeToken(DoctypeToken* doctypeToken)
       
   196 {
       
   197     if (!m_current)
       
   198         createContainingTable();
       
   199     m_current = addSpanWithClassName("webkit-html-doctype");
       
   200     String text = "<";
       
   201     text += String::adopt(doctypeToken->m_source);
       
   202     text += ">";
       
   203     addText(text, "webkit-html-doctype");
       
   204 }
       
   205 
       
   206 PassRefPtr<Element> HTMLViewSourceDocument::addSpanWithClassName(const String& className)
       
   207 {
       
   208     if (m_current == m_tbody) {
       
   209         addLine(className);
       
   210         return m_current;
       
   211     }
       
   212 
       
   213     RefPtr<HTMLElement> span = HTMLElement::create(spanTag, this);
       
   214     RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
       
   215     attrs->addAttribute(Attribute::createMapped(classAttr, className));
       
   216     span->setAttributeMap(attrs.release());
       
   217     m_current->legacyParserAddChild(span);
       
   218     span->attach();
       
   219     return span.release();
       
   220 }
       
   221 
       
   222 void HTMLViewSourceDocument::addLine(const String& className)
       
   223 {
       
   224     // Create a table row.
       
   225     RefPtr<HTMLTableRowElement> trow = HTMLTableRowElement::create(this);
       
   226     m_tbody->legacyParserAddChild(trow);
       
   227     trow->attach();
       
   228     
       
   229     // Create a cell that will hold the line number (it is generated in the stylesheet using counters).
       
   230     RefPtr<HTMLTableCellElement> td = HTMLTableCellElement::create(tdTag, this);
       
   231     RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
       
   232     attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-number"));
       
   233     td->setAttributeMap(attrs.release());
       
   234     trow->legacyParserAddChild(td);
       
   235     td->attach();
       
   236 
       
   237     // Create a second cell for the line contents
       
   238     td = HTMLTableCellElement::create(tdTag, this);
       
   239     attrs = NamedNodeMap::create();
       
   240     attrs->addAttribute(Attribute::createMapped(classAttr, "webkit-line-content"));
       
   241     td->setAttributeMap(attrs.release());
       
   242     trow->legacyParserAddChild(td);
       
   243     td->attach();
       
   244     m_current = m_td = td;
       
   245 
       
   246 #ifdef DEBUG_LINE_NUMBERS
       
   247     RefPtr<Text> lineNumberText = Text::create(this, String::number(parser()->lineNumber() + 1) + " ");
       
   248     td->addChild(lineNumberText);
       
   249     lineNumberText->attach();
       
   250 #endif
       
   251 
       
   252     // Open up the needed spans.
       
   253     if (!className.isEmpty()) {
       
   254         if (className == "webkit-html-attribute-name" || className == "webkit-html-attribute-value")
       
   255             m_current = addSpanWithClassName("webkit-html-tag");
       
   256         m_current = addSpanWithClassName(className);
       
   257     }
       
   258 }
       
   259 
       
   260 void HTMLViewSourceDocument::addText(const String& text, const String& className)
       
   261 {
       
   262     if (text.isEmpty())
       
   263         return;
       
   264 
       
   265     // Add in the content, splitting on newlines.
       
   266     Vector<String> lines;
       
   267     text.split('\n', true, lines);
       
   268     unsigned size = lines.size();
       
   269     for (unsigned i = 0; i < size; i++) {
       
   270         String substring = lines[i];
       
   271         if (substring.isEmpty()) {
       
   272             if (i == size - 1)
       
   273                 break;
       
   274             substring = " ";
       
   275         }
       
   276         if (m_current == m_tbody)
       
   277             addLine(className);
       
   278         RefPtr<Text> t = Text::create(this, substring);
       
   279         m_current->legacyParserAddChild(t);
       
   280         t->attach();
       
   281         if (i < size - 1)
       
   282             m_current = m_tbody;
       
   283     }
       
   284     
       
   285     // Set current to m_tbody if the last character was a newline.
       
   286     if (text[text.length() - 1] == '\n')
       
   287         m_current = m_tbody;
       
   288 }
       
   289 
       
   290 PassRefPtr<Element> HTMLViewSourceDocument::addLink(const String& url, bool isAnchor)
       
   291 {
       
   292     if (m_current == m_tbody)
       
   293         addLine("webkit-html-tag");
       
   294     
       
   295     // Now create a link for the attribute value instead of a span.
       
   296     RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(this);
       
   297     RefPtr<NamedNodeMap> attrs = NamedNodeMap::create();
       
   298     const char* classValue;
       
   299     if (isAnchor)
       
   300         classValue = "webkit-html-attribute-value webkit-html-external-link";
       
   301     else
       
   302         classValue = "webkit-html-attribute-value webkit-html-resource-link";
       
   303     attrs->addAttribute(Attribute::createMapped(classAttr, classValue));
       
   304     attrs->addAttribute(Attribute::createMapped(targetAttr, "_blank"));
       
   305     attrs->addAttribute(Attribute::createMapped(hrefAttr, url));
       
   306     anchor->setAttributeMap(attrs.release());
       
   307     m_current->legacyParserAddChild(anchor);
       
   308     anchor->attach();
       
   309     return anchor.release();
       
   310 }
       
   311 
       
   312 }