Index: third_party/WebKit/Source/web/WebPageSerializer.cpp |
diff --git a/third_party/WebKit/Source/web/WebPageSerializer.cpp b/third_party/WebKit/Source/web/WebPageSerializer.cpp |
index c6954126ab227b4c3426e95364bc56011dc3c294..501cb39b75a8879c5e99d2228c0265b63df5b420 100644 |
--- a/third_party/WebKit/Source/web/WebPageSerializer.cpp |
+++ b/third_party/WebKit/Source/web/WebPageSerializer.cpp |
@@ -45,6 +45,7 @@ |
#include "core/page/PageSerializer.h" |
#include "platform/SerializedResource.h" |
#include "platform/mhtml/MHTMLArchive.h" |
+#include "platform/mhtml/MHTMLParser.h" |
#include "platform/weborigin/KURL.h" |
#include "public/platform/WebCString.h" |
#include "public/platform/WebString.h" |
@@ -56,6 +57,9 @@ |
#include "web/WebLocalFrameImpl.h" |
#include "web/WebPageSerializerImpl.h" |
#include "web/WebViewImpl.h" |
+#include "wtf/Assertions.h" |
+#include "wtf/HashMap.h" |
+#include "wtf/Noncopyable.h" |
#include "wtf/Vector.h" |
#include "wtf/text/StringConcatenate.h" |
@@ -63,14 +67,28 @@ namespace blink { |
namespace { |
-class MHTMLPageSerializerDelegate final : public PageSerializer::Delegate { |
+using ContentIDMap = WillBeHeapHashMap<RawPtrWillBeMember<Frame>, String>; |
+ |
+class MHTMLPageSerializerDelegate final : |
+ public NoBaseWillBeGarbageCollected<MHTMLPageSerializerDelegate>, |
+ public PageSerializer::Delegate { |
+ WTF_MAKE_NONCOPYABLE(MHTMLPageSerializerDelegate); |
public: |
- ~MHTMLPageSerializerDelegate() override; |
+ MHTMLPageSerializerDelegate(const ContentIDMap& frameToContentID); |
bool shouldIgnoreAttribute(const Attribute&) override; |
-}; |
+ bool rewriteLink(const Element&, String& rewrittenLink) override; |
+ |
+#if ENABLE(OILPAN) |
+ void trace(Visitor* visitor) { visitor->trace(m_frameToContentID); } |
+#endif |
+private: |
+ const ContentIDMap& m_frameToContentID; |
+}; |
-MHTMLPageSerializerDelegate::~MHTMLPageSerializerDelegate() |
+MHTMLPageSerializerDelegate::MHTMLPageSerializerDelegate( |
+ const ContentIDMap& frameToContentID) |
+ : m_frameToContentID(frameToContentID) |
{ |
} |
@@ -82,12 +100,62 @@ bool MHTMLPageSerializerDelegate::shouldIgnoreAttribute(const Attribute& attribu |
return attribute.localName() == HTMLNames::srcsetAttr; |
} |
-} // namespace |
+bool MHTMLPageSerializerDelegate::rewriteLink( |
+ const Element& element, |
+ String& rewrittenLink) |
+{ |
+ if (!element.isFrameOwnerElement()) |
+ return false; |
-static PassRefPtr<SharedBuffer> serializePageToMHTML(Page* page, MHTMLArchive::EncodingPolicy encodingPolicy) |
+ auto* frameOwnerElement = toHTMLFrameOwnerElement(&element); |
+ Frame* frame = frameOwnerElement->contentFrame(); |
+ if (!frame) |
+ return false; |
+ |
+ KURL cidURI = MHTMLParser::convertContentIDToURI(m_frameToContentID.get(frame)); |
+ ASSERT(cidURI.isValid()); |
+ |
+ if (isHTMLFrameElementBase(&element)) { |
+ rewrittenLink = cidURI.string(); |
+ return true; |
+ } |
+ |
+ if (isHTMLObjectElement(&element)) { |
+ Document* doc = frameOwnerElement->contentDocument(); |
+ bool isHandledBySerializer = doc->isHTMLDocument() |
+ || doc->isXHTMLDocument() || doc->isImageDocument(); |
+ if (isHandledBySerializer) { |
+ rewrittenLink = cidURI.string(); |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+ContentIDMap generateFrameContentIDs(Page* page) |
+{ |
+ ContentIDMap frameToContentID; |
+ int frameID = 0; |
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) { |
+ // TODO(lukasza): Move cid generation to the browser + use base/guid.h |
+ // (see the draft at crrev.com/1386873003). |
+ StringBuilder contentIDBuilder; |
+ contentIDBuilder.appendLiteral("<frame"); |
+ contentIDBuilder.appendNumber(frameID++); |
+ contentIDBuilder.appendLiteral("@mhtml.blink>"); |
+ |
+ frameToContentID.add(frame, contentIDBuilder.toString()); |
+ } |
+ return frameToContentID; |
+} |
+ |
+PassRefPtr<SharedBuffer> serializePageToMHTML(Page* page, MHTMLArchive::EncodingPolicy encodingPolicy) |
{ |
Vector<SerializedResource> resources; |
- PageSerializer serializer(&resources, adoptPtr(new MHTMLPageSerializerDelegate)); |
+ ContentIDMap frameToContentID = generateFrameContentIDs(page); |
+ MHTMLPageSerializerDelegate delegate(frameToContentID); |
+ PageSerializer serializer(resources, &delegate); |
RefPtr<SharedBuffer> output = SharedBuffer::create(); |
String boundary = MHTMLArchive::generateMHTMLBoundary(); |
@@ -105,9 +173,16 @@ static PassRefPtr<SharedBuffer> serializePageToMHTML(Page* page, MHTMLArchive::E |
resources.clear(); |
serializer.serializeFrame(*toLocalFrame(frame)); |
- for (const auto& resource : resources) { |
+ bool isFirstResource = true; |
+ for (const SerializedResource& resource : resources) { |
+ // Frame is the 1st resource (see PageSerializer::serializeFrame doc |
+ // comment). Frames need a Content-ID header. |
+ String contentID = isFirstResource ? frameToContentID.get(frame) : String(); |
+ |
MHTMLArchive::generateMHTMLPart( |
- boundary, encodingPolicy, resource, *output); |
+ boundary, contentID, encodingPolicy, resource, *output); |
+ |
+ isFirstResource = false; |
} |
} |
@@ -115,6 +190,8 @@ static PassRefPtr<SharedBuffer> serializePageToMHTML(Page* page, MHTMLArchive::E |
return output.release(); |
} |
+} // namespace |
+ |
WebCString WebPageSerializer::serializeToMHTML(WebView* view) |
{ |
RefPtr<SharedBuffer> mhtml = serializePageToMHTML(toWebViewImpl(view)->page(), MHTMLArchive::UseDefaultEncoding); |