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