15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/PageSerializer.h"
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "HTMLNames.h"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/CSSImageValue.h"
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/CSSImportRule.h"
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/CSSStyleRule.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/StylePropertySet.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/StyleRule.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/StyleSheetContents.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Document.h"
4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Element.h"
4353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Text.h"
4453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/MarkupAccumulator.h"
4553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLFrameOwnerElement.h"
4653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLImageElement.h"
471fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch#include "core/html/HTMLInputElement.h"
4853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLLinkElement.h"
4953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLStyleElement.h"
5053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/parser/HTMLMetaCharsetParser.h"
51e6d4491e48613634a83c1957c72759da80987961Ben Murdoch#include "core/loader/cache/ImageResource.h"
5253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Frame.h"
5353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Page.h"
545267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "core/platform/SerializedResource.h"
5553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/Image.h"
561fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch#include "core/rendering/RenderImage.h"
57e6d4491e48613634a83c1957c72759da80987961Ben Murdoch#include "core/rendering/style/StyleFetchedImage.h"
5853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/style/StyleImage.h"
5981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)#include "wtf/text/CString.h"
6081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)#include "wtf/text/StringBuilder.h"
6181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)#include "wtf/text/TextEncoding.h"
6281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)#include "wtf/text/WTFString.h"
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isCharsetSpecifyingNode(Node* node)
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!node->isHTMLElement())
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HTMLElement* element = toHTMLElement(node);
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!element->hasTagName(HTMLNames::metaTag))
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HTMLMetaCharsetParser::AttributeList attributes;
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (element->hasAttributes()) {
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = 0; i < element->attributeCount(); ++i) {
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            const Attribute* attribute = element->attributeItem(i);
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // FIXME: We should deal appropriately with the attribute if they have a namespace.
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            attributes.append(std::make_pair(attribute->name().toString(), attribute->value().string()));
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    WTF::TextEncoding textEncoding = HTMLMetaCharsetParser::encodingFromMetaAttributes(attributes);
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return textEncoding.isValid();
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool shouldIgnoreElement(Element* element)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return element->hasTagName(HTMLNames::scriptTag) || element->hasTagName(HTMLNames::noscriptTag) || isCharsetSpecifyingNode(element);
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const QualifiedName& frameOwnerURLAttributeName(const HTMLFrameOwnerElement& frameOwner)
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: We should support all frame owners including applets.
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return frameOwner.hasTagName(HTMLNames::objectTag) ? HTMLNames::dataAttr : HTMLNames::srcAttr;
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class SerializerMarkupAccumulator : public WebCore::MarkupAccumulator {
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public:
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SerializerMarkupAccumulator(PageSerializer*, Document*, Vector<Node*>*);
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    virtual ~SerializerMarkupAccumulator();
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)protected:
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    virtual void appendText(StringBuilder& out, Text*);
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    virtual void appendElement(StringBuilder& out, Element*, Namespaces*);
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    virtual void appendCustomAttributes(StringBuilder& out, Element*, Namespaces*);
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    virtual void appendEndTag(Node*);
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)private:
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PageSerializer* m_serializer;
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Document* m_document;
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)SerializerMarkupAccumulator::SerializerMarkupAccumulator(PageSerializer* serializer, Document* document, Vector<Node*>* nodes)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : MarkupAccumulator(nodes, ResolveAllURLs)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_serializer(serializer)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_document(document)
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // MarkupAccumulator does not serialize the <?xml ... line, so we add it explicitely to ensure the right encoding is specified.
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_document->isXHTMLDocument() || m_document->xmlStandalone() || m_document->isSVGDocument())
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        appendString("<?xml version=\"" + m_document->xmlVersion() + "\" encoding=\"" + m_document->charset() + "\"?>");
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)SerializerMarkupAccumulator::~SerializerMarkupAccumulator()
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void SerializerMarkupAccumulator::appendText(StringBuilder& out, Text* text)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Element* parent = text->parentElement();
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (parent && !shouldIgnoreElement(parent))
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        MarkupAccumulator::appendText(out, text);
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void SerializerMarkupAccumulator::appendElement(StringBuilder& out, Element* element, Namespaces* namespaces)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!shouldIgnoreElement(element))
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        MarkupAccumulator::appendElement(out, element, namespaces);
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (element->hasTagName(HTMLNames::headTag)) {
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out.append("<meta charset=\"");
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out.append(m_document->charset());
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out.append("\">");
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: For object (plugins) tags and video tag we could replace them by an image of their current contents.
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void SerializerMarkupAccumulator::appendCustomAttributes(StringBuilder& out, Element* element, Namespaces* namespaces)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!element->isFrameOwnerElement())
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
153926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    HTMLFrameOwnerElement* frameOwner = toFrameOwnerElement(element);
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Frame* frame = frameOwner->contentFrame();
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!frame)
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    KURL url = frame->document()->url();
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (url.isValid() && !url.isBlankURL())
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We need to give a fake location to blank frames so they can be referenced by the serialized frame.
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    url = m_serializer->urlForBlankFrame(frame);
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendAttribute(out, element, Attribute(frameOwnerURLAttributeName(*frameOwner), url.string()), namespaces);
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void SerializerMarkupAccumulator::appendEndTag(Node* node)
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (node->isElementNode() && !shouldIgnoreElement(toElement(node)))
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        MarkupAccumulator::appendEndTag(node);
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1735267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)PageSerializer::PageSerializer(Vector<SerializedResource>* resources)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_resources(resources)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_blankFrameCounter(0)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PageSerializer::serialize(Page* page)
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    serializeFrame(page->mainFrame());
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PageSerializer::serializeFrame(Frame* frame)
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Document* document = frame->document();
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    KURL url = document->url();
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!url.isValid() || url.isBlankURL()) {
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // For blank frames we generate a fake URL so they can be referenced by their containing frame.
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        url = urlForBlankFrame(frame);
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_resourceURLs.contains(url)) {
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: We could have 2 frame with the same URL but which were dynamically changed and have now
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // different content. So we should serialize both and somehow rename the frame src in the containing
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // frame. Arg!
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<Node*> nodes;
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SerializerMarkupAccumulator accumulator(this, document, &nodes);
20281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    WTF::TextEncoding textEncoding(document->charset());
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    CString data;
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!textEncoding.isValid()) {
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: iframes used as images trigger this. We should deal with them correctly.
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
20853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    String text = accumulator.serializeNodes(document->documentElement(), IncludeNode);
20902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    CString frameHTML = textEncoding.normalizeAndEncode(text, WTF::EntitiesForUnencodables);
2105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    m_resources->append(SerializedResource(url, document->suggestedMIMEType(), SharedBuffer::create(frameHTML.data(), frameHTML.length())));
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_resourceURLs.add(url);
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Vector<Node*>::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Node* node = *iter;
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!node->isElementNode())
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Element* element = toElement(node);
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // We have to process in-line style as it might contain some resources (typically background images).
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (element->isStyledElement())
221591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch            retrieveResourcesForProperties(element->inlineStyle(), document);
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (element->hasTagName(HTMLNames::imgTag)) {
224521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            HTMLImageElement* imageElement = toHTMLImageElement(element);
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            KURL url = document->completeURL(imageElement->getAttribute(HTMLNames::srcAttr));
226e6d4491e48613634a83c1957c72759da80987961Ben Murdoch            ImageResource* cachedImage = imageElement->cachedImage();
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            addImageToResources(cachedImage, imageElement->renderer(), url);
2281fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        } else if (element->hasTagName(HTMLNames::inputTag)) {
2291fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch            HTMLInputElement* inputElement = toHTMLInputElement(element);
2301fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch            if (inputElement->isImageButton() && inputElement->hasImageLoader()) {
2311fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch                KURL url = inputElement->src();
232e6d4491e48613634a83c1957c72759da80987961Ben Murdoch                ImageResource* cachedImage = inputElement->imageLoader()->image();
2331fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch                addImageToResources(cachedImage, inputElement->renderer(), url);
2341fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch            }
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else if (element->hasTagName(HTMLNames::linkTag)) {
236e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch            HTMLLinkElement* linkElement = toHTMLLinkElement(element);
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (CSSStyleSheet* sheet = linkElement->sheet()) {
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                KURL url = document->completeURL(linkElement->getAttribute(HTMLNames::hrefAttr));
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                serializeCSSStyleSheet(sheet, url);
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ASSERT(m_resourceURLs.contains(url));
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else if (element->hasTagName(HTMLNames::styleTag)) {
243591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch            HTMLStyleElement* styleElement = toHTMLStyleElement(element);
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (CSSStyleSheet* sheet = styleElement->sheet())
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                serializeCSSStyleSheet(sheet, KURL());
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Frame* childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        serializeFrame(childFrame);
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PageSerializer::serializeCSSStyleSheet(CSSStyleSheet* styleSheet, const KURL& url)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StringBuilder cssText;
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < styleSheet->length(); ++i) {
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        CSSRule* rule = styleSheet->item(i);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        String itemText = rule->cssText();
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!itemText.isEmpty()) {
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cssText.append(itemText);
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (i < styleSheet->length() - 1)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                cssText.append("\n\n");
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Document* document = styleSheet->ownerDocument();
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Some rules have resources associated with them that we need to retrieve.
266926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (rule->type() == CSSRule::IMPORT_RULE) {
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            CSSImportRule* importRule = static_cast<CSSImportRule*>(rule);
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            KURL importURL = document->completeURL(importRule->href());
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (m_resourceURLs.contains(importURL))
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            serializeCSSStyleSheet(importRule->styleSheet(), importURL);
272926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        } else if (rule->type() == CSSRule::FONT_FACE_RULE) {
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // FIXME: Add support for font face rule. It is not clear to me at this point if the actual otf/eot file can
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // be retrieved from the CSSFontFaceRule object.
2751fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        } else if (rule->type() == CSSRule::STYLE_RULE) {
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            retrieveResourcesForRule(static_cast<CSSStyleRule*>(rule)->styleRule(), document);
2771fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch        }
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (url.isValid() && !m_resourceURLs.contains(url)) {
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: We should check whether a charset has been specified and if none was found add one.
28281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)        WTF::TextEncoding textEncoding(styleSheet->contents()->charset());
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(textEncoding.isValid());
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        String textString = cssText.toString();
28502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        CString text = textEncoding.normalizeAndEncode(textString, WTF::EntitiesForUnencodables);
2865267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        m_resources->append(SerializedResource(url, String("text/css"), SharedBuffer::create(text.data(), text.length())));
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_resourceURLs.add(url);
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
291e6d4491e48613634a83c1957c72759da80987961Ben Murdochvoid PageSerializer::addImageToResources(ImageResource* image, RenderObject* imageRenderer, const KURL& url)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
29383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch    if (!url.isValid() || m_resourceURLs.contains(url) || url.protocolIsData())
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!image || image->image() == Image::nullImage())
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RefPtr<SharedBuffer> data = imageRenderer ? image->imageForRenderer(imageRenderer)->data() : 0;
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!data)
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        data = image->image()->data();
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!data) {
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LOG_ERROR("No data for image %s", url.string().utf8().data());
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String mimeType = image->response().mimeType();
3095267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    m_resources->append(SerializedResource(url, mimeType, data));
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_resourceURLs.add(url);
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PageSerializer::retrieveResourcesForRule(StyleRule* rule, Document* document)
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    retrieveResourcesForProperties(rule->properties(), document);
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void PageSerializer::retrieveResourcesForProperties(const StylePropertySet* styleDeclaration, Document* document)
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!styleDeclaration)
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The background-image and list-style-image (for ul or ol) are the CSS properties
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // that make use of images. We iterate to make sure we include any other
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // image properties there might be.
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned propertyCount = styleDeclaration->propertyCount();
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < propertyCount; ++i) {
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        RefPtr<CSSValue> cssValue = styleDeclaration->propertyAt(i).value();
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!cssValue->isImageValue())
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
332e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        CSSImageValue* imageValue = toCSSImageValue(cssValue.get());
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StyleImage* styleImage = imageValue->cachedOrPendingImage();
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Non cached-images are just place-holders and do not contain data.
335e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        if (!styleImage || !styleImage->isImageResource())
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
338e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        ImageResource* image = static_cast<StyleFetchedImage*>(styleImage)->cachedImage();
33993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        addImageToResources(image, 0, image->url());
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)KURL PageSerializer::urlForBlankFrame(Frame* frame)
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HashMap<Frame*, KURL>::iterator iter = m_blankFrameURLs.find(frame);
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (iter != m_blankFrameURLs.end())
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return iter->value;
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String url = "wyciwyg://frame/" + String::number(m_blankFrameCounter++);
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    KURL fakeURL(ParsedURLString, url);
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_blankFrameURLs.add(frame, fakeURL);
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return fakeURL;
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
356