Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 #include "core/dom/Element.h" | 46 #include "core/dom/Element.h" |
| 47 #include "core/dom/Text.h" | 47 #include "core/dom/Text.h" |
| 48 #include "core/editing/MarkupAccumulator.h" | 48 #include "core/editing/MarkupAccumulator.h" |
| 49 #include "core/fetch/FontResource.h" | 49 #include "core/fetch/FontResource.h" |
| 50 #include "core/fetch/ImageResource.h" | 50 #include "core/fetch/ImageResource.h" |
| 51 #include "core/html/HTMLFrameOwnerElement.h" | 51 #include "core/html/HTMLFrameOwnerElement.h" |
| 52 #include "core/html/HTMLImageElement.h" | 52 #include "core/html/HTMLImageElement.h" |
| 53 #include "core/html/HTMLInputElement.h" | 53 #include "core/html/HTMLInputElement.h" |
| 54 #include "core/html/HTMLLinkElement.h" | 54 #include "core/html/HTMLLinkElement.h" |
| 55 #include "core/html/HTMLStyleElement.h" | 55 #include "core/html/HTMLStyleElement.h" |
| 56 #include "core/html/ImageDocument.h" | |
| 56 #include "core/html/parser/HTMLMetaCharsetParser.h" | 57 #include "core/html/parser/HTMLMetaCharsetParser.h" |
| 57 #include "core/frame/Frame.h" | 58 #include "core/frame/Frame.h" |
| 58 #include "core/page/Page.h" | 59 #include "core/page/Page.h" |
| 59 #include "core/platform/graphics/Image.h" | 60 #include "core/platform/graphics/Image.h" |
| 60 #include "core/rendering/RenderImage.h" | 61 #include "core/rendering/RenderImage.h" |
| 61 #include "core/rendering/style/StyleFetchedImage.h" | 62 #include "core/rendering/style/StyleFetchedImage.h" |
| 62 #include "core/rendering/style/StyleImage.h" | 63 #include "core/rendering/style/StyleImage.h" |
| 63 #include "platform/SerializedResource.h" | 64 #include "platform/SerializedResource.h" |
| 64 #include "wtf/text/CString.h" | 65 #include "wtf/text/CString.h" |
| 65 #include "wtf/text/StringBuilder.h" | 66 #include "wtf/text/StringBuilder.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 // FIXME: We should support all frame owners including applets. | 99 // FIXME: We should support all frame owners including applets. |
| 99 return frameOwner.hasTagName(HTMLNames::objectTag) ? HTMLNames::dataAttr : H TMLNames::srcAttr; | 100 return frameOwner.hasTagName(HTMLNames::objectTag) ? HTMLNames::dataAttr : H TMLNames::srcAttr; |
| 100 } | 101 } |
| 101 | 102 |
| 102 class SerializerMarkupAccumulator : public WebCore::MarkupAccumulator { | 103 class SerializerMarkupAccumulator : public WebCore::MarkupAccumulator { |
| 103 public: | 104 public: |
| 104 SerializerMarkupAccumulator(PageSerializer*, Document*, Vector<Node*>*); | 105 SerializerMarkupAccumulator(PageSerializer*, Document*, Vector<Node*>*); |
| 105 virtual ~SerializerMarkupAccumulator(); | 106 virtual ~SerializerMarkupAccumulator(); |
| 106 | 107 |
| 107 protected: | 108 protected: |
| 108 virtual void appendText(StringBuilder& out, Text*); | 109 virtual void appendText(StringBuilder&, Text*) OVERRIDE; |
| 109 virtual void appendElement(StringBuilder& out, Element*, Namespaces*); | 110 virtual void appendElement(StringBuilder&, Element*, Namespaces*) OVERRIDE; |
| 110 virtual void appendCustomAttributes(StringBuilder& out, Element*, Namespaces *); | 111 virtual void appendCustomAttributes(StringBuilder&, Element*, Namespaces*) O VERRIDE; |
| 111 virtual void appendEndTag(Node*); | 112 virtual void appendEndTag(Node*) OVERRIDE; |
| 112 | 113 |
| 113 private: | |
| 114 PageSerializer* m_serializer; | 114 PageSerializer* m_serializer; |
| 115 Document* m_document; | 115 Document* m_document; |
| 116 }; | 116 }; |
| 117 | 117 |
| 118 SerializerMarkupAccumulator::SerializerMarkupAccumulator(PageSerializer* seriali zer, Document* document, Vector<Node*>* nodes) | 118 SerializerMarkupAccumulator::SerializerMarkupAccumulator(PageSerializer* seriali zer, Document* document, Vector<Node*>* nodes) |
| 119 : MarkupAccumulator(nodes, ResolveAllURLs) | 119 : MarkupAccumulator(nodes, ResolveAllURLs) |
| 120 , m_serializer(serializer) | 120 , m_serializer(serializer) |
| 121 , m_document(document) | 121 , m_document(document) |
| 122 { | 122 { |
| 123 } | 123 } |
| 124 | 124 |
| 125 SerializerMarkupAccumulator::~SerializerMarkupAccumulator() | 125 SerializerMarkupAccumulator::~SerializerMarkupAccumulator() |
| 126 { | 126 { |
| 127 } | 127 } |
| 128 | 128 |
| 129 void SerializerMarkupAccumulator::appendText(StringBuilder& out, Text* text) | 129 void SerializerMarkupAccumulator::appendText(StringBuilder& result, Text* text) |
| 130 { | 130 { |
| 131 Element* parent = text->parentElement(); | 131 Element* parent = text->parentElement(); |
| 132 if (parent && !shouldIgnoreElement(parent)) | 132 if (parent && !shouldIgnoreElement(parent)) |
| 133 MarkupAccumulator::appendText(out, text); | 133 MarkupAccumulator::appendText(result, text); |
| 134 } | 134 } |
| 135 | 135 |
| 136 void SerializerMarkupAccumulator::appendElement(StringBuilder& out, Element* ele ment, Namespaces* namespaces) | 136 void SerializerMarkupAccumulator::appendElement(StringBuilder& result, Element* element, Namespaces* namespaces) |
| 137 { | 137 { |
| 138 if (!shouldIgnoreElement(element)) | 138 if (!shouldIgnoreElement(element)) |
| 139 MarkupAccumulator::appendElement(out, element, namespaces); | 139 MarkupAccumulator::appendElement(result, element, namespaces); |
| 140 | 140 |
| 141 // FIXME: Refactor MarkupAccumulator so it is easier to append an element li ke this, without special cases for XHTML | |
| 141 if (element->hasTagName(HTMLNames::headTag)) { | 142 if (element->hasTagName(HTMLNames::headTag)) { |
| 142 out.append("<meta charset=\""); | 143 result.appendLiteral("<meta charset=\""); |
| 143 out.append(m_document->charset()); | 144 result.append(m_document->charset()); |
| 144 out.append("\">"); | 145 if (m_document->isXHTMLDocument()) |
| 146 result.appendLiteral("\" />"); | |
| 147 else | |
| 148 result.appendLiteral("\">"); | |
| 145 } | 149 } |
| 146 | 150 |
| 147 // FIXME: For object (plugins) tags and video tag we could replace them by a n image of their current contents. | 151 // FIXME: For object (plugins) tags and video tag we could replace them by a n image of their current contents. |
| 148 } | 152 } |
| 149 | 153 |
| 150 void SerializerMarkupAccumulator::appendCustomAttributes(StringBuilder& out, Ele ment* element, Namespaces* namespaces) | 154 void SerializerMarkupAccumulator::appendCustomAttributes(StringBuilder& result, Element* element, Namespaces* namespaces) |
| 151 { | 155 { |
| 152 if (!element->isFrameOwnerElement()) | 156 if (!element->isFrameOwnerElement()) |
| 153 return; | 157 return; |
| 154 | 158 |
| 155 HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(element); | 159 HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(element); |
| 156 Frame* frame = frameOwner->contentFrame(); | 160 Frame* frame = frameOwner->contentFrame(); |
| 157 if (!frame) | 161 if (!frame) |
| 158 return; | 162 return; |
| 159 | 163 |
| 160 KURL url = frame->document()->url(); | 164 KURL url = frame->document()->url(); |
| 161 if (url.isValid() && !url.isBlankURL()) | 165 if (url.isValid() && !url.isBlankURL()) |
| 162 return; | 166 return; |
| 163 | 167 |
| 164 // We need to give a fake location to blank frames so they can be referenced by the serialized frame. | 168 // We need to give a fake location to blank frames so they can be referenced by the serialized frame. |
| 165 url = m_serializer->urlForBlankFrame(frame); | 169 url = m_serializer->urlForBlankFrame(frame); |
| 166 appendAttribute(out, element, Attribute(frameOwnerURLAttributeName(*frameOwn er), url.string()), namespaces); | 170 appendAttribute(result, element, Attribute(frameOwnerURLAttributeName(*frame Owner), url.string()), namespaces); |
| 167 } | 171 } |
| 168 | 172 |
| 169 void SerializerMarkupAccumulator::appendEndTag(Node* node) | 173 void SerializerMarkupAccumulator::appendEndTag(Node* node) |
| 170 { | 174 { |
| 171 if (node->isElementNode() && !shouldIgnoreElement(toElement(node))) | 175 if (node->isElementNode() && !shouldIgnoreElement(toElement(node))) |
| 172 MarkupAccumulator::appendEndTag(node); | 176 MarkupAccumulator::appendEndTag(node); |
| 173 } | 177 } |
| 174 | 178 |
| 175 PageSerializer::PageSerializer(Vector<SerializedResource>* resources) | 179 class LinkChangeSerializerMarkupAccumulator : public SerializerMarkupAccumulator { |
| 176 : m_resources(resources) | 180 public: |
| 177 , m_blankFrameCounter(0) | 181 LinkChangeSerializerMarkupAccumulator(PageSerializer*, Document*, Vector<Nod e*>*, LinkLocalPathMap*, String); |
| 182 | |
| 183 protected: | |
| 184 virtual void appendElement(StringBuilder&, Element*, Namespaces*) OVERRIDE; | |
| 185 virtual void appendAttribute(StringBuilder&, Element*, const Attribute&, Nam espaces*) OVERRIDE; | |
| 186 | |
| 187 private: | |
| 188 // local_links_ include all pair of local resource path and corresponding | |
|
abarth-chromium
2013/11/15 15:58:51
What is local_links_? Do you mean m_replaceLinks?
| |
| 189 // original link. | |
| 190 LinkLocalPathMap* m_replaceLinks; | |
| 191 String m_directoryName; | |
| 192 }; | |
| 193 | |
| 194 LinkChangeSerializerMarkupAccumulator::LinkChangeSerializerMarkupAccumulator(Pag eSerializer* serializer, Document* document, Vector<Node*>* nodes, LinkLocalPath Map* links, String directoryName) | |
| 195 : SerializerMarkupAccumulator(serializer, document, nodes) | |
| 196 , m_replaceLinks(links) | |
| 197 , m_directoryName(directoryName) | |
| 178 { | 198 { |
| 179 } | 199 } |
| 180 | 200 |
| 201 void LinkChangeSerializerMarkupAccumulator::appendElement(StringBuilder& result, Element* element, Namespaces* namespaces) | |
| 202 { | |
| 203 // FIXME: We could move the uncommenting to appendOpenTag and appendCloseTag , or just remove it | |
| 204 if (element->hasTagName(HTMLNames::baseTag)) { | |
| 205 // Comment the BASE tag when serializing dom. | |
| 206 result.append("<!--"); | |
| 207 } else if (element->hasTagName(HTMLNames::htmlTag)) { | |
| 208 // Add MOTW (Mark of the Web) declaration before html tag. | |
| 209 // See http://msdn2.microsoft.com/en-us/library/ms537628(VS.85).aspx. | |
| 210 result.append(String::format("\n<!-- saved from url=(%04d)%s -->\n", | |
| 211 static_cast<int>(m_document->url().string().utf8().length()), | |
| 212 m_document->url().string().utf8().data())); | |
| 213 } | |
| 214 | |
| 215 SerializerMarkupAccumulator::appendElement(result, element, namespaces); | |
| 216 | |
| 217 if (element->hasTagName(HTMLNames::baseTag)) { | |
| 218 // Comment the BASE tag when serializing dom. | |
| 219 result.appendLiteral("-->"); | |
| 220 | |
| 221 // FIXME: Refactor MarkupAccumulator so it is easier to append an elemen t like this, without special cases for XHTML | |
| 222 // Append a new base tag declaration. | |
| 223 result.appendLiteral("<base href=\".\""); | |
| 224 if (!m_document->baseTarget().isEmpty()) { | |
| 225 result.appendLiteral(" target=\""); | |
| 226 result.append(m_document->baseTarget()); | |
| 227 result.append('"'); | |
| 228 } | |
| 229 if (m_document->isXHTMLDocument()) | |
| 230 result.appendLiteral(" />"); | |
| 231 else | |
| 232 result.appendLiteral(">"); | |
| 233 } | |
| 234 } | |
| 235 void LinkChangeSerializerMarkupAccumulator::appendAttribute(StringBuilder& resul t, Element* element, const Attribute& attribute, Namespaces* namespaces) | |
| 236 { | |
| 237 if (m_replaceLinks && element->isURLAttribute(attribute) | |
| 238 && !element->isJavaScriptURLAttribute(attribute)) { | |
|
abarth-chromium
2013/11/15 15:58:51
You can merge these lines. There's no 80 col limi
| |
| 239 | |
| 240 String completeURL = m_document->completeURL(attribute.value()); | |
| 241 | |
| 242 if (m_replaceLinks->contains(completeURL)) { | |
| 243 // FIXME: Refactor MarkupAccumulator so it is easier to append an at tribute like this. | |
| 244 result.append(' '); | |
| 245 result.append(attribute.name().toString()); | |
| 246 result.appendLiteral("=\""); | |
| 247 if (!m_directoryName.isEmpty()) { | |
| 248 result.appendLiteral("./"); | |
| 249 result.append(m_directoryName); | |
|
abarth-chromium
2013/11/15 15:58:51
Do we need to escape the directory name at all?
| |
| 250 result.append('/'); | |
| 251 } | |
| 252 result.append(m_replaceLinks->get(completeURL)); | |
| 253 result.appendLiteral("\""); | |
| 254 return; | |
| 255 } | |
| 256 } | |
| 257 MarkupAccumulator::appendAttribute(result, element, attribute, namespaces); | |
| 258 } | |
| 259 | |
| 260 | |
|
abarth-chromium
2013/11/15 15:58:51
no need for this blank line
| |
| 261 PageSerializer::PageSerializer(Vector<SerializedResource>* resources, LinkLocalP athMap* urls, String directory) | |
| 262 : m_resources(resources) | |
| 263 , m_URLs(urls) | |
| 264 , m_directory(directory) | |
| 265 , m_blankFrameCounter(0) | |
| 266 { | |
| 267 | |
|
abarth-chromium
2013/11/15 15:58:51
ditto
| |
| 268 } | |
| 269 | |
| 181 void PageSerializer::serialize(Page* page) | 270 void PageSerializer::serialize(Page* page) |
| 182 { | 271 { |
| 183 serializeFrame(page->mainFrame()); | 272 serializeFrame(page->mainFrame()); |
| 184 } | 273 } |
| 185 | 274 |
| 186 void PageSerializer::serializeFrame(Frame* frame) | 275 void PageSerializer::serializeFrame(Frame* frame) |
| 187 { | 276 { |
| 188 Document* document = frame->document(); | 277 Document* document = frame->document(); |
| 189 KURL url = document->url(); | 278 KURL url = document->url(); |
| 190 if (!url.isValid() || url.isBlankURL()) { | 279 if (!url.isValid() || url.isBlankURL()) { |
| 191 // For blank frames we generate a fake URL so they can be referenced by their containing frame. | 280 // For blank frames we generate a fake URL so they can be referenced by their containing frame. |
| 192 url = urlForBlankFrame(frame); | 281 url = urlForBlankFrame(frame); |
| 193 } | 282 } |
| 194 | 283 |
| 195 if (m_resourceURLs.contains(url)) { | 284 if (m_resourceURLs.contains(url)) { |
| 196 // FIXME: We could have 2 frame with the same URL but which were dynamic ally changed and have now | 285 // FIXME: We could have 2 frame with the same URL but which were dynamic ally changed and have now |
| 197 // different content. So we should serialize both and somehow rename the frame src in the containing | 286 // different content. So we should serialize both and somehow rename the frame src in the containing |
| 198 // frame. Arg! | 287 // frame. Arg! |
| 199 return; | 288 return; |
| 200 } | 289 } |
| 201 | 290 |
| 291 // If frame is an image document, add the image and don't continue | |
| 292 if (document->isImageDocument()) { | |
| 293 ImageDocument* imageDocument = toImageDocument(document); | |
| 294 addImageToResources(imageDocument->cachedImage(), imageDocument->imageEl ement()->renderer(), url); | |
| 295 return; | |
| 296 } | |
| 297 | |
| 202 Vector<Node*> nodes; | 298 Vector<Node*> nodes; |
| 203 SerializerMarkupAccumulator accumulator(this, document, &nodes); | 299 OwnPtr<SerializerMarkupAccumulator> accumulator; |
| 300 if (m_URLs) | |
| 301 accumulator = adoptPtr(new LinkChangeSerializerMarkupAccumulator(this, d ocument, &nodes, m_URLs, m_directory)); | |
| 302 else | |
| 303 accumulator = adoptPtr(new SerializerMarkupAccumulator(this, document, & nodes)); | |
| 304 String text = accumulator->serializeNodes(document, IncludeNode); | |
| 204 WTF::TextEncoding textEncoding(document->charset()); | 305 WTF::TextEncoding textEncoding(document->charset()); |
| 205 CString data; | |
| 206 if (!textEncoding.isValid()) { | |
| 207 // FIXME: iframes used as images trigger this. We should deal with them correctly. | |
| 208 return; | |
| 209 } | |
| 210 String text = accumulator.serializeNodes(document, IncludeNode); | |
| 211 CString frameHTML = textEncoding.normalizeAndEncode(text, WTF::EntitiesForUn encodables); | 306 CString frameHTML = textEncoding.normalizeAndEncode(text, WTF::EntitiesForUn encodables); |
| 212 m_resources->append(SerializedResource(url, document->suggestedMIMEType(), S haredBuffer::create(frameHTML.data(), frameHTML.length()))); | 307 m_resources->append(SerializedResource(url, document->suggestedMIMEType(), S haredBuffer::create(frameHTML.data(), frameHTML.length()))); |
| 213 m_resourceURLs.add(url); | 308 m_resourceURLs.add(url); |
| 214 | 309 |
| 215 for (Vector<Node*>::iterator iter = nodes.begin(); iter != nodes.end(); ++it er) { | 310 for (Vector<Node*>::iterator iter = nodes.begin(); iter != nodes.end(); ++it er) { |
| 216 Node* node = *iter; | 311 Node* node = *iter; |
| 217 if (!node->isElementNode()) | 312 if (!node->isElementNode()) |
| 218 continue; | 313 continue; |
| 219 | 314 |
| 220 Element* element = toElement(node); | 315 Element* element = toElement(node); |
| 221 // We have to process in-line style as it might contain some resources ( typically background images). | 316 // We have to process in-line style as it might contain some resources ( typically background images). |
| 222 if (element->isStyledElement()) | 317 if (element->isStyledElement()) { |
| 223 retrieveResourcesForProperties(element->inlineStyle(), document); | 318 retrieveResourcesForProperties(element->inlineStyle(), document); |
| 319 retrieveResourcesForProperties(element->presentationAttributeStyle() , document); | |
| 320 } | |
| 224 | 321 |
| 225 if (element->hasTagName(HTMLNames::imgTag)) { | 322 if (element->hasTagName(HTMLNames::imgTag)) { |
| 226 HTMLImageElement* imageElement = toHTMLImageElement(element); | 323 HTMLImageElement* imageElement = toHTMLImageElement(element); |
| 227 KURL url = document->completeURL(imageElement->getAttribute(HTMLName s::srcAttr)); | 324 KURL url = document->completeURL(imageElement->getAttribute(HTMLName s::srcAttr)); |
| 228 ImageResource* cachedImage = imageElement->cachedImage(); | 325 ImageResource* cachedImage = imageElement->cachedImage(); |
| 229 addImageToResources(cachedImage, imageElement->renderer(), url); | 326 addImageToResources(cachedImage, imageElement->renderer(), url); |
| 230 } else if (element->hasTagName(HTMLNames::inputTag)) { | 327 } else if (element->hasTagName(HTMLNames::inputTag)) { |
| 231 HTMLInputElement* inputElement = toHTMLInputElement(element); | 328 HTMLInputElement* inputElement = toHTMLInputElement(element); |
| 232 if (inputElement->isImageButton() && inputElement->hasImageLoader()) { | 329 if (inputElement->isImageButton() && inputElement->hasImageLoader()) { |
| 233 KURL url = inputElement->src(); | 330 KURL url = inputElement->src(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 String mimeType = resource->response().mimeType(); | 401 String mimeType = resource->response().mimeType(); |
| 305 m_resources->append(SerializedResource(url, mimeType, data)); | 402 m_resources->append(SerializedResource(url, mimeType, data)); |
| 306 m_resourceURLs.add(url); | 403 m_resourceURLs.add(url); |
| 307 } | 404 } |
| 308 | 405 |
| 309 void PageSerializer::addImageToResources(ImageResource* image, RenderObject* ima geRenderer, const KURL& url) | 406 void PageSerializer::addImageToResources(ImageResource* image, RenderObject* ima geRenderer, const KURL& url) |
| 310 { | 407 { |
| 311 if (!shouldAddURL(url)) | 408 if (!shouldAddURL(url)) |
| 312 return; | 409 return; |
| 313 | 410 |
| 314 if (!image || image->image() == Image::nullImage()) | 411 if (!image || !image->hasImage() || image->image() == Image::nullImage()) |
| 315 return; | 412 return; |
| 316 | 413 |
| 317 RefPtr<SharedBuffer> data = imageRenderer ? image->imageForRenderer(imageRen derer)->data() : 0; | 414 RefPtr<SharedBuffer> data = imageRenderer ? image->imageForRenderer(imageRen derer)->data() : 0; |
| 318 if (!data) | 415 if (!data) |
| 319 data = image->image()->data(); | 416 data = image->image()->data(); |
| 320 | 417 |
| 321 addToResources(image, data, url); | 418 addToResources(image, data, url); |
| 322 } | 419 } |
| 323 | 420 |
| 324 void PageSerializer::addFontToResources(FontResource* font) | 421 void PageSerializer::addFontToResources(FontResource* font) |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 if (iter != m_blankFrameURLs.end()) | 473 if (iter != m_blankFrameURLs.end()) |
| 377 return iter->value; | 474 return iter->value; |
| 378 String url = "wyciwyg://frame/" + String::number(m_blankFrameCounter++); | 475 String url = "wyciwyg://frame/" + String::number(m_blankFrameCounter++); |
| 379 KURL fakeURL(ParsedURLString, url); | 476 KURL fakeURL(ParsedURLString, url); |
| 380 m_blankFrameURLs.add(frame, fakeURL); | 477 m_blankFrameURLs.add(frame, fakeURL); |
| 381 | 478 |
| 382 return fakeURL; | 479 return fakeURL; |
| 383 } | 480 } |
| 384 | 481 |
| 385 } | 482 } |
| OLD | NEW |